test-driver.c
author Dan Winship <danw@gnome.org>
Wed Feb 20 13:34:55 2008 -0500 (2008-02-20)
changeset 127 4a12eceb0858
parent 109 313b0a615c14
child 129 d221757574c1
permissions -rw-r--r--
Merge file lists when updating

Currently a bit of a mess due to repeated rewriting. To be cleaned up
after we decide whether or not to keep the current file layout
     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 };
    64 
    65 static void
    66 get_atts(const char **atts, ...)
    67 {
    68 	va_list ap;
    69 	const char *name, **ptr;
    70 	int i;
    71 
    72 	va_start(ap, atts);
    73 	while (name = va_arg(ap, const char *), name != NULL) {
    74 		ptr = va_arg(ap, const char **);
    75 		*ptr = NULL;
    76 		for (i = 0; atts[i]; i += 2) {
    77 			if (strcmp(atts[i], name) == 0)
    78 				*ptr = atts[i + 1];
    79 		}
    80 	}
    81 	va_end(ap);
    82 }
    83 
    84 static enum razor_version_relation
    85 parse_relation (const char *rel_str)
    86 {
    87 	if (!rel_str)
    88 		return -1;
    89 	if (rel_str[0] == 'l')
    90 		return rel_str[1] == 'e' ? RAZOR_VERSION_LESS_OR_EQUAL : RAZOR_VERSION_LESS;
    91 	else if (rel_str[0] == 'g')
    92 		return rel_str[1] == 'e' ? RAZOR_VERSION_GREATER_OR_EQUAL : RAZOR_VERSION_GREATER;
    93 	else if (rel_str[0] == 'e' || rel_str[1] == 'q')
    94 		return RAZOR_VERSION_EQUAL;
    95 	else
    96 		return -1;
    97 }
    98 
    99 static void
   100 start_test(struct test_context *ctx, const char **atts)
   101 {
   102 	const char *name = NULL;
   103 
   104 	get_atts(atts, "name", &name, NULL);
   105 	if (!name) {
   106 		fprintf(stderr, "Test with no name\n");
   107 		exit(1);
   108 	}
   109 	printf("%s\n", name);
   110 }
   111 
   112 static void
   113 end_test(struct test_context *ctx)
   114 {
   115 	if (ctx->system_set) {
   116 		razor_set_destroy(ctx->system_set);
   117 		ctx->system_set = NULL;
   118 	}
   119 	if (ctx->repo_set) {
   120 		razor_set_destroy(ctx->repo_set);
   121 		ctx->repo_set = NULL;
   122 	}
   123 	if (ctx->result_set) {
   124 		razor_set_destroy(ctx->result_set);
   125 		ctx->result_set = NULL;
   126 	}
   127 }
   128 
   129 static void
   130 start_set(struct test_context *ctx, const char **atts)
   131 {
   132 	const char *name = NULL;
   133 
   134 	ctx->importer = razor_importer_new();
   135 	get_atts(atts, "name", &name, NULL);
   136 	if (!name)
   137 		ctx->importer_set = &ctx->result_set;
   138 	else if (!strcmp(name, "system"))
   139 		ctx->importer_set = &ctx->system_set;
   140 	else if (!strcmp(name, "repo"))
   141 		ctx->importer_set = &ctx->repo_set;
   142 	else {
   143 		fprintf(stderr, "  bad set name '%s'\n", name);
   144 		exit(1);
   145 	}
   146 }
   147 
   148 static void
   149 end_set(struct test_context *ctx)
   150 {
   151 	*ctx->importer_set = razor_importer_finish(ctx->importer);
   152 	ctx->importer = NULL;
   153 }
   154 
   155 static void
   156 start_package(struct test_context *ctx, const char **atts)
   157 {
   158 	const char *name = NULL, *version = NULL, *arch = NULL;
   159 
   160 	get_atts(atts, "name", &name, "version", &version, "arch", &arch, NULL);
   161 	if (!name) {
   162 		fprintf(stderr, "  package with no name\n");
   163 		exit(1);
   164 	}
   165 
   166 	razor_importer_begin_package(ctx->importer, name, version);
   167 	razor_importer_add_property(ctx->importer, name,
   168 				    RAZOR_VERSION_EQUAL, version,
   169 				    RAZOR_PROPERTY_PROVIDES);
   170 }
   171 
   172 static void
   173 end_package(struct test_context *ctx)
   174 {
   175 	razor_importer_finish_package(ctx->importer);
   176 }
   177 
   178 static void
   179 start_property(struct test_context *ctx, enum razor_property_type type, const char **atts)
   180 {
   181 	const char *name = NULL, *rel_str = NULL, *version = NULL;
   182 	enum razor_version_relation rel;
   183 
   184 	get_atts(atts, "name", &name, "rel", &rel_str, "version", &version, NULL);
   185 	if (name == NULL) {
   186 		fprintf(stderr, "  no name specified for property\n");
   187 		exit(1);
   188 	}
   189 	if (version) {
   190 		rel = parse_relation(rel_str);
   191 		if (rel == -1) {
   192 			fprintf(stderr, "  bad or missing version relation for property %s\n", name);
   193 			exit(1);
   194 		}
   195 	} else
   196 		rel = RAZOR_VERSION_EQUAL;
   197 	
   198 	razor_importer_add_property(ctx->importer, name,
   199 				    rel, version, type);
   200 }
   201 
   202 static void
   203 start_transaction(struct test_context *ctx, const char **atts)
   204 {
   205 	ctx->n_install_pkgs = 0;
   206 	ctx->n_remove_pkgs = 0;
   207 }
   208 
   209 static void
   210 end_transaction(struct test_context *ctx)
   211 {
   212 	/* FIXME: removes */
   213 	ctx->system_set = razor_set_update(ctx->system_set,
   214 					   ctx->repo_set,
   215 					   ctx->n_install_pkgs,
   216 					   (const char **)ctx->install_pkgs);
   217 
   218 	while (ctx->n_install_pkgs--)
   219 		free(ctx->install_pkgs[ctx->n_install_pkgs]);
   220 	while (ctx->n_remove_pkgs--)
   221 		free(ctx->remove_pkgs[ctx->n_remove_pkgs]);
   222 }
   223 
   224 static void
   225 start_install_or_update(struct test_context *ctx, const char **atts)
   226 {
   227 	const char *name = NULL;
   228 
   229 	get_atts(atts, "name", &name, NULL);
   230 	if (!name) {
   231 		fprintf(stderr, "  install/update with no name\n");
   232 		exit(1);
   233 	}
   234 
   235 	ctx->install_pkgs[ctx->n_install_pkgs++] = strdup(name);
   236 }
   237 
   238 static void
   239 start_remove(struct test_context *ctx, const char **atts)
   240 {
   241 	const char *name = NULL;
   242 
   243 	get_atts(atts, "name", &name, NULL);
   244 	if (!name) {
   245 		fprintf(stderr, "  remove with no name\n");
   246 		exit(1);
   247 	}
   248 
   249 	ctx->remove_pkgs[ctx->n_remove_pkgs++] = strdup(name);
   250 }
   251 
   252 static void
   253 start_result(struct test_context *ctx, const char **atts)
   254 {
   255 	ctx->in_result = 1;
   256 }
   257 
   258 static void
   259 diff_callback(const char *name,
   260 	      const char *old_version, const char *new_version,
   261 	      void *data)
   262 {
   263 	struct test_context *ctx = data;
   264 
   265 	ctx->result_errors++;
   266 	if (old_version) {
   267 		fprintf(stderr, "  result set should not contain %s %s\n",
   268 			name, old_version);
   269 	} else {
   270 		fprintf(stderr, "  result set should contain %s %s\n",
   271 			name, new_version);
   272 	}
   273 }
   274 
   275 static void
   276 end_result(struct test_context *ctx)
   277 {
   278 	ctx->in_result = 0;
   279 
   280 	/* FIXME */
   281 	if (ctx->n_remove_pkgs) {
   282 		printf ("  (ignoring because of unimplemented remove)\n");
   283 		return;
   284 	}
   285 
   286 	if (ctx->system_set && ctx->result_set) {
   287 		ctx->result_errors = 0;
   288 		razor_set_diff(ctx->system_set, ctx->result_set,
   289 			       diff_callback, ctx);
   290 		if (ctx->result_errors)
   291 			exit(1);
   292 	}
   293 
   294 }
   295 
   296 static void
   297 start_unsatisfied(struct test_context *ctx, const char **atts)
   298 {
   299 	/* FIXME */
   300 	fprintf(stderr, "Can't handle <unsatisfied>\n");
   301 	exit(1);
   302 }
   303 
   304 static void
   305 end_unsatisfied(struct test_context *ctx)
   306 {
   307 }
   308 
   309 static void
   310 start_test_element(void *data, const char *element, const char **atts)
   311 {
   312 	struct test_context *ctx = data;
   313 
   314 	if (strcmp(element, "tests") == 0) {
   315 		;
   316 	} else if (strcmp(element, "test") == 0) {
   317 		start_test(ctx, atts);
   318 	} else if (strcmp(element, "set") == 0) {
   319 		start_set(ctx, atts);
   320 	} else if (strcmp(element, "transaction") == 0) {
   321 		start_transaction(ctx, atts);
   322 	} else if (strcmp(element, "install") == 0) {
   323 		start_install_or_update(ctx, atts);
   324 	} else if (strcmp(element, "install") == 0) {
   325 		start_install_or_update(ctx, atts);
   326 	} else if (strcmp(element, "remove") == 0) {
   327 		start_remove(ctx, atts);
   328 	} else if (strcmp(element, "result") == 0) {
   329 		start_result(ctx, atts);
   330 	} else if (strcmp(element, "unsatisfied") == 0) {
   331 		start_unsatisfied(ctx, atts);
   332 	} else if (strcmp(element, "package") == 0) {
   333 		start_package(ctx, atts);
   334 	} else if (strcmp(element, "requires") == 0) {
   335 		start_property(ctx, RAZOR_PROPERTY_REQUIRES, atts);
   336 	} else if (strcmp(element, "provides") == 0) {
   337 		start_property(ctx, RAZOR_PROPERTY_PROVIDES, atts);
   338 	} else if (strcmp(element, "conflicts") == 0) {
   339 		start_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts);
   340 	} else if (strcmp(element, "obsoletes") == 0) {
   341 		start_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts);
   342 	} else {
   343 		fprintf(stderr, "Unrecognized element '%s'\n", element);
   344 		exit(1);
   345 	}
   346 }
   347 
   348 static void
   349 end_test_element (void *data, const char *element)
   350 {
   351 	struct test_context *ctx = data;
   352 
   353 	if (strcmp(element, "test") == 0) {
   354 		end_test(ctx);
   355 	} else if (strcmp(element, "set") == 0) {
   356 		end_set(ctx);
   357 	} else if (strcmp(element, "package") == 0) {
   358 		end_package(ctx);
   359 	} else if (strcmp(element, "transaction") == 0) {
   360 		end_transaction(ctx);
   361 	} else if (strcmp(element, "result") == 0) {
   362 		end_result(ctx);
   363 	} else if (strcmp(element, "unsatisfied") == 0) {
   364 		end_unsatisfied(ctx);
   365 	}
   366 }
   367 
   368 int main(int argc, char *argv[])
   369 {
   370 	struct test_context ctx;
   371 
   372 	if (argc != 2) {
   373 		fprintf(stderr, "usage: %s TESTS-FILE\n", argv[0]);
   374 		exit(-1);			
   375 	}
   376 
   377 	memset(&ctx, 0, sizeof ctx);
   378 	parse_xml_file(argv[1], start_test_element, end_test_element, &ctx);
   379 
   380 	return 0;
   381 }