src/test-driver.c
author James Bowes <jbowes@redhat.com>
Mon Jun 23 19:58:13 2008 -0400 (2008-06-23)
changeset 274 7a86660bcc67
parent 241 c3eb520e2219
child 284 6e19775d8930
permissions -rw-r--r--
Make file listing (either per-repo or per-package) use the correct string pool
rhughes@241
     1
#include <stdio.h>
rhughes@241
     2
#include <string.h>
rhughes@241
     3
#include <stdarg.h>
rhughes@241
     4
#include <unistd.h>
rhughes@241
     5
#include <fcntl.h>
rhughes@241
     6
#include <errno.h>
rhughes@241
     7
#include <expat.h>
rhughes@241
     8
rhughes@241
     9
#include "razor.h"
rhughes@241
    10
rhughes@241
    11
#define XML_BUFFER_SIZE 4096
rhughes@241
    12
rhughes@241
    13
static void
rhughes@241
    14
parse_xml_file(const char *filename,
rhughes@241
    15
	       XML_StartElementHandler start,
rhughes@241
    16
	       XML_EndElementHandler end,
rhughes@241
    17
	       void *data)
rhughes@241
    18
{
rhughes@241
    19
	XML_Parser parser;
rhughes@241
    20
	char *buffer;
rhughes@241
    21
	int fd, len, err;
rhughes@241
    22
rhughes@241
    23
	parser = XML_ParserCreate(NULL);
rhughes@241
    24
	XML_SetElementHandler(parser, start, end);
rhughes@241
    25
	XML_SetUserData(parser, data);
rhughes@241
    26
rhughes@241
    27
	fd = open(filename, O_RDONLY);
rhughes@241
    28
	if (fd < 0) {
rhughes@241
    29
		fprintf(stderr, "failed to open %s: %m\n", filename);
rhughes@241
    30
		exit(-1);
rhughes@241
    31
	}
rhughes@241
    32
rhughes@241
    33
	while (1) {
rhughes@241
    34
		buffer = XML_GetBuffer(parser, XML_BUFFER_SIZE);
rhughes@241
    35
		len = read(fd, buffer, XML_BUFFER_SIZE);
rhughes@241
    36
		if (len == 0)
rhughes@241
    37
			break;
rhughes@241
    38
		err = XML_ParseBuffer(parser, len, len == 0);
rhughes@241
    39
		if (err == XML_STATUS_ERROR) {
rhughes@241
    40
			fprintf(stderr, "parse error at line %lu:\n%s\n",
rhughes@241
    41
				XML_GetCurrentLineNumber(parser),
rhughes@241
    42
				XML_ErrorString(XML_GetErrorCode(parser)));
rhughes@241
    43
			exit(-1);
rhughes@241
    44
		}
rhughes@241
    45
	}
rhughes@241
    46
rhughes@241
    47
	if (fd < 0) {
rhughes@241
    48
		fprintf(stderr, "read: %m\n");
rhughes@241
    49
		exit(-1);
rhughes@241
    50
	}
rhughes@241
    51
rhughes@241
    52
	close(fd);
rhughes@241
    53
}
rhughes@241
    54
rhughes@241
    55
struct test_context {
rhughes@241
    56
	struct razor_set *system_set, *repo_set, *result_set;
rhughes@241
    57
rhughes@241
    58
	struct razor_importer *importer;
rhughes@241
    59
	struct razor_set **importer_set;
rhughes@241
    60
rhughes@241
    61
	struct razor_transaction *trans;
rhughes@241
    62
rhughes@241
    63
	char *install_pkgs[3], *remove_pkgs[3];
rhughes@241
    64
	int n_install_pkgs, n_remove_pkgs;
rhughes@241
    65
rhughes@241
    66
	int unsat;
rhughes@241
    67
	int in_result;
rhughes@241
    68
rhughes@241
    69
	int debug, errors;
rhughes@241
    70
};
rhughes@241
    71
rhughes@241
    72
static void
rhughes@241
    73
get_atts(const char **atts, ...)
rhughes@241
    74
{
rhughes@241
    75
	va_list ap;
rhughes@241
    76
	const char *name, **ptr;
rhughes@241
    77
	int i;
rhughes@241
    78
rhughes@241
    79
	va_start(ap, atts);
rhughes@241
    80
	while (name = va_arg(ap, const char *), name != NULL) {
rhughes@241
    81
		ptr = va_arg(ap, const char **);
rhughes@241
    82
		*ptr = NULL;
rhughes@241
    83
		for (i = 0; atts[i]; i += 2) {
rhughes@241
    84
			if (strcmp(atts[i], name) == 0)
rhughes@241
    85
				*ptr = atts[i + 1];
rhughes@241
    86
		}
rhughes@241
    87
	}
rhughes@241
    88
	va_end(ap);
rhughes@241
    89
}
rhughes@241
    90
rhughes@241
    91
static enum razor_version_relation
rhughes@241
    92
parse_relation (const char *rel_str)
rhughes@241
    93
{
rhughes@241
    94
	if (!rel_str)
rhughes@241
    95
		return -1;
rhughes@241
    96
	if (rel_str[0] == 'L')
rhughes@241
    97
		return rel_str[1] == 'E' ? RAZOR_VERSION_LESS_OR_EQUAL : RAZOR_VERSION_LESS;
rhughes@241
    98
	else if (rel_str[0] == 'G')
rhughes@241
    99
		return rel_str[1] == 'E' ? RAZOR_VERSION_GREATER_OR_EQUAL : RAZOR_VERSION_GREATER;
rhughes@241
   100
	else if (rel_str[0] == 'E' || rel_str[1] == 'Q')
rhughes@241
   101
		return RAZOR_VERSION_EQUAL;
rhughes@241
   102
	else
rhughes@241
   103
		return -1;
rhughes@241
   104
}
rhughes@241
   105
rhughes@241
   106
static void
rhughes@241
   107
start_test(struct test_context *ctx, const char **atts)
rhughes@241
   108
{
rhughes@241
   109
	const char *name = NULL;
rhughes@241
   110
rhughes@241
   111
	get_atts(atts, "name", &name, NULL);
rhughes@241
   112
	if (!name) {
rhughes@241
   113
		fprintf(stderr, "Test with no name\n");
rhughes@241
   114
		exit(1);
rhughes@241
   115
	}
rhughes@241
   116
	printf("%s\n", name);
rhughes@241
   117
}
rhughes@241
   118
rhughes@241
   119
static void
rhughes@241
   120
end_test(struct test_context *ctx)
rhughes@241
   121
{
rhughes@241
   122
	if (ctx->system_set) {
rhughes@241
   123
		razor_set_destroy(ctx->system_set);
rhughes@241
   124
		ctx->system_set = NULL;
rhughes@241
   125
	}
rhughes@241
   126
	if (ctx->repo_set) {
rhughes@241
   127
		razor_set_destroy(ctx->repo_set);
rhughes@241
   128
		ctx->repo_set = NULL;
rhughes@241
   129
	}
rhughes@241
   130
	if (ctx->result_set) {
rhughes@241
   131
		razor_set_destroy(ctx->result_set);
rhughes@241
   132
		ctx->result_set = NULL;
rhughes@241
   133
	}
rhughes@241
   134
	if (ctx->trans) {
rhughes@241
   135
		razor_transaction_destroy(ctx->trans);
rhughes@241
   136
		ctx->trans = NULL;
rhughes@241
   137
	}
rhughes@241
   138
}
rhughes@241
   139
rhughes@241
   140
static void
rhughes@241
   141
start_set(struct test_context *ctx, const char **atts)
rhughes@241
   142
{
rhughes@241
   143
	const char *name = NULL;
rhughes@241
   144
rhughes@241
   145
	ctx->importer = razor_importer_new();
rhughes@241
   146
	get_atts(atts, "name", &name, NULL);
rhughes@241
   147
	if (!name)
rhughes@241
   148
		ctx->importer_set = &ctx->result_set;
rhughes@241
   149
	else if (!strcmp(name, "system"))
rhughes@241
   150
		ctx->importer_set = &ctx->system_set;
rhughes@241
   151
	else if (!strcmp(name, "repo"))
rhughes@241
   152
		ctx->importer_set = &ctx->repo_set;
rhughes@241
   153
	else {
rhughes@241
   154
		fprintf(stderr, "  bad set name '%s'\n", name);
rhughes@241
   155
		exit(1);
rhughes@241
   156
	}
rhughes@241
   157
}
rhughes@241
   158
rhughes@241
   159
static void
rhughes@241
   160
end_set(struct test_context *ctx)
rhughes@241
   161
{
rhughes@241
   162
	*ctx->importer_set = razor_importer_finish(ctx->importer);
rhughes@241
   163
	ctx->importer = NULL;
rhughes@241
   164
}
rhughes@241
   165
rhughes@241
   166
static void
rhughes@241
   167
start_package(struct test_context *ctx, const char **atts)
rhughes@241
   168
{
rhughes@241
   169
	const char *name = NULL, *version = NULL, *arch = NULL;
rhughes@241
   170
rhughes@241
   171
	get_atts(atts, "name", &name,
rhughes@241
   172
		 "version", &version,
rhughes@241
   173
		 "arch", &arch,
rhughes@241
   174
		 NULL);
rhughes@241
   175
rhughes@241
   176
	if (!name) {
rhughes@241
   177
		fprintf(stderr, "  package with no name\n");
rhughes@241
   178
		exit(1);
rhughes@241
   179
	}
rhughes@241
   180
rhughes@241
   181
	razor_importer_begin_package(ctx->importer, name, version, arch);
rhughes@241
   182
	razor_importer_add_property(ctx->importer, name,
rhughes@241
   183
				    RAZOR_VERSION_EQUAL, version,
rhughes@241
   184
				    RAZOR_PROPERTY_PROVIDES);
rhughes@241
   185
}
rhughes@241
   186
rhughes@241
   187
static void
rhughes@241
   188
end_package(struct test_context *ctx)
rhughes@241
   189
{
rhughes@241
   190
	razor_importer_finish_package(ctx->importer);
rhughes@241
   191
}
rhughes@241
   192
rhughes@241
   193
static void
rhughes@241
   194
add_property(struct test_context *ctx, enum razor_property_type type, const char *name, enum razor_version_relation rel, const char *version)
rhughes@241
   195
{
rhughes@241
   196
	razor_importer_add_property(ctx->importer, name,
rhughes@241
   197
				    rel, version, type);
rhughes@241
   198
}
rhughes@241
   199
rhughes@241
   200
static void
rhughes@241
   201
check_unsatisfiable_property(struct test_context *ctx,
rhughes@241
   202
			     enum razor_property_type type,
rhughes@241
   203
			     const char *name,
rhughes@241
   204
			     enum razor_version_relation rel,
rhughes@241
   205
			     const char *version)
rhughes@241
   206
{
rhughes@241
   207
	static const char *relation_string[] = { "<", "<=", "=", ">=", ">" };
rhughes@241
   208
rhughes@241
   209
	if (!version)
rhughes@241
   210
		version = "";
rhughes@241
   211
rhughes@241
   212
	if (razor_transaction_unsatisfied_property(ctx->trans,
rhughes@241
   213
						   name, rel, version, type))
rhughes@241
   214
		return;
rhughes@241
   215
rhughes@241
   216
	fprintf(stderr, "  didn't get unsatisfiable '%s %s %s'\n",
rhughes@241
   217
		name, relation_string[rel], version);
rhughes@241
   218
	ctx->errors++;
rhughes@241
   219
}
rhughes@241
   220
rhughes@241
   221
static void
rhughes@241
   222
start_property(struct test_context *ctx, enum razor_property_type type, const char **atts)
rhughes@241
   223
{
rhughes@241
   224
	const char *name = NULL, *rel_str = NULL, *version = NULL;
rhughes@241
   225
	enum razor_version_relation rel;
rhughes@241
   226
rhughes@241
   227
	get_atts(atts, "name", &name, "relation", &rel_str, "version", &version, NULL);
rhughes@241
   228
	if (name == NULL) {
rhughes@241
   229
		fprintf(stderr, "  no name specified for property\n");
rhughes@241
   230
		exit(1);
rhughes@241
   231
	}
rhughes@241
   232
	if (version) {
rhughes@241
   233
		rel = parse_relation(rel_str);
rhughes@241
   234
		if (rel == -1) {
rhughes@241
   235
			fprintf(stderr, "  bad or missing version relation for property %s\n", name);
rhughes@241
   236
			exit(1);
rhughes@241
   237
		}
rhughes@241
   238
	} else
rhughes@241
   239
		rel = RAZOR_VERSION_EQUAL;
rhughes@241
   240
rhughes@241
   241
	if (ctx->unsat)
rhughes@241
   242
		check_unsatisfiable_property(ctx, type, name, rel, version);
rhughes@241
   243
	else
rhughes@241
   244
		add_property(ctx, type, name, rel, version);
rhughes@241
   245
}
rhughes@241
   246
rhughes@241
   247
static void
rhughes@241
   248
start_transaction(struct test_context *ctx, const char **atts)
rhughes@241
   249
{
rhughes@241
   250
	ctx->n_install_pkgs = 0;
rhughes@241
   251
	ctx->n_remove_pkgs = 0;
rhughes@241
   252
}
rhughes@241
   253
rhughes@241
   254
static void
rhughes@241
   255
end_transaction(struct test_context *ctx)
rhughes@241
   256
{
rhughes@241
   257
	struct razor_package *pkg;
rhughes@241
   258
	int errors, i;
rhughes@241
   259
rhughes@241
   260
	ctx->trans = razor_transaction_create(ctx->system_set, ctx->repo_set);
rhughes@241
   261
	for (i = 0; i < ctx->n_install_pkgs; i++) {
rhughes@241
   262
		pkg = razor_set_get_package(ctx->repo_set,
rhughes@241
   263
					    ctx->install_pkgs[i]);
rhughes@241
   264
		razor_transaction_install_package(ctx->trans, pkg);
rhughes@241
   265
	}
rhughes@241
   266
	for (i = 0; i < ctx->n_remove_pkgs; i++) {
jbowes@258
   267
		pkg = razor_set_get_package(ctx->system_set,
rhughes@241
   268
					    ctx->remove_pkgs[i]);
jbowes@258
   269
		if (!pkg)
jbowes@258
   270
			pkg = razor_set_get_package(ctx->repo_set,
jbowes@258
   271
						    ctx->remove_pkgs[i]);
jbowes@258
   272
rhughes@241
   273
		razor_transaction_remove_package(ctx->trans, pkg);
rhughes@241
   274
	}
rhughes@241
   275
rhughes@241
   276
	errors = razor_transaction_resolve(ctx->trans);
rhughes@241
   277
	printf("\n");
rhughes@241
   278
rhughes@241
   279
	while (ctx->n_install_pkgs--)
rhughes@241
   280
		free(ctx->install_pkgs[ctx->n_install_pkgs]);
rhughes@241
   281
	while (ctx->n_remove_pkgs--)
rhughes@241
   282
		free(ctx->remove_pkgs[ctx->n_remove_pkgs]);
rhughes@241
   283
rhughes@241
   284
	if (!errors) {
rhughes@241
   285
		struct razor_set *new;
rhughes@241
   286
		new = razor_transaction_finish(ctx->trans);
jbowes@258
   287
		ctx->trans = NULL;
rhughes@241
   288
		ctx->system_set = new;
rhughes@241
   289
	}
rhughes@241
   290
}
rhughes@241
   291
rhughes@241
   292
static void
rhughes@241
   293
start_install_or_update(struct test_context *ctx, const char **atts)
rhughes@241
   294
{
rhughes@241
   295
	const char *name = NULL;
rhughes@241
   296
rhughes@241
   297
	get_atts(atts, "name", &name, NULL);
rhughes@241
   298
	if (!name) {
rhughes@241
   299
		fprintf(stderr, "  install/update with no name\n");
rhughes@241
   300
		exit(1);
rhughes@241
   301
	}
rhughes@241
   302
rhughes@241
   303
	ctx->install_pkgs[ctx->n_install_pkgs++] = strdup(name);
rhughes@241
   304
}
rhughes@241
   305
rhughes@241
   306
static void
rhughes@241
   307
start_remove(struct test_context *ctx, const char **atts)
rhughes@241
   308
{
rhughes@241
   309
	const char *name = NULL;
rhughes@241
   310
rhughes@241
   311
	get_atts(atts, "name", &name, NULL);
rhughes@241
   312
	if (!name) {
rhughes@241
   313
		fprintf(stderr, "  remove with no name\n");
rhughes@241
   314
		exit(1);
rhughes@241
   315
	}
rhughes@241
   316
rhughes@241
   317
	ctx->remove_pkgs[ctx->n_remove_pkgs++] = strdup(name);
rhughes@241
   318
}
rhughes@241
   319
rhughes@241
   320
static void
rhughes@241
   321
start_result(struct test_context *ctx, const char **atts)
rhughes@241
   322
{
rhughes@241
   323
	ctx->in_result = 1;
rhughes@241
   324
}
rhughes@241
   325
rhughes@241
   326
static void
rhughes@241
   327
diff_callback(const char *name,
rhughes@241
   328
	      const char *old_version,
rhughes@241
   329
	      const char *new_version,
rhughes@241
   330
	      const char *arch,
rhughes@241
   331
	      void *data)
rhughes@241
   332
{
rhughes@241
   333
	struct test_context *ctx = data;
rhughes@241
   334
rhughes@241
   335
	ctx->errors++;
rhughes@241
   336
	if (old_version) {
rhughes@241
   337
		fprintf(stderr, "  result set should not contain %s %s\n",
rhughes@241
   338
			name, old_version);
rhughes@241
   339
	} else {
rhughes@241
   340
		fprintf(stderr, "  result set should contain %s %s\n",
rhughes@241
   341
			name, new_version);
rhughes@241
   342
	}
rhughes@241
   343
}
rhughes@241
   344
rhughes@241
   345
static void
rhughes@241
   346
end_result(struct test_context *ctx)
rhughes@241
   347
{
rhughes@241
   348
	ctx->in_result = 0;
rhughes@241
   349
rhughes@241
   350
	if (ctx->result_set) {
rhughes@241
   351
		if (!ctx->system_set)
rhughes@241
   352
			ctx->system_set = razor_set_create();
rhughes@241
   353
		razor_set_diff(ctx->system_set, ctx->result_set,
rhughes@241
   354
			       diff_callback, ctx);
rhughes@241
   355
	}
rhughes@241
   356
}
rhughes@241
   357
rhughes@241
   358
static void
rhughes@241
   359
start_unsatisfiable(struct test_context *ctx, const char **atts)
rhughes@241
   360
{
rhughes@241
   361
	if (ctx->result_set) {
rhughes@241
   362
		fprintf(stderr, "Expected to fail, but didn't\n");
rhughes@241
   363
		exit(1);
rhughes@241
   364
	}
rhughes@241
   365
rhughes@241
   366
	ctx->unsat = 1;
rhughes@241
   367
}
rhughes@241
   368
rhughes@241
   369
static void
rhughes@241
   370
end_unsatisfiable(struct test_context *ctx)
rhughes@241
   371
{
rhughes@241
   372
	ctx->unsat = 0;
rhughes@241
   373
}
rhughes@241
   374
rhughes@241
   375
static void
rhughes@241
   376
start_test_element(void *data, const char *element, const char **atts)
rhughes@241
   377
{
rhughes@241
   378
	struct test_context *ctx = data;
rhughes@241
   379
rhughes@241
   380
	if (strcmp(element, "tests") == 0) {
rhughes@241
   381
		;
rhughes@241
   382
	} else if (strcmp(element, "test") == 0) {
rhughes@241
   383
		start_test(ctx, atts);
rhughes@241
   384
	} else if (strcmp(element, "set") == 0) {
rhughes@241
   385
		start_set(ctx, atts);
rhughes@241
   386
	} else if (strcmp(element, "transaction") == 0) {
rhughes@241
   387
		start_transaction(ctx, atts);
rhughes@241
   388
	} else if (strcmp(element, "install") == 0) {
rhughes@241
   389
		start_install_or_update(ctx, atts);
rhughes@241
   390
	} else if (strcmp(element, "install") == 0) {
rhughes@241
   391
		start_install_or_update(ctx, atts);
rhughes@241
   392
	} else if (strcmp(element, "remove") == 0) {
rhughes@241
   393
		start_remove(ctx, atts);
rhughes@241
   394
	} else if (strcmp(element, "result") == 0) {
rhughes@241
   395
		start_result(ctx, atts);
rhughes@241
   396
	} else if (strcmp(element, "unsatisfiable") == 0) {
rhughes@241
   397
		start_unsatisfiable(ctx, atts);
rhughes@241
   398
	} else if (strcmp(element, "package") == 0) {
rhughes@241
   399
		start_package(ctx, atts);
rhughes@241
   400
	} else if (strcmp(element, "requires") == 0) {
rhughes@241
   401
		start_property(ctx, RAZOR_PROPERTY_REQUIRES, atts);
rhughes@241
   402
	} else if (strcmp(element, "provides") == 0) {
rhughes@241
   403
		start_property(ctx, RAZOR_PROPERTY_PROVIDES, atts);
rhughes@241
   404
	} else if (strcmp(element, "conflicts") == 0) {
rhughes@241
   405
		start_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts);
rhughes@241
   406
	} else if (strcmp(element, "obsoletes") == 0) {
rhughes@241
   407
		start_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts);
rhughes@241
   408
	} else {
rhughes@241
   409
		fprintf(stderr, "Unrecognized element '%s'\n", element);
rhughes@241
   410
		exit(1);
rhughes@241
   411
	}
rhughes@241
   412
}
rhughes@241
   413
rhughes@241
   414
static void
rhughes@241
   415
end_test_element (void *data, const char *element)
rhughes@241
   416
{
rhughes@241
   417
	struct test_context *ctx = data;
rhughes@241
   418
rhughes@241
   419
	if (strcmp(element, "test") == 0) {
rhughes@241
   420
		end_test(ctx);
rhughes@241
   421
	} else if (strcmp(element, "set") == 0) {
rhughes@241
   422
		end_set(ctx);
rhughes@241
   423
	} else if (strcmp(element, "package") == 0) {
rhughes@241
   424
		end_package(ctx);
rhughes@241
   425
	} else if (strcmp(element, "transaction") == 0) {
rhughes@241
   426
		end_transaction(ctx);
rhughes@241
   427
	} else if (strcmp(element, "result") == 0) {
rhughes@241
   428
		end_result(ctx);
rhughes@241
   429
	} else if (strcmp(element, "unsatisfiable") == 0) {
rhughes@241
   430
		end_unsatisfiable(ctx);
rhughes@241
   431
	}
rhughes@241
   432
}
rhughes@241
   433
rhughes@241
   434
int main(int argc, char *argv[])
rhughes@241
   435
{
rhughes@241
   436
	struct test_context ctx;
rhughes@241
   437
	const char *test_file;
rhughes@241
   438
rhughes@241
   439
	memset(&ctx, 0, sizeof ctx);
rhughes@241
   440
rhughes@241
   441
	if (argc > 3) {
rhughes@241
   442
		fprintf(stderr, "usage: %s [-d] [TESTS-FILE]\n", argv[0]);
rhughes@241
   443
		exit(-1);
rhughes@241
   444
	}
rhughes@241
   445
rhughes@241
   446
	if (argc >= 2 && !strcmp (argv[1], "-d")) {
rhughes@241
   447
		ctx.debug = 1;
rhughes@241
   448
		argc--;
rhughes@241
   449
		argv++;
rhughes@241
   450
	}
rhughes@241
   451
	if (argc == 2)
rhughes@241
   452
		test_file = argv[1];
rhughes@241
   453
	else
rhughes@241
   454
		test_file = "test.xml";
rhughes@241
   455
rhughes@241
   456
	parse_xml_file(test_file, start_test_element, end_test_element, &ctx);
rhughes@241
   457
rhughes@241
   458
	if (ctx.errors) {
rhughes@241
   459
		fprintf(stderr, "\n%d errors\n", ctx.errors);
rhughes@241
   460
		return 1;
rhughes@241
   461
	} else
rhughes@241
   462
		return 0;
rhughes@241
   463
}