|
1 /* |
|
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
3 * |
|
4 * Copyright 2020 Olaf Wintermann. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * 1. Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
26 * POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #include "xml.h" |
|
30 |
|
31 #include <stdio.h> |
|
32 #include <stdlib.h> |
|
33 |
|
34 #include <libxml/tree.h> |
|
35 |
|
36 #include "testutils.h" |
|
37 |
|
38 #include "../public/webdav.h" |
|
39 #include "../util/writer.h" |
|
40 |
|
41 #include "../webdav/webdav.h" |
|
42 #include "../webdav/xml.h" |
|
43 |
|
44 typedef struct Test1Data { |
|
45 int beginCounter; |
|
46 int endCounter; |
|
47 int elmCounter; |
|
48 int endElmCounter; |
|
49 int textErr; |
|
50 int err; |
|
51 int endErr; |
|
52 int nodesWithAttributesCounter; |
|
53 xmlNode *prev; |
|
54 } Test1Data; |
|
55 |
|
56 static int test1_begin(xmlNode *node, void *userdata) { |
|
57 Test1Data *data = userdata; |
|
58 data->beginCounter++; |
|
59 |
|
60 if(node->type == XML_ELEMENT_NODE) { |
|
61 data->elmCounter++; |
|
62 const char *name = (const char*)node->name; |
|
63 |
|
64 if(!strcmp(name, "ignore") || !strcmp(name, "ignore")) { |
|
65 data->err = 1; |
|
66 return 1; |
|
67 } |
|
68 |
|
69 switch(data->elmCounter) { |
|
70 case 1: if(strcmp(name, "test")){ data->err = 1; return 1; } break; |
|
71 case 2: if(strcmp(name, "elm1")) { data->err = 1; return 1; } break; |
|
72 case 3: if(strcmp(name, "elm2")) { data->err = 1; return 1; } break; |
|
73 case 4: if(strcmp(name, "c")) { data->err = 1; return 1; } break; |
|
74 case 5: if(strcmp(name, "a")) { data->err = 1; return 1; } break; |
|
75 case 6: if(strcmp(name, "d")) { data->err = 1; return 1; } break; |
|
76 case 7: if(strcmp(name, "e")) { data->err = 1; return 1; } break; |
|
77 case 8: if(strcmp(name, "b")) { data->err = 1; return 1; } break; |
|
78 case 9: if(strcmp(name, "x")) { data->err = 1; return 1; } break; |
|
79 case 10: if(strcmp(name, "z")) { data->err = 1; return 1; } break; |
|
80 case 11: if(strcmp(name, "nextelm")) { data->err = 1; return 1; } break; |
|
81 } |
|
82 } else if(node->type == XML_TEXT_NODE) { |
|
83 const char *text = (const char*)node->content; |
|
84 if(!strcmp(text, "teststr")) { |
|
85 if(strcmp((const char*)data->prev->name, "elm1")) { |
|
86 data->textErr = 1; |
|
87 return 1; |
|
88 } |
|
89 } else if(!strcmp(text, "hello") || !strcmp(text, "world")) { |
|
90 if(strcmp((const char*)data->prev->name, "a")) { |
|
91 data->textErr = 1; |
|
92 return 1; |
|
93 } |
|
94 } |
|
95 } |
|
96 |
|
97 if(node->type == XML_ELEMENT_NODE) { |
|
98 data->prev = node; |
|
99 } |
|
100 return 0; |
|
101 } |
|
102 |
|
103 static int test1_end(xmlNode *node, void *userdata) { |
|
104 Test1Data *data = userdata; |
|
105 data->endCounter++; |
|
106 |
|
107 if(node->type == XML_ELEMENT_NODE) { |
|
108 data->endElmCounter++; |
|
109 const char *name = (const char*)node->name; |
|
110 |
|
111 if(!strcmp(name, "ignore") || !strcmp(name, "ignore")) { |
|
112 data->err = 1; |
|
113 return 1; |
|
114 } |
|
115 |
|
116 switch(data->endElmCounter) { |
|
117 case 1: if(strcmp(name, "elm1")){ data->endErr = 1; return 1; } break; |
|
118 case 2: if(strcmp(name, "elm2")){ data->endErr = 1; return 1; } break; |
|
119 case 3: if(strcmp(name, "a")){ data->endErr = 1; return 1; } break; |
|
120 case 4: if(strcmp(name, "b")){ data->endErr = 1; return 1; } break; |
|
121 case 5: if(strcmp(name, "e")){ data->endErr = 1; return 1; } break; |
|
122 case 6: if(strcmp(name, "d")){ data->endErr = 1; return 1; } break; |
|
123 case 7: if(strcmp(name, "c")){ data->endErr = 1; return 1; } break; |
|
124 case 8: if(strcmp(name, "z")){ data->endErr = 1; return 1; } break; |
|
125 case 9: if(strcmp(name, "x")){ data->endErr = 1; return 1; } break; |
|
126 case 10: if(strcmp(name, "test")){ data->endErr = 1; return 1; } break; |
|
127 case 11: if(strcmp(name, "nextelm")) { data->endErr = 1; return 1; } break; |
|
128 } |
|
129 } |
|
130 |
|
131 return 0; |
|
132 } |
|
133 |
|
134 static int test2_begin(xmlNode *node, void *userdata) { |
|
135 Test1Data *data = userdata; |
|
136 data->beginCounter++; |
|
137 if(node->type == XML_ELEMENT_NODE) { |
|
138 data->elmCounter++; |
|
139 if(node->properties) { |
|
140 data->nodesWithAttributesCounter++; |
|
141 } |
|
142 } |
|
143 return 0; |
|
144 } |
|
145 |
|
146 static int test2_end(xmlNode *node, void *userdata) { |
|
147 Test1Data *data = userdata; |
|
148 data->endCounter++; |
|
149 if(node->type == XML_ELEMENT_NODE) { |
|
150 data->endElmCounter++; |
|
151 } |
|
152 return 0; |
|
153 } |
|
154 |
|
155 UCX_TEST(test_wsxml_iterator) { |
|
156 Session *sn = testutil_session(); |
|
157 |
|
158 UCX_TEST_BEGIN; |
|
159 |
|
160 xmlDoc *doc = xmlReadMemory( |
|
161 XML_TESTDATA1, strlen(XML_TESTDATA1), NULL, NULL, 0); |
|
162 xmlDoc *doc2 = xmlReadMemory( |
|
163 XML_TESTDATA2, strlen(XML_TESTDATA2), NULL, NULL, 0); |
|
164 xmlDoc *doc6 = xmlReadMemory( |
|
165 XML_TESTDATA6, strlen(XML_TESTDATA6), NULL, NULL, 0); |
|
166 UCX_TEST_ASSERT(doc, "doc is NULL"); |
|
167 UCX_TEST_ASSERT(doc2, "doc2 is NULL"); |
|
168 UCX_TEST_ASSERT(doc6, "doc6 is NULL"); |
|
169 |
|
170 xmlNode *root = xmlDocGetRootElement(doc); |
|
171 |
|
172 // Test 1: iterate over complete document |
|
173 Test1Data testdata; |
|
174 ZERO(&testdata, sizeof(Test1Data)); |
|
175 int ret = wsxml_iterator(sn->pool, root, test1_begin, test1_end, &testdata); |
|
176 UCX_TEST_ASSERT(ret == 0, "wsxml_iterator failed"); |
|
177 UCX_TEST_ASSERT(!testdata.err, "wrong element order (begin)"); |
|
178 UCX_TEST_ASSERT(!testdata.endErr, "wrong element order (end)"); |
|
179 UCX_TEST_ASSERT(!testdata.textErr, "text order error"); |
|
180 UCX_TEST_ASSERT(testdata.beginCounter == testdata.endCounter, "begin/end counter not equal"); |
|
181 |
|
182 // Test 2: iterate over sub-document |
|
183 ZERO(&testdata, sizeof(Test1Data)); |
|
184 xmlNode *root2 = xmlDocGetRootElement(doc2); |
|
185 xmlNode *sub = root2->children->children; |
|
186 ret = wsxml_iterator(sn->pool, sub, test1_begin, test1_end, &testdata); |
|
187 UCX_TEST_ASSERT(ret == 0, "test2: wsxml_iterator failed"); |
|
188 UCX_TEST_ASSERT(!testdata.err, "test2: wrong element order (begin)"); |
|
189 UCX_TEST_ASSERT(!testdata.endErr, "test2: wrong element order (end)"); |
|
190 UCX_TEST_ASSERT(!testdata.textErr, "test2: text order error"); |
|
191 UCX_TEST_ASSERT(testdata.beginCounter == testdata.endCounter, "test2: begin/end counter not equal"); |
|
192 |
|
193 // Test 3: iterate over document with all kinds of node types |
|
194 xmlNode *root6 = xmlDocGetRootElement(doc6); |
|
195 ZERO(&testdata, sizeof(Test1Data)); |
|
196 ret = wsxml_iterator(sn->pool, root6, test2_begin, test2_end, &testdata); |
|
197 UCX_TEST_ASSERT(ret == 0, "test3: wsxml_iterator failed"); |
|
198 UCX_TEST_ASSERT(testdata.elmCounter == testdata.endElmCounter, "test3: begin/end counter not equal"); |
|
199 UCX_TEST_ASSERT(testdata.elmCounter == 12, "test3: wrong elm counter"); |
|
200 UCX_TEST_ASSERT(testdata.nodesWithAttributesCounter == 5, "test3: wrong entity ref counter"); |
|
201 |
|
202 xmlFreeDoc(doc); |
|
203 xmlFreeDoc(doc2); |
|
204 xmlFreeDoc(doc6); |
|
205 UCX_TEST_END; |
|
206 |
|
207 testutil_destroy_session(sn); |
|
208 } |
|
209 |
|
210 // checks if the namespace list contains the test namespaces x1, x2, x3 and x4 |
|
211 static void check_ns_list(WebdavNSList *list, int *x1, int *x2, int *x3, int *x4) { |
|
212 *x1 = 0; |
|
213 *x2 = 0; |
|
214 *x3 = 0; |
|
215 *x4 = 0; |
|
216 |
|
217 WebdavNSList *elm = list; |
|
218 while(elm) { |
|
219 if(!strcmp((const char*)elm->namespace->prefix, "x1") && |
|
220 !strcmp((const char*)elm->namespace->href, "http://example.com/ns1/")) |
|
221 { |
|
222 *x1 = 1; |
|
223 } else if(!strcmp((const char*)elm->namespace->prefix, "x2") && |
|
224 !strcmp((const char*)elm->namespace->href, "http://example.com/ns2/")) |
|
225 { |
|
226 *x2 = 1; |
|
227 } else if(!strcmp((const char*)elm->namespace->prefix, "x3") && |
|
228 !strcmp((const char*)elm->namespace->href, "http://example.com/ns_0/")) |
|
229 { |
|
230 *x3 = 1; |
|
231 } else if(!strcmp((const char*)elm->namespace->prefix, "x4") && |
|
232 !strcmp((const char*)elm->namespace->href, "http://example.com/ns_0/")) |
|
233 { |
|
234 *x4 = 1; |
|
235 } |
|
236 |
|
237 elm = elm->next; |
|
238 } |
|
239 } |
|
240 |
|
241 UCX_TEST(test_wsxml_get_required_namespaces) { |
|
242 Session *sn = testutil_session(); |
|
243 |
|
244 UCX_TEST_BEGIN; |
|
245 |
|
246 xmlDoc *doc3 = xmlReadMemory( |
|
247 XML_TESTDATA3, strlen(XML_TESTDATA3), NULL, NULL, 0); |
|
248 xmlDoc *doc4 = xmlReadMemory( |
|
249 XML_TESTDATA4, strlen(XML_TESTDATA4), NULL, NULL, 0); |
|
250 xmlDoc *doc5 = xmlReadMemory( |
|
251 XML_TESTDATA5, strlen(XML_TESTDATA5), NULL, NULL, 0); |
|
252 |
|
253 xmlNode *node0 = xmlDocGetRootElement(doc3); |
|
254 xmlNode *node1 = xmlDocGetRootElement(doc3)->children; |
|
255 xmlNode *node2 = xmlDocGetRootElement(doc4)->children; |
|
256 xmlNode *node3 = xmlDocGetRootElement(doc5)->children; |
|
257 |
|
258 UCX_TEST_ASSERT(doc3, "doc3 is NULL"); |
|
259 UCX_TEST_ASSERT(doc4, "doc4 is NULL"); |
|
260 UCX_TEST_ASSERT(doc5, "doc5 is NULL"); |
|
261 |
|
262 int err0, err1, err2, err3; |
|
263 int x1 = 0; |
|
264 int x2 = 0; |
|
265 int x3 = 0; |
|
266 int x4 = 0; |
|
267 WebdavNSList *elm = NULL; |
|
268 |
|
269 // Test 0: |
|
270 WebdavNSList *ns0 = wsxml_get_required_namespaces(sn->pool, node0, &err0); |
|
271 UCX_TEST_ASSERT(!err0, "ns0 failed"); |
|
272 UCX_TEST_ASSERT(!ns0, "ns0: nsdefs should be ignored"); |
|
273 |
|
274 WebdavNSList *ns1 = wsxml_get_required_namespaces(sn->pool, node1, &err1); |
|
275 check_ns_list(ns1, &x1, &x2, &x3, &x4); |
|
276 UCX_TEST_ASSERT(!err1, "ns1 failed"); |
|
277 UCX_TEST_ASSERT(ns1, "ns1: no list"); |
|
278 UCX_TEST_ASSERT(x1, "ns1: x1 missing"); |
|
279 UCX_TEST_ASSERT(x2, "ns1: x2 missing"); |
|
280 UCX_TEST_ASSERT(x3, "ns1: x3 missing"); |
|
281 UCX_TEST_ASSERT(x4, "ns1: x4 missing"); |
|
282 |
|
283 WebdavNSList *ns2 = wsxml_get_required_namespaces(sn->pool, node2, &err2); |
|
284 check_ns_list(ns2, &x1, &x2, &x3, &x4); |
|
285 UCX_TEST_ASSERT(!err2, "ns2 failed"); |
|
286 UCX_TEST_ASSERT(ns2, "ns2: no list"); |
|
287 UCX_TEST_ASSERT(x1, "ns2: x1 missing"); |
|
288 UCX_TEST_ASSERT(x2, "ns2: x2 missing"); |
|
289 UCX_TEST_ASSERT(!x3, "ns2: x3"); |
|
290 UCX_TEST_ASSERT(!x4, "ns2: x4"); |
|
291 |
|
292 WebdavNSList *ns3 = wsxml_get_required_namespaces(sn->pool, node3, &err3); |
|
293 check_ns_list(ns3, &x1, &x2, &x3, &x4); |
|
294 UCX_TEST_ASSERT(!err3, "ns3 failed"); |
|
295 UCX_TEST_ASSERT(ns3, "ns3: no list"); |
|
296 UCX_TEST_ASSERT(x1, "ns3: x1 missing"); |
|
297 UCX_TEST_ASSERT(x2, "ns3: x2 missing"); |
|
298 UCX_TEST_ASSERT(!x3, "ns3: x3"); |
|
299 UCX_TEST_ASSERT(!x4, "ns3: x4"); |
|
300 |
|
301 xmlFreeDoc(doc3); |
|
302 xmlFreeDoc(doc4); |
|
303 xmlFreeDoc(doc5); |
|
304 UCX_TEST_END; |
|
305 |
|
306 testutil_destroy_session(sn); |
|
307 } |
|
308 |
|
309 UCX_TEST(test_wsxml_write_nodes) { |
|
310 Session *sn = testutil_session(); |
|
311 TestIOStream *st = testutil_iostream(2048, TRUE); |
|
312 |
|
313 UCX_TEST_BEGIN; |
|
314 xmlDoc *doc = xmlReadMemory( |
|
315 XML_TESTDATA6, strlen(XML_TESTDATA6), NULL, NULL, 0); |
|
316 UCX_TEST_ASSERT(doc, "xml parser error"); |
|
317 xmlNode *root = xmlDocGetRootElement(doc); |
|
318 |
|
319 Writer writer; |
|
320 char buffer[1024]; |
|
321 writer_init(&writer, st, buffer, 1024); |
|
322 |
|
323 int err = wsxml_write_nodes(sn->pool, &writer, NULL, root); |
|
324 writer_flush(&writer); |
|
325 UCX_TEST_ASSERT(err == 0, "wsxml_write_nodes error"); |
|
326 UCX_TEST_ASSERT(st->buf->pos > 0, "buffer is empty"); |
|
327 |
|
328 //printf("\n\n"); |
|
329 //printf("%.*s\n", (int)st->buf->size, st->buf->space); |
|
330 //printf("\n\n"); |
|
331 |
|
332 xmlDoc *genDoc = xmlReadMemory( |
|
333 st->buf->space, st->buf->size, NULL, NULL, 0); |
|
334 UCX_TEST_ASSERT(genDoc, "generated doc is not valid xml"); |
|
335 |
|
336 xmlFreeDoc(doc); |
|
337 xmlFreeDoc(genDoc); |
|
338 |
|
339 UCX_TEST_END; |
|
340 testutil_iostream_destroy(st); |
|
341 testutil_destroy_session(sn); |
|
342 } |
|
343 |
|
344 UCX_TEST(test_wsxml_nslist2string) { |
|
345 Session *sn = testutil_session(); |
|
346 |
|
347 UCX_TEST_BEGIN; |
|
348 |
|
349 WSNamespace ns1; |
|
350 WSNamespace ns2; |
|
351 WSNamespace ns3; |
|
352 memset(&ns1, 0, sizeof(WSNamespace)); |
|
353 memset(&ns2, 0, sizeof(WSNamespace)); |
|
354 memset(&ns3, 0, sizeof(WSNamespace)); |
|
355 ns1.prefix = (const xmlChar*)"x"; |
|
356 ns1.href = (const xmlChar*)"ns1"; |
|
357 ns2.prefix = (const xmlChar*)"y"; |
|
358 ns2.href = (const xmlChar*)"ns2"; |
|
359 ns3.prefix = (const xmlChar*)"z"; |
|
360 ns3.href = (const xmlChar*)"ns3"; |
|
361 |
|
362 WebdavNSList elm1 = { &ns1, NULL, NULL }; |
|
363 WebdavNSList elm2 = { &ns2, NULL, NULL }; |
|
364 WebdavNSList elm3 = { &ns3, NULL, NULL }; |
|
365 |
|
366 // single elm test |
|
367 char *str1 = wsxml_nslist2string(sn->pool, &elm1); |
|
368 UCX_TEST_ASSERT(str1, "str1 is null"); |
|
369 UCX_TEST_ASSERT(!strcmp(str1, "x:ns1"), "str1: wrong content"); |
|
370 |
|
371 // 2 elm test |
|
372 elm1.next = &elm2; |
|
373 char *str2 = wsxml_nslist2string(sn->pool, &elm1); |
|
374 UCX_TEST_ASSERT(str2, "str2 is null"); |
|
375 UCX_TEST_ASSERT(!strcmp(str2, "x:ns1\ny:ns2"), "str2: wrong content"); |
|
376 |
|
377 // 3 elm test |
|
378 elm2.next = &elm3; |
|
379 char *str3 = wsxml_nslist2string(sn->pool, &elm1); |
|
380 UCX_TEST_ASSERT(str3, "str3 is null"); |
|
381 UCX_TEST_ASSERT(!strcmp(str3, "x:ns1\ny:ns2\nz:ns3"), "str3: wrong content"); |
|
382 |
|
383 // empty prefix test |
|
384 ns1.prefix = NULL; |
|
385 char *str4 = wsxml_nslist2string(sn->pool, &elm1); |
|
386 UCX_TEST_ASSERT(str4, "str3 is null"); |
|
387 UCX_TEST_ASSERT(!strcmp(str4, ":ns1\ny:ns2\nz:ns3"), "str4: wrong content"); |
|
388 |
|
389 UCX_TEST_END; |
|
390 testutil_destroy_session(sn); |
|
391 } |
|
392 |
|
393 UCX_TEST(test_wsxml_string2nslist) { |
|
394 Session *sn = testutil_session(); |
|
395 |
|
396 UCX_TEST_BEGIN; |
|
397 |
|
398 // empty list |
|
399 WebdavNSList *list1 = wsxml_string2nslist(sn->pool, ""); |
|
400 UCX_TEST_ASSERT(!list1, "list1 should be NULL"); |
|
401 |
|
402 // 1 elm list |
|
403 WebdavNSList *list2 = wsxml_string2nslist(sn->pool, "x:ns1"); |
|
404 UCX_TEST_ASSERT(list2, "list2 is NULL"); |
|
405 UCX_TEST_ASSERT(list2->namespace, "list2 namespace is NULL"); |
|
406 UCX_TEST_ASSERT(!strcmp((const char*)list2->namespace->prefix, "x"), "list2: wrong prefix"); |
|
407 UCX_TEST_ASSERT(!strcmp((const char*)list2->namespace->href, "ns1"), "list2: wrong href"); |
|
408 |
|
409 // 2 elm list |
|
410 WebdavNSList *list3 = wsxml_string2nslist(sn->pool, "x:ns1\ny:ns2"); |
|
411 UCX_TEST_ASSERT(list3, "list3 is NULL"); |
|
412 UCX_TEST_ASSERT(list3->namespace, "list3 namespace is NULL"); |
|
413 UCX_TEST_ASSERT(!strcmp((const char*)list3->namespace->prefix, "x"), "list3: wrong prefix"); |
|
414 UCX_TEST_ASSERT(!strcmp((const char*)list3->namespace->href, "ns1"), "list3: wrong href"); |
|
415 UCX_TEST_ASSERT(list3->next, "list3 elm2 is NULL"); |
|
416 UCX_TEST_ASSERT(list3->next->namespace, "list3 namespace 2 is NULL"); |
|
417 UCX_TEST_ASSERT(!strcmp((const char*)list3->namespace->prefix, "x"), "list3: elm2 wrong prefix"); |
|
418 UCX_TEST_ASSERT(!strcmp((const char*)list3->namespace->href, "ns1"), "list3: elm2 wrong href"); |
|
419 |
|
420 // empty prefix |
|
421 WebdavNSList *list4 = wsxml_string2nslist(sn->pool, ":x\ny:ns2"); |
|
422 UCX_TEST_ASSERT(list4, "list4 is NULL"); |
|
423 UCX_TEST_ASSERT(list4->namespace, "list4 namespace is NULL"); |
|
424 UCX_TEST_ASSERT(!list4->namespace->prefix, "list4 elm1 prefix should be NULL"); |
|
425 UCX_TEST_ASSERT(!strcmp((const char*)list3->namespace->href, "ns1"), "list3: wrong href"); |
|
426 |
|
427 |
|
428 UCX_TEST_END; |
|
429 testutil_destroy_session(sn); |
|
430 } |