Add iterator API, boot-strap test suite.
authorKristian Høgsberg <krh@redhat.com>
Fri, 4 Jan 2008 00:50:20 +0000 (19:50 -0500)
committerKristian Høgsberg <krh@redhat.com>
Fri, 4 Jan 2008 00:50:20 +0000 (19:50 -0500)
Makefile
main.c
razor.c
razor.h
sets.xml
test-driver.c

index ae7cb78..1d2db52 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ razor : razor.o import.o main.o rpm.o util.o
 test-driver : razor.o util.o test-driver.o
 
 test : test-driver
-       ./test-driver sets.xml test.xml
+       ./test-driver test.xml
 
 clean :
        rm -f *.o razor
diff --git a/main.c b/main.c
index 5835332..f43784c 100644 (file)
--- a/main.c
+++ b/main.c
@@ -17,60 +17,80 @@ static int
 command_list(int argc, const char *argv[])
 {
        struct razor_set *set;
+       struct razor_package_iterator *pi;
+       struct razor_package *package;
+       const char *pattern = argv[0], *name, *version;
 
        set = razor_set_open(repo_filename);
-       razor_set_list(set, argv[0]);
+       pi = razor_package_iterator_create(set);
+       while (razor_package_iterator_next(pi, &package, &name, &version)) {
+               if (pattern && fnmatch(pattern, name, 0) != 0)
+                       continue;
+
+               printf("%s-%s\n", name, version);
+       }
+       razor_package_iterator_destroy(pi);
        razor_set_destroy(set);
 
        return 0;
 }
 
 static int
-command_list_requires(int argc, const char *argv[])
+list_properties(const char *package_name,
+               enum razor_property_type required_type)
 {
        struct razor_set *set;
+       struct razor_property *property;
+       struct razor_package *package;
+       struct razor_property_iterator *pi;
+       const char *name, *version;
+       enum razor_property_type type;
 
        set = razor_set_open(repo_filename);
-       razor_set_list_properties(set, argv[0], RAZOR_PROPERTY_REQUIRES);
+       if (package_name)
+               package = razor_set_get_package(set, package_name);
+       else
+               package = NULL;
+
+       pi = razor_property_iterator_create(set, package);
+       while (razor_property_iterator_next(pi, &property,
+                                           &name, &version, &type)) {
+               if (type != required_type)
+                       continue;
+               if (version[0] == '\0')
+                       printf("%s\n", name);
+               else
+                       printf("%s-%s\n", name, version);
+       }
+       razor_property_iterator_destroy(pi);
+
        razor_set_destroy(set);
 
        return 0;
 }
 
 static int
-command_list_provides(int argc, const char *argv[])
+command_list_requires(int argc, const char *argv[])
 {
-       struct razor_set *set;
-
-       set = razor_set_open(repo_filename);
-       razor_set_list_properties(set, argv[0], RAZOR_PROPERTY_PROVIDES);
-       razor_set_destroy(set);
+       return list_properties(argv[0], RAZOR_PROPERTY_REQUIRES);
+}
 
-       return 0;
+static int
+command_list_provides(int argc, const char *argv[])
+{
+       return list_properties(argv[0], RAZOR_PROPERTY_PROVIDES);
 }
 
 static int
 command_list_obsoletes(int argc, const char *argv[])
 {
-       struct razor_set *set;
-
-       set = razor_set_open(repo_filename);
-       razor_set_list_properties(set, argv[0], RAZOR_PROPERTY_OBSOLETES);
-       razor_set_destroy(set);
-
-       return 0;
+       return list_properties(argv[0], RAZOR_PROPERTY_OBSOLETES);
 }
 
 static int
 command_list_conflicts(int argc, const char *argv[])
 {
-       struct razor_set *set;
-
-       set = razor_set_open(repo_filename);
-       razor_set_list_properties(set, argv[0], RAZOR_PROPERTY_CONFLICTS);
-       razor_set_destroy(set);
-
-       return 0;
+       return list_properties(argv[0], RAZOR_PROPERTY_CONFLICTS);
 }
 
 static int
diff --git a/razor.c b/razor.c
index cd531dd..e4841d2 100644 (file)
--- a/razor.c
+++ b/razor.c
@@ -323,7 +323,12 @@ add_to_string_pool(struct hashtable *table, const char *key)
 static unsigned long
 add_to_property_pool(struct array *pool, struct array *properties)
 {
-       unsigned long  *p;
+       unsigned long *p;
+
+       if (properties->size == 0)
+               return ~0;
+       else if (properties->size == sizeof *p)
+               return *(unsigned long *) properties->data | RAZOR_IMMEDIATE;
 
        p = array_add(pool, properties->size);
        memcpy(p, properties->data, properties->size);
@@ -756,9 +761,7 @@ serialize_files(struct razor_set *set,
                s += p->count;
 
                if (p->packages.size == 0) {
-                       /* FIXME: We need to make sure this is handled
-                        * correctly as the empty list. */
-                       e->packages = 0 | RAZOR_IMMEDIATE;
+                       e->packages = ~0;
                } else if (p->packages.size / sizeof *r == 1) {
                        r = p->packages.data;
                        e->packages = *r | RAZOR_IMMEDIATE;
@@ -855,7 +858,7 @@ build_file_tree(struct razor_importer *importer)
        e = array_add(&importer->set->files, sizeof *e);
        e->name = root.name | RAZOR_ENTRY_LAST;
        e->start = 1;
-       e->packages = 0;
+       e->packages = ~0;
 
        serialize_files(importer->set, &root, &importer->set->files);
 
@@ -874,10 +877,11 @@ build_package_file_lists(struct razor_set *set, unsigned long *rmap)
        count = set->packages.size / sizeof *p;
        pkgs = zalloc(count * sizeof *pkgs);
 
-       e = set->files.data;
        end = set->files.data + set->files.size;
-       while (e < end) {
-               if (e->packages & RAZOR_IMMEDIATE) {
+       for (e = set->files.data; e < end; e++) {
+               if (e->packages == ~0) {
+                       continue;
+               } else if (e->packages & RAZOR_IMMEDIATE) {
                        e->packages = rmap[e->packages & RAZOR_ENTRY_MASK] |
                                RAZOR_IMMEDIATE;
                        r = &e->packages;
@@ -891,7 +895,6 @@ build_package_file_lists(struct razor_set *set, unsigned long *rmap)
                        if (*r++ & RAZOR_IMMEDIATE)
                                break;
                }
-               e++;
        }
 
        packages = set->packages.data;
@@ -939,23 +942,43 @@ razor_importer_finish(struct razor_importer *importer)
        return set;
 }
 
-void
-razor_set_list(struct razor_set *set, const char *pattern)
+struct razor_package_iterator {
+       struct razor_set *set;
+       struct razor_package *package, *end;
+};
+
+struct razor_package_iterator *
+razor_package_iterator_create(struct razor_set *set)
+{
+       struct razor_package_iterator *pi;
+
+       pi = zalloc(sizeof *pi);
+       pi->set = set;
+       pi->package = set->packages.data;
+       pi->end = set->packages.data + set->packages.size;
+
+       return pi;
+}
+
+int
+razor_package_iterator_next(struct razor_package_iterator *pi,
+                           struct razor_package **package,
+                           const char **name, const char **version)
 {
-       struct razor_package *p, *end;
-       int with_version = 0;
        char *pool;
 
-       pool = set->string_pool.data;
-       end = set->packages.data + set->packages.size;
-       for (p = set->packages.data; p < end; p++) {
-               if (pattern && fnmatch(pattern, &pool[p->name], 0) != 0)
-                   continue;
-               if (with_version)
-                       printf("%s-%s\n", &pool[p->name], &pool[p->version]);
-               else
-                       printf("%s\n", &pool[p->name]);
-       }
+       pool = pi->set->string_pool.data;
+       *package = pi->package;
+       *name = &pool[pi->package->name];
+       *version = &pool[pi->package->version];
+
+       return pi->package++ < pi->end;
+}
+
+void
+razor_package_iterator_destroy(struct razor_package_iterator *pi)
+{
+       free(pi);
 }
 
 struct razor_set *bsearch_set;
@@ -1010,51 +1033,71 @@ razor_set_get_property(struct razor_set *set, const char *property)
        return p;
 }
 
-void
-razor_set_list_properties(struct razor_set *set, const char *name,
-                         enum razor_property_type type)
-{
-       struct razor_property *p, *properties, *end;
-       struct razor_package *package;
-       unsigned long *r;
-       char *pool;
+struct razor_property_iterator {
+       struct razor_set *set;
+       struct razor_property *property, *end;
+       unsigned long *index;
+       int last;
+};
 
-       pool = set->string_pool.data;
+struct razor_property_iterator *
+razor_property_iterator_create(struct razor_set *set,
+                              struct razor_package *package)
+{
+       struct razor_property_iterator *pi;
 
-       if (name) {
-               package = razor_set_get_package(set, name);
-               r = (unsigned long *) set->property_pool.data +
-                       package->properties;
-               properties = set->properties.data;
-               while (1) {
-                       p = &properties[*r & RAZOR_ENTRY_MASK];
-                       if ((p->name >> 30) != type)
-                               goto next;
-                       if (pool[p->version] == '\0')
-                               printf("%s\n",
-                                      &pool[p->name & RAZOR_ENTRY_MASK]);
-                       else
-                               printf("%s-%s\n",
-                                      &pool[p->name & RAZOR_ENTRY_MASK],
-                                      &pool[p->version]);
-               next:
-                       if (*r++ & RAZOR_IMMEDIATE)
-                               break;
-               }
+       pi = zalloc(sizeof *pi);
+       pi->set = set;
+       pi->property = set->properties.data;
+       pi->end = set->properties.data + set->properties.size;
+       if (package) {
+               pi->index = (unsigned long *)
+                       set->property_pool.data + package->properties;
+               pi->last = 0;
        } else {
-               end = set->properties.data + set->properties.size;
-               for (p = set->properties.data; p < end; p++) {
-                       if ((p->name >> 30) != type)
-                               continue;
-                       if (pool[p->version] == '\0')
-                               printf("%s\n",
-                                      &pool[p->name & RAZOR_ENTRY_MASK]);
-                       else
-                               printf("%s-%s\n",
-                                      &pool[p->name & RAZOR_ENTRY_MASK],
-                                      &pool[p->version]);
-               }
+               pi->index = NULL;
+               pi->last = 0;
        }
+
+       return pi;
+}
+
+int
+razor_property_iterator_next(struct razor_property_iterator *pi,
+                            struct razor_property **property,
+                            const char **name, const char **version,
+                            enum razor_property_type *type)
+{
+       char *pool;
+       unsigned long flags, index;
+       int valid;
+       struct razor_property *p, *properties;
+
+       if (pi->index) {
+               properties = pi->set->properties.data;
+               p = &properties[*pi->index & RAZOR_ENTRY_MASK];
+               valid = !pi->last;
+               pi->last = (*pi->index++ & RAZOR_IMMEDIATE) != 0;
+               if (!valid)
+                       return valid;
+       } else {
+               p = pi->property++;
+               valid = p < pi->end;
+       }                       
+
+       pool = pi->set->string_pool.data;
+       *property = p;
+       *name = &pool[p->name & RAZOR_ENTRY_MASK];
+       *version = &pool[p->version];
+       *type = p->name >> 30;
+
+       return valid;
+}
+
+void
+razor_property_iterator_destroy(struct razor_property_iterator *pi)
+{
+       free(pi);
 }
 
 void
diff --git a/razor.h b/razor.h
index 0f7083d..b400711 100644 (file)
--- a/razor.h
+++ b/razor.h
@@ -4,6 +4,8 @@
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
 struct razor_set;
+struct razor_package;
+struct razor_property;
 
 enum razor_property_type {
        RAZOR_PROPERTY_REQUIRES,
@@ -17,7 +19,33 @@ struct razor_set *razor_set_open(const char *filename);
 void razor_set_destroy(struct razor_set *set);
 int razor_set_write(struct razor_set *set, const char *filename);
 
-void razor_set_list(struct razor_set *set, const char *pattern);
+struct razor_package *
+razor_set_get_package(struct razor_set *set, const char *package);
+
+struct razor_property *
+razor_set_get_property(struct razor_set *set, const char *property);
+
+struct razor_package_iterator;
+struct razor_package_iterator *
+razor_package_iterator_create(struct razor_set *set);
+
+int razor_package_iterator_next(struct razor_package_iterator *pi,
+                               struct razor_package **package,
+                               const char **name, const char **version);
+void razor_package_iterator_destroy(struct razor_package_iterator *pi);
+
+struct razor_property_iterator;
+struct razor_property_iterator *
+razor_property_iterator_create(struct razor_set *set,
+                              struct razor_package *package);
+int razor_property_iterator_next(struct razor_property_iterator *pi,
+                                struct razor_property **property,
+                                const char **name, const char **version,
+                                enum razor_property_type *type);
+void
+razor_property_iterator_destroy(struct razor_property_iterator *pi);
+
+
 void razor_set_list_properties(struct razor_set *set, const char *name,
                               enum razor_property_type type);
 void razor_set_list_property_packages(struct razor_set *set,
index 8f8ae12..88bc376 100644 (file)
--- a/sets.xml
+++ b/sets.xml
@@ -1,4 +1,5 @@
 <test-sets>
+
   <set name="b">
     <package name="bash" version="3.2-18.fc8">
       <requires name="libc.so.6"/>
@@ -8,4 +9,16 @@
       <file name="/bin/bash"/>
     </package>
   </set>
+
+  <set name="c">
+    <package name="nss" version="1.8-fc10">
+      <provides name="nss" eq="1.8-fc10"/>
+      <file name="/bin/nss"/>
+    </package>
+
+    <package name="x" version="2">
+      <conflicts name="y" eq="1.1"/>
+    </package>
+  </set>
+
 </test-sets>
index b7e3b4f..fa548b3 100644 (file)
@@ -28,7 +28,7 @@ parse_xml_file(const char *filename,
 
        fd = open(filename, O_RDONLY);
        if (fd < 0) {
-               fprintf(stderr, "open: %m\n");
+               fprintf(stderr, "failed to open %s: %m\n", filename);
                exit(-1);
        }
 
@@ -59,6 +59,8 @@ struct test_set {
 struct test_context {
        struct razor_importer *importer;
        struct test_set *sets;
+       struct razor_package_iterator *package_iterator;
+       struct razor_property_iterator *property_iterator;
 };
 
 static void
@@ -71,6 +73,7 @@ get_atts(const char **atts, ...)
        va_start(ap, atts);
        while (name = va_arg(ap, const char *), name != NULL) {
                ptr = va_arg(ap, const char **);
+               *ptr = NULL;
                for (i = 0; atts[i]; i += 2) {
                        if (strcmp(atts[i], name) == 0)
                                *ptr = atts[i + 1];
@@ -84,14 +87,8 @@ parse_property(struct test_context *ctx, const char **atts,
               enum razor_property_type type)
 {
        const char *name = NULL, *version = NULL;
-       int i;
 
-       for (i = 0; atts[i]; i += 2) {
-               if (strcmp(atts[i], "name") == 0)
-                       name = atts[i + 1];
-               else if (strcmp(atts[i], "eq") == 0)
-                       version = atts[i + 1];
-       }
+       get_atts(atts, "name", &name, "eq", &version, NULL);
 
        if (name == NULL) {
                fprintf(stderr, "no name specified for property\n");
@@ -102,7 +99,7 @@ parse_property(struct test_context *ctx, const char **atts,
 }
 
 static void
-start_test_sets_element(void *data, const char *element, const char **atts)
+start_set_element(void *data, const char *element, const char **atts)
 {
        struct test_context *ctx = data;
        struct test_set *set;
@@ -136,7 +133,7 @@ start_test_sets_element(void *data, const char *element, const char **atts)
 }
 
 static void
-end_test_sets_element (void *data, const char *name)
+end_set_element (void *data, const char *name)
 {
        struct test_context *ctx = data;
 
@@ -147,24 +144,193 @@ end_test_sets_element (void *data, const char *name)
        }
 }
 
+static struct razor_set *
+lookup_set(struct test_context *ctx, const char *name)
+{
+       struct test_set *set;
+
+       for (set = ctx->sets; set != NULL; set = set->next) {
+               if (strcmp(set->name, name) == 0)
+                       return set->set;
+       }
+
+       return NULL;
+}
+
+static void
+verify_begin(struct test_context *ctx, const char **atts)
+{
+       struct razor_set *set;
+       const char *type, *name;
+
+       get_atts(atts, "type", &type, "set", &name, NULL);
+       set = lookup_set(ctx, name);
+       if (set == NULL) {
+               fprintf(stderr, "set %s not found\n", name);
+               exit(-1);
+       }
+
+       if (strcmp(type, "packages") == 0) {
+               ctx->package_iterator =
+                       razor_package_iterator_create(set);
+       } else if (strcmp(type, "properties") == 0) {
+               ctx->property_iterator =
+                       razor_property_iterator_create(set, NULL);
+       } else {
+               fprintf(stderr,
+                       "unknown compare type \"%s\"\n", type);
+               exit(-1);
+       }
+}
+
+static void
+verify_end(struct test_context *ctx)
+{
+       struct razor_package *package;
+       struct razor_property *property;
+       const char *name, *version, *ref_name, *ref_version;
+       enum razor_property_type type;
+
+       if (ctx->package_iterator != NULL) {
+               if (razor_package_iterator_next(ctx->package_iterator,
+                                               &package,
+                                               &name, &version)) {
+                       fprintf(stderr, "too few packages in set\n");
+                       exit(-1);
+               }
+                               
+               razor_package_iterator_destroy(ctx->package_iterator);
+               ctx->package_iterator = NULL;
+       }
+
+       if (ctx->property_iterator != NULL) {
+               if (razor_property_iterator_next(ctx->property_iterator,
+                                                &property,
+                                                &name, &version, &type)) {
+                       fprintf(stderr, "too few properties in set\n");
+                       exit(-1);
+               }
+
+               razor_property_iterator_destroy(ctx->property_iterator);
+               ctx->property_iterator = NULL;
+       }
+}
+
+static void
+verify_package(struct test_context *ctx, const char **atts)
+{
+       struct razor_package *package;
+       const char *name, *version, *ref_name, *ref_version;
+
+       if (ctx->package_iterator == NULL) {
+               fprintf(stderr,
+                       "\"package\" element seen, "
+                       "but not in package verify mode\n");
+               exit(-1);
+       }
+
+       get_atts(atts, "name", &ref_name, "version", &ref_version, NULL);
+       if (!razor_package_iterator_next(ctx->package_iterator,
+                                        &package, &name, &version)) {
+               fprintf(stderr, "too many packages in set\n");
+               exit(-1);
+       }
+                       
+       if (strcmp(name, ref_name) != 0 || strcmp(version, ref_version) != 0) {
+               fprintf(stderr,
+                       "package mismatch; expected %s-%s, got %s-%s\n",
+                       ref_name, ref_version, name, version);
+               exit(-1);
+       }
+}
+
+static void
+verify_property(struct test_context *ctx,
+               enum razor_property_type ref_type, const char **atts)
+{
+       struct razor_property *property;
+       const char *name, *version, *ref_name, *ref_version;
+       enum razor_property_type type;
+       int same_version;
+
+       if (ctx->property_iterator == NULL) {
+               fprintf(stderr,
+                       "\"requires/provides\" element seen, "
+                       "but not in property verify mode\n");
+               exit(-1);
+       }
+
+       get_atts(atts, "name", &ref_name, "eq", &ref_version, NULL);
+       if (!razor_property_iterator_next(ctx->property_iterator, &property,
+                                         &name, &version, &type)) {
+               fprintf(stderr, "too many properties in set\n");
+               exit(-1);
+       }
+                       
+       if (version != NULL && ref_version != NULL)
+               same_version = strcmp(version, ref_version) == 0;
+       else if (version == NULL && ref_version == NULL)
+               same_version = 1;
+       else
+               same_version = 0;
+
+       if (strcmp(name, ref_name) != 0 || !same_version || type != ref_type) {
+               fprintf(stderr,
+                       "property mismatch; expected %s-%s/%d, got %s-%s/%d\n",
+                       ref_name, ref_version, ref_type,
+                       name, version, type);
+               exit(-1);
+       }
+}
+
+static void
+start_test_element(void *data, const char *element, const char **atts)
+{
+       struct test_context *ctx = data;
+       struct razor_set *set;
+       const char *name;
+
+       if (strcmp(element, "import") == 0) {
+               get_atts(atts, "file", &name, NULL);
+               parse_xml_file(name, start_set_element, end_set_element, ctx);
+       } else if (strcmp(element, "update") == 0) {
+               /* run update to create new set */
+       } else if (strcmp(element, "verify") == 0) {
+               verify_begin(ctx, atts);
+       } else if (strcmp(element, "package") == 0) {
+               verify_package(ctx, atts);
+       } else if (strcmp(element, "requires") == 0) {
+               verify_property(ctx, RAZOR_PROPERTY_REQUIRES, atts);
+       } else if (strcmp(element, "provides") == 0) {
+               verify_property(ctx, RAZOR_PROPERTY_PROVIDES, atts);
+       } else if (strcmp(element, "conflicts") == 0) {
+               verify_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts);
+       } else if (strcmp(element, "obsoletes") == 0) {
+               verify_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts);
+       }
+}
+
+static void
+end_test_element (void *data, const char *element)
+{
+       struct test_context *ctx = data;
+
+       if (strcmp(element, "verify") == 0)
+               verify_end(ctx);
+}
+
 int main(int argc, char *argv[])
 {
        struct test_context ctx;
        struct test_set *set;
 
-       if (argc != 3) {
-               fprintf(stderr, "usage: %s SETS-FILE TESTS-FILE\n", argv[0]);
+       if (argc != 2) {
+               fprintf(stderr, "usage: %s TESTS-FILE\n", argv[0]);
                exit(-1);                       
        }
 
        memset(&ctx, 0, sizeof ctx);
-       parse_xml_file(argv[1],
-                      start_test_sets_element,
-                      end_test_sets_element,
-                      &ctx);
-
-       for (set = ctx.sets; set != NULL; set = set->next)
-               printf("set %s\n", set->name);
+       parse_xml_file(argv[1], start_test_element, end_test_element, &ctx);
 
        return 0;
 }