xml_parser: Report warnings via callback.
authorTomas Mlcoch <tmlcoch@redhat.com>
Thu, 30 May 2013 07:45:46 +0000 (09:45 +0200)
committerTomas Mlcoch <tmlcoch@redhat.com>
Thu, 30 May 2013 08:39:19 +0000 (10:39 +0200)
src/error.c
src/error.h
src/xml_parser.c
src/xml_parser.h
src/xml_parser_filelists.c
src/xml_parser_internal.h
tests/test_xml_parser_filelists.c

index b021527..399c39d 100644 (file)
@@ -137,6 +137,12 @@ cr_xml_file_error_quark(void)
 }
 
 GQuark
+cr_xml_parser_error_quark(void)
+{
+    return g_quark_from_static_string("cr_xml_parser_error");
+}
+
+GQuark
 cr_xml_parser_fil_error_quark(void)
 {
     return g_quark_from_static_string("cr_xml_parser_filelists_error");
index b5ad55a..194f50a 100644 (file)
@@ -91,6 +91,7 @@ const char *cr_strerror(cr_Error rc);
 #define CR_XML_DUMP_OTHER_ERROR         cr_xml_dump_other_error_quark()
 #define CR_XML_DUMP_PRIMARY_ERROR       cr_xml_dump_primary_error_quark()
 #define CR_XML_FILE_ERROR               cr_xml_file_error_quark()
+#define CR_XML_PARSER_ERROR             cr_xml_parser_error_quark()
 #define CR_XML_PARSER_FIL_ERROR         cr_xml_parser_fil_error_quark()
 #define CR_XML_PARSER_OTH_ERROR         cr_xml_parser_oth_error_quark()
 #define CR_XML_PARSER_PRI_ERROR         cr_xml_parser_pri_error_quark()
@@ -107,6 +108,7 @@ GQuark cr_xml_dump_filelists_error_quark(void);
 GQuark cr_xml_dump_other_error_quark(void);
 GQuark cr_xml_dump_primary_error_quark(void);
 GQuark cr_xml_file_error_quark(void);
+GQuark cr_xml_parser_error_quark(void);
 GQuark cr_xml_parser_fil_error_quark(void);
 GQuark cr_xml_parser_oth_error_quark(void);
 GQuark cr_xml_parser_pri_error_quark(void);
index 71e53e8..e169619 100644 (file)
@@ -1,3 +1,5 @@
+#include <glib.h>
+#include <glib/gprintf.h>
 #include <assert.h>
 #include "error.h"
 #include "xml_parser.h"
@@ -10,23 +12,19 @@ cr_xml_parser_data(unsigned int numstates)
     cr_ParserData *pd = g_new0(cr_ParserData, 1);
     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;
 }
 
-char *
+void
 cr_xml_parser_data_free(cr_ParserData *pd)
 {
-    char *msgs;
     g_free(pd->content);
-    msgs = g_string_free(pd->msgs, FALSE);
     g_free(pd->swtab);
     g_free(pd->sbtab);
     g_free(pd);
-    return msgs;
 }
 
 void XMLCALL
@@ -56,6 +54,44 @@ cr_char_handler(void *pdata, const XML_Char *s, int len)
 }
 
 int
+cr_xml_parser_warning(cr_ParserData *pd,
+                      cr_XmlParserWarningType type,
+                      const char *msg,
+                      ...)
+{
+    int ret;
+    va_list args;
+    char *warn;
+    GError *tmp_err;
+
+    assert(pd);
+    assert(msg);
+
+    if (!pd->warningcb)
+        return CR_CB_RET_OK;
+
+    va_start(args, msg);
+    g_vasprintf(&warn, msg, args);
+    va_end(args);
+
+    tmp_err = NULL;
+    ret = pd->warningcb(type, warn, pd->warningcb_data, &tmp_err);
+    if (ret != CR_CB_RET_OK) {
+        if (tmp_err)
+            g_propagate_prefixed_error(&pd->err, tmp_err,
+                                       "Parsing interrupted: ");
+        else
+            g_set_error(&pd->err, CR_XML_PARSER_ERROR, CRE_CBINTERRUPTED,
+                        "Parsing interrupted");
+    }
+
+
+    assert(pd->err || ret == CR_CB_RET_OK);
+
+    return ret;
+}
+
+int
 cr_newpkgcb(cr_Package **pkg,
             const char *pkgId,
             const char *name,
index 078dab2..e6a6f86 100644 (file)
@@ -34,6 +34,12 @@ extern "C" {
 #define CR_CB_RET_OK    0
 #define CR_CB_RET_ERR   1
 
+typedef enum {
+    CR_XML_WARNING_UNKNOWNTAG,  /*!< Unknown tag */
+    CR_XML_WARNING_MISSINGATTR, /*!< Missing attribute */
+    CR_XML_WARNING_UNKNOWNVAL,  /*!< Unknown tag or attribute value */
+    CR_XML_WARNING_SENTINEL,
+} cr_XmlParserWarningType;
 
 /** Callback for XML parser wich is called when a package element is parsed.
  * @param pkg       Currently parsed package.
@@ -66,27 +72,42 @@ typedef int (*cr_XmlParserNewPkgCb)(cr_Package **pkg,
                                     void *cbdata,
                                     GError **err);
 
+/** Callback for XML parser warnings. All reported warnings are non-fatal,
+ * and ignored by default. But if callback return CR_CB_RET_ERR instead of
+ * CR_CB_RET_OK then parsing is immediately interrupted.
+ * @param type      Type of warning
+ * @param msg       Warning msg
+ * @param cbdata    User data.
+ * @param err       GError **
+ * @return          CR_CB_RET_OK (0) or CR_CB_RET_ERR (1) - stops the parsing
+ */
+typedef int (*cr_XmlParserWarningCb)(cr_XmlParserWarningType type,
+                                     char *msg,
+                                     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.
+ * @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 warningcb      Callback for warning messages.
+ * @param warningcb_data User data for the warningcb.
+ * @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,
+                           cr_XmlParserWarningCb warningcb,
+                           void *warningcb_data,
                            GError **err);
 /** @} */
 
index 574773a..fe7f4e1 100644 (file)
@@ -31,6 +31,9 @@
 #include "logging.h"
 #include "misc.h"
 
+#define ERR_DOMAIN      CR_XML_PARSER_FIL_ERROR
+#define ERR_CODE_XML    CRE_BADXMLFILELISTS
+
 typedef enum {
     STATE_START,
     STATE_FILELISTS,
@@ -64,14 +67,16 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
         return;  // There was an error -> do nothing
 
     if (pd->depth != pd->statedepth) {
-        // There probably was an unknown element
+        // We are inside of unknown element
         pd->depth++;
         return;
     }
     pd->depth++;
 
-    if (!pd->swtab[pd->state])
-         return;  // Current element should not have any sub elements
+    if (!pd->swtab[pd->state]) {
+        // Current element should not have any sub elements
+        return;
+    }
 
     if (!pd->pkg && pd->state != STATE_FILELISTS && pd->state != STATE_START)
         return;  // Do not parse current package tag and its content
@@ -80,8 +85,12 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
     for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
         if (!strcmp(element, sw->ename))
             break;
-    if (sw->from != pd->state)
-      return; // There is no state for the name -> skip
+    if (sw->from != pd->state) {
+        // No state for current element (unknown element)
+        cr_xml_parser_warning(pd, CR_XML_WARNING_UNKNOWNTAG,
+                              "Unknown element \"%s\"", element);
+        return;
+    }
 
     // Update parser data
     pd->state      = sw->to;
@@ -103,11 +112,19 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
 
         if (!pkgId) {
             // Package without a pkgid attr is error
-            g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_BADXMLFILELISTS,
+            g_set_error(&pd->err, ERR_DOMAIN, ERR_CODE_XML,
                         "Package pkgid attributte is missing!");
             break;
         }
 
+        if (!name)
+            cr_xml_parser_warning(pd, CR_XML_WARNING_MISSINGATTR,
+                           "Missing attribute \"name\" of a package element");
+
+        if (!arch)
+            cr_xml_parser_warning(pd, CR_XML_WARNING_MISSINGATTR,
+                           "Missing attribute \"arch\" of a package element");
+
         // Get package object to store current package or NULL if
         // current XML package element shoud be skipped/ignored.
         if (pd->newpkgcb(&pd->pkg,
@@ -122,8 +139,9 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
                                            tmp_err,
                                            "Parsing interrupted:");
             else
-                g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_CBINTERRUPTED,
+                g_set_error(&pd->err, ERR_DOMAIN, CRE_CBINTERRUPTED,
                             "Parsing interrupted");
+            break;
         } else {
             // If callback return CRE_OK but it simultaneously set
             // the tmp_err then it's a programming error.
@@ -142,8 +160,7 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
     }
 
     case STATE_VERSION:
-        if (!pd->pkg)
-            break;
+        assert(pd->pkg);
 
         // Version string insert only if them don't already exists
 
@@ -159,6 +176,8 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
         break;
 
     case STATE_FILE: {
+        assert(pd->pkg);
+
         const char *type = cr_find_attr("type", attr);
         pd->last_file_type = FILE_FILE;
         if (type) {
@@ -167,9 +186,8 @@ cr_start_handler(void *pdata, const char *element, const char **attr)
             else if (!strcmp(type, "ghost"))
                 pd->last_file_type = FILE_GHOST;
             else
-                g_string_append_printf(pd->msgs,
-                                       "Unknown file type \"%s\";",
-                                       type);
+                cr_xml_parser_warning(pd, CR_XML_WARNING_UNKNOWNVAL,
+                                      "Unknown file type \"%s\"", type);
         }
         break;
     }
@@ -189,10 +207,10 @@ cr_end_handler(void *pdata, const char *element)
     CR_UNUSED(element);
 
     if (pd->err)
-        return; /* There was an error -> do nothing */
+        return; // There was an error -> do nothing
 
     if (pd->depth != pd->statedepth) {
-        /* Back from the unknown state */
+        // Back from the unknown state
         pd->depth--;
         return;
     }
@@ -216,9 +234,9 @@ cr_end_handler(void *pdata, const char *element)
             if (tmp_err)
                 g_propagate_prefixed_error(&pd->err,
                                            tmp_err,
-                                           "Parsing interrupted:");
+                                           "Parsing interrupted: ");
             else
-                g_set_error(&pd->err, CR_XML_PARSER_FIL_ERROR, CRE_CBINTERRUPTED,
+                g_set_error(&pd->err, ERR_DOMAIN, CRE_CBINTERRUPTED,
                             "Parsing interrupted");
         } else {
             // If callback return CRE_OK but it simultaneously set
@@ -230,7 +248,9 @@ cr_end_handler(void *pdata, const char *element)
         break;
 
     case STATE_FILE: {
-        if (!pd->pkg || !pd->content)
+        assert(pd->pkg);
+
+        if (!pd->content)
             break;
 
         cr_PackageFile *pkg_file = cr_package_file_new();
@@ -259,18 +279,17 @@ cr_xml_parse_filelists(const char *path,
                        void *newpkgcb_data,
                        cr_XmlParserPkgCb pkgcb,
                        void *pkgcb_data,
-                       char **messages,
+                       cr_XmlParserWarningCb warningcb,
+                       void *warningcb_data,
                        GError **err)
 {
     int ret = CRE_OK;
     cr_ParserData *pd;
     XML_Parser parser;
-    char *msgs;
     GError *tmp_err = NULL;
 
     assert(path);
     assert(newpkgcb || pkgcb);
-    assert(!messages || *messages == NULL);
     assert(!err || *err == NULL);
 
     if (!newpkgcb)  // Use default newpkgcb
@@ -289,6 +308,8 @@ cr_xml_parse_filelists(const char *path,
     pd->newpkgcb = newpkgcb;
     pd->pkgcb_data = pkgcb_data;
     pd->pkgcb = pkgcb;
+    pd->warningcb = warningcb;
+    pd->warningcb_data = warningcb_data;
     for (cr_StatesSwitch *sw = stateswitches; sw->from != NUMSTATES; sw++) {
         if (!pd->swtab[sw->from])
             pd->swtab[sw->from] = sw;
@@ -315,12 +336,7 @@ cr_xml_parse_filelists(const char *path,
         cr_package_free(pd->pkg);
     }
 
-    msgs = cr_xml_parser_data_free(pd);
-    if (messages)
-        *messages = msgs;
-    else
-        g_free(msgs);
-
+    cr_xml_parser_data_free(pd);
     XML_ParserFree(parser);
 
     return ret;
index e011061..8647774 100644 (file)
@@ -87,10 +87,11 @@ typedef struct _cr_ParserData {
         User data for the pkgcb. */
     cr_XmlParserPkgCb       pkgcb;              /*!<
         Callback called when a signel pkg data are completly parsed. */
+    void                    *warningcb_data;    /*!<
+        User data fot he warningcb. */
+    cr_XmlParserWarningCb   warningcb;
     cr_Package              *pkg;               /*!<
         The package which is currently loaded. */
-    GString                 *msgs;              /*!<
-        Messages from xml parser (warnings about unknown elements etc.) */
 
     /* Filelists related stuff */
 
@@ -103,7 +104,7 @@ cr_ParserData *cr_xml_parser_data();
 
 /** Frees XML parser data.
  */
-char *cr_xml_parser_data_free(cr_ParserData *pd);
+void cr_xml_parser_data_free(cr_ParserData *pd);
 
 /** Find attribute in list of attributes.
  * @param name      Attribute name.
@@ -126,6 +127,15 @@ cr_find_attr(const char *name, const char **attr)
  */
 void XMLCALL cr_char_handler(void *pdata, const XML_Char *s, int len);
 
+/** Wrapper for user warning cb.
+ * It checks if warningcb is defined, if defined, it build warning msg from
+ * va_args, calls warningcb and propagate (set) error if necessary.
+ */
+int cr_xml_parser_warning(cr_ParserData *pd,
+                          cr_XmlParserWarningType type,
+                          const char *msg,
+                          ...);
+
 /** Default callback for the new package.
  */
 int cr_newpkgcb(cr_Package **pkg,
index e7728f1..166e178 100644 (file)
@@ -35,7 +35,7 @@ pkgcb(cr_Package *pkg, void *cbdata, GError **err)
     g_assert(!err || *err == NULL);
     if (cbdata) *((int *)cbdata) += 1;
     cr_package_free(pkg);
-    return CRE_OK;
+    return CR_CB_RET_OK;
 }
 
 static int
@@ -45,7 +45,7 @@ pkgcb_interrupt(cr_Package *pkg, void *cbdata, GError **err)
     g_assert(!err || *err == NULL);
     if (cbdata) *((int *)cbdata) += 1;
     cr_package_free(pkg);
-    return 1;
+    return CR_CB_RET_ERR;
 }
 
 static int
@@ -69,7 +69,7 @@ newpkgcb_skip_fake_bash(cr_Package **pkg,
         return CRE_OK;
 
     *pkg = cr_package_new();
-    return CRE_OK;
+    return CR_CB_RET_OK;
 }
 
 static int
@@ -90,7 +90,47 @@ newpkgcb_interrupt(cr_Package **pkg,
     g_assert(pkgId != NULL);
     g_assert(!err || *err == NULL);
 
-    return 1;
+    if (cbdata) *((int *)cbdata) += 1;
+
+    return CR_CB_RET_ERR;
+}
+
+static int
+warningcb(cr_XmlParserWarningType type,
+                    char *msg,
+                    void *cbdata,
+                    GError **err)
+{
+    CR_UNUSED(type);
+    CR_UNUSED(msg);
+    CR_UNUSED(err);
+
+    g_assert(type < CR_XML_WARNING_SENTINEL);
+    g_assert(!err || *err == NULL);
+
+    g_string_append((GString *) cbdata, msg);
+    g_string_append((GString *) cbdata, ";");
+
+    return CR_CB_RET_OK;
+}
+
+static int
+warningcb_interrupt(cr_XmlParserWarningType type,
+                    char *msg,
+                    void *cbdata,
+                    GError **err)
+{
+    CR_UNUSED(type);
+    CR_UNUSED(msg);
+    CR_UNUSED(cbdata);
+    CR_UNUSED(err);
+
+    g_assert(type < CR_XML_WARNING_SENTINEL);
+    g_assert(!err || *err == NULL);
+
+    if (cbdata) *((int *)cbdata) += 1;
+
+    return CR_CB_RET_ERR;
 }
 
 // Tests
@@ -100,7 +140,7 @@ 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);
+                                     pkgcb, NULL, NULL, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
 }
@@ -111,7 +151,7 @@ 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);
+                                     pkgcb, &parsed, NULL, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 1);
@@ -123,7 +163,7 @@ 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);
+                                     pkgcb, &parsed, NULL, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 2);
@@ -135,7 +175,7 @@ test_cr_xml_parse_filelists_unknown_element_00(void)
     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);
+                                     pkgcb, &parsed, NULL, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 2);
@@ -147,7 +187,7 @@ 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);
+                                     pkgcb, &parsed, NULL, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 1);
@@ -159,7 +199,7 @@ 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);
+                                     pkgcb, &parsed, NULL, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 2);
@@ -171,7 +211,7 @@ test_cr_xml_parse_filelists_no_pkgid(void)
     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);
+                                     pkgcb, &parsed, NULL, NULL, &tmp_err);
     g_assert(tmp_err != NULL);
     g_error_free(tmp_err);
     g_assert_cmpint(ret, ==, CRE_BADXMLFILELISTS);
@@ -184,7 +224,7 @@ test_cr_xml_parse_filelists_skip_fake_bash_00(void)
     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);
+                                     pkgcb, &parsed, NULL, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 1);
@@ -197,7 +237,7 @@ test_cr_xml_parse_filelists_skip_fake_bash_01(void)
     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);
+                                     pkgcb, &parsed, NULL, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 0);
@@ -209,7 +249,7 @@ 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);
+                            pkgcb_interrupt, &parsed, NULL, NULL, &tmp_err);
     g_assert(tmp_err != NULL);
     g_error_free(tmp_err);
     g_assert_cmpint(ret, ==, CRE_CBINTERRUPTED);
@@ -223,7 +263,7 @@ test_cr_xml_parse_filelists_newpkgcb_interrupt(void)
     GError *tmp_err = NULL;
     int ret = cr_xml_parse_filelists(TEST_REPO_02_FILELISTS,
                                      newpkgcb_interrupt, NULL,
-                                     pkgcb, &parsed,  NULL, &tmp_err);
+                                     pkgcb, &parsed,  NULL, NULL, &tmp_err);
     g_assert(tmp_err != NULL);
     g_error_free(tmp_err);
     g_assert_cmpint(ret, ==, CRE_CBINTERRUPTED);
@@ -231,13 +271,28 @@ test_cr_xml_parse_filelists_newpkgcb_interrupt(void)
 }
 
 static void
-test_cr_xml_parse_filelists_bad_file_type_00(void)
+test_cr_xml_parse_filelists_warningcb_interrupt(void)
 {
-    int parsed = 0;
+    int parsed = 0, numofwarnings = 0;
     GError *tmp_err = NULL;
     int ret = cr_xml_parse_filelists(TEST_MRF_BAD_TYPE_FIL,
                                      NULL, NULL,
-                                     pkgcb, &parsed, NULL, &tmp_err);
+                                     pkgcb, &parsed,  warningcb_interrupt,
+                                     &numofwarnings, &tmp_err);
+    g_assert(tmp_err != NULL);
+    g_error_free(tmp_err);
+    g_assert_cmpint(ret, ==, CRE_CBINTERRUPTED);
+    g_assert_cmpint(parsed, ==, 1);
+    g_assert_cmpint(numofwarnings, ==, 1);
+}
+
+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, NULL, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 2);
@@ -246,18 +301,19 @@ test_cr_xml_parse_filelists_bad_file_type_00(void)
 static void
 test_cr_xml_parse_filelists_bad_file_type_01(void)
 {
+    char *warnmsgs;
     int parsed = 0;
-    char *msgs = NULL;
+    GString *warn_strings = g_string_new(0);
     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);
+    int ret = cr_xml_parse_filelists(TEST_MRF_BAD_TYPE_FIL, NULL, NULL,
+                                     pkgcb, &parsed, warningcb,
+                                     warn_strings, &tmp_err);
     g_assert(tmp_err == NULL);
     g_assert_cmpint(ret, ==, CRE_OK);
     g_assert_cmpint(parsed, ==, 2);
+    warnmsgs = g_string_free(warn_strings, FALSE);
+    g_assert_cmpstr(warnmsgs, ==, "Unknown file type \"foo\";");
+    g_free(warnmsgs);
 }
 
 int
@@ -287,6 +343,8 @@ main(int argc, char *argv[])
                     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_warningcb_interrupt",
+                    test_cr_xml_parse_filelists_warningcb_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",