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