add test for xml iterator webdav

Thu, 16 Jan 2020 19:14:53 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 16 Jan 2020 19:14:53 +0100
branch
webdav
changeset 224
0de1ec82628e
parent 223
bbaec8415c10
child 225
e4f3e1433098

add test for xml iterator

src/server/test/main.c file | annotate | diff | comparison | revisions
src/server/test/objs.mk file | annotate | diff | comparison | revisions
src/server/test/xml.c file | annotate | diff | comparison | revisions
src/server/test/xml.h file | annotate | diff | comparison | revisions
src/server/webdav/objs.mk file | annotate | diff | comparison | revisions
src/server/webdav/xml.c file | annotate | diff | comparison | revisions
--- a/src/server/test/main.c	Tue Jan 14 22:05:34 2020 +0100
+++ b/src/server/test/main.c	Thu Jan 16 19:14:53 2020 +0100
@@ -42,6 +42,7 @@
 #include <ucx/test.h>
 
 #include "vfs.h"
+#include "xml.h"
 #include "webdav.h"
 
 void test() {
@@ -68,6 +69,9 @@
     ucx_test_register(suite, test_vfs_opendir);
     ucx_test_register(suite, test_vfs_readdir);
     
+    // xml tests
+    ucx_test_register(suite, test_wsxml_iterator);
+    
     // webdav tests
     ucx_test_register(suite, test_propfind_parse);
     ucx_test_register(suite, test_proppatch_parse);
--- a/src/server/test/objs.mk	Tue Jan 14 22:05:34 2020 +0100
+++ b/src/server/test/objs.mk	Thu Jan 16 19:14:53 2020 +0100
@@ -34,6 +34,7 @@
 TESTOBJ += testutils.o
 TESTOBJ += webdav.o
 TESTOBJ += vfs.o
+TESTOBJ += xml.o
 
 TESTOBJS = $(TESTOBJ:%=$(TEST_OBJPRE)%)
 TESTSOURCE = $(TESTOBJ:%.o=test/%.c)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/test/xml.c	Thu Jan 16 19:14:53 2020 +0100
@@ -0,0 +1,167 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2020 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "xml.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libxml/tree.h>
+
+#include "testutils.h"
+
+#include "../public/webdav.h"
+
+typedef struct Test1Data {
+    int beginCounter;
+    int endCounter;
+    int elmCounter;
+    int endElmCounter;
+    int textErr;
+    int err;
+    int endErr;
+    xmlNode *prev;
+} Test1Data;
+
+static int test1_begin(xmlNode *node, void *userdata) {
+    Test1Data *data = userdata;
+    data->beginCounter++;
+    
+    if(node->type == XML_ELEMENT_NODE) {
+        data->elmCounter++;
+        const char *name = (const char*)node->name;
+        
+        if(!strcmp(name, "ignore") || !strcmp(name, "ignore")) {
+            data->err = 1;
+            return 1;
+        }
+        
+        switch(data->elmCounter) {
+            case 1: if(strcmp(name, "test")){ data->err = 1; return 1; } break;
+            case 2: if(strcmp(name, "elm1")) { data->err = 1; return 1; } break;
+            case 3: if(strcmp(name, "elm2")) { data->err = 1; return 1; } break;
+            case 4: if(strcmp(name, "c")) { data->err = 1; return 1; } break;
+            case 5: if(strcmp(name, "a")) { data->err = 1; return 1; } break;
+            case 6: if(strcmp(name, "d")) { data->err = 1; return 1; } break;
+            case 7: if(strcmp(name, "e")) { data->err = 1; return 1; } break;
+            case 8: if(strcmp(name, "b")) { data->err = 1; return 1; } break;
+            case 9: if(strcmp(name, "x")) { data->err = 1; return 1; } break;
+            case 10: if(strcmp(name, "z")) { data->err = 1; return 1; } break;
+            case 11: if(strcmp(name, "nextelm")) { data->err = 1; return 1; } break;
+        }
+    } else if(node->type == XML_TEXT_NODE) {
+        const char *text = (const char*)node->content;
+        if(!strcmp(text, "teststr")) {
+            if(strcmp((const char*)data->prev->name, "elm1")) {
+                data->textErr = 1;
+                return 1;
+            }
+        } else if(!strcmp(text, "hello") || !strcmp(text, "world")) {
+            if(strcmp((const char*)data->prev->name, "a")) {
+                data->textErr = 1;
+                return 1;
+            }
+        }
+    }
+    
+    if(node->type == XML_ELEMENT_NODE) {
+        data->prev = node;
+    }
+    return 0;
+}
+
+static int test1_end(xmlNode *node, void *userdata) {
+    Test1Data *data = userdata;
+    data->endCounter++;
+    
+    if(node->type == XML_ELEMENT_NODE) {
+        data->endElmCounter++;
+        const char *name = (const char*)node->name;
+        
+        if(!strcmp(name, "ignore") || !strcmp(name, "ignore")) {
+            data->err = 1;
+            return 1;
+        }
+        
+        switch(data->endElmCounter) {
+            case 1: if(strcmp(name, "elm1")){ data->endErr = 1; return 1; } break;
+            case 2: if(strcmp(name, "elm2")){ data->endErr = 1; return 1; } break;
+            case 3: if(strcmp(name, "a")){ data->endErr = 1; return 1; } break;
+            case 4: if(strcmp(name, "b")){ data->endErr = 1; return 1; } break;
+            case 5: if(strcmp(name, "e")){ data->endErr = 1; return 1; } break;
+            case 6: if(strcmp(name, "d")){ data->endErr = 1; return 1; } break;
+            case 7: if(strcmp(name, "c")){ data->endErr = 1; return 1; } break;
+            case 8: if(strcmp(name, "z")){ data->endErr = 1; return 1; } break;
+            case 9: if(strcmp(name, "x")){ data->endErr = 1; return 1; } break;
+            case 10: if(strcmp(name, "test")){ data->endErr = 1; return 1; } break;
+            case 11: if(strcmp(name, "nextelm")) { data->endErr = 1; return 1; } break;
+        }
+    }
+    
+    return 0;
+}
+
+UCX_TEST(test_wsxml_iterator) {
+    Session *sn = testutil_session();
+    
+    UCX_TEST_BEGIN;
+    
+    xmlDoc *doc = xmlReadMemory(
+            XML_TESTDATA1, strlen(XML_TESTDATA1), NULL, NULL, 0);
+    xmlDoc *doc2 = xmlReadMemory(
+            XML_TESTDATA2, strlen(XML_TESTDATA2), NULL, NULL, 0);
+    UCX_TEST_ASSERT(doc, "doc is NULL");
+    UCX_TEST_ASSERT(doc2, "doc2 is NULL");
+    
+    xmlNode *root = xmlDocGetRootElement(doc);
+    
+    // Test 1: iterate over complete document
+    Test1Data testdata;
+    ZERO(&testdata, sizeof(Test1Data));
+    int ret = wsxml_iterator(sn->pool, root, test1_begin, test1_end, &testdata);
+    UCX_TEST_ASSERT(ret == 0, "wsxml_iterator failed");
+    UCX_TEST_ASSERT(!testdata.err, "wrong element order (begin)");
+    UCX_TEST_ASSERT(!testdata.endErr, "wrong element order (end)");
+    UCX_TEST_ASSERT(!testdata.textErr, "text order error");
+    UCX_TEST_ASSERT(testdata.beginCounter == testdata.endCounter, "begin/end counter not equal");
+    
+    // Test 2: iterate over sub-document
+    ZERO(&testdata, sizeof(Test1Data));
+    xmlNode *root2 = xmlDocGetRootElement(doc2);
+    xmlNode *sub = root2->children->children;
+    ret = wsxml_iterator(sn->pool, sub, test1_begin, test1_end, &testdata);
+    UCX_TEST_ASSERT(ret == 0, "test2: wsxml_iterator failed");
+    UCX_TEST_ASSERT(!testdata.err, "test2: wrong element order (begin)");
+    UCX_TEST_ASSERT(!testdata.endErr, "test2: wrong element order (end)");
+    UCX_TEST_ASSERT(!testdata.textErr, "test2: text order error");
+    UCX_TEST_ASSERT(testdata.beginCounter == testdata.endCounter, "test2: begin/end counter not equal");
+    
+    xmlFreeDoc(doc);
+    xmlFreeDoc(doc2);
+    UCX_TEST_END;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/test/xml.h	Thu Jan 16 19:14:53 2020 +0100
@@ -0,0 +1,74 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2020 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TEST_XML_H
+#define TEST_XML_H
+
+#include "../public/nsapi.h"
+#include <ucx/test.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UCX_TEST(test_wsxml_iterator);
+
+
+#define XML_TESTDATA1 "<?xml version=\"1.0\" encoding=\"utf-8\" ?> \
+        <test> \
+            <elm1>teststr</elm1> \
+            <!-- comment -->\
+            <elm2 /> \
+            <c> \
+                <a>hello</a> \
+                world\
+                <d><e><b/></e></d>\
+            </c> \
+            <x><z/></x> \
+        </test>"
+
+#define XML_TESTDATA2 "<?xml version=\"1.0\" encoding=\"utf-8\" ?> \
+        <root><wrapper><test> \
+            <elm1>teststr</elm1> \
+            <!-- comment -->\
+            <elm2 /> \
+            <c> \
+                <a>hello</a> \
+                world\
+                <d><e><b/></e></d>\
+            </c> \
+            <x><z/></x> \
+        </test><nextelm/></wrapper><ignore/></root>"
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TEST_XML_H */
+
--- a/src/server/webdav/objs.mk	Tue Jan 14 22:05:34 2020 +0100
+++ b/src/server/webdav/objs.mk	Thu Jan 16 19:14:53 2020 +0100
@@ -31,6 +31,7 @@
 DAV_OBJPRE = $(OBJ_DIR)$(DAV_SRC_DIR)
 
 DAVOBJ = webdav.o
+DAVOBJ += xml.o
 DAVOBJ += requestparser.o
 DAVOBJ += operation.o
 DAVOBJ += multistatus.o
--- a/src/server/webdav/xml.c	Tue Jan 14 22:05:34 2020 +0100
+++ b/src/server/webdav/xml.c	Thu Jan 16 19:14:53 2020 +0100
@@ -30,12 +30,12 @@
 #include <stdlib.h>
 #include <string.h>
 
-
 #include "xml.h"
 
 typedef struct StackElm {
     WSXmlNode *node; // list of nodes
-    WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL
+    //WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL
+    int endonly;
     struct StackElm *next;
 } StackElm;
 
@@ -58,7 +58,8 @@
     }
     stack->next = NULL;
     stack->node = node;
-    stack->parent = NULL;
+    stack->endonly = 0;
+    //stack->parent = NULL;
     
     int ret = 0;
     int br = 0;
@@ -68,7 +69,7 @@
         stack = cur->next;              // and remove it
         cur->next = NULL;
         
-        while(xmlnode) {
+        while(xmlnode && !cur->endonly) {
             // element begin callback
             if(begincb(xmlnode, udata)) {
                 br = 1;
@@ -88,20 +89,37 @@
                 newelm->node = xmlnode->children;
                 // setting the parent will make sure endcb will be called
                 // for the current xmlnode after all children are processed
-                newelm->parent = xmlnode;
+                //newelm->parent = xmlnode;
+                newelm->endonly = 0;
                 
                 // if xmlnode->next is not NULL, there are still nodes at
                 // this level, therefore we have to put these also on the
                 // stack
                 // this way, the remaining nodes are processed after all
-                // children of the current node are processed
+                // children and the end tag are processed
                 if(xmlnode->next) {
-                    // reuse current StackElm
-                    cur->node = xmlnode->next;
-                    STACK_PUSH(stack, cur);
-                    cur = NULL;
+                    StackElm *nextelm = pool_malloc(pool, sizeof(StackElm));
+                    if(!nextelm) {
+                        ret = 1;
+                        br = 1;
+                        break;
+                    }
+                    nextelm->node = xmlnode->next;
+                    nextelm->next = NULL;
+                    nextelm->endonly = 0;
+                    STACK_PUSH(stack, nextelm);
                 }
                 
+                // we have to put the end tag of the current element
+                // on the stack to ensure endcb is called for the current
+                // element, after all children are processed
+                // reuse cur
+                cur->node = xmlnode;
+                cur->endonly = 1;
+                STACK_PUSH(stack, cur);
+                
+                cur = NULL;
+                
                 // now we can put the children on the stack
                 STACK_PUSH(stack, newelm);
                 // break, because we don't want to process xmlnode->next now
@@ -109,6 +127,7 @@
             } else {
                 // no children means, the end callback can be called directly
                 // after the begin callback (no intermediate nodes)
+                cur->node = NULL;
                 if(endcb(xmlnode, udata)) {
                     br = 1;
                     break;
@@ -122,11 +141,11 @@
             break; // break because of an error
         }
         
-        if(cur) {
-            if(cur->parent) {
-                if(endcb(cur->parent, udata)) {
-                    break;
-                }
+        if(cur && cur->node) {
+            //xmlNode *endNode = cur->parent ? cur->parent : cur->node;
+            xmlNode *endNode = cur->node;
+            if(endcb(endNode, udata)) {
+                break;
             }
             pool_free(pool, cur);
         }

mercurial