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