krh@80: #include krh@80: #include krh@80: #include krh@80: #include krh@80: #include krh@80: #include krh@80: #include krh@80: krh@80: #include "razor.h" krh@80: krh@80: #define XML_BUFFER_SIZE 4096 krh@80: krh@80: static void krh@80: parse_xml_file(const char *filename, krh@80: XML_StartElementHandler start, krh@80: XML_EndElementHandler end, krh@80: void *data) krh@80: { krh@80: XML_Parser parser; krh@80: char *buffer; krh@80: int fd, len, err; krh@80: krh@80: parser = XML_ParserCreate(NULL); krh@80: XML_SetElementHandler(parser, start, end); krh@80: XML_SetUserData(parser, data); krh@80: krh@80: buffer = XML_GetBuffer(parser, XML_BUFFER_SIZE); krh@80: krh@80: fd = open(filename, O_RDONLY); krh@80: if (fd < 0) { krh@92: fprintf(stderr, "failed to open %s: %m\n", filename); krh@80: exit(-1); krh@80: } krh@80: krh@80: while (len = read(fd, buffer, XML_BUFFER_SIZE), len > 0) { krh@80: err = XML_ParseBuffer(parser, len, len == 0); krh@80: if (err == XML_STATUS_ERROR) { krh@80: fprintf(stderr, "parse error at line %lu:\n%s\n", krh@80: XML_GetCurrentLineNumber(parser), krh@80: XML_ErrorString(XML_GetErrorCode(parser))); krh@80: exit(-1); krh@80: } krh@80: } krh@80: krh@80: if (fd < 0) { krh@80: fprintf(stderr, "read: %m\n"); krh@80: exit(-1); krh@80: } krh@80: krh@80: close(fd); krh@80: } krh@80: krh@80: struct test_set { krh@80: char *name; krh@80: struct razor_set *set; krh@80: struct test_set *next; krh@80: }; krh@80: krh@80: struct test_context { krh@80: struct razor_importer *importer; krh@80: struct test_set *sets; krh@92: struct razor_package_iterator *package_iterator; krh@92: struct razor_property_iterator *property_iterator; krh@80: }; krh@80: krh@80: static void krh@80: get_atts(const char **atts, ...) krh@80: { krh@80: va_list ap; krh@80: const char *name, **ptr; krh@80: int i; krh@80: krh@80: va_start(ap, atts); krh@80: while (name = va_arg(ap, const char *), name != NULL) { krh@80: ptr = va_arg(ap, const char **); krh@92: *ptr = NULL; krh@80: for (i = 0; atts[i]; i += 2) { krh@80: if (strcmp(atts[i], name) == 0) krh@80: *ptr = atts[i + 1]; krh@80: } krh@80: } krh@80: va_end(ap); krh@80: } krh@80: krh@80: static void krh@80: parse_property(struct test_context *ctx, const char **atts, krh@80: enum razor_property_type type) krh@80: { krh@80: const char *name = NULL, *version = NULL; krh@80: krh@92: get_atts(atts, "name", &name, "eq", &version, NULL); krh@80: krh@80: if (name == NULL) { krh@80: fprintf(stderr, "no name specified for property\n"); krh@80: exit(-1); krh@80: } krh@80: krh@80: razor_importer_add_property(ctx->importer, name, version, type); krh@80: } krh@80: krh@80: static void krh@92: start_set_element(void *data, const char *element, const char **atts) krh@80: { krh@80: struct test_context *ctx = data; krh@80: struct test_set *set; krh@80: const char *name, *version; krh@80: krh@80: if (strcmp(element, "set") == 0) { krh@80: get_atts(atts, "name", &name, NULL); krh@80: ctx->importer = razor_importer_new(); krh@80: set = malloc(sizeof *set); krh@80: set->name = strdup(name); krh@80: set->next = ctx->sets; krh@80: ctx->sets = set; krh@80: } else if (strcmp(element, "package") == 0) { krh@80: get_atts(atts, "name", &name, "version", &version, NULL); krh@80: razor_importer_begin_package(ctx->importer, name, version); krh@80: } else if (strcmp(element, "requires") == 0) { krh@80: parse_property(ctx, atts, RAZOR_PROPERTY_REQUIRES); krh@80: } else if (strcmp(element, "provides") == 0) { krh@80: parse_property(ctx, atts, RAZOR_PROPERTY_PROVIDES); krh@80: } else if (strcmp(element, "obsoletes") == 0) { krh@80: parse_property(ctx, atts, RAZOR_PROPERTY_OBSOLETES); krh@80: } else if (strcmp(element, "conflicts") == 0) { krh@80: parse_property(ctx, atts, RAZOR_PROPERTY_CONFLICTS); krh@80: } else if (strcmp(element, "file") == 0) { krh@80: get_atts(atts, "name", &name, NULL); krh@80: razor_importer_add_file(ctx->importer, name); krh@80: } else if (strcmp(element, "dir") == 0) { krh@80: get_atts(atts, "name", &name, NULL); krh@80: razor_importer_add_file(ctx->importer, name); krh@80: } krh@80: } krh@80: krh@80: static void krh@92: end_set_element (void *data, const char *name) krh@80: { krh@80: struct test_context *ctx = data; krh@80: krh@80: if (strcmp(name, "set") == 0) { krh@80: ctx->sets->set = razor_importer_finish(ctx->importer); krh@80: } else if (strcmp(name, "package") == 0) { krh@80: razor_importer_finish_package(ctx->importer); krh@80: } krh@80: } krh@80: krh@92: static struct razor_set * krh@92: lookup_set(struct test_context *ctx, const char *name) krh@92: { krh@92: struct test_set *set; krh@92: krh@92: for (set = ctx->sets; set != NULL; set = set->next) { krh@92: if (strcmp(set->name, name) == 0) krh@92: return set->set; krh@92: } krh@92: krh@92: return NULL; krh@92: } krh@92: krh@92: static void krh@92: verify_begin(struct test_context *ctx, const char **atts) krh@92: { krh@92: struct razor_set *set; krh@92: const char *type, *name; krh@92: krh@92: get_atts(atts, "type", &type, "set", &name, NULL); krh@92: set = lookup_set(ctx, name); krh@92: if (set == NULL) { krh@92: fprintf(stderr, "set %s not found\n", name); krh@92: exit(-1); krh@92: } krh@92: krh@92: if (strcmp(type, "packages") == 0) { krh@92: ctx->package_iterator = krh@92: razor_package_iterator_create(set); krh@92: } else if (strcmp(type, "properties") == 0) { krh@92: ctx->property_iterator = krh@92: razor_property_iterator_create(set, NULL); krh@92: } else { krh@92: fprintf(stderr, krh@92: "unknown compare type \"%s\"\n", type); krh@92: exit(-1); krh@92: } krh@92: } krh@92: krh@92: static void krh@92: verify_end(struct test_context *ctx) krh@92: { krh@92: struct razor_package *package; krh@92: struct razor_property *property; krh@94: const char *name, *version; krh@92: enum razor_property_type type; krh@92: krh@92: if (ctx->package_iterator != NULL) { krh@92: if (razor_package_iterator_next(ctx->package_iterator, krh@92: &package, krh@92: &name, &version)) { krh@92: fprintf(stderr, "too few packages in set\n"); krh@92: exit(-1); krh@92: } krh@92: krh@92: razor_package_iterator_destroy(ctx->package_iterator); krh@92: ctx->package_iterator = NULL; krh@92: } krh@92: krh@92: if (ctx->property_iterator != NULL) { krh@92: if (razor_property_iterator_next(ctx->property_iterator, krh@92: &property, krh@92: &name, &version, &type)) { krh@92: fprintf(stderr, "too few properties in set\n"); krh@92: exit(-1); krh@92: } krh@92: krh@92: razor_property_iterator_destroy(ctx->property_iterator); krh@92: ctx->property_iterator = NULL; krh@92: } krh@92: } krh@92: krh@92: static void krh@92: verify_package(struct test_context *ctx, const char **atts) krh@92: { krh@92: struct razor_package *package; krh@92: const char *name, *version, *ref_name, *ref_version; krh@92: krh@92: if (ctx->package_iterator == NULL) { krh@92: fprintf(stderr, krh@92: "\"package\" element seen, " krh@92: "but not in package verify mode\n"); krh@92: exit(-1); krh@92: } krh@92: krh@92: get_atts(atts, "name", &ref_name, "version", &ref_version, NULL); krh@92: if (!razor_package_iterator_next(ctx->package_iterator, krh@92: &package, &name, &version)) { krh@92: fprintf(stderr, "too many packages in set\n"); krh@92: exit(-1); krh@92: } krh@92: krh@92: if (strcmp(name, ref_name) != 0 || strcmp(version, ref_version) != 0) { krh@92: fprintf(stderr, krh@92: "package mismatch; expected %s-%s, got %s-%s\n", krh@92: ref_name, ref_version, name, version); krh@92: exit(-1); krh@92: } krh@92: } krh@92: krh@92: static void krh@92: verify_property(struct test_context *ctx, krh@92: enum razor_property_type ref_type, const char **atts) krh@92: { krh@92: struct razor_property *property; krh@92: const char *name, *version, *ref_name, *ref_version; krh@92: enum razor_property_type type; krh@92: int same_version; krh@92: krh@92: if (ctx->property_iterator == NULL) { krh@92: fprintf(stderr, krh@92: "\"requires/provides\" element seen, " krh@92: "but not in property verify mode\n"); krh@92: exit(-1); krh@92: } krh@92: krh@92: get_atts(atts, "name", &ref_name, "eq", &ref_version, NULL); krh@92: if (!razor_property_iterator_next(ctx->property_iterator, &property, krh@92: &name, &version, &type)) { krh@92: fprintf(stderr, "too many properties in set\n"); krh@92: exit(-1); krh@92: } krh@92: krh@92: if (version != NULL && ref_version != NULL) krh@92: same_version = strcmp(version, ref_version) == 0; krh@92: else if (version == NULL && ref_version == NULL) krh@92: same_version = 1; krh@92: else krh@92: same_version = 0; krh@92: krh@92: if (strcmp(name, ref_name) != 0 || !same_version || type != ref_type) { krh@92: fprintf(stderr, krh@92: "property mismatch; expected %s-%s/%d, got %s-%s/%d\n", krh@92: ref_name, ref_version, ref_type, krh@92: name, version, type); krh@92: exit(-1); krh@92: } krh@92: } krh@92: krh@92: static void krh@92: start_test_element(void *data, const char *element, const char **atts) krh@92: { krh@92: struct test_context *ctx = data; krh@92: const char *name; krh@92: krh@92: if (strcmp(element, "import") == 0) { krh@92: get_atts(atts, "file", &name, NULL); krh@92: parse_xml_file(name, start_set_element, end_set_element, ctx); krh@92: } else if (strcmp(element, "update") == 0) { krh@92: /* run update to create new set */ krh@92: } else if (strcmp(element, "verify") == 0) { krh@92: verify_begin(ctx, atts); krh@92: } else if (strcmp(element, "package") == 0) { krh@92: verify_package(ctx, atts); krh@92: } else if (strcmp(element, "requires") == 0) { krh@92: verify_property(ctx, RAZOR_PROPERTY_REQUIRES, atts); krh@92: } else if (strcmp(element, "provides") == 0) { krh@92: verify_property(ctx, RAZOR_PROPERTY_PROVIDES, atts); krh@92: } else if (strcmp(element, "conflicts") == 0) { krh@92: verify_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts); krh@92: } else if (strcmp(element, "obsoletes") == 0) { krh@92: verify_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts); krh@92: } krh@92: } krh@92: krh@92: static void krh@92: end_test_element (void *data, const char *element) krh@92: { krh@92: struct test_context *ctx = data; krh@92: krh@92: if (strcmp(element, "verify") == 0) krh@92: verify_end(ctx); krh@92: } krh@92: krh@80: int main(int argc, char *argv[]) krh@80: { krh@80: struct test_context ctx; krh@80: krh@92: if (argc != 2) { krh@92: fprintf(stderr, "usage: %s TESTS-FILE\n", argv[0]); krh@80: exit(-1); krh@80: } krh@80: krh@80: memset(&ctx, 0, sizeof ctx); krh@92: parse_xml_file(argv[1], start_test_element, end_test_element, &ctx); krh@80: krh@80: return 0; krh@80: }