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