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