rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: rhughes@241: #include "razor.h" rhughes@241: rhughes@241: #define XML_BUFFER_SIZE 4096 rhughes@241: rhughes@241: static void rhughes@241: parse_xml_file(const char *filename, rhughes@241: XML_StartElementHandler start, rhughes@241: XML_EndElementHandler end, rhughes@241: void *data) rhughes@241: { rhughes@241: XML_Parser parser; rhughes@241: char *buffer; rhughes@241: int fd, len, err; rhughes@241: rhughes@241: parser = XML_ParserCreate(NULL); rhughes@241: XML_SetElementHandler(parser, start, end); rhughes@241: XML_SetUserData(parser, data); rhughes@241: rhughes@241: fd = open(filename, O_RDONLY); rhughes@241: if (fd < 0) { rhughes@241: fprintf(stderr, "failed to open %s: %m\n", filename); rhughes@241: exit(-1); rhughes@241: } rhughes@241: rhughes@241: while (1) { rhughes@241: buffer = XML_GetBuffer(parser, XML_BUFFER_SIZE); rhughes@241: len = read(fd, buffer, XML_BUFFER_SIZE); rhughes@241: if (len == 0) rhughes@241: break; rhughes@241: err = XML_ParseBuffer(parser, len, len == 0); rhughes@241: if (err == XML_STATUS_ERROR) { rhughes@241: fprintf(stderr, "parse error at line %lu:\n%s\n", rhughes@241: XML_GetCurrentLineNumber(parser), rhughes@241: XML_ErrorString(XML_GetErrorCode(parser))); rhughes@241: exit(-1); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: if (fd < 0) { rhughes@241: fprintf(stderr, "read: %m\n"); rhughes@241: exit(-1); rhughes@241: } rhughes@241: rhughes@241: close(fd); rhughes@241: } rhughes@241: rhughes@241: struct test_context { rhughes@241: struct razor_set *system_set, *repo_set, *result_set; rhughes@241: rhughes@241: struct razor_importer *importer; rhughes@241: struct razor_set **importer_set; rhughes@241: rhughes@241: struct razor_transaction *trans; rhughes@241: rhughes@241: char *install_pkgs[3], *remove_pkgs[3]; rhughes@241: int n_install_pkgs, n_remove_pkgs; rhughes@241: rhughes@241: int unsat; rhughes@241: int in_result; rhughes@241: rhughes@241: int debug, errors; rhughes@241: }; rhughes@241: rhughes@241: static void rhughes@241: get_atts(const char **atts, ...) rhughes@241: { rhughes@241: va_list ap; rhughes@241: const char *name, **ptr; rhughes@241: int i; rhughes@241: rhughes@241: va_start(ap, atts); rhughes@241: while (name = va_arg(ap, const char *), name != NULL) { rhughes@241: ptr = va_arg(ap, const char **); rhughes@241: *ptr = NULL; rhughes@241: for (i = 0; atts[i]; i += 2) { rhughes@241: if (strcmp(atts[i], name) == 0) rhughes@241: *ptr = atts[i + 1]; rhughes@241: } rhughes@241: } rhughes@241: va_end(ap); rhughes@241: } rhughes@241: rhughes@241: static enum razor_version_relation rhughes@241: parse_relation (const char *rel_str) rhughes@241: { rhughes@241: if (!rel_str) rhughes@241: return -1; rhughes@241: if (rel_str[0] == 'L') rhughes@241: return rel_str[1] == 'E' ? RAZOR_VERSION_LESS_OR_EQUAL : RAZOR_VERSION_LESS; rhughes@241: else if (rel_str[0] == 'G') rhughes@241: return rel_str[1] == 'E' ? RAZOR_VERSION_GREATER_OR_EQUAL : RAZOR_VERSION_GREATER; rhughes@241: else if (rel_str[0] == 'E' || rel_str[1] == 'Q') rhughes@241: return RAZOR_VERSION_EQUAL; rhughes@241: else rhughes@241: return -1; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_test(struct test_context *ctx, const char **atts) rhughes@241: { rhughes@241: const char *name = NULL; rhughes@241: rhughes@241: get_atts(atts, "name", &name, NULL); rhughes@241: if (!name) { rhughes@241: fprintf(stderr, "Test with no name\n"); rhughes@241: exit(1); rhughes@241: } rhughes@241: printf("%s\n", name); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: end_test(struct test_context *ctx) rhughes@241: { rhughes@241: if (ctx->system_set) { rhughes@241: razor_set_destroy(ctx->system_set); rhughes@241: ctx->system_set = NULL; rhughes@241: } rhughes@241: if (ctx->repo_set) { rhughes@241: razor_set_destroy(ctx->repo_set); rhughes@241: ctx->repo_set = NULL; rhughes@241: } rhughes@241: if (ctx->result_set) { rhughes@241: razor_set_destroy(ctx->result_set); rhughes@241: ctx->result_set = NULL; rhughes@241: } rhughes@241: if (ctx->trans) { rhughes@241: razor_transaction_destroy(ctx->trans); rhughes@241: ctx->trans = NULL; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_set(struct test_context *ctx, const char **atts) rhughes@241: { rhughes@241: const char *name = NULL; rhughes@241: rhughes@241: ctx->importer = razor_importer_new(); rhughes@241: get_atts(atts, "name", &name, NULL); rhughes@241: if (!name) rhughes@241: ctx->importer_set = &ctx->result_set; rhughes@241: else if (!strcmp(name, "system")) rhughes@241: ctx->importer_set = &ctx->system_set; rhughes@241: else if (!strcmp(name, "repo")) rhughes@241: ctx->importer_set = &ctx->repo_set; rhughes@241: else { rhughes@241: fprintf(stderr, " bad set name '%s'\n", name); rhughes@241: exit(1); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: end_set(struct test_context *ctx) rhughes@241: { rhughes@241: *ctx->importer_set = razor_importer_finish(ctx->importer); rhughes@241: ctx->importer = NULL; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_package(struct test_context *ctx, const char **atts) rhughes@241: { rhughes@241: const char *name = NULL, *version = NULL, *arch = NULL; rhughes@241: rhughes@241: get_atts(atts, "name", &name, rhughes@241: "version", &version, rhughes@241: "arch", &arch, rhughes@241: NULL); rhughes@241: rhughes@241: if (!name) { rhughes@241: fprintf(stderr, " package with no name\n"); rhughes@241: exit(1); rhughes@241: } rhughes@241: rhughes@241: razor_importer_begin_package(ctx->importer, name, version, arch); rhughes@241: razor_importer_add_property(ctx->importer, name, rhughes@241: RAZOR_VERSION_EQUAL, version, rhughes@241: RAZOR_PROPERTY_PROVIDES); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: end_package(struct test_context *ctx) rhughes@241: { rhughes@241: razor_importer_finish_package(ctx->importer); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: add_property(struct test_context *ctx, enum razor_property_type type, const char *name, enum razor_version_relation rel, const char *version) rhughes@241: { rhughes@241: razor_importer_add_property(ctx->importer, name, rhughes@241: rel, version, type); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: check_unsatisfiable_property(struct test_context *ctx, rhughes@241: enum razor_property_type type, rhughes@241: const char *name, rhughes@241: enum razor_version_relation rel, rhughes@241: const char *version) rhughes@241: { rhughes@241: static const char *relation_string[] = { "<", "<=", "=", ">=", ">" }; rhughes@241: rhughes@241: if (!version) rhughes@241: version = ""; rhughes@241: rhughes@241: if (razor_transaction_unsatisfied_property(ctx->trans, rhughes@241: name, rel, version, type)) rhughes@241: return; rhughes@241: rhughes@241: fprintf(stderr, " didn't get unsatisfiable '%s %s %s'\n", rhughes@241: name, relation_string[rel], version); rhughes@241: ctx->errors++; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_property(struct test_context *ctx, enum razor_property_type type, const char **atts) rhughes@241: { rhughes@241: const char *name = NULL, *rel_str = NULL, *version = NULL; rhughes@241: enum razor_version_relation rel; rhughes@241: rhughes@241: get_atts(atts, "name", &name, "relation", &rel_str, "version", &version, NULL); rhughes@241: if (name == NULL) { rhughes@241: fprintf(stderr, " no name specified for property\n"); rhughes@241: exit(1); rhughes@241: } rhughes@241: if (version) { rhughes@241: rel = parse_relation(rel_str); rhughes@241: if (rel == -1) { rhughes@241: fprintf(stderr, " bad or missing version relation for property %s\n", name); rhughes@241: exit(1); rhughes@241: } rhughes@241: } else rhughes@241: rel = RAZOR_VERSION_EQUAL; rhughes@241: rhughes@241: if (ctx->unsat) rhughes@241: check_unsatisfiable_property(ctx, type, name, rel, version); rhughes@241: else rhughes@241: add_property(ctx, type, name, rel, version); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_transaction(struct test_context *ctx, const char **atts) rhughes@241: { rhughes@241: ctx->n_install_pkgs = 0; rhughes@241: ctx->n_remove_pkgs = 0; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: end_transaction(struct test_context *ctx) rhughes@241: { rhughes@241: struct razor_package *pkg; rhughes@241: int errors, i; rhughes@241: rhughes@241: ctx->trans = razor_transaction_create(ctx->system_set, ctx->repo_set); rhughes@241: for (i = 0; i < ctx->n_install_pkgs; i++) { rhughes@241: pkg = razor_set_get_package(ctx->repo_set, rhughes@241: ctx->install_pkgs[i]); rhughes@241: razor_transaction_install_package(ctx->trans, pkg); rhughes@241: } rhughes@241: for (i = 0; i < ctx->n_remove_pkgs; i++) { jbowes@258: pkg = razor_set_get_package(ctx->system_set, rhughes@241: ctx->remove_pkgs[i]); jbowes@258: if (!pkg) jbowes@258: pkg = razor_set_get_package(ctx->repo_set, jbowes@258: ctx->remove_pkgs[i]); jbowes@258: rhughes@241: razor_transaction_remove_package(ctx->trans, pkg); rhughes@241: } rhughes@241: rhughes@241: errors = razor_transaction_resolve(ctx->trans); rhughes@241: printf("\n"); rhughes@241: rhughes@241: while (ctx->n_install_pkgs--) rhughes@241: free(ctx->install_pkgs[ctx->n_install_pkgs]); rhughes@241: while (ctx->n_remove_pkgs--) rhughes@241: free(ctx->remove_pkgs[ctx->n_remove_pkgs]); rhughes@241: rhughes@241: if (!errors) { rhughes@241: struct razor_set *new; rhughes@241: new = razor_transaction_finish(ctx->trans); jbowes@258: ctx->trans = NULL; rhughes@241: ctx->system_set = new; rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_install_or_update(struct test_context *ctx, const char **atts) rhughes@241: { rhughes@241: const char *name = NULL; rhughes@241: rhughes@241: get_atts(atts, "name", &name, NULL); rhughes@241: if (!name) { rhughes@241: fprintf(stderr, " install/update with no name\n"); rhughes@241: exit(1); rhughes@241: } rhughes@241: rhughes@241: ctx->install_pkgs[ctx->n_install_pkgs++] = strdup(name); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_remove(struct test_context *ctx, const char **atts) rhughes@241: { rhughes@241: const char *name = NULL; rhughes@241: rhughes@241: get_atts(atts, "name", &name, NULL); rhughes@241: if (!name) { rhughes@241: fprintf(stderr, " remove with no name\n"); rhughes@241: exit(1); rhughes@241: } rhughes@241: rhughes@241: ctx->remove_pkgs[ctx->n_remove_pkgs++] = strdup(name); rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_result(struct test_context *ctx, const char **atts) rhughes@241: { rhughes@241: ctx->in_result = 1; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: diff_callback(const char *name, rhughes@241: const char *old_version, rhughes@241: const char *new_version, rhughes@241: const char *arch, rhughes@241: void *data) rhughes@241: { rhughes@241: struct test_context *ctx = data; rhughes@241: rhughes@241: ctx->errors++; rhughes@241: if (old_version) { rhughes@241: fprintf(stderr, " result set should not contain %s %s\n", rhughes@241: name, old_version); rhughes@241: } else { rhughes@241: fprintf(stderr, " result set should contain %s %s\n", rhughes@241: name, new_version); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: end_result(struct test_context *ctx) rhughes@241: { rhughes@241: ctx->in_result = 0; rhughes@241: rhughes@241: if (ctx->result_set) { rhughes@241: if (!ctx->system_set) rhughes@241: ctx->system_set = razor_set_create(); rhughes@241: razor_set_diff(ctx->system_set, ctx->result_set, rhughes@241: diff_callback, ctx); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_unsatisfiable(struct test_context *ctx, const char **atts) rhughes@241: { rhughes@241: if (ctx->result_set) { rhughes@241: fprintf(stderr, "Expected to fail, but didn't\n"); rhughes@241: exit(1); rhughes@241: } rhughes@241: rhughes@241: ctx->unsat = 1; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: end_unsatisfiable(struct test_context *ctx) rhughes@241: { rhughes@241: ctx->unsat = 0; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: start_test_element(void *data, const char *element, const char **atts) rhughes@241: { rhughes@241: struct test_context *ctx = data; rhughes@241: rhughes@241: if (strcmp(element, "tests") == 0) { rhughes@241: ; rhughes@241: } else if (strcmp(element, "test") == 0) { rhughes@241: start_test(ctx, atts); rhughes@241: } else if (strcmp(element, "set") == 0) { rhughes@241: start_set(ctx, atts); rhughes@241: } else if (strcmp(element, "transaction") == 0) { rhughes@241: start_transaction(ctx, atts); rhughes@241: } else if (strcmp(element, "install") == 0) { rhughes@241: start_install_or_update(ctx, atts); rhughes@241: } else if (strcmp(element, "install") == 0) { rhughes@241: start_install_or_update(ctx, atts); rhughes@241: } else if (strcmp(element, "remove") == 0) { rhughes@241: start_remove(ctx, atts); rhughes@241: } else if (strcmp(element, "result") == 0) { rhughes@241: start_result(ctx, atts); rhughes@241: } else if (strcmp(element, "unsatisfiable") == 0) { rhughes@241: start_unsatisfiable(ctx, atts); rhughes@241: } else if (strcmp(element, "package") == 0) { rhughes@241: start_package(ctx, atts); rhughes@241: } else if (strcmp(element, "requires") == 0) { rhughes@241: start_property(ctx, RAZOR_PROPERTY_REQUIRES, atts); rhughes@241: } else if (strcmp(element, "provides") == 0) { rhughes@241: start_property(ctx, RAZOR_PROPERTY_PROVIDES, atts); rhughes@241: } else if (strcmp(element, "conflicts") == 0) { rhughes@241: start_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts); rhughes@241: } else if (strcmp(element, "obsoletes") == 0) { rhughes@241: start_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts); rhughes@241: } else { rhughes@241: fprintf(stderr, "Unrecognized element '%s'\n", element); rhughes@241: exit(1); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: end_test_element (void *data, const char *element) rhughes@241: { rhughes@241: struct test_context *ctx = data; rhughes@241: rhughes@241: if (strcmp(element, "test") == 0) { rhughes@241: end_test(ctx); rhughes@241: } else if (strcmp(element, "set") == 0) { rhughes@241: end_set(ctx); rhughes@241: } else if (strcmp(element, "package") == 0) { rhughes@241: end_package(ctx); rhughes@241: } else if (strcmp(element, "transaction") == 0) { rhughes@241: end_transaction(ctx); rhughes@241: } else if (strcmp(element, "result") == 0) { rhughes@241: end_result(ctx); rhughes@241: } else if (strcmp(element, "unsatisfiable") == 0) { rhughes@241: end_unsatisfiable(ctx); rhughes@241: } rhughes@241: } rhughes@241: rhughes@241: int main(int argc, char *argv[]) rhughes@241: { rhughes@241: struct test_context ctx; rhughes@241: const char *test_file; rhughes@241: rhughes@241: memset(&ctx, 0, sizeof ctx); rhughes@241: rhughes@241: if (argc > 3) { rhughes@241: fprintf(stderr, "usage: %s [-d] [TESTS-FILE]\n", argv[0]); rhughes@241: exit(-1); rhughes@241: } rhughes@241: rhughes@241: if (argc >= 2 && !strcmp (argv[1], "-d")) { rhughes@241: ctx.debug = 1; rhughes@241: argc--; rhughes@241: argv++; rhughes@241: } rhughes@241: if (argc == 2) rhughes@241: test_file = argv[1]; rhughes@241: else rhughes@241: test_file = "test.xml"; rhughes@241: rhughes@241: parse_xml_file(test_file, start_test_element, end_test_element, &ctx); rhughes@241: rhughes@241: if (ctx.errors) { rhughes@241: fprintf(stderr, "\n%d errors\n", ctx.errors); rhughes@241: return 1; rhughes@241: } else rhughes@241: return 0; rhughes@241: }