xml_parser: More tests for xml_parser_filelists.
authorTomas Mlcoch <xtojaj@gmail.com>
Sun, 26 May 2013 12:22:20 +0000 (14:22 +0200)
committerTomas Mlcoch <xtojaj@gmail.com>
Sun, 26 May 2013 12:22:20 +0000 (14:22 +0200)
src/xml_parser.c
src/xml_parser.h
src/xml_parser_filelists.c
src/xml_parser_internal.h
tests/fixtures.h
tests/test_xml_parser_filelists.c
tests/testdata/modified_repo_files/bad_file_type-filelists.xml [new file with mode: 0644]

index 9cdccf1..67255c3 100644 (file)
@@ -5,23 +5,29 @@
 #include "misc.h"
 
 cr_ParserData *
-cr_xml_parser_data()
+cr_xml_parser_data(unsigned int numstates)
 {
     cr_ParserData *pd = g_new0(cr_ParserData, 1);
     pd->ret = CRE_OK;
     pd->content = g_malloc(CONTENT_REALLOC_STEP);
     pd->acontent = CONTENT_REALLOC_STEP;
     pd->msgs = g_string_new(0);
+    pd->swtab = g_malloc0(sizeof(cr_StatesSwitch *) * numstates);
+    pd->sbtab = g_malloc(sizeof(unsigned int) * numstates);
 
     return pd;
 }
 
-void
+char *
 cr_xml_parser_data_free(cr_ParserData *pd)
 {
+    char *msgs;
     g_free(pd->content);
-    g_string_free(pd->msgs, TRUE);
+    msgs = g_string_free(pd->msgs, FALSE);
+    g_free(pd->swtab);
+    g_free(pd->sbtab);
     g_free(pd);
+    return msgs;
 }
 
 void XMLCALL
@@ -37,7 +43,6 @@ cr_char_handler(void *pdata, const XML_Char *s, int len)
     if (!pd->docontent)
         return; /* Do not store the content */
 
-    /* XXX: TODO: Maybe rewrite this reallocation step */
     l = pd->lcontent + len + 1;
     if (l > pd->acontent) {
         pd->acontent = l + CONTENT_REALLOC_STEP;
index 1ecec4e..5863afd 100644 (file)
@@ -62,6 +62,8 @@ typedef int (*cr_XmlParserNewPkgCb)(cr_Package **pkg,
                                     void *cbdata,
                                     GError **err);
 
+/** Default callback for the new package.
+ */
 int cr_newpkgcb(cr_Package **pkg,
                 const char *pkgId,
                 const char *name,
@@ -69,14 +71,28 @@ int cr_newpkgcb(cr_Package **pkg,
                 void *cbdata,
                 GError **err);
 
+/** Parse filelists.xml. File could be compressed.
+ * @param path          Path to filelists.xml (plain or compressed)
+ * @param newpkgcb      Callback for new package (Called when new package
+ *                      xml chunk is found and package object to store
+ *                      the data is needed). If NULL cr_newpkgcb is used.
+ * @param newpkgcb_data User data for the newpkgcb.
+ * @param pkgcb         Package callback. (Called when complete package
+ *                      xml chunk is parsed.). Could be NULL if newpkgcb is
+ *                      not NULL.
+ * @param pkgcb_data    User data for the pkgcb.
+ * @param messages      Pointer to char* where messages (warnings)
+ *                      from parsing will be stored.
+ * @param err           GError **
+ * @return              cr_Error code.
+ */
 int cr_xml_parse_filelists(const char *path,
                            cr_XmlParserNewPkgCb newpkgcb,
                            void *newpkgcb_data,
                            cr_XmlParserPkgCb pkgcb,
                            void *pkgcb_data,
+                           char **messages,
                            GError **err);
-
-
 /** @} */
 
 #ifdef __cplusplus
index 5d3d382..fc4d6cd 100644 (file)
@@ -73,7 +73,6 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
     if (!pd->swtab[pd->state])
          return;  // Current element should not have any sub elements
 
-    /* TODO TEST THIS */
     if (!pd->pkg && pd->state != STATE_FILELISTS && pd->state != STATE_START)
         return;  // Do not parse current package tag and its content
 
@@ -97,18 +96,21 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
         break;
 
     case STATE_PACKAGE: {
-        /* TODO: Parse all attrs in single loop instead of use cr_find_attr */
         const char *pkgId = cr_find_attr("pkgid", attr);
         const char *name  = cr_find_attr("name", attr);
         const char *arch  = cr_find_attr("arch", attr);
 
+
         if (!pkgId) {
+            // Package without a pkgid attr is error
             pd->ret = CRE_BADXMLFILELISTS;
-            g_set_error(pd->err, CR_XML_PARSER_FIL_ERROR, CRE_BADXMLFILELISTS,
+            g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_BADXMLFILELISTS,
                         "Package pkgid attributte is missing!");
             break;
         }
 
+        // Get package object to store current package or NULL if
+        // current XML package element shoud be skipped/ignored.
         if (pd->newpkgcb(&pd->pkg,
                          pkgId,
                          name,
@@ -118,20 +120,40 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
         {
             pd->ret = CRE_CBINTERRUPTED;
             if (tmp_err)
-                g_propagate_prefixed_error(pd->err,
+                g_propagate_prefixed_error(&pd->err,
                                            tmp_err,
                                            "Parsing interrupted:");
             else
-                g_set_error(pd->err, CR_XML_PARSER_FIL_ERROR, CRE_CBINTERRUPTED,
+                g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_CBINTERRUPTED,
                             "Parsing interrupted");
         }
 
-        /* TODO: Insert name and pkg id to the package */
+        if (pd->pkg) {
+            if (!pd->pkg->pkgId)
+                pd->pkg->pkgId = g_string_chunk_insert(pd->pkg->chunk, pkgId);
+            if (!pd->pkg->name && name)
+                pd->pkg->name = g_string_chunk_insert(pd->pkg->chunk, name);
+            if (!pd->pkg->arch && arch)
+                pd->pkg->arch = g_string_chunk_insert(pd->pkg->chunk, arch);
+        }
         break;
     }
 
     case STATE_VERSION:
-        /* TODO: Parse version */
+        if (!pd->pkg)
+            break;
+
+        // Version string insert only if them don't already exists
+
+        if (!pd->pkg->epoch)
+            pd->pkg->epoch = cr_safe_string_chunk_insert(pd->pkg->chunk,
+                                            cr_find_attr("epoch", attr));
+        if (!pd->pkg->version)
+            pd->pkg->version = cr_safe_string_chunk_insert(pd->pkg->chunk,
+                                            cr_find_attr("ver", attr));
+        if (!pd->pkg->release)
+            pd->pkg->release = cr_safe_string_chunk_insert(pd->pkg->chunk,
+                                            cr_find_attr("rel", attr));
         break;
 
     case STATE_FILE: {
@@ -188,16 +210,21 @@ cr_end_handler(void *pdata, const char *element)
         if (!pd->pkg)
             return;
 
-        if (pd->pkgcb(pd->pkg, pd->pkgcb_data, &tmp_err)) {
+        if (pd->pkgcb && pd->pkgcb(pd->pkg, pd->pkgcb_data, &tmp_err)) {
             pd->ret = CRE_CBINTERRUPTED;
             if (tmp_err)
-                g_propagate_prefixed_error(pd->err,
+                g_propagate_prefixed_error(&pd->err,
                                            tmp_err,
                                            "Parsing interrupted:");
             else
-                g_set_error(pd->err, CR_XML_PARSER_FIL_ERROR, CRE_CBINTERRUPTED,
+                g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_CBINTERRUPTED,
                             "Parsing interrupted");
+        } else {
+            // If callback return CRE_OK but it simultaneously set
+            // the tmp_err then it's a programming error.
+            assert(tmp_err == NULL);
         }
+
         pd->pkg = NULL;
         break;
 
@@ -231,15 +258,18 @@ cr_xml_parse_filelists(const char *path,
                        void *newpkgcb_data,
                        cr_XmlParserPkgCb pkgcb,
                        void *pkgcb_data,
+                       char **messages,
                        GError **err)
 {
     int ret = CRE_OK;
     CR_FILE *f;
     cr_ParserData *pd;
     XML_Parser parser;
+    char *msgs;
 
     assert(path);
-    assert(pkgcb);
+    assert(newpkgcb || pkgcb);
+    assert(!messages || *messages == NULL);
     assert(!err || *err == NULL);
 
     if (!newpkgcb)
@@ -255,15 +285,13 @@ cr_xml_parse_filelists(const char *path,
     XML_SetElementHandler(parser, cr_start_handler, cr_end_handler);
     XML_SetCharacterDataHandler(parser, cr_char_handler);
 
-    pd = cr_xml_parser_data();
+    pd = cr_xml_parser_data(NUMSTATES);
     pd->parser = &parser;
     pd->state = STATE_START;
     pd->newpkgcb_data = newpkgcb_data;
     pd->newpkgcb = newpkgcb;
     pd->pkgcb_data = pkgcb_data;
     pd->pkgcb = pkgcb;
-    pd->swtab = g_malloc0(sizeof(cr_StatesSwitch *) * NUMSTATES);
-    pd->sbtab = g_malloc(sizeof(cr_FilState) * NUMSTATES);
     for (cr_StatesSwitch *sw = stateswitches; sw->from != NUMSTATES; sw++) {
         if (!pd->swtab[sw->from])
             pd->swtab[sw->from] = sw;
@@ -303,17 +331,26 @@ cr_xml_parse_filelists(const char *path,
             break;
         }
 
-        if (len == 0)
-            break;
-
         if (pd->ret != CRE_OK) {
             ret = pd->ret;
             break;
         }
+
+        if (len == 0)
+            break;
     }
 
-    cr_xml_parser_data_free(pd);
+    if (pd->err)
+        g_propagate_error(err, pd->err);
+
+    msgs = cr_xml_parser_data_free(pd);
     XML_ParserFree(parser);
+    cr_close(f);
+
+    if (messages)
+        *messages = msgs;
+    else
+        g_free(msgs);
 
     return ret;
 }
index 39fa360..fc66e96 100644 (file)
@@ -80,7 +80,7 @@ typedef struct _cr_ParserData {
         The package which is currently loaded. */
     GString                 *msgs;              /*!<
         Messages from xml parser (warnings about unknown elements etc.) */
-    GError **err;                               /*!<
+    GError *err;                                /*!<
         Error message */
 
     /* Filelists related stuff */
@@ -90,7 +90,7 @@ typedef struct _cr_ParserData {
 
 cr_ParserData *cr_xml_parser_data();
 
-void cr_xml_parser_data_free(cr_ParserData *pd);
+char *cr_xml_parser_data_free(cr_ParserData *pd);
 
 static inline const char *
 cr_find_attr(const char *name, const char **attr)
index 172eacf..c048114 100644 (file)
@@ -48,6 +48,7 @@
 
 // Modified repo files (MFR)
 
+#define TEST_MRF_BAD_TYPE_FIL   TEST_MODIFIED_REPO_FILES_PATH"bad_file_type-filelists.xml"
 #define TEST_MRF_NO_PKGID_FIL   TEST_MODIFIED_REPO_FILES_PATH"no_pkgid-filelists.xml"
 #define TEST_MRF_NO_PKGID_OTH   TEST_MODIFIED_REPO_FILES_PATH"no_pkgid-other.xml"
 #define TEST_MRF_UE_PRI_00      TEST_MODIFIED_REPO_FILES_PATH"unknown_element_00-primary.xml"
index 73d315f..fb1d286 100644 (file)
 #include "createrepo/misc.h"
 #include "createrepo/xml_parser.h"
 
+// Callbacks
+
 static int
 pkgcb(cr_Package *pkg, void *cbdata, GError **err)
 {
+    g_assert(pkg);
     g_assert(!err || *err == NULL);
     if (cbdata) *((int *)cbdata) += 1;
+    cr_package_free(pkg);
     return CRE_OK;
 }
 
-static void test_cr_xml_parse_filelists_00(void)
+static int
+pkgcb_interrupt(cr_Package *pkg, void *cbdata, GError **err)
+{
+    g_assert(pkg);
+    g_assert(!err || *err == NULL);
+    if (cbdata) *((int *)cbdata) += 1;
+    cr_package_free(pkg);
+    return 1;
+}
+
+static int
+newpkgcb_skip_fake_bash(cr_Package **pkg,
+                        const char *pkgId,
+                        const char *name,
+                        const char *arch,
+                        void *cbdata,
+                        GError **err)
+{
+    CR_UNUSED(pkgId);
+    CR_UNUSED(arch);
+    CR_UNUSED(cbdata);
+
+    g_assert(pkg != NULL);
+    g_assert(*pkg == NULL);
+    g_assert(pkgId != NULL);
+    g_assert(!err || *err == NULL);
+
+    if (!g_strcmp0(name, "fake_bash"))
+        return CRE_OK;
+
+    *pkg = cr_package_new();
+    return CRE_OK;
+}
+
+static int
+newpkgcb_interrupt(cr_Package **pkg,
+                   const char *pkgId,
+                   const char *name,
+                   const char *arch,
+                   void *cbdata,
+                   GError **err)
+{
+    CR_UNUSED(pkgId);
+    CR_UNUSED(arch);
+    CR_UNUSED(cbdata);
+
+    g_assert(pkg != NULL);
+    g_assert(*pkg == NULL);
+    g_assert(pkgId != NULL);
+    g_assert(!err || *err == NULL);
+
+    return 1;
+}
+
+// Tests
+
+static void
+test_cr_xml_parse_filelists_00(void)
+{
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_REPO_00_FILELISTS, NULL, NULL,
+                                     pkgcb, NULL, NULL, &tmp_err);
+    g_assert(tmp_err == NULL);
+    g_assert_cmpint(ret, ==, CRE_OK);
+}
+
+static void
+test_cr_xml_parse_filelists_01(void)
+{
+    int parsed = 0;
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_REPO_01_FILELISTS, NULL, NULL,
+                                     pkgcb, &parsed, NULL, &tmp_err);
+    g_assert(tmp_err == NULL);
+    g_assert_cmpint(ret, ==, CRE_OK);
+    g_assert_cmpint(parsed, ==, 1);
+}
+
+static void
+test_cr_xml_parse_filelists_02(void)
+{
+    int parsed = 0;
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_REPO_02_FILELISTS, NULL, NULL,
+                                     pkgcb, &parsed, NULL, &tmp_err);
+    g_assert(tmp_err == NULL);
+    g_assert_cmpint(ret, ==, CRE_OK);
+    g_assert_cmpint(parsed, ==, 2);
+}
+
+static void
+test_cr_xml_parse_filelists_unknown_element_00(void)
 {
-    int ret;
+    int parsed = 0;
     GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_00, NULL, NULL,
+                                     pkgcb, &parsed, NULL, &tmp_err);
+    g_assert(tmp_err == NULL);
+    g_assert_cmpint(ret, ==, CRE_OK);
+    g_assert_cmpint(parsed, ==, 2);
+}
 
-    ret = cr_xml_parse_filelists(TEST_REPO_00_FILELISTS,
-                                 NULL,
-                                 NULL,
-                                 pkgcb,
-                                 NULL,
-                                 &tmp_err);
+static void
+test_cr_xml_parse_filelists_unknown_element_01(void)
+{
+    int parsed = 0;
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_01, NULL, NULL,
+                                     pkgcb, &parsed, NULL, &tmp_err);
+    g_assert(tmp_err == NULL);
+    g_assert_cmpint(ret, ==, CRE_OK);
+    g_assert_cmpint(parsed, ==, 1);
+}
 
+static void
+test_cr_xml_parse_filelists_unknown_element_02(void)
+{
+    int parsed = 0;
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_02, NULL, NULL,
+                                     pkgcb, &parsed, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
+    g_assert_cmpint(parsed, ==, 2);
 }
 
-static void test_cr_xml_parse_filelists_01(void)
+static void
+test_cr_xml_parse_filelists_no_pkgid(void)
 {
-    int ret;
     int parsed = 0;
     GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_MRF_NO_PKGID_FIL, NULL, NULL,
+                                     pkgcb, &parsed, NULL, &tmp_err);
+    g_assert(tmp_err != NULL);
+    g_error_free(tmp_err);
+    g_assert_cmpint(ret, ==, CRE_BADXMLFILELISTS);
+}
 
-    ret = cr_xml_parse_filelists(TEST_REPO_01_FILELISTS,
-                                 NULL,
-                                 NULL,
-                                 pkgcb,
-                                 &parsed,
-                                 &tmp_err);
+static void
+test_cr_xml_parse_filelists_skip_fake_bash_00(void)
+{
+    int parsed = 0;
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_00,
+                                     newpkgcb_skip_fake_bash, NULL,
+                                     pkgcb, &parsed, NULL, &tmp_err);
+    g_assert(tmp_err == NULL);
+    g_assert_cmpint(ret, ==, CRE_OK);
+    g_assert_cmpint(parsed, ==, 1);
+}
 
+static void
+test_cr_xml_parse_filelists_skip_fake_bash_01(void)
+{
+    int parsed = 0;
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_MRF_UE_FIL_01,
+                                     newpkgcb_skip_fake_bash, NULL,
+                                     pkgcb, &parsed, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
+    g_assert_cmpint(parsed, ==, 0);
+}
+
+static void
+test_cr_xml_parse_filelists_pkgcb_interrupt(void)
+{
+    int parsed = 0;
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_REPO_02_FILELISTS, NULL, NULL,
+                                     pkgcb_interrupt, &parsed, NULL, &tmp_err);
+    g_assert(tmp_err != NULL);
+    g_error_free(tmp_err);
+    g_assert_cmpint(ret, ==, CRE_CBINTERRUPTED);
     g_assert_cmpint(parsed, ==, 1);
 }
 
-static void test_cr_xml_parse_filelists_02(void)
+static void
+test_cr_xml_parse_filelists_newpkgcb_interrupt(void)
 {
-    int ret;
     int parsed = 0;
     GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_REPO_02_FILELISTS,
+                                     newpkgcb_interrupt, NULL,
+                                     pkgcb, &parsed,  NULL, &tmp_err);
+    g_assert(tmp_err != NULL);
+    g_error_free(tmp_err);
+    g_assert_cmpint(ret, ==, CRE_CBINTERRUPTED);
+    g_assert_cmpint(parsed, ==, 0);
+}
 
-    ret = cr_xml_parse_filelists(TEST_REPO_02_FILELISTS,
-                                 NULL,
-                                 NULL,
-                                 pkgcb,
-                                 &parsed,
-                                 &tmp_err);
+static void
+test_cr_xml_parse_filelists_bad_file_type_00(void)
+{
+    int parsed = 0;
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_MRF_BAD_TYPE_FIL,
+                                     NULL, NULL,
+                                     pkgcb, &parsed, NULL, &tmp_err);
+    g_assert(tmp_err == NULL);
+    g_assert_cmpint(ret, ==, CRE_OK);
+    g_assert_cmpint(parsed, ==, 2);
+}
 
+static void
+test_cr_xml_parse_filelists_bad_file_type_01(void)
+{
+    int parsed = 0;
+    char *msgs = NULL;
+    GError *tmp_err = NULL;
+    int ret = cr_xml_parse_filelists(TEST_MRF_BAD_TYPE_FIL,
+                                     NULL, NULL,
+                                     pkgcb, &parsed, &msgs, &tmp_err);
+    g_assert(msgs != NULL);
+    g_assert_cmpstr(msgs, ==, "Unknown file type \"foo\";");
+    g_free(msgs);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 2);
 }
 
-int main(int argc, char *argv[])
+int
+main(int argc, char *argv[])
 {
     g_test_init(&argc, &argv, NULL);
 
@@ -96,5 +270,26 @@ int main(int argc, char *argv[])
                     test_cr_xml_parse_filelists_01);
     g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_02",
                     test_cr_xml_parse_filelists_02);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_unknown_element_00",
+                    test_cr_xml_parse_filelists_unknown_element_00);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_unknown_element_01",
+                    test_cr_xml_parse_filelists_unknown_element_01);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_unknown_element_02",
+                    test_cr_xml_parse_filelists_unknown_element_02);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_no_pgkid",
+                    test_cr_xml_parse_filelists_no_pkgid);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_skip_fake_bash_00",
+                    test_cr_xml_parse_filelists_skip_fake_bash_00);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_skip_fake_bash_01",
+                    test_cr_xml_parse_filelists_skip_fake_bash_01);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_pkgcb_interrupt",
+                    test_cr_xml_parse_filelists_pkgcb_interrupt);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_newpkgcb_interrupt",
+                    test_cr_xml_parse_filelists_newpkgcb_interrupt);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_bad_file_type_00",
+                    test_cr_xml_parse_filelists_bad_file_type_00);
+    g_test_add_func("/xml_parser_filelists/test_cr_xml_parse_filelists_bad_file_type_01",
+                    test_cr_xml_parse_filelists_bad_file_type_01);
+
     return g_test_run();
 }
diff --git a/tests/testdata/modified_repo_files/bad_file_type-filelists.xml b/tests/testdata/modified_repo_files/bad_file_type-filelists.xml
new file mode 100644 (file)
index 0000000..e3158fb
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<filelists xmlns="http://linux.duke.edu/metadata/filelists" packages="2">
+<package pkgid="90f61e546938a11449b710160ad294618a5bd3062e46f8cf851fd0088af184b7" name="fake_bash" arch="x86_64">
+  <version epoch="0" ver="1.1.1" rel="1"/>
+  <file>/usr/bin/fake_bash</file>
+</package>
+<package pkgid="6d43a638af70ef899933b1fd86a866f18f65b0e0e17dcbf2e42bfd0cdd7c63c3" name="super_kernel" arch="x86_64">
+  <version epoch="0" ver="6.0.1" rel="2"/>
+  <file>/usr/bin/super_kernel</file>
+  <file>/usr/share/man/super_kernel.8.gz</file>
+  <file type="foo">/usr/file_with_bad_type</file>
+</package>
+</filelists>
\ No newline at end of file