test-driver.c
author Dan Winship <danw@gnome.org>
Fri Feb 29 11:51:58 2008 -0500 (2008-02-29)
changeset 136 eef2b734f2cc
parent 129 d221757574c1
child 137 4722cd3437cb
permissions -rw-r--r--
use -Wmissing-prototypes to help find dead code

(by forcing us to declare functions static, allowing gcc to tell us
"warning: foo defined by not used")
krh@80
     1
#include <stdio.h>
krh@80
     2
#include <string.h>
krh@80
     3
#include <stdarg.h>
krh@80
     4
#include <unistd.h>
krh@80
     5
#include <fcntl.h>
krh@80
     6
#include <errno.h>
krh@80
     7
#include <expat.h>
krh@80
     8
krh@80
     9
#include "razor.h"
krh@80
    10
krh@80
    11
#define XML_BUFFER_SIZE 4096
krh@80
    12
krh@80
    13
static void
krh@80
    14
parse_xml_file(const char *filename,
krh@80
    15
	       XML_StartElementHandler start,
krh@80
    16
	       XML_EndElementHandler end,
krh@80
    17
	       void *data)
krh@80
    18
{
krh@80
    19
	XML_Parser parser;
krh@80
    20
	char *buffer;
krh@80
    21
	int fd, len, err;
krh@80
    22
krh@80
    23
	parser = XML_ParserCreate(NULL);
krh@80
    24
	XML_SetElementHandler(parser, start, end);
krh@80
    25
	XML_SetUserData(parser, data);
krh@80
    26
krh@80
    27
	buffer = XML_GetBuffer(parser, XML_BUFFER_SIZE);
krh@80
    28
krh@80
    29
	fd = open(filename, O_RDONLY);
krh@80
    30
	if (fd < 0) {
krh@92
    31
		fprintf(stderr, "failed to open %s: %m\n", filename);
krh@80
    32
		exit(-1);
krh@80
    33
	}
krh@80
    34
krh@80
    35
	while (len = read(fd, buffer, XML_BUFFER_SIZE), len > 0) {
krh@80
    36
		err = XML_ParseBuffer(parser, len, len == 0);
krh@80
    37
		if (err == XML_STATUS_ERROR) {
krh@80
    38
			fprintf(stderr, "parse error at line %lu:\n%s\n",
krh@80
    39
				XML_GetCurrentLineNumber(parser),
krh@80
    40
				XML_ErrorString(XML_GetErrorCode(parser)));
krh@80
    41
			exit(-1);
krh@80
    42
		}
krh@80
    43
	}
krh@80
    44
krh@80
    45
	if (fd < 0) {
krh@80
    46
		fprintf(stderr, "read: %m\n");
krh@80
    47
		exit(-1);
krh@80
    48
	}
krh@80
    49
krh@80
    50
	close(fd);
krh@80
    51
}
krh@80
    52
danw@125
    53
struct test_context {
danw@125
    54
	struct razor_set *system_set, *repo_set, *result_set;
krh@80
    55
krh@80
    56
	struct razor_importer *importer;
danw@125
    57
	struct razor_set **importer_set;
danw@125
    58
danw@125
    59
	char *install_pkgs[3], *remove_pkgs[3];
danw@125
    60
	int n_install_pkgs, n_remove_pkgs;
danw@125
    61
danw@125
    62
	int in_result, result_errors;
danw@131
    63
	int in_unsatisfiable;
krh@80
    64
};
krh@80
    65
krh@80
    66
static void
krh@80
    67
get_atts(const char **atts, ...)
krh@80
    68
{
krh@80
    69
	va_list ap;
krh@80
    70
	const char *name, **ptr;
krh@80
    71
	int i;
krh@80
    72
krh@80
    73
	va_start(ap, atts);
krh@80
    74
	while (name = va_arg(ap, const char *), name != NULL) {
krh@80
    75
		ptr = va_arg(ap, const char **);
krh@92
    76
		*ptr = NULL;
krh@80
    77
		for (i = 0; atts[i]; i += 2) {
krh@80
    78
			if (strcmp(atts[i], name) == 0)
krh@80
    79
				*ptr = atts[i + 1];
krh@80
    80
		}
krh@80
    81
	}
krh@80
    82
	va_end(ap);
krh@80
    83
}
krh@80
    84
danw@125
    85
static enum razor_version_relation
danw@125
    86
parse_relation (const char *rel_str)
krh@80
    87
{
danw@125
    88
	if (!rel_str)
danw@125
    89
		return -1;
danw@125
    90
	if (rel_str[0] == 'l')
danw@125
    91
		return rel_str[1] == 'e' ? RAZOR_VERSION_LESS_OR_EQUAL : RAZOR_VERSION_LESS;
danw@125
    92
	else if (rel_str[0] == 'g')
danw@125
    93
		return rel_str[1] == 'e' ? RAZOR_VERSION_GREATER_OR_EQUAL : RAZOR_VERSION_GREATER;
danw@125
    94
	else if (rel_str[0] == 'e' || rel_str[1] == 'q')
danw@125
    95
		return RAZOR_VERSION_EQUAL;
danw@125
    96
	else
danw@125
    97
		return -1;
krh@80
    98
}
krh@80
    99
krh@80
   100
static void
danw@125
   101
start_test(struct test_context *ctx, const char **atts)
krh@80
   102
{
danw@125
   103
	const char *name = NULL;
krh@80
   104
danw@125
   105
	get_atts(atts, "name", &name, NULL);
danw@125
   106
	if (!name) {
danw@125
   107
		fprintf(stderr, "Test with no name\n");
danw@125
   108
		exit(1);
danw@125
   109
	}
danw@125
   110
	printf("%s\n", name);
danw@125
   111
}
danw@125
   112
danw@125
   113
static void
danw@125
   114
end_test(struct test_context *ctx)
danw@125
   115
{
danw@125
   116
	if (ctx->system_set) {
danw@125
   117
		razor_set_destroy(ctx->system_set);
danw@125
   118
		ctx->system_set = NULL;
danw@125
   119
	}
danw@125
   120
	if (ctx->repo_set) {
danw@125
   121
		razor_set_destroy(ctx->repo_set);
danw@125
   122
		ctx->repo_set = NULL;
danw@125
   123
	}
danw@125
   124
	if (ctx->result_set) {
danw@125
   125
		razor_set_destroy(ctx->result_set);
danw@125
   126
		ctx->result_set = NULL;
krh@80
   127
	}
krh@80
   128
}
krh@80
   129
krh@80
   130
static void
danw@125
   131
start_set(struct test_context *ctx, const char **atts)
krh@80
   132
{
danw@125
   133
	const char *name = NULL;
krh@80
   134
danw@125
   135
	ctx->importer = razor_importer_new();
danw@125
   136
	get_atts(atts, "name", &name, NULL);
danw@125
   137
	if (!name)
danw@125
   138
		ctx->importer_set = &ctx->result_set;
danw@125
   139
	else if (!strcmp(name, "system"))
danw@125
   140
		ctx->importer_set = &ctx->system_set;
danw@125
   141
	else if (!strcmp(name, "repo"))
danw@125
   142
		ctx->importer_set = &ctx->repo_set;
danw@125
   143
	else {
danw@125
   144
		fprintf(stderr, "  bad set name '%s'\n", name);
danw@125
   145
		exit(1);
krh@92
   146
	}
krh@92
   147
}
krh@92
   148
krh@92
   149
static void
danw@125
   150
end_set(struct test_context *ctx)
krh@92
   151
{
danw@125
   152
	*ctx->importer_set = razor_importer_finish(ctx->importer);
danw@125
   153
	ctx->importer = NULL;
danw@125
   154
}
krh@92
   155
danw@125
   156
static void
danw@125
   157
start_package(struct test_context *ctx, const char **atts)
danw@125
   158
{
danw@125
   159
	const char *name = NULL, *version = NULL, *arch = NULL;
danw@125
   160
danw@125
   161
	get_atts(atts, "name", &name, "version", &version, "arch", &arch, NULL);
danw@125
   162
	if (!name) {
danw@125
   163
		fprintf(stderr, "  package with no name\n");
danw@125
   164
		exit(1);
krh@92
   165
	}
krh@92
   166
danw@125
   167
	razor_importer_begin_package(ctx->importer, name, version);
danw@125
   168
	razor_importer_add_property(ctx->importer, name,
danw@125
   169
				    RAZOR_VERSION_EQUAL, version,
danw@125
   170
				    RAZOR_PROPERTY_PROVIDES);
danw@125
   171
}
danw@125
   172
danw@125
   173
static void
danw@125
   174
end_package(struct test_context *ctx)
danw@125
   175
{
danw@125
   176
	razor_importer_finish_package(ctx->importer);
danw@125
   177
}
danw@125
   178
danw@125
   179
static void
danw@125
   180
start_property(struct test_context *ctx, enum razor_property_type type, const char **atts)
danw@125
   181
{
danw@125
   182
	const char *name = NULL, *rel_str = NULL, *version = NULL;
danw@125
   183
	enum razor_version_relation rel;
danw@125
   184
danw@131
   185
	if (ctx->in_unsatisfiable)
danw@131
   186
		return;
danw@131
   187
danw@125
   188
	get_atts(atts, "name", &name, "rel", &rel_str, "version", &version, NULL);
danw@125
   189
	if (name == NULL) {
danw@125
   190
		fprintf(stderr, "  no name specified for property\n");
danw@125
   191
		exit(1);
danw@125
   192
	}
danw@125
   193
	if (version) {
danw@125
   194
		rel = parse_relation(rel_str);
danw@125
   195
		if (rel == -1) {
danw@125
   196
			fprintf(stderr, "  bad or missing version relation for property %s\n", name);
danw@125
   197
			exit(1);
krh@92
   198
		}
danw@125
   199
	} else
danw@125
   200
		rel = RAZOR_VERSION_EQUAL;
danw@125
   201
	
danw@125
   202
	razor_importer_add_property(ctx->importer, name,
danw@125
   203
				    rel, version, type);
danw@125
   204
}
krh@92
   205
danw@125
   206
static void
danw@125
   207
start_transaction(struct test_context *ctx, const char **atts)
danw@125
   208
{
danw@125
   209
	ctx->n_install_pkgs = 0;
danw@125
   210
	ctx->n_remove_pkgs = 0;
danw@125
   211
}
danw@125
   212
danw@125
   213
static void
danw@125
   214
end_transaction(struct test_context *ctx)
danw@125
   215
{
danw@131
   216
	if (ctx->n_install_pkgs) {
danw@131
   217
		ctx->system_set = razor_set_update(ctx->system_set,
danw@131
   218
						   ctx->repo_set,
danw@131
   219
						   ctx->n_install_pkgs,
danw@131
   220
						   (const char **)ctx->install_pkgs);
danw@131
   221
	}
danw@131
   222
	if (ctx->n_remove_pkgs && ctx->system_set) {
danw@131
   223
		ctx->system_set = razor_set_remove(ctx->system_set,
danw@131
   224
						   ctx->n_remove_pkgs,
danw@131
   225
						   (const char **)ctx->remove_pkgs);
danw@131
   226
	}
danw@125
   227
danw@125
   228
	while (ctx->n_install_pkgs--)
danw@125
   229
		free(ctx->install_pkgs[ctx->n_install_pkgs]);
danw@125
   230
	while (ctx->n_remove_pkgs--)
danw@125
   231
		free(ctx->remove_pkgs[ctx->n_remove_pkgs]);
danw@125
   232
}
danw@125
   233
danw@125
   234
static void
danw@125
   235
start_install_or_update(struct test_context *ctx, const char **atts)
danw@125
   236
{
danw@125
   237
	const char *name = NULL;
danw@125
   238
danw@125
   239
	get_atts(atts, "name", &name, NULL);
danw@125
   240
	if (!name) {
danw@125
   241
		fprintf(stderr, "  install/update with no name\n");
danw@125
   242
		exit(1);
danw@125
   243
	}
danw@125
   244
danw@125
   245
	ctx->install_pkgs[ctx->n_install_pkgs++] = strdup(name);
danw@125
   246
}
danw@125
   247
danw@125
   248
static void
danw@125
   249
start_remove(struct test_context *ctx, const char **atts)
danw@125
   250
{
danw@125
   251
	const char *name = NULL;
danw@125
   252
danw@125
   253
	get_atts(atts, "name", &name, NULL);
danw@125
   254
	if (!name) {
danw@125
   255
		fprintf(stderr, "  remove with no name\n");
danw@125
   256
		exit(1);
danw@125
   257
	}
danw@125
   258
danw@125
   259
	ctx->remove_pkgs[ctx->n_remove_pkgs++] = strdup(name);
danw@125
   260
}
danw@125
   261
danw@125
   262
static void
danw@125
   263
start_result(struct test_context *ctx, const char **atts)
danw@125
   264
{
danw@125
   265
	ctx->in_result = 1;
danw@125
   266
}
danw@125
   267
danw@125
   268
static void
danw@125
   269
diff_callback(const char *name,
danw@125
   270
	      const char *old_version, const char *new_version,
danw@125
   271
	      void *data)
danw@125
   272
{
danw@125
   273
	struct test_context *ctx = data;
danw@125
   274
danw@125
   275
	ctx->result_errors++;
danw@125
   276
	if (old_version) {
danw@125
   277
		fprintf(stderr, "  result set should not contain %s %s\n",
danw@125
   278
			name, old_version);
danw@125
   279
	} else {
danw@125
   280
		fprintf(stderr, "  result set should contain %s %s\n",
danw@125
   281
			name, new_version);
krh@92
   282
	}
krh@92
   283
}
krh@92
   284
krh@92
   285
static void
danw@125
   286
end_result(struct test_context *ctx)
krh@92
   287
{
danw@125
   288
	ctx->in_result = 0;
krh@92
   289
danw@131
   290
	if (ctx->result_set) {
danw@131
   291
		if (!ctx->system_set)
danw@131
   292
			ctx->system_set = razor_set_create();
danw@125
   293
		ctx->result_errors = 0;
danw@125
   294
		razor_set_diff(ctx->system_set, ctx->result_set,
danw@125
   295
			       diff_callback, ctx);
danw@125
   296
		if (ctx->result_errors)
danw@125
   297
			exit(1);
krh@92
   298
	}
krh@92
   299
}
krh@92
   300
krh@92
   301
static void
danw@131
   302
start_unsatisfiable(struct test_context *ctx, const char **atts)
krh@92
   303
{
danw@131
   304
	if (ctx->system_set) {
danw@131
   305
		fprintf(stderr, "Expected to fail, but didn't\n");
danw@131
   306
		exit(1);
danw@131
   307
	}
danw@131
   308
danw@125
   309
	/* FIXME */
danw@131
   310
	fprintf(stderr, "  Not actually checking <unsatisfiable>\n");
danw@131
   311
	ctx->in_unsatisfiable = 1;
danw@125
   312
}
krh@92
   313
danw@125
   314
static void
danw@131
   315
end_unsatisfiable(struct test_context *ctx)
danw@125
   316
{
danw@131
   317
	ctx->in_unsatisfiable = 0;
krh@92
   318
}
krh@92
   319
krh@92
   320
static void
krh@92
   321
start_test_element(void *data, const char *element, const char **atts)
krh@92
   322
{
krh@92
   323
	struct test_context *ctx = data;
krh@92
   324
danw@125
   325
	if (strcmp(element, "tests") == 0) {
danw@125
   326
		;
danw@125
   327
	} else if (strcmp(element, "test") == 0) {
danw@125
   328
		start_test(ctx, atts);
danw@125
   329
	} else if (strcmp(element, "set") == 0) {
danw@125
   330
		start_set(ctx, atts);
danw@125
   331
	} else if (strcmp(element, "transaction") == 0) {
danw@125
   332
		start_transaction(ctx, atts);
danw@125
   333
	} else if (strcmp(element, "install") == 0) {
danw@125
   334
		start_install_or_update(ctx, atts);
danw@125
   335
	} else if (strcmp(element, "install") == 0) {
danw@125
   336
		start_install_or_update(ctx, atts);
danw@125
   337
	} else if (strcmp(element, "remove") == 0) {
danw@125
   338
		start_remove(ctx, atts);
danw@125
   339
	} else if (strcmp(element, "result") == 0) {
danw@125
   340
		start_result(ctx, atts);
danw@131
   341
	} else if (strcmp(element, "unsatisfiable") == 0) {
danw@131
   342
		start_unsatisfiable(ctx, atts);
krh@92
   343
	} else if (strcmp(element, "package") == 0) {
danw@125
   344
		start_package(ctx, atts);
krh@92
   345
	} else if (strcmp(element, "requires") == 0) {
danw@125
   346
		start_property(ctx, RAZOR_PROPERTY_REQUIRES, atts);
krh@92
   347
	} else if (strcmp(element, "provides") == 0) {
danw@125
   348
		start_property(ctx, RAZOR_PROPERTY_PROVIDES, atts);
krh@92
   349
	} else if (strcmp(element, "conflicts") == 0) {
danw@125
   350
		start_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts);
krh@92
   351
	} else if (strcmp(element, "obsoletes") == 0) {
danw@125
   352
		start_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts);
danw@125
   353
	} else {
danw@125
   354
		fprintf(stderr, "Unrecognized element '%s'\n", element);
danw@125
   355
		exit(1);
krh@92
   356
	}
krh@92
   357
}
krh@92
   358
krh@92
   359
static void
krh@92
   360
end_test_element (void *data, const char *element)
krh@92
   361
{
krh@92
   362
	struct test_context *ctx = data;
krh@92
   363
danw@125
   364
	if (strcmp(element, "test") == 0) {
danw@125
   365
		end_test(ctx);
danw@125
   366
	} else if (strcmp(element, "set") == 0) {
danw@125
   367
		end_set(ctx);
danw@125
   368
	} else if (strcmp(element, "package") == 0) {
danw@125
   369
		end_package(ctx);
danw@125
   370
	} else if (strcmp(element, "transaction") == 0) {
danw@125
   371
		end_transaction(ctx);
danw@125
   372
	} else if (strcmp(element, "result") == 0) {
danw@125
   373
		end_result(ctx);
danw@131
   374
	} else if (strcmp(element, "unsatisfiable") == 0) {
danw@131
   375
		end_unsatisfiable(ctx);
danw@125
   376
	}
krh@92
   377
}
krh@92
   378
krh@80
   379
int main(int argc, char *argv[])
krh@80
   380
{
krh@80
   381
	struct test_context ctx;
krh@80
   382
krh@92
   383
	if (argc != 2) {
krh@92
   384
		fprintf(stderr, "usage: %s TESTS-FILE\n", argv[0]);
krh@80
   385
		exit(-1);			
krh@80
   386
	}
krh@80
   387
krh@80
   388
	memset(&ctx, 0, sizeof ctx);
krh@92
   389
	parse_xml_file(argv[1], start_test_element, end_test_element, &ctx);
krh@80
   390
krh@80
   391
	return 0;
krh@80
   392
}