1 /*
2 * runsuite.c: C program to run libxml2 against published testsuites
3 *
4 * See Copyright for the status of this software.
5 *
6 * [email protected]
7 */
8
9 #include "libxml.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14
15 #include <libxml/catalog.h>
16 #include <libxml/parser.h>
17 #include <libxml/parserInternals.h>
18 #include <libxml/tree.h>
19 #include <libxml/uri.h>
20 #if defined(LIBXML_SCHEMAS_ENABLED) && defined(LIBXML_XPATH_ENABLED)
21 #include <libxml/xmlreader.h>
22
23 #include <libxml/xpath.h>
24 #include <libxml/xpathInternals.h>
25
26 #include <libxml/relaxng.h>
27 #include <libxml/xmlschemas.h>
28 #include <libxml/xmlschemastypes.h>
29
30 #define LOGFILE "runsuite.log"
31 static FILE *logfile = NULL;
32 static int verbose = 0;
33
34
35 /************************************************************************
36 * *
37 * File name and path utilities *
38 * *
39 ************************************************************************/
40
checkTestFile(const char * filename)41 static int checkTestFile(const char *filename) {
42 struct stat buf;
43
44 if (stat(filename, &buf) == -1)
45 return(0);
46
47 #if defined(_WIN32)
48 if (!(buf.st_mode & _S_IFREG))
49 return(0);
50 #else
51 if (!S_ISREG(buf.st_mode))
52 return(0);
53 #endif
54
55 return(1);
56 }
57
composeDir(const xmlChar * dir,const xmlChar * path)58 static xmlChar *composeDir(const xmlChar *dir, const xmlChar *path) {
59 char buf[500];
60
61 if (dir == NULL) return(xmlStrdup(path));
62 if (path == NULL) return(NULL);
63
64 snprintf(buf, 500, "%s/%s", (const char *) dir, (const char *) path);
65 return(xmlStrdup((const xmlChar *) buf));
66 }
67
68 /************************************************************************
69 * *
70 * Libxml2 specific routines *
71 * *
72 ************************************************************************/
73
74 static int nb_tests = 0;
75 static int nb_errors = 0;
76 static int nb_internals = 0;
77 static int nb_schematas = 0;
78 static int nb_unimplemented = 0;
79 static int nb_leaks = 0;
80
81 static int
fatalError(void)82 fatalError(void) {
83 fprintf(stderr, "Exitting tests on fatal error\n");
84 exit(1);
85 }
86
87 /*
88 * that's needed to implement <resource>
89 */
90 #define MAX_ENTITIES 20
91 static char *testEntitiesName[MAX_ENTITIES];
92 static char *testEntitiesValue[MAX_ENTITIES];
93 static int nb_entities = 0;
resetEntities(void)94 static void resetEntities(void) {
95 int i;
96
97 for (i = 0;i < nb_entities;i++) {
98 if (testEntitiesName[i] != NULL)
99 xmlFree(testEntitiesName[i]);
100 if (testEntitiesValue[i] != NULL)
101 xmlFree(testEntitiesValue[i]);
102 }
103 nb_entities = 0;
104 }
addEntity(char * name,char * content)105 static int addEntity(char *name, char *content) {
106 if (nb_entities >= MAX_ENTITIES) {
107 fprintf(stderr, "Too many entities defined\n");
108 return(-1);
109 }
110 testEntitiesName[nb_entities] = name;
111 testEntitiesValue[nb_entities] = content;
112 nb_entities++;
113 return(0);
114 }
115
116 static int
testResourceLoader(void * vctxt ATTRIBUTE_UNUSED,const char * URL,const char * ID ATTRIBUTE_UNUSED,xmlResourceType type ATTRIBUTE_UNUSED,int flags ATTRIBUTE_UNUSED,xmlParserInputPtr * out)117 testResourceLoader(void *vctxt ATTRIBUTE_UNUSED, const char *URL,
118 const char *ID ATTRIBUTE_UNUSED,
119 xmlResourceType type ATTRIBUTE_UNUSED,
120 int flags ATTRIBUTE_UNUSED, xmlParserInputPtr *out) {
121 int i;
122
123 for (i = 0; i < nb_entities; i++) {
124 if (!strcmp(testEntitiesName[i], URL)) {
125 *out = xmlNewInputFromString(testEntitiesName[i],
126 testEntitiesValue[i],
127 XML_INPUT_BUF_STATIC);
128 return(XML_ERR_OK);
129 }
130 }
131
132 return(xmlNewInputFromUrl(URL, 0, out));
133 }
134
135 /*
136 * Trapping the error messages at the generic level to grab the equivalent of
137 * stderr messages on CLI tools.
138 */
139 static char testErrors[32769];
140 static int testErrorsSize = 0;
141
test_log(const char * msg,...)142 static void test_log(const char *msg, ...) {
143 va_list args;
144 if (logfile != NULL) {
145 fprintf(logfile, "\n------------\n");
146 va_start(args, msg);
147 vfprintf(logfile, msg, args);
148 va_end(args);
149 fprintf(logfile, "%s", testErrors);
150 testErrorsSize = 0; testErrors[0] = 0;
151 }
152 if (verbose) {
153 va_start(args, msg);
154 vfprintf(stderr, msg, args);
155 va_end(args);
156 }
157 }
158
159 static void
testErrorHandler(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)160 testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
161 va_list args;
162 int res;
163
164 if (testErrorsSize >= 32768)
165 return;
166 va_start(args, msg);
167 res = vsnprintf(&testErrors[testErrorsSize],
168 32768 - testErrorsSize,
169 msg, args);
170 va_end(args);
171 if (testErrorsSize + res >= 32768) {
172 /* buffer is full */
173 testErrorsSize = 32768;
174 testErrors[testErrorsSize] = 0;
175 } else {
176 testErrorsSize += res;
177 }
178 testErrors[testErrorsSize] = 0;
179 }
180
181 static xmlXPathContextPtr ctxtXPath;
182
183 static void
initializeLibxml2(void)184 initializeLibxml2(void) {
185 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
186 xmlInitParser();
187 ctxtXPath = xmlXPathNewContext(NULL);
188 /*
189 * Deactivate the cache if created; otherwise we have to create/free it
190 * for every test, since it will confuse the memory leak detection.
191 * Note that normally this need not be done, since the cache is not
192 * created until set explicitly with xmlXPathContextSetCache();
193 * but for test purposes it is sometimes useful to activate the
194 * cache by default for the whole library.
195 */
196 if (ctxtXPath->cache != NULL)
197 xmlXPathContextSetCache(ctxtXPath, 0, -1, 0);
198 /* used as default namespace in xstc tests */
199 xmlXPathRegisterNs(ctxtXPath, BAD_CAST "ts", BAD_CAST "TestSuite");
200 xmlXPathRegisterNs(ctxtXPath, BAD_CAST "xlink",
201 BAD_CAST "http://www.w3.org/1999/xlink");
202 xmlSetGenericErrorFunc(NULL, testErrorHandler);
203 #ifdef LIBXML_CATALOG_ENABLED
204 xmlInitializeCatalog();
205 xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
206 #endif
207 #ifdef LIBXML_SCHEMAS_ENABLED
208 xmlSchemaInitTypes();
209 xmlRelaxNGInitTypes();
210 #endif
211 }
212
213 static xmlNodePtr
getNext(xmlNodePtr cur,const char * xpath)214 getNext(xmlNodePtr cur, const char *xpath) {
215 xmlNodePtr ret = NULL;
216 xmlXPathObjectPtr res;
217 xmlXPathCompExprPtr comp;
218
219 if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL))
220 return(NULL);
221 ctxtXPath->doc = cur->doc;
222 ctxtXPath->node = cur;
223 comp = xmlXPathCompile(BAD_CAST xpath);
224 if (comp == NULL) {
225 fprintf(stderr, "Failed to compile %s\n", xpath);
226 return(NULL);
227 }
228 res = xmlXPathCompiledEval(comp, ctxtXPath);
229 xmlXPathFreeCompExpr(comp);
230 if (res == NULL)
231 return(NULL);
232 if ((res->type == XPATH_NODESET) &&
233 (res->nodesetval != NULL) &&
234 (res->nodesetval->nodeNr > 0) &&
235 (res->nodesetval->nodeTab != NULL))
236 ret = res->nodesetval->nodeTab[0];
237 xmlXPathFreeObject(res);
238 return(ret);
239 }
240
241 static xmlChar *
getString(xmlNodePtr cur,const char * xpath)242 getString(xmlNodePtr cur, const char *xpath) {
243 xmlChar *ret = NULL;
244 xmlXPathObjectPtr res;
245 xmlXPathCompExprPtr comp;
246
247 if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL))
248 return(NULL);
249 ctxtXPath->doc = cur->doc;
250 ctxtXPath->node = cur;
251 comp = xmlXPathCompile(BAD_CAST xpath);
252 if (comp == NULL) {
253 fprintf(stderr, "Failed to compile %s\n", xpath);
254 return(NULL);
255 }
256 res = xmlXPathCompiledEval(comp, ctxtXPath);
257 xmlXPathFreeCompExpr(comp);
258 if (res == NULL)
259 return(NULL);
260 if (res->type == XPATH_STRING) {
261 ret = res->stringval;
262 res->stringval = NULL;
263 }
264 xmlXPathFreeObject(res);
265 return(ret);
266 }
267
268 /************************************************************************
269 * *
270 * Test test/xsdtest/xsdtestsuite.xml *
271 * *
272 ************************************************************************/
273
274 static int
xsdIncorrectTestCase(xmlNodePtr cur)275 xsdIncorrectTestCase(xmlNodePtr cur) {
276 xmlNodePtr test;
277 xmlBufferPtr buf;
278 xmlRelaxNGParserCtxtPtr pctxt;
279 xmlRelaxNGPtr rng = NULL;
280 int ret = 0, memt;
281
282 cur = getNext(cur, "./incorrect[1]");
283 if (cur == NULL) {
284 return(0);
285 }
286
287 test = getNext(cur, "./*");
288 if (test == NULL) {
289 test_log("Failed to find test in correct line %ld\n",
290 xmlGetLineNo(cur));
291 return(1);
292 }
293
294 memt = xmlMemUsed();
295 /*
296 * dump the schemas to a buffer, then reparse it and compile the schemas
297 */
298 buf = xmlBufferCreate();
299 if (buf == NULL) {
300 fprintf(stderr, "out of memory !\n");
301 fatalError();
302 }
303 xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
304 xmlNodeDump(buf, test->doc, test, 0, 0);
305 pctxt = xmlRelaxNGNewMemParserCtxt(
306 (const char *) xmlBufferContent(buf), xmlBufferLength(buf));
307 xmlRelaxNGSetParserErrors(pctxt, testErrorHandler, testErrorHandler,
308 pctxt);
309 xmlRelaxNGSetResourceLoader(pctxt, testResourceLoader, NULL);
310 rng = xmlRelaxNGParse(pctxt);
311 xmlRelaxNGFreeParserCtxt(pctxt);
312 if (rng != NULL) {
313 test_log("Failed to detect incorrect RNG line %ld\n",
314 xmlGetLineNo(test));
315 ret = 1;
316 goto done;
317 }
318
319 done:
320 if (buf != NULL)
321 xmlBufferFree(buf);
322 if (rng != NULL)
323 xmlRelaxNGFree(rng);
324 xmlResetLastError();
325 if (memt != xmlMemUsed()) {
326 test_log("Validation of tests starting line %ld leaked %d\n",
327 xmlGetLineNo(cur), xmlMemUsed() - memt);
328 nb_leaks++;
329 }
330 return(ret);
331 }
332
333 static void
installResources(xmlNodePtr tst,const xmlChar * base)334 installResources(xmlNodePtr tst, const xmlChar *base) {
335 xmlNodePtr test;
336 xmlBufferPtr buf;
337 xmlChar *name, *content, *res;
338
339 buf = xmlBufferCreate();
340 if (buf == NULL) {
341 fprintf(stderr, "out of memory !\n");
342 fatalError();
343 }
344 xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
345 xmlNodeDump(buf, tst->doc, tst, 0, 0);
346
347 while (tst != NULL) {
348 test = getNext(tst, "./*");
349 if (test != NULL) {
350 xmlBufferEmpty(buf);
351 xmlNodeDump(buf, test->doc, test, 0, 0);
352 name = getString(tst, "string(@name)");
353 content = xmlStrdup(xmlBufferContent(buf));
354 if ((name != NULL) && (content != NULL)) {
355 res = composeDir(base, name);
356 xmlFree(name);
357 addEntity((char *) res, (char *) content);
358 } else {
359 if (name != NULL) xmlFree(name);
360 if (content != NULL) xmlFree(content);
361 }
362 }
363 tst = getNext(tst, "following-sibling::resource[1]");
364 }
365 if (buf != NULL)
366 xmlBufferFree(buf);
367 }
368
369 static void
installDirs(xmlNodePtr tst,const xmlChar * base)370 installDirs(xmlNodePtr tst, const xmlChar *base) {
371 xmlNodePtr test;
372 xmlChar *name, *res;
373
374 name = getString(tst, "string(@name)");
375 if (name == NULL)
376 return;
377 res = composeDir(base, name);
378 xmlFree(name);
379 if (res == NULL) {
380 return;
381 }
382 /* Now process resources and subdir recursively */
383 test = getNext(tst, "./resource[1]");
384 if (test != NULL) {
385 installResources(test, res);
386 }
387 test = getNext(tst, "./dir[1]");
388 while (test != NULL) {
389 installDirs(test, res);
390 test = getNext(test, "following-sibling::dir[1]");
391 }
392 xmlFree(res);
393 }
394
395 static int
xsdTestCase(xmlNodePtr tst)396 xsdTestCase(xmlNodePtr tst) {
397 xmlNodePtr test, tmp, cur;
398 xmlBufferPtr buf;
399 xmlDocPtr doc = NULL;
400 xmlRelaxNGParserCtxtPtr pctxt;
401 xmlRelaxNGValidCtxtPtr ctxt;
402 xmlRelaxNGPtr rng = NULL;
403 int ret = 0, mem, memt;
404 xmlChar *dtd;
405
406 resetEntities();
407 testErrorsSize = 0; testErrors[0] = 0;
408
409 tmp = getNext(tst, "./dir[1]");
410 if (tmp != NULL) {
411 installDirs(tmp, NULL);
412 }
413 tmp = getNext(tst, "./resource[1]");
414 if (tmp != NULL) {
415 installResources(tmp, NULL);
416 }
417
418 cur = getNext(tst, "./correct[1]");
419 if (cur == NULL) {
420 return(xsdIncorrectTestCase(tst));
421 }
422
423 test = getNext(cur, "./*");
424 if (test == NULL) {
425 fprintf(stderr, "Failed to find test in correct line %ld\n",
426 xmlGetLineNo(cur));
427 return(1);
428 }
429
430 memt = xmlMemUsed();
431 /*
432 * dump the schemas to a buffer, then reparse it and compile the schemas
433 */
434 buf = xmlBufferCreate();
435 if (buf == NULL) {
436 fprintf(stderr, "out of memory !\n");
437 fatalError();
438 }
439 xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
440 xmlNodeDump(buf, test->doc, test, 0, 0);
441 pctxt = xmlRelaxNGNewMemParserCtxt(
442 (const char *) xmlBufferContent(buf), xmlBufferLength(buf));
443 xmlRelaxNGSetParserErrors(pctxt, testErrorHandler, testErrorHandler,
444 pctxt);
445 xmlRelaxNGSetResourceLoader(pctxt, testResourceLoader, NULL);
446 rng = xmlRelaxNGParse(pctxt);
447 xmlRelaxNGFreeParserCtxt(pctxt);
448
449 if (rng == NULL) {
450 test_log("Failed to parse RNGtest line %ld\n",
451 xmlGetLineNo(test));
452 nb_errors++;
453 ret = 1;
454 goto done;
455 }
456 /*
457 * now scan all the siblings of correct to process the <valid> tests
458 */
459 tmp = getNext(cur, "following-sibling::valid[1]");
460 while (tmp != NULL) {
461 dtd = xmlGetProp(tmp, BAD_CAST "dtd");
462 test = getNext(tmp, "./*");
463 if (test == NULL) {
464 fprintf(stderr, "Failed to find test in <valid> line %ld\n",
465 xmlGetLineNo(tmp));
466
467 } else {
468 xmlBufferEmpty(buf);
469 if (dtd != NULL)
470 xmlBufferAdd(buf, dtd, -1);
471 xmlNodeDump(buf, test->doc, test, 0, 0);
472
473 /*
474 * We are ready to run the test
475 */
476 mem = xmlMemUsed();
477 doc = xmlReadMemory((const char *) xmlBufferContent(buf),
478 xmlBufferLength(buf), "test", NULL, 0);
479 if (doc == NULL) {
480 test_log("Failed to parse valid instance line %ld\n",
481 xmlGetLineNo(tmp));
482 nb_errors++;
483 } else {
484 nb_tests++;
485 ctxt = xmlRelaxNGNewValidCtxt(rng);
486 xmlRelaxNGSetValidErrors(ctxt,
487 testErrorHandler, testErrorHandler, ctxt);
488 ret = xmlRelaxNGValidateDoc(ctxt, doc);
489 xmlRelaxNGFreeValidCtxt(ctxt);
490 if (ret > 0) {
491 test_log("Failed to validate valid instance line %ld\n",
492 xmlGetLineNo(tmp));
493 nb_errors++;
494 } else if (ret < 0) {
495 test_log("Internal error validating instance line %ld\n",
496 xmlGetLineNo(tmp));
497 nb_errors++;
498 }
499 xmlFreeDoc(doc);
500 }
501 xmlResetLastError();
502 if (mem != xmlMemUsed()) {
503 test_log("Validation of instance line %ld leaked %d\n",
504 xmlGetLineNo(tmp), xmlMemUsed() - mem);
505 nb_leaks++;
506 }
507 }
508 if (dtd != NULL)
509 xmlFree(dtd);
510 tmp = getNext(tmp, "following-sibling::valid[1]");
511 }
512 /*
513 * now scan all the siblings of correct to process the <invalid> tests
514 */
515 tmp = getNext(cur, "following-sibling::invalid[1]");
516 while (tmp != NULL) {
517 test = getNext(tmp, "./*");
518 if (test == NULL) {
519 fprintf(stderr, "Failed to find test in <invalid> line %ld\n",
520 xmlGetLineNo(tmp));
521
522 } else {
523 xmlBufferEmpty(buf);
524 xmlNodeDump(buf, test->doc, test, 0, 0);
525
526 /*
527 * We are ready to run the test
528 */
529 mem = xmlMemUsed();
530 doc = xmlReadMemory((const char *) xmlBufferContent(buf),
531 xmlBufferLength(buf), "test", NULL, 0);
532 if (doc == NULL) {
533 test_log("Failed to parse valid instance line %ld\n",
534 xmlGetLineNo(tmp));
535 nb_errors++;
536 } else {
537 nb_tests++;
538 ctxt = xmlRelaxNGNewValidCtxt(rng);
539 xmlRelaxNGSetValidErrors(ctxt,
540 testErrorHandler, testErrorHandler, ctxt);
541 ret = xmlRelaxNGValidateDoc(ctxt, doc);
542 xmlRelaxNGFreeValidCtxt(ctxt);
543 if (ret == 0) {
544 test_log("Failed to detect invalid instance line %ld\n",
545 xmlGetLineNo(tmp));
546 nb_errors++;
547 } else if (ret < 0) {
548 test_log("Internal error validating instance line %ld\n",
549 xmlGetLineNo(tmp));
550 nb_errors++;
551 }
552 xmlFreeDoc(doc);
553 }
554 xmlResetLastError();
555 if (mem != xmlMemUsed()) {
556 test_log("Validation of instance line %ld leaked %d\n",
557 xmlGetLineNo(tmp), xmlMemUsed() - mem);
558 nb_leaks++;
559 }
560 }
561 tmp = getNext(tmp, "following-sibling::invalid[1]");
562 }
563
564 done:
565 if (buf != NULL)
566 xmlBufferFree(buf);
567 if (rng != NULL)
568 xmlRelaxNGFree(rng);
569 xmlResetLastError();
570 if ((memt != xmlMemUsed()) && (memt != 0)) {
571 test_log("Validation of tests starting line %ld leaked %d\n",
572 xmlGetLineNo(cur), xmlMemUsed() - memt);
573 nb_leaks++;
574 }
575 return(ret);
576 }
577
578 static int
xsdTestSuite(xmlNodePtr cur)579 xsdTestSuite(xmlNodePtr cur) {
580 if (verbose) {
581 xmlChar *doc = getString(cur, "string(documentation)");
582
583 if (doc != NULL) {
584 printf("Suite %s\n", doc);
585 xmlFree(doc);
586 }
587 }
588 cur = getNext(cur, "./testCase[1]");
589 while (cur != NULL) {
590 xsdTestCase(cur);
591 cur = getNext(cur, "following-sibling::testCase[1]");
592 }
593
594 return(0);
595 }
596
597 static int
xsdTest(void)598 xsdTest(void) {
599 xmlDocPtr doc;
600 xmlNodePtr cur;
601 const char *filename = "test/xsdtest/xsdtestsuite.xml";
602 int ret = 0;
603
604 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
605 if (doc == NULL) {
606 fprintf(stderr, "Failed to parse %s\n", filename);
607 return(-1);
608 }
609 printf("## XML Schemas datatypes test suite from James Clark\n");
610
611 cur = xmlDocGetRootElement(doc);
612 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
613 fprintf(stderr, "Unexpected format %s\n", filename);
614 ret = -1;
615 goto done;
616 }
617
618 cur = getNext(cur, "./testSuite[1]");
619 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
620 fprintf(stderr, "Unexpected format %s\n", filename);
621 ret = -1;
622 goto done;
623 }
624 while (cur != NULL) {
625 xsdTestSuite(cur);
626 cur = getNext(cur, "following-sibling::testSuite[1]");
627 }
628
629 done:
630 if (doc != NULL)
631 xmlFreeDoc(doc);
632 return(ret);
633 }
634
635 static int
rngTestSuite(xmlNodePtr cur)636 rngTestSuite(xmlNodePtr cur) {
637 if (verbose) {
638 xmlChar *doc = getString(cur, "string(documentation)");
639
640 if (doc != NULL) {
641 printf("Suite %s\n", doc);
642 xmlFree(doc);
643 } else {
644 doc = getString(cur, "string(section)");
645 if (doc != NULL) {
646 printf("Section %s\n", doc);
647 xmlFree(doc);
648 }
649 }
650 }
651 cur = getNext(cur, "./testSuite[1]");
652 while (cur != NULL) {
653 xsdTestSuite(cur);
654 cur = getNext(cur, "following-sibling::testSuite[1]");
655 }
656
657 return(0);
658 }
659
660 static int
rngTest1(void)661 rngTest1(void) {
662 xmlDocPtr doc;
663 xmlNodePtr cur;
664 const char *filename = "test/relaxng/OASIS/spectest.xml";
665 int ret = 0;
666
667 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
668 if (doc == NULL) {
669 fprintf(stderr, "Failed to parse %s\n", filename);
670 return(-1);
671 }
672 printf("## Relax NG test suite from James Clark\n");
673
674 cur = xmlDocGetRootElement(doc);
675 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
676 fprintf(stderr, "Unexpected format %s\n", filename);
677 ret = -1;
678 goto done;
679 }
680
681 cur = getNext(cur, "./testSuite[1]");
682 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
683 fprintf(stderr, "Unexpected format %s\n", filename);
684 ret = -1;
685 goto done;
686 }
687 while (cur != NULL) {
688 rngTestSuite(cur);
689 cur = getNext(cur, "following-sibling::testSuite[1]");
690 }
691
692 done:
693 if (doc != NULL)
694 xmlFreeDoc(doc);
695 return(ret);
696 }
697
698 static int
rngTest2(void)699 rngTest2(void) {
700 xmlDocPtr doc;
701 xmlNodePtr cur;
702 const char *filename = "test/relaxng/testsuite.xml";
703 int ret = 0;
704
705 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
706 if (doc == NULL) {
707 fprintf(stderr, "Failed to parse %s\n", filename);
708 return(-1);
709 }
710 printf("## Relax NG test suite for libxml2\n");
711
712 cur = xmlDocGetRootElement(doc);
713 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
714 fprintf(stderr, "Unexpected format %s\n", filename);
715 ret = -1;
716 goto done;
717 }
718
719 cur = getNext(cur, "./testSuite[1]");
720 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
721 fprintf(stderr, "Unexpected format %s\n", filename);
722 ret = -1;
723 goto done;
724 }
725 while (cur != NULL) {
726 xsdTestSuite(cur);
727 cur = getNext(cur, "following-sibling::testSuite[1]");
728 }
729
730 done:
731 if (doc != NULL)
732 xmlFreeDoc(doc);
733 return(ret);
734 }
735
736 /************************************************************************
737 * *
738 * Schemas test suites from W3C/NIST/MS/Sun *
739 * *
740 ************************************************************************/
741
742 static int
xstcTestInstance(xmlNodePtr cur,xmlSchemaPtr schemas,const xmlChar * spath,const char * base)743 xstcTestInstance(xmlNodePtr cur, xmlSchemaPtr schemas,
744 const xmlChar *spath, const char *base) {
745 xmlChar *href = NULL;
746 xmlChar *path = NULL;
747 xmlChar *validity = NULL;
748 xmlSchemaValidCtxtPtr ctxt = NULL;
749 xmlDocPtr doc = NULL;
750 int ret = 0, mem;
751
752 xmlResetLastError();
753 testErrorsSize = 0; testErrors[0] = 0;
754 mem = xmlMemUsed();
755 href = getString(cur,
756 "string(ts:instanceDocument/@xlink:href)");
757 if ((href == NULL) || (href[0] == 0)) {
758 test_log("testGroup line %ld misses href for schemaDocument\n",
759 xmlGetLineNo(cur));
760 ret = -1;
761 goto done;
762 }
763 path = xmlBuildURI(href, BAD_CAST base);
764 if (path == NULL) {
765 fprintf(stderr,
766 "Failed to build path to schemas testGroup line %ld : %s\n",
767 xmlGetLineNo(cur), href);
768 ret = -1;
769 goto done;
770 }
771 if (checkTestFile((const char *) path) <= 0) {
772 test_log("schemas for testGroup line %ld is missing: %s\n",
773 xmlGetLineNo(cur), path);
774 ret = -1;
775 goto done;
776 }
777 validity = getString(cur,
778 "string(ts:expected/@validity)");
779 if (validity == NULL) {
780 fprintf(stderr, "instanceDocument line %ld misses expected validity\n",
781 xmlGetLineNo(cur));
782 ret = -1;
783 goto done;
784 }
785 nb_tests++;
786 doc = xmlReadFile((const char *) path, NULL, XML_PARSE_NOENT);
787 if (doc == NULL) {
788 fprintf(stderr, "instance %s fails to parse\n", path);
789 ret = -1;
790 nb_errors++;
791 goto done;
792 }
793
794 ctxt = xmlSchemaNewValidCtxt(schemas);
795 xmlSchemaSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
796 ret = xmlSchemaValidateDoc(ctxt, doc);
797
798 if (xmlStrEqual(validity, BAD_CAST "valid")) {
799 if (ret > 0) {
800 test_log("valid instance %s failed to validate against %s\n",
801 path, spath);
802 nb_errors++;
803 } else if (ret < 0) {
804 test_log("valid instance %s got internal error validating %s\n",
805 path, spath);
806 nb_internals++;
807 nb_errors++;
808 }
809 } else if (xmlStrEqual(validity, BAD_CAST "invalid")) {
810 if (ret == 0) {
811 test_log("Failed to detect invalid instance %s against %s\n",
812 path, spath);
813 nb_errors++;
814 }
815 } else {
816 test_log("instanceDocument line %ld has unexpected validity value%s\n",
817 xmlGetLineNo(cur), validity);
818 ret = -1;
819 goto done;
820 }
821
822 done:
823 if (href != NULL) xmlFree(href);
824 if (path != NULL) xmlFree(path);
825 if (validity != NULL) xmlFree(validity);
826 if (ctxt != NULL) xmlSchemaFreeValidCtxt(ctxt);
827 if (doc != NULL) xmlFreeDoc(doc);
828 xmlResetLastError();
829 if (mem != xmlMemUsed()) {
830 test_log("Validation of tests starting line %ld leaked %d\n",
831 xmlGetLineNo(cur), xmlMemUsed() - mem);
832 nb_leaks++;
833 }
834 return(ret);
835 }
836
837 static int
xstcTestGroup(xmlNodePtr cur,const char * base)838 xstcTestGroup(xmlNodePtr cur, const char *base) {
839 xmlChar *href = NULL;
840 xmlChar *path = NULL;
841 xmlChar *validity = NULL;
842 xmlSchemaPtr schemas = NULL;
843 xmlSchemaParserCtxtPtr ctxt;
844 xmlNodePtr instance;
845 int ret = 0, mem;
846
847 xmlResetLastError();
848 testErrorsSize = 0; testErrors[0] = 0;
849 mem = xmlMemUsed();
850 href = getString(cur,
851 "string(ts:schemaTest/ts:schemaDocument/@xlink:href)");
852 if ((href == NULL) || (href[0] == 0)) {
853 test_log("testGroup line %ld misses href for schemaDocument\n",
854 xmlGetLineNo(cur));
855 ret = -1;
856 goto done;
857 }
858 path = xmlBuildURI(href, BAD_CAST base);
859 if (path == NULL) {
860 test_log("Failed to build path to schemas testGroup line %ld : %s\n",
861 xmlGetLineNo(cur), href);
862 ret = -1;
863 goto done;
864 }
865 if (checkTestFile((const char *) path) <= 0) {
866 test_log("schemas for testGroup line %ld is missing: %s\n",
867 xmlGetLineNo(cur), path);
868 ret = -1;
869 goto done;
870 }
871 validity = getString(cur,
872 "string(ts:schemaTest/ts:expected/@validity)");
873 if (validity == NULL) {
874 test_log("testGroup line %ld misses expected validity\n",
875 xmlGetLineNo(cur));
876 ret = -1;
877 goto done;
878 }
879 nb_tests++;
880 if (xmlStrEqual(validity, BAD_CAST "valid")) {
881 nb_schematas++;
882 ctxt = xmlSchemaNewParserCtxt((const char *) path);
883 xmlSchemaSetParserErrors(ctxt, testErrorHandler, testErrorHandler,
884 ctxt);
885 schemas = xmlSchemaParse(ctxt);
886 xmlSchemaFreeParserCtxt(ctxt);
887 if (schemas == NULL) {
888 test_log("valid schemas %s failed to parse\n",
889 path);
890 ret = 1;
891 nb_errors++;
892 }
893 if ((ret == 0) && (strstr(testErrors, "nimplemented") != NULL)) {
894 test_log("valid schemas %s hit an unimplemented block\n",
895 path);
896 ret = 1;
897 nb_unimplemented++;
898 nb_errors++;
899 }
900 instance = getNext(cur, "./ts:instanceTest[1]");
901 while (instance != NULL) {
902 if (schemas != NULL) {
903 xstcTestInstance(instance, schemas, path, base);
904 } else {
905 /*
906 * We'll automatically mark the instances as failed
907 * if the schema was broken.
908 */
909 nb_errors++;
910 }
911 instance = getNext(instance,
912 "following-sibling::ts:instanceTest[1]");
913 }
914 } else if (xmlStrEqual(validity, BAD_CAST "invalid")) {
915 nb_schematas++;
916 ctxt = xmlSchemaNewParserCtxt((const char *) path);
917 xmlSchemaSetParserErrors(ctxt, testErrorHandler, testErrorHandler,
918 ctxt);
919 schemas = xmlSchemaParse(ctxt);
920 xmlSchemaFreeParserCtxt(ctxt);
921 if (schemas != NULL) {
922 test_log("Failed to detect error in schemas %s\n",
923 path);
924 nb_errors++;
925 ret = 1;
926 }
927 if ((ret == 0) && (strstr(testErrors, "nimplemented") != NULL)) {
928 nb_unimplemented++;
929 test_log("invalid schemas %s hit an unimplemented block\n",
930 path);
931 ret = 1;
932 nb_errors++;
933 }
934 } else {
935 test_log("testGroup line %ld misses unexpected validity value%s\n",
936 xmlGetLineNo(cur), validity);
937 ret = -1;
938 goto done;
939 }
940
941 done:
942 if (href != NULL) xmlFree(href);
943 if (path != NULL) xmlFree(path);
944 if (validity != NULL) xmlFree(validity);
945 if (schemas != NULL) xmlSchemaFree(schemas);
946 xmlResetLastError();
947 if (mem != xmlMemUsed()) {
948 test_log("Processing test line %ld %s leaked %d\n",
949 xmlGetLineNo(cur), path, xmlMemUsed() - mem);
950 nb_leaks++;
951 }
952 return(ret);
953 }
954
955 static int
xstcMetadata(const char * metadata,const char * base)956 xstcMetadata(const char *metadata, const char *base) {
957 xmlDocPtr doc;
958 xmlNodePtr cur;
959 xmlChar *contributor;
960 xmlChar *name;
961 int ret = 0;
962
963 doc = xmlReadFile(metadata, NULL, XML_PARSE_NOENT);
964 if (doc == NULL) {
965 fprintf(stderr, "Failed to parse %s\n", metadata);
966 return(-1);
967 }
968
969 cur = xmlDocGetRootElement(doc);
970 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSet"))) {
971 fprintf(stderr, "Unexpected format %s\n", metadata);
972 return(-1);
973 }
974 contributor = xmlGetProp(cur, BAD_CAST "contributor");
975 if (contributor == NULL) {
976 contributor = xmlStrdup(BAD_CAST "Unknown");
977 }
978 name = xmlGetProp(cur, BAD_CAST "name");
979 if (name == NULL) {
980 name = xmlStrdup(BAD_CAST "Unknown");
981 }
982 printf("## %s test suite for Schemas version %s\n", contributor, name);
983 xmlFree(contributor);
984 xmlFree(name);
985
986 cur = getNext(cur, "./ts:testGroup[1]");
987 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testGroup"))) {
988 fprintf(stderr, "Unexpected format %s\n", metadata);
989 ret = -1;
990 goto done;
991 }
992 while (cur != NULL) {
993 xstcTestGroup(cur, base);
994 cur = getNext(cur, "following-sibling::ts:testGroup[1]");
995 }
996
997 done:
998 xmlFreeDoc(doc);
999 return(ret);
1000 }
1001
1002 /************************************************************************
1003 * *
1004 * The driver for the tests *
1005 * *
1006 ************************************************************************/
1007
1008 int
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)1009 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1010 int ret = 0;
1011 int old_errors, old_tests, old_leaks, expected_errors;
1012
1013 logfile = fopen(LOGFILE, "wb");
1014 if (logfile == NULL) {
1015 fprintf(stderr,
1016 "Could not open the log file, running in verbose mode\n");
1017 verbose = 1;
1018 }
1019 initializeLibxml2();
1020
1021 if ((argc >= 2) && (!strcmp(argv[1], "-v")))
1022 verbose = 1;
1023
1024
1025 old_errors = nb_errors;
1026 old_tests = nb_tests;
1027 old_leaks = nb_leaks;
1028 xsdTest();
1029 expected_errors = 3;
1030 printf("Ran %d tests, %d errors, %d leaks\n",
1031 nb_tests - old_tests,
1032 nb_errors - old_errors,
1033 nb_leaks - old_leaks);
1034 if (nb_errors - old_errors == expected_errors) {
1035 printf("%d errors were expected\n", expected_errors);
1036 nb_errors = old_errors;
1037 } else {
1038 printf("%d errors were expected, got %d errors\n",
1039 expected_errors, nb_errors - old_errors);
1040 nb_errors = old_errors + 1;
1041 }
1042
1043 old_errors = nb_errors;
1044 old_tests = nb_tests;
1045 old_leaks = nb_leaks;
1046 rngTest1();
1047 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1048 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1049 else
1050 printf("Ran %d tests, %d errors, %d leaks\n",
1051 nb_tests - old_tests,
1052 nb_errors - old_errors,
1053 nb_leaks - old_leaks);
1054
1055 old_errors = nb_errors;
1056 old_tests = nb_tests;
1057 old_leaks = nb_leaks;
1058 rngTest2();
1059 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1060 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1061 else
1062 printf("Ran %d tests, %d errors, %d leaks\n",
1063 nb_tests - old_tests,
1064 nb_errors - old_errors,
1065 nb_leaks - old_leaks);
1066
1067 old_errors = nb_errors;
1068 old_tests = nb_tests;
1069 old_leaks = nb_leaks;
1070 nb_internals = 0;
1071 nb_schematas = 0;
1072 xstcMetadata("xstc/Tests/Metadata/NISTXMLSchemaDatatypes.testSet",
1073 "xstc/Tests/Metadata/");
1074 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1075 printf("Ran %d tests (%d schemata), no errors\n",
1076 nb_tests - old_tests, nb_schematas);
1077 else
1078 printf("Ran %d tests (%d schemata), %d errors (%d internals), %d leaks\n",
1079 nb_tests - old_tests,
1080 nb_schematas,
1081 nb_errors - old_errors,
1082 nb_internals,
1083 nb_leaks - old_leaks);
1084
1085 old_errors = nb_errors;
1086 old_tests = nb_tests;
1087 old_leaks = nb_leaks;
1088 nb_internals = 0;
1089 nb_schematas = 0;
1090 xstcMetadata("xstc/Tests/Metadata/SunXMLSchema1-0-20020116.testSet",
1091 "xstc/Tests/");
1092 if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) {
1093 printf("Ran %d tests (%d schemata), no errors\n",
1094 nb_tests - old_tests, nb_schematas);
1095 } else {
1096 printf("Ran %d tests (%d schemata), %d errors (%d internals), %d leaks\n",
1097 nb_tests - old_tests,
1098 nb_schematas,
1099 nb_errors - old_errors,
1100 nb_internals,
1101 nb_leaks - old_leaks);
1102 printf("Some errors were expected.\n");
1103 nb_errors = old_errors;
1104 }
1105
1106 old_errors = nb_errors;
1107 old_tests = nb_tests;
1108 old_leaks = nb_leaks;
1109 nb_internals = 0;
1110 nb_schematas = 0;
1111 xstcMetadata("xstc/Tests/Metadata/MSXMLSchema1-0-20020116.testSet",
1112 "xstc/Tests/");
1113 if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) {
1114 printf("Ran %d tests (%d schemata), no errors\n",
1115 nb_tests - old_tests, nb_schematas);
1116 } else {
1117 printf("Ran %d tests (%d schemata), %d errors (%d internals), %d leaks\n",
1118 nb_tests - old_tests,
1119 nb_schematas,
1120 nb_errors - old_errors,
1121 nb_internals,
1122 nb_leaks - old_leaks);
1123 printf("Some errors were expected.\n");
1124 nb_errors = old_errors;
1125 }
1126
1127 if ((nb_errors == 0) && (nb_leaks == 0)) {
1128 ret = 0;
1129 printf("Total %d tests, no errors\n",
1130 nb_tests);
1131 } else {
1132 ret = 1;
1133 printf("Total %d tests, %d errors, %d leaks\n",
1134 nb_tests, nb_errors, nb_leaks);
1135 }
1136 xmlXPathFreeContext(ctxtXPath);
1137 xmlCleanupParser();
1138
1139 if (logfile != NULL)
1140 fclose(logfile);
1141 return(ret);
1142 }
1143 #else /* !SCHEMAS */
1144 int
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)1145 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1146 fprintf(stderr, "runsuite requires support for schemas and xpath in libxml2\n");
1147 }
1148 #endif
1149