src/test-driver.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 23:13:09 2008 -0400 (2008-06-20)
changeset 257 0c3db660514d
child 258 29d5002bd17f
permissions -rw-r--r--
When uniquifying properties, also sort them on the owning package.

This ensures that whenever two packages provide or (or require, obsolete
or conflict) the same property, they appear in the same order in the
propertys list of packages.
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++) {
rhughes@241
   267
		pkg = razor_set_get_package(ctx->repo_set,
rhughes@241
   268
					    ctx->remove_pkgs[i]);
rhughes@241
   269
		razor_transaction_remove_package(ctx->trans, pkg);
rhughes@241
   270
	}
rhughes@241
   271
rhughes@241
   272
	errors = razor_transaction_resolve(ctx->trans);
rhughes@241
   273
	printf("\n");
rhughes@241
   274
rhughes@241
   275
	while (ctx->n_install_pkgs--)
rhughes@241
   276
		free(ctx->install_pkgs[ctx->n_install_pkgs]);
rhughes@241
   277
	while (ctx->n_remove_pkgs--)
rhughes@241
   278
		free(ctx->remove_pkgs[ctx->n_remove_pkgs]);
rhughes@241
   279
rhughes@241
   280
	if (!errors) {
rhughes@241
   281
		struct razor_set *new;
rhughes@241
   282
		new = razor_transaction_finish(ctx->trans);
rhughes@241
   283
		ctx->system_set = new;
rhughes@241
   284
	}
rhughes@241
   285
}
rhughes@241
   286
rhughes@241
   287
static void
rhughes@241
   288
start_install_or_update(struct test_context *ctx, const char **atts)
rhughes@241
   289
{
rhughes@241
   290
	const char *name = NULL;
rhughes@241
   291
rhughes@241
   292
	get_atts(atts, "name", &name, NULL);
rhughes@241
   293
	if (!name) {
rhughes@241
   294
		fprintf(stderr, "  install/update with no name\n");
rhughes@241
   295
		exit(1);
rhughes@241
   296
	}
rhughes@241
   297
rhughes@241
   298
	ctx->install_pkgs[ctx->n_install_pkgs++] = strdup(name);
rhughes@241
   299
}
rhughes@241
   300
rhughes@241
   301
static void
rhughes@241
   302
start_remove(struct test_context *ctx, const char **atts)
rhughes@241
   303
{
rhughes@241
   304
	const char *name = NULL;
rhughes@241
   305
rhughes@241
   306
	get_atts(atts, "name", &name, NULL);
rhughes@241
   307
	if (!name) {
rhughes@241
   308
		fprintf(stderr, "  remove with no name\n");
rhughes@241
   309
		exit(1);
rhughes@241
   310
	}
rhughes@241
   311
rhughes@241
   312
	ctx->remove_pkgs[ctx->n_remove_pkgs++] = strdup(name);
rhughes@241
   313
}
rhughes@241
   314
rhughes@241
   315
static void
rhughes@241
   316
start_result(struct test_context *ctx, const char **atts)
rhughes@241
   317
{
rhughes@241
   318
	ctx->in_result = 1;
rhughes@241
   319
}
rhughes@241
   320
rhughes@241
   321
static void
rhughes@241
   322
diff_callback(const char *name,
rhughes@241
   323
	      const char *old_version,
rhughes@241
   324
	      const char *new_version,
rhughes@241
   325
	      const char *arch,
rhughes@241
   326
	      void *data)
rhughes@241
   327
{
rhughes@241
   328
	struct test_context *ctx = data;
rhughes@241
   329
rhughes@241
   330
	ctx->errors++;
rhughes@241
   331
	if (old_version) {
rhughes@241
   332
		fprintf(stderr, "  result set should not contain %s %s\n",
rhughes@241
   333
			name, old_version);
rhughes@241
   334
	} else {
rhughes@241
   335
		fprintf(stderr, "  result set should contain %s %s\n",
rhughes@241
   336
			name, new_version);
rhughes@241
   337
	}
rhughes@241
   338
}
rhughes@241
   339
rhughes@241
   340
static void
rhughes@241
   341
end_result(struct test_context *ctx)
rhughes@241
   342
{
rhughes@241
   343
	ctx->in_result = 0;
rhughes@241
   344
rhughes@241
   345
	if (ctx->result_set) {
rhughes@241
   346
		if (!ctx->system_set)
rhughes@241
   347
			ctx->system_set = razor_set_create();
rhughes@241
   348
		razor_set_diff(ctx->system_set, ctx->result_set,
rhughes@241
   349
			       diff_callback, ctx);
rhughes@241
   350
	}
rhughes@241
   351
}
rhughes@241
   352
rhughes@241
   353
static void
rhughes@241
   354
start_unsatisfiable(struct test_context *ctx, const char **atts)
rhughes@241
   355
{
rhughes@241
   356
	if (ctx->result_set) {
rhughes@241
   357
		fprintf(stderr, "Expected to fail, but didn't\n");
rhughes@241
   358
		exit(1);
rhughes@241
   359
	}
rhughes@241
   360
rhughes@241
   361
	ctx->unsat = 1;
rhughes@241
   362
}
rhughes@241
   363
rhughes@241
   364
static void
rhughes@241
   365
end_unsatisfiable(struct test_context *ctx)
rhughes@241
   366
{
rhughes@241
   367
	ctx->unsat = 0;
rhughes@241
   368
}
rhughes@241
   369
rhughes@241
   370
static void
rhughes@241
   371
start_test_element(void *data, const char *element, const char **atts)
rhughes@241
   372
{
rhughes@241
   373
	struct test_context *ctx = data;
rhughes@241
   374
rhughes@241
   375
	if (strcmp(element, "tests") == 0) {
rhughes@241
   376
		;
rhughes@241
   377
	} else if (strcmp(element, "test") == 0) {
rhughes@241
   378
		start_test(ctx, atts);
rhughes@241
   379
	} else if (strcmp(element, "set") == 0) {
rhughes@241
   380
		start_set(ctx, atts);
rhughes@241
   381
	} else if (strcmp(element, "transaction") == 0) {
rhughes@241
   382
		start_transaction(ctx, atts);
rhughes@241
   383
	} else if (strcmp(element, "install") == 0) {
rhughes@241
   384
		start_install_or_update(ctx, atts);
rhughes@241
   385
	} else if (strcmp(element, "install") == 0) {
rhughes@241
   386
		start_install_or_update(ctx, atts);
rhughes@241
   387
	} else if (strcmp(element, "remove") == 0) {
rhughes@241
   388
		start_remove(ctx, atts);
rhughes@241
   389
	} else if (strcmp(element, "result") == 0) {
rhughes@241
   390
		start_result(ctx, atts);
rhughes@241
   391
	} else if (strcmp(element, "unsatisfiable") == 0) {
rhughes@241
   392
		start_unsatisfiable(ctx, atts);
rhughes@241
   393
	} else if (strcmp(element, "package") == 0) {
rhughes@241
   394
		start_package(ctx, atts);
rhughes@241
   395
	} else if (strcmp(element, "requires") == 0) {
rhughes@241
   396
		start_property(ctx, RAZOR_PROPERTY_REQUIRES, atts);
rhughes@241
   397
	} else if (strcmp(element, "provides") == 0) {
rhughes@241
   398
		start_property(ctx, RAZOR_PROPERTY_PROVIDES, atts);
rhughes@241
   399
	} else if (strcmp(element, "conflicts") == 0) {
rhughes@241
   400
		start_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts);
rhughes@241
   401
	} else if (strcmp(element, "obsoletes") == 0) {
rhughes@241
   402
		start_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts);
rhughes@241
   403
	} else {
rhughes@241
   404
		fprintf(stderr, "Unrecognized element '%s'\n", element);
rhughes@241
   405
		exit(1);
rhughes@241
   406
	}
rhughes@241
   407
}
rhughes@241
   408
rhughes@241
   409
static void
rhughes@241
   410
end_test_element (void *data, const char *element)
rhughes@241
   411
{
rhughes@241
   412
	struct test_context *ctx = data;
rhughes@241
   413
rhughes@241
   414
	if (strcmp(element, "test") == 0) {
rhughes@241
   415
		end_test(ctx);
rhughes@241
   416
	} else if (strcmp(element, "set") == 0) {
rhughes@241
   417
		end_set(ctx);
rhughes@241
   418
	} else if (strcmp(element, "package") == 0) {
rhughes@241
   419
		end_package(ctx);
rhughes@241
   420
	} else if (strcmp(element, "transaction") == 0) {
rhughes@241
   421
		end_transaction(ctx);
rhughes@241
   422
	} else if (strcmp(element, "result") == 0) {
rhughes@241
   423
		end_result(ctx);
rhughes@241
   424
	} else if (strcmp(element, "unsatisfiable") == 0) {
rhughes@241
   425
		end_unsatisfiable(ctx);
rhughes@241
   426
	}
rhughes@241
   427
}
rhughes@241
   428
rhughes@241
   429
int main(int argc, char *argv[])
rhughes@241
   430
{
rhughes@241
   431
	struct test_context ctx;
rhughes@241
   432
	const char *test_file;
rhughes@241
   433
rhughes@241
   434
	memset(&ctx, 0, sizeof ctx);
rhughes@241
   435
rhughes@241
   436
	if (argc > 3) {
rhughes@241
   437
		fprintf(stderr, "usage: %s [-d] [TESTS-FILE]\n", argv[0]);
rhughes@241
   438
		exit(-1);
rhughes@241
   439
	}
rhughes@241
   440
rhughes@241
   441
	if (argc >= 2 && !strcmp (argv[1], "-d")) {
rhughes@241
   442
		ctx.debug = 1;
rhughes@241
   443
		argc--;
rhughes@241
   444
		argv++;
rhughes@241
   445
	}
rhughes@241
   446
	if (argc == 2)
rhughes@241
   447
		test_file = argv[1];
rhughes@241
   448
	else
rhughes@241
   449
		test_file = "test.xml";
rhughes@241
   450
rhughes@241
   451
	parse_xml_file(test_file, start_test_element, end_test_element, &ctx);
rhughes@241
   452
rhughes@241
   453
	if (ctx.errors) {
rhughes@241
   454
		fprintf(stderr, "\n%d errors\n", ctx.errors);
rhughes@241
   455
		return 1;
rhughes@241
   456
	} else
rhughes@241
   457
		return 0;
rhughes@241
   458
}