1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/test-driver.c Fri Jun 20 23:13:09 2008 -0400
1.3 @@ -0,0 +1,458 @@
1.4 +#include <stdio.h>
1.5 +#include <string.h>
1.6 +#include <stdarg.h>
1.7 +#include <unistd.h>
1.8 +#include <fcntl.h>
1.9 +#include <errno.h>
1.10 +#include <expat.h>
1.11 +
1.12 +#include "razor.h"
1.13 +
1.14 +#define XML_BUFFER_SIZE 4096
1.15 +
1.16 +static void
1.17 +parse_xml_file(const char *filename,
1.18 + XML_StartElementHandler start,
1.19 + XML_EndElementHandler end,
1.20 + void *data)
1.21 +{
1.22 + XML_Parser parser;
1.23 + char *buffer;
1.24 + int fd, len, err;
1.25 +
1.26 + parser = XML_ParserCreate(NULL);
1.27 + XML_SetElementHandler(parser, start, end);
1.28 + XML_SetUserData(parser, data);
1.29 +
1.30 + fd = open(filename, O_RDONLY);
1.31 + if (fd < 0) {
1.32 + fprintf(stderr, "failed to open %s: %m\n", filename);
1.33 + exit(-1);
1.34 + }
1.35 +
1.36 + while (1) {
1.37 + buffer = XML_GetBuffer(parser, XML_BUFFER_SIZE);
1.38 + len = read(fd, buffer, XML_BUFFER_SIZE);
1.39 + if (len == 0)
1.40 + break;
1.41 + err = XML_ParseBuffer(parser, len, len == 0);
1.42 + if (err == XML_STATUS_ERROR) {
1.43 + fprintf(stderr, "parse error at line %lu:\n%s\n",
1.44 + XML_GetCurrentLineNumber(parser),
1.45 + XML_ErrorString(XML_GetErrorCode(parser)));
1.46 + exit(-1);
1.47 + }
1.48 + }
1.49 +
1.50 + if (fd < 0) {
1.51 + fprintf(stderr, "read: %m\n");
1.52 + exit(-1);
1.53 + }
1.54 +
1.55 + close(fd);
1.56 +}
1.57 +
1.58 +struct test_context {
1.59 + struct razor_set *system_set, *repo_set, *result_set;
1.60 +
1.61 + struct razor_importer *importer;
1.62 + struct razor_set **importer_set;
1.63 +
1.64 + struct razor_transaction *trans;
1.65 +
1.66 + char *install_pkgs[3], *remove_pkgs[3];
1.67 + int n_install_pkgs, n_remove_pkgs;
1.68 +
1.69 + int unsat;
1.70 + int in_result;
1.71 +
1.72 + int debug, errors;
1.73 +};
1.74 +
1.75 +static void
1.76 +get_atts(const char **atts, ...)
1.77 +{
1.78 + va_list ap;
1.79 + const char *name, **ptr;
1.80 + int i;
1.81 +
1.82 + va_start(ap, atts);
1.83 + while (name = va_arg(ap, const char *), name != NULL) {
1.84 + ptr = va_arg(ap, const char **);
1.85 + *ptr = NULL;
1.86 + for (i = 0; atts[i]; i += 2) {
1.87 + if (strcmp(atts[i], name) == 0)
1.88 + *ptr = atts[i + 1];
1.89 + }
1.90 + }
1.91 + va_end(ap);
1.92 +}
1.93 +
1.94 +static enum razor_version_relation
1.95 +parse_relation (const char *rel_str)
1.96 +{
1.97 + if (!rel_str)
1.98 + return -1;
1.99 + if (rel_str[0] == 'L')
1.100 + return rel_str[1] == 'E' ? RAZOR_VERSION_LESS_OR_EQUAL : RAZOR_VERSION_LESS;
1.101 + else if (rel_str[0] == 'G')
1.102 + return rel_str[1] == 'E' ? RAZOR_VERSION_GREATER_OR_EQUAL : RAZOR_VERSION_GREATER;
1.103 + else if (rel_str[0] == 'E' || rel_str[1] == 'Q')
1.104 + return RAZOR_VERSION_EQUAL;
1.105 + else
1.106 + return -1;
1.107 +}
1.108 +
1.109 +static void
1.110 +start_test(struct test_context *ctx, const char **atts)
1.111 +{
1.112 + const char *name = NULL;
1.113 +
1.114 + get_atts(atts, "name", &name, NULL);
1.115 + if (!name) {
1.116 + fprintf(stderr, "Test with no name\n");
1.117 + exit(1);
1.118 + }
1.119 + printf("%s\n", name);
1.120 +}
1.121 +
1.122 +static void
1.123 +end_test(struct test_context *ctx)
1.124 +{
1.125 + if (ctx->system_set) {
1.126 + razor_set_destroy(ctx->system_set);
1.127 + ctx->system_set = NULL;
1.128 + }
1.129 + if (ctx->repo_set) {
1.130 + razor_set_destroy(ctx->repo_set);
1.131 + ctx->repo_set = NULL;
1.132 + }
1.133 + if (ctx->result_set) {
1.134 + razor_set_destroy(ctx->result_set);
1.135 + ctx->result_set = NULL;
1.136 + }
1.137 + if (ctx->trans) {
1.138 + razor_transaction_destroy(ctx->trans);
1.139 + ctx->trans = NULL;
1.140 + }
1.141 +}
1.142 +
1.143 +static void
1.144 +start_set(struct test_context *ctx, const char **atts)
1.145 +{
1.146 + const char *name = NULL;
1.147 +
1.148 + ctx->importer = razor_importer_new();
1.149 + get_atts(atts, "name", &name, NULL);
1.150 + if (!name)
1.151 + ctx->importer_set = &ctx->result_set;
1.152 + else if (!strcmp(name, "system"))
1.153 + ctx->importer_set = &ctx->system_set;
1.154 + else if (!strcmp(name, "repo"))
1.155 + ctx->importer_set = &ctx->repo_set;
1.156 + else {
1.157 + fprintf(stderr, " bad set name '%s'\n", name);
1.158 + exit(1);
1.159 + }
1.160 +}
1.161 +
1.162 +static void
1.163 +end_set(struct test_context *ctx)
1.164 +{
1.165 + *ctx->importer_set = razor_importer_finish(ctx->importer);
1.166 + ctx->importer = NULL;
1.167 +}
1.168 +
1.169 +static void
1.170 +start_package(struct test_context *ctx, const char **atts)
1.171 +{
1.172 + const char *name = NULL, *version = NULL, *arch = NULL;
1.173 +
1.174 + get_atts(atts, "name", &name,
1.175 + "version", &version,
1.176 + "arch", &arch,
1.177 + NULL);
1.178 +
1.179 + if (!name) {
1.180 + fprintf(stderr, " package with no name\n");
1.181 + exit(1);
1.182 + }
1.183 +
1.184 + razor_importer_begin_package(ctx->importer, name, version, arch);
1.185 + razor_importer_add_property(ctx->importer, name,
1.186 + RAZOR_VERSION_EQUAL, version,
1.187 + RAZOR_PROPERTY_PROVIDES);
1.188 +}
1.189 +
1.190 +static void
1.191 +end_package(struct test_context *ctx)
1.192 +{
1.193 + razor_importer_finish_package(ctx->importer);
1.194 +}
1.195 +
1.196 +static void
1.197 +add_property(struct test_context *ctx, enum razor_property_type type, const char *name, enum razor_version_relation rel, const char *version)
1.198 +{
1.199 + razor_importer_add_property(ctx->importer, name,
1.200 + rel, version, type);
1.201 +}
1.202 +
1.203 +static void
1.204 +check_unsatisfiable_property(struct test_context *ctx,
1.205 + enum razor_property_type type,
1.206 + const char *name,
1.207 + enum razor_version_relation rel,
1.208 + const char *version)
1.209 +{
1.210 + static const char *relation_string[] = { "<", "<=", "=", ">=", ">" };
1.211 +
1.212 + if (!version)
1.213 + version = "";
1.214 +
1.215 + if (razor_transaction_unsatisfied_property(ctx->trans,
1.216 + name, rel, version, type))
1.217 + return;
1.218 +
1.219 + fprintf(stderr, " didn't get unsatisfiable '%s %s %s'\n",
1.220 + name, relation_string[rel], version);
1.221 + ctx->errors++;
1.222 +}
1.223 +
1.224 +static void
1.225 +start_property(struct test_context *ctx, enum razor_property_type type, const char **atts)
1.226 +{
1.227 + const char *name = NULL, *rel_str = NULL, *version = NULL;
1.228 + enum razor_version_relation rel;
1.229 +
1.230 + get_atts(atts, "name", &name, "relation", &rel_str, "version", &version, NULL);
1.231 + if (name == NULL) {
1.232 + fprintf(stderr, " no name specified for property\n");
1.233 + exit(1);
1.234 + }
1.235 + if (version) {
1.236 + rel = parse_relation(rel_str);
1.237 + if (rel == -1) {
1.238 + fprintf(stderr, " bad or missing version relation for property %s\n", name);
1.239 + exit(1);
1.240 + }
1.241 + } else
1.242 + rel = RAZOR_VERSION_EQUAL;
1.243 +
1.244 + if (ctx->unsat)
1.245 + check_unsatisfiable_property(ctx, type, name, rel, version);
1.246 + else
1.247 + add_property(ctx, type, name, rel, version);
1.248 +}
1.249 +
1.250 +static void
1.251 +start_transaction(struct test_context *ctx, const char **atts)
1.252 +{
1.253 + ctx->n_install_pkgs = 0;
1.254 + ctx->n_remove_pkgs = 0;
1.255 +}
1.256 +
1.257 +static void
1.258 +end_transaction(struct test_context *ctx)
1.259 +{
1.260 + struct razor_package *pkg;
1.261 + int errors, i;
1.262 +
1.263 + ctx->trans = razor_transaction_create(ctx->system_set, ctx->repo_set);
1.264 + for (i = 0; i < ctx->n_install_pkgs; i++) {
1.265 + pkg = razor_set_get_package(ctx->repo_set,
1.266 + ctx->install_pkgs[i]);
1.267 + razor_transaction_install_package(ctx->trans, pkg);
1.268 + }
1.269 + for (i = 0; i < ctx->n_remove_pkgs; i++) {
1.270 + pkg = razor_set_get_package(ctx->repo_set,
1.271 + ctx->remove_pkgs[i]);
1.272 + razor_transaction_remove_package(ctx->trans, pkg);
1.273 + }
1.274 +
1.275 + errors = razor_transaction_resolve(ctx->trans);
1.276 + printf("\n");
1.277 +
1.278 + while (ctx->n_install_pkgs--)
1.279 + free(ctx->install_pkgs[ctx->n_install_pkgs]);
1.280 + while (ctx->n_remove_pkgs--)
1.281 + free(ctx->remove_pkgs[ctx->n_remove_pkgs]);
1.282 +
1.283 + if (!errors) {
1.284 + struct razor_set *new;
1.285 + new = razor_transaction_finish(ctx->trans);
1.286 + ctx->system_set = new;
1.287 + }
1.288 +}
1.289 +
1.290 +static void
1.291 +start_install_or_update(struct test_context *ctx, const char **atts)
1.292 +{
1.293 + const char *name = NULL;
1.294 +
1.295 + get_atts(atts, "name", &name, NULL);
1.296 + if (!name) {
1.297 + fprintf(stderr, " install/update with no name\n");
1.298 + exit(1);
1.299 + }
1.300 +
1.301 + ctx->install_pkgs[ctx->n_install_pkgs++] = strdup(name);
1.302 +}
1.303 +
1.304 +static void
1.305 +start_remove(struct test_context *ctx, const char **atts)
1.306 +{
1.307 + const char *name = NULL;
1.308 +
1.309 + get_atts(atts, "name", &name, NULL);
1.310 + if (!name) {
1.311 + fprintf(stderr, " remove with no name\n");
1.312 + exit(1);
1.313 + }
1.314 +
1.315 + ctx->remove_pkgs[ctx->n_remove_pkgs++] = strdup(name);
1.316 +}
1.317 +
1.318 +static void
1.319 +start_result(struct test_context *ctx, const char **atts)
1.320 +{
1.321 + ctx->in_result = 1;
1.322 +}
1.323 +
1.324 +static void
1.325 +diff_callback(const char *name,
1.326 + const char *old_version,
1.327 + const char *new_version,
1.328 + const char *arch,
1.329 + void *data)
1.330 +{
1.331 + struct test_context *ctx = data;
1.332 +
1.333 + ctx->errors++;
1.334 + if (old_version) {
1.335 + fprintf(stderr, " result set should not contain %s %s\n",
1.336 + name, old_version);
1.337 + } else {
1.338 + fprintf(stderr, " result set should contain %s %s\n",
1.339 + name, new_version);
1.340 + }
1.341 +}
1.342 +
1.343 +static void
1.344 +end_result(struct test_context *ctx)
1.345 +{
1.346 + ctx->in_result = 0;
1.347 +
1.348 + if (ctx->result_set) {
1.349 + if (!ctx->system_set)
1.350 + ctx->system_set = razor_set_create();
1.351 + razor_set_diff(ctx->system_set, ctx->result_set,
1.352 + diff_callback, ctx);
1.353 + }
1.354 +}
1.355 +
1.356 +static void
1.357 +start_unsatisfiable(struct test_context *ctx, const char **atts)
1.358 +{
1.359 + if (ctx->result_set) {
1.360 + fprintf(stderr, "Expected to fail, but didn't\n");
1.361 + exit(1);
1.362 + }
1.363 +
1.364 + ctx->unsat = 1;
1.365 +}
1.366 +
1.367 +static void
1.368 +end_unsatisfiable(struct test_context *ctx)
1.369 +{
1.370 + ctx->unsat = 0;
1.371 +}
1.372 +
1.373 +static void
1.374 +start_test_element(void *data, const char *element, const char **atts)
1.375 +{
1.376 + struct test_context *ctx = data;
1.377 +
1.378 + if (strcmp(element, "tests") == 0) {
1.379 + ;
1.380 + } else if (strcmp(element, "test") == 0) {
1.381 + start_test(ctx, atts);
1.382 + } else if (strcmp(element, "set") == 0) {
1.383 + start_set(ctx, atts);
1.384 + } else if (strcmp(element, "transaction") == 0) {
1.385 + start_transaction(ctx, atts);
1.386 + } else if (strcmp(element, "install") == 0) {
1.387 + start_install_or_update(ctx, atts);
1.388 + } else if (strcmp(element, "install") == 0) {
1.389 + start_install_or_update(ctx, atts);
1.390 + } else if (strcmp(element, "remove") == 0) {
1.391 + start_remove(ctx, atts);
1.392 + } else if (strcmp(element, "result") == 0) {
1.393 + start_result(ctx, atts);
1.394 + } else if (strcmp(element, "unsatisfiable") == 0) {
1.395 + start_unsatisfiable(ctx, atts);
1.396 + } else if (strcmp(element, "package") == 0) {
1.397 + start_package(ctx, atts);
1.398 + } else if (strcmp(element, "requires") == 0) {
1.399 + start_property(ctx, RAZOR_PROPERTY_REQUIRES, atts);
1.400 + } else if (strcmp(element, "provides") == 0) {
1.401 + start_property(ctx, RAZOR_PROPERTY_PROVIDES, atts);
1.402 + } else if (strcmp(element, "conflicts") == 0) {
1.403 + start_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts);
1.404 + } else if (strcmp(element, "obsoletes") == 0) {
1.405 + start_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts);
1.406 + } else {
1.407 + fprintf(stderr, "Unrecognized element '%s'\n", element);
1.408 + exit(1);
1.409 + }
1.410 +}
1.411 +
1.412 +static void
1.413 +end_test_element (void *data, const char *element)
1.414 +{
1.415 + struct test_context *ctx = data;
1.416 +
1.417 + if (strcmp(element, "test") == 0) {
1.418 + end_test(ctx);
1.419 + } else if (strcmp(element, "set") == 0) {
1.420 + end_set(ctx);
1.421 + } else if (strcmp(element, "package") == 0) {
1.422 + end_package(ctx);
1.423 + } else if (strcmp(element, "transaction") == 0) {
1.424 + end_transaction(ctx);
1.425 + } else if (strcmp(element, "result") == 0) {
1.426 + end_result(ctx);
1.427 + } else if (strcmp(element, "unsatisfiable") == 0) {
1.428 + end_unsatisfiable(ctx);
1.429 + }
1.430 +}
1.431 +
1.432 +int main(int argc, char *argv[])
1.433 +{
1.434 + struct test_context ctx;
1.435 + const char *test_file;
1.436 +
1.437 + memset(&ctx, 0, sizeof ctx);
1.438 +
1.439 + if (argc > 3) {
1.440 + fprintf(stderr, "usage: %s [-d] [TESTS-FILE]\n", argv[0]);
1.441 + exit(-1);
1.442 + }
1.443 +
1.444 + if (argc >= 2 && !strcmp (argv[1], "-d")) {
1.445 + ctx.debug = 1;
1.446 + argc--;
1.447 + argv++;
1.448 + }
1.449 + if (argc == 2)
1.450 + test_file = argv[1];
1.451 + else
1.452 + test_file = "test.xml";
1.453 +
1.454 + parse_xml_file(test_file, start_test_element, end_test_element, &ctx);
1.455 +
1.456 + if (ctx.errors) {
1.457 + fprintf(stderr, "\n%d errors\n", ctx.errors);
1.458 + return 1;
1.459 + } else
1.460 + return 0;
1.461 +}