blob: 2ec4ffbbd68581dc02e74ca56698a6fe89c528fa [file] [log] [blame]
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001/*
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +00002 * runsuite.c: C program to run libxml2 againts published testsuites
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003 *
4 * See Copyright for the status of this software.
5 *
6 * daniel@veillard.com
7 */
8
9#include <unistd.h>
10#include <string.h>
11#include <stdio.h>
12#include <glob.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <unistd.h>
17
18#include <libxml/parser.h>
Daniel Veillarde84f2312005-07-02 07:31:28 +000019#include <libxml/parserInternals.h>
Daniel Veillardf2e066a2005-06-30 13:04:44 +000020#include <libxml/tree.h>
21#include <libxml/uri.h>
22#include <libxml/xmlreader.h>
23
24#include <libxml/xpath.h>
25#include <libxml/xpathInternals.h>
26
27#include <libxml/relaxng.h>
28#include <libxml/xmlschemas.h>
29#include <libxml/xmlschemastypes.h>
30
31/************************************************************************
32 * *
33 * File name and path utilities *
34 * *
35 ************************************************************************/
36
37static int checkTestFile(const char *filename) {
38 struct stat buf;
39
40 if (stat(filename, &buf) == -1)
41 return(0);
42
43 if (!S_ISREG(buf.st_mode))
44 return(0);
45
46 return(1);
47}
Daniel Veillarde84f2312005-07-02 07:31:28 +000048static xmlChar *composeDir(const xmlChar *dir, const xmlChar *path) {
49 char buf[500];
50
51 if (dir == NULL) return(xmlStrdup(path));
52 if (path == NULL) return(NULL);
53
54 snprintf(buf, 500, "%s/%s", (const char *) dir, (const char *) path);
55 return(xmlStrdup((const xmlChar *) buf));
56}
Daniel Veillardf2e066a2005-06-30 13:04:44 +000057
58/************************************************************************
59 * *
60 * Libxml2 specific routines *
61 * *
62 ************************************************************************/
63
64static int nb_tests = 0;
65static int nb_errors = 0;
66static int nb_leaks = 0;
67static long libxmlMemoryAllocatedBase = 0;
68static int extraMemoryFromResolver = 0;
69
70static int
71fatalError(void) {
72 fprintf(stderr, "Exitting tests on fatal error\n");
73 exit(1);
74}
75
76/*
Daniel Veillarde84f2312005-07-02 07:31:28 +000077 * that's needed to implement <resource>
78 */
79#define MAX_ENTITIES 20
80char *testEntitiesName[MAX_ENTITIES];
81char *testEntitiesValue[MAX_ENTITIES];
82int nb_entities = 0;
83static void resetEntities(void) {
84 int i;
85
86 for (i = 0;i < nb_entities;i++) {
87 if (testEntitiesName[i] != NULL)
88 xmlFree(testEntitiesName[i]);
89 if (testEntitiesValue[i] != NULL)
90 xmlFree(testEntitiesValue[i]);
91 }
92 nb_entities = 0;
93}
94static int addEntity(char *name, char *content) {
95 if (nb_entities >= MAX_ENTITIES) {
96 fprintf(stderr, "Too many entities defined\n");
97 return(-1);
98 }
99 testEntitiesName[nb_entities] = name;
100 testEntitiesValue[nb_entities] = content;
101 nb_entities++;
102 return(0);
103}
104
105/*
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000106 * We need to trap calls to the resolver to not account memory for the catalog
107 * which is shared to the current running test. We also don't want to have
108 * network downloads modifying tests.
109 */
110static xmlParserInputPtr
111testExternalEntityLoader(const char *URL, const char *ID,
112 xmlParserCtxtPtr ctxt) {
113 xmlParserInputPtr ret;
Daniel Veillarde84f2312005-07-02 07:31:28 +0000114 int i;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000115
Daniel Veillarde84f2312005-07-02 07:31:28 +0000116 for (i = 0;i < nb_entities;i++) {
117 if (!strcmp(testEntitiesName[i], URL)) {
118 ret = xmlNewStringInputStream(ctxt,
119 (const xmlChar *) testEntitiesValue[i]);
120 if (ret != NULL) {
121 ret->filename = (const char *)
122 xmlStrdup((xmlChar *)testEntitiesName[i]);
123 }
124 return(ret);
125 }
126 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000127 if (checkTestFile(URL)) {
128 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
129 } else {
130 int memused = xmlMemUsed();
131 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
132 extraMemoryFromResolver += xmlMemUsed() - memused;
133 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000134#if 0
Daniel Veillarde84f2312005-07-02 07:31:28 +0000135 if (ret == NULL) {
136 fprintf(stderr, "Failed to find resource %s\n", URL);
137 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000138#endif
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000139
140 return(ret);
141}
142
143/*
144 * Trapping the error messages at the generic level to grab the equivalent of
145 * stderr messages on CLI tools.
146 */
147static char testErrors[32769];
148static int testErrorsSize = 0;
149
150static void
151testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
152 va_list args;
153 int res;
154
155 if (testErrorsSize >= 32768)
156 return;
157 va_start(args, msg);
158 res = vsnprintf(&testErrors[testErrorsSize],
159 32768 - testErrorsSize,
160 msg, args);
161 va_end(args);
162 if (testErrorsSize + res >= 32768) {
163 /* buffer is full */
164 testErrorsSize = 32768;
165 testErrors[testErrorsSize] = 0;
166 } else {
167 testErrorsSize += res;
168 }
169 testErrors[testErrorsSize] = 0;
170}
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000171
172xmlXPathContextPtr ctxtXPath;
173
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000174static void
175initializeLibxml2(void) {
176 xmlGetWarningsDefaultValue = 0;
177 xmlPedanticParserDefault(0);
178
179 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
180 xmlInitParser();
181 xmlSetExternalEntityLoader(testExternalEntityLoader);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000182 ctxtXPath = xmlXPathNewContext(NULL);
183 /* used as default nanemspace in xstc tests */
184 xmlXPathRegisterNs(ctxtXPath, BAD_CAST "ts", BAD_CAST "TestSuite");
185 xmlXPathRegisterNs(ctxtXPath, BAD_CAST "xlink",
186 BAD_CAST "http://www.w3.org/1999/xlink");
187 xmlSetGenericErrorFunc(NULL, testErrorHandler);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000188#ifdef LIBXML_SCHEMAS_ENABLED
189 xmlSchemaInitTypes();
190 xmlRelaxNGInitTypes();
191#endif
192 libxmlMemoryAllocatedBase = xmlMemUsed();
193}
194
195static xmlNodePtr
196getNext(xmlNodePtr cur, const char *xpath) {
197 xmlNodePtr ret = NULL;
198 xmlXPathObjectPtr res;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000199 xmlXPathCompExprPtr comp;
200
201 if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL))
202 return(NULL);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000203 ctxtXPath->doc = cur->doc;
204 ctxtXPath->node = cur;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000205 comp = xmlXPathCompile(BAD_CAST xpath);
206 if (comp == NULL) {
207 fprintf(stderr, "Failed to compile %s\n", xpath);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000208 return(NULL);
209 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000210 res = xmlXPathCompiledEval(comp, ctxtXPath);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000211 xmlXPathFreeCompExpr(comp);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000212 if (res == NULL)
213 return(NULL);
214 if ((res->type == XPATH_NODESET) &&
215 (res->nodesetval != NULL) &&
216 (res->nodesetval->nodeNr > 0) &&
217 (res->nodesetval->nodeTab != NULL))
218 ret = res->nodesetval->nodeTab[0];
219 xmlXPathFreeObject(res);
220 return(ret);
221}
222
223static xmlChar *
224getString(xmlNodePtr cur, const char *xpath) {
225 xmlChar *ret = NULL;
226 xmlXPathObjectPtr res;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000227 xmlXPathCompExprPtr comp;
228
229 if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL))
230 return(NULL);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000231 ctxtXPath->doc = cur->doc;
232 ctxtXPath->node = cur;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000233 comp = xmlXPathCompile(BAD_CAST xpath);
234 if (comp == NULL) {
235 fprintf(stderr, "Failed to compile %s\n", xpath);
236 return(NULL);
237 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000238 res = xmlXPathCompiledEval(comp, ctxtXPath);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000239 xmlXPathFreeCompExpr(comp);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000240 if (res == NULL)
241 return(NULL);
242 if (res->type == XPATH_STRING) {
243 ret = res->stringval;
244 res->stringval = NULL;
245 }
246 xmlXPathFreeObject(res);
247 return(ret);
248}
249
250/************************************************************************
251 * *
252 * Test test/xsdtest/xsdtestsuite.xml *
253 * *
254 ************************************************************************/
255
256static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000257xsdIncorectTestCase(int verbose, xmlNodePtr cur) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000258 xmlNodePtr test;
259 xmlBufferPtr buf;
260 xmlRelaxNGParserCtxtPtr pctxt;
261 xmlRelaxNGPtr rng = NULL;
262 int ret = 0, memt;
263
264 cur = getNext(cur, "./incorrect[1]");
265 if (cur == NULL) {
266 return(0);
267 }
268
269 test = getNext(cur, "./*");
270 if (test == NULL) {
271 fprintf(stderr, "Failed to find test in correct line %ld\n",
272 xmlGetLineNo(cur));
273 return(1);
274 }
275
276 memt = xmlMemUsed();
277 extraMemoryFromResolver = 0;
278 /*
279 * dump the schemas to a buffer, then reparse it and compile the schemas
280 */
281 buf = xmlBufferCreate();
282 if (buf == NULL) {
283 fprintf(stderr, "out of memory !\n");
284 fatalError();
285 }
286 xmlNodeDump(buf, test->doc, test, 0, 0);
287 pctxt = xmlRelaxNGNewMemParserCtxt((const char *)buf->content, buf->use);
288 xmlRelaxNGSetParserErrors(pctxt,
289 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
290 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
291 pctxt);
292 rng = xmlRelaxNGParse(pctxt);
293 xmlRelaxNGFreeParserCtxt(pctxt);
294 if (rng != NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000295 if (verbose) {
296 fprintf(stderr, "Failed to detect incorect RNG line %ld\n",
297 xmlGetLineNo(test));
298 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000299 ret = 1;
300 goto done;
301 }
302
303done:
304 if (buf != NULL)
305 xmlBufferFree(buf);
306 if (rng != NULL)
307 xmlRelaxNGFree(rng);
308 xmlResetLastError();
309 if ((memt != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
310 fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
311 xmlGetLineNo(cur), xmlMemUsed() - memt);
312 nb_leaks++;
313 }
314 return(ret);
315}
316
Daniel Veillarde84f2312005-07-02 07:31:28 +0000317static void
318installResources(xmlNodePtr tst, const xmlChar *base) {
319 xmlNodePtr test;
320 xmlBufferPtr buf;
321 xmlChar *name, *content, *res;
322 buf = xmlBufferCreate();
323 if (buf == NULL) {
324 fprintf(stderr, "out of memory !\n");
325 fatalError();
326 }
327 xmlNodeDump(buf, tst->doc, tst, 0, 0);
328
329 while (tst != NULL) {
330 test = getNext(tst, "./*");
331 if (test != NULL) {
332 xmlBufferEmpty(buf);
333 xmlNodeDump(buf, test->doc, test, 0, 0);
334 name = getString(tst, "string(@name)");
335 content = xmlStrdup(buf->content);
336 if ((name != NULL) && (content != NULL)) {
337 res = composeDir(base, name);
338 xmlFree(name);
339 addEntity((char *) res, (char *) content);
340 } else {
341 if (name != NULL) xmlFree(name);
342 if (content != NULL) xmlFree(content);
343 }
344 }
345 tst = getNext(tst, "following-sibling::resource[1]");
346 }
347 if (buf != NULL)
348 xmlBufferFree(buf);
349}
350
351static void
352installDirs(xmlNodePtr tst, const xmlChar *base) {
353 xmlNodePtr test;
354 xmlChar *name, *res;
355
356 name = getString(tst, "string(@name)");
357 if (name == NULL)
358 return;
359 res = composeDir(base, name);
360 xmlFree(name);
361 if (res == NULL) {
362 return;
363 }
364 /* Now process resources and subdir recursively */
365 test = getNext(tst, "./resource[1]");
366 if (test != NULL) {
367 installResources(test, res);
368 }
369 test = getNext(tst, "./dir[1]");
370 while (test != NULL) {
371 installDirs(test, res);
372 test = getNext(test, "following-sibling::dir[1]");
373 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000374 xmlFree(res);
Daniel Veillarde84f2312005-07-02 07:31:28 +0000375}
376
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000377static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000378xsdTestCase(int verbose, xmlNodePtr tst) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000379 xmlNodePtr test, tmp, cur;
380 xmlBufferPtr buf;
381 xmlDocPtr doc = NULL;
382 xmlRelaxNGParserCtxtPtr pctxt;
383 xmlRelaxNGValidCtxtPtr ctxt;
384 xmlRelaxNGPtr rng = NULL;
385 int ret = 0, mem, memt;
Daniel Veillarde84f2312005-07-02 07:31:28 +0000386 xmlChar *dtd;
387
388 resetEntities();
389
390 tmp = getNext(tst, "./dir[1]");
391 if (tmp != NULL) {
392 installDirs(tmp, NULL);
393 }
394 tmp = getNext(tst, "./resource[1]");
395 if (tmp != NULL) {
396 installResources(tmp, NULL);
397 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000398
399 cur = getNext(tst, "./correct[1]");
400 if (cur == NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000401 return(xsdIncorectTestCase(verbose, tst));
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000402 }
403
404 test = getNext(cur, "./*");
405 if (test == NULL) {
406 fprintf(stderr, "Failed to find test in correct line %ld\n",
407 xmlGetLineNo(cur));
408 return(1);
409 }
410
411 memt = xmlMemUsed();
412 extraMemoryFromResolver = 0;
413 /*
414 * dump the schemas to a buffer, then reparse it and compile the schemas
415 */
416 buf = xmlBufferCreate();
417 if (buf == NULL) {
418 fprintf(stderr, "out of memory !\n");
419 fatalError();
420 }
421 xmlNodeDump(buf, test->doc, test, 0, 0);
422 pctxt = xmlRelaxNGNewMemParserCtxt((const char *)buf->content, buf->use);
423 xmlRelaxNGSetParserErrors(pctxt,
424 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
425 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
426 pctxt);
427 rng = xmlRelaxNGParse(pctxt);
428 xmlRelaxNGFreeParserCtxt(pctxt);
429 if (extraMemoryFromResolver)
430 memt = 0;
431
432 if (rng == NULL) {
433 fprintf(stderr, "Failed to parse RNGtest line %ld\n",
434 xmlGetLineNo(test));
435 nb_errors++;
436 ret = 1;
437 goto done;
438 }
439 /*
440 * now scan all the siblings of correct to process the <valid> tests
441 */
442 tmp = getNext(cur, "following-sibling::valid[1]");
443 while (tmp != NULL) {
Daniel Veillarde84f2312005-07-02 07:31:28 +0000444 dtd = xmlGetProp(tmp, BAD_CAST "dtd");
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000445 test = getNext(tmp, "./*");
446 if (test == NULL) {
447 fprintf(stderr, "Failed to find test in <valid> line %ld\n",
448 xmlGetLineNo(tmp));
449
450 } else {
451 xmlBufferEmpty(buf);
Daniel Veillarde84f2312005-07-02 07:31:28 +0000452 if (dtd != NULL)
453 xmlBufferAdd(buf, dtd, -1);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000454 xmlNodeDump(buf, test->doc, test, 0, 0);
455
456 /*
457 * We are ready to run the test
458 */
459 mem = xmlMemUsed();
460 extraMemoryFromResolver = 0;
461 doc = xmlReadMemory((const char *)buf->content, buf->use,
462 "test", NULL, 0);
463 if (doc == NULL) {
464 fprintf(stderr,
465 "Failed to parse valid instance line %ld\n",
466 xmlGetLineNo(tmp));
467 nb_errors++;
468 } else {
469 nb_tests++;
470 ctxt = xmlRelaxNGNewValidCtxt(rng);
471 xmlRelaxNGSetValidErrors(ctxt,
472 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
473 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
474 ctxt);
475 ret = xmlRelaxNGValidateDoc(ctxt, doc);
476 xmlRelaxNGFreeValidCtxt(ctxt);
477 if (ret > 0) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000478 if (verbose) {
479 fprintf(stderr,
480 "Failed to validate valid instance line %ld\n",
481 xmlGetLineNo(tmp));
482 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000483 nb_errors++;
484 } else if (ret < 0) {
485 fprintf(stderr,
486 "Internal error validating instance line %ld\n",
487 xmlGetLineNo(tmp));
488 nb_errors++;
489 }
490 xmlFreeDoc(doc);
491 }
492 xmlResetLastError();
493 if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
494 fprintf(stderr, "Validation of instance line %ld leaked %d\n",
495 xmlGetLineNo(tmp), xmlMemUsed() - mem);
496 xmlMemoryDump();
497 nb_leaks++;
498 }
499 }
Daniel Veillarde84f2312005-07-02 07:31:28 +0000500 if (dtd != NULL)
501 xmlFree(dtd);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000502 tmp = getNext(tmp, "following-sibling::valid[1]");
503 }
504 /*
505 * now scan all the siblings of correct to process the <invalid> tests
506 */
507 tmp = getNext(cur, "following-sibling::invalid[1]");
508 while (tmp != NULL) {
509 test = getNext(tmp, "./*");
510 if (test == NULL) {
511 fprintf(stderr, "Failed to find test in <invalid> line %ld\n",
512 xmlGetLineNo(tmp));
513
514 } else {
515 xmlBufferEmpty(buf);
516 xmlNodeDump(buf, test->doc, test, 0, 0);
517
518 /*
519 * We are ready to run the test
520 */
521 mem = xmlMemUsed();
522 extraMemoryFromResolver = 0;
523 doc = xmlReadMemory((const char *)buf->content, buf->use,
524 "test", NULL, 0);
525 if (doc == NULL) {
526 fprintf(stderr,
527 "Failed to parse valid instance line %ld\n",
528 xmlGetLineNo(tmp));
529 nb_errors++;
530 } else {
531 nb_tests++;
532 ctxt = xmlRelaxNGNewValidCtxt(rng);
533 xmlRelaxNGSetValidErrors(ctxt,
534 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
535 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
536 ctxt);
537 ret = xmlRelaxNGValidateDoc(ctxt, doc);
538 xmlRelaxNGFreeValidCtxt(ctxt);
539 if (ret == 0) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000540 if (verbose) {
541 fprintf(stderr,
542 "Failed to detect invalid instance line %ld\n",
543 xmlGetLineNo(tmp));
544 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000545 nb_errors++;
546 } else if (ret < 0) {
547 fprintf(stderr,
548 "Internal error validating instance line %ld\n",
549 xmlGetLineNo(tmp));
550 nb_errors++;
551 }
552 xmlFreeDoc(doc);
553 }
554 xmlResetLastError();
555 if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
556 fprintf(stderr, "Validation of instance line %ld leaked %d\n",
557 xmlGetLineNo(tmp), xmlMemUsed() - mem);
558 xmlMemoryDump();
559 nb_leaks++;
560 }
561 }
562 tmp = getNext(tmp, "following-sibling::invalid[1]");
563 }
564
565done:
566 if (buf != NULL)
567 xmlBufferFree(buf);
568 if (rng != NULL)
569 xmlRelaxNGFree(rng);
570 xmlResetLastError();
571 if ((memt != xmlMemUsed()) && (memt != 0)) {
572 fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
573 xmlGetLineNo(cur), xmlMemUsed() - memt);
574 nb_leaks++;
575 }
576 return(ret);
577}
578
579static int
580xsdTestSuite(int verbose, xmlNodePtr cur) {
581 if (verbose) {
582 xmlChar *doc = getString(cur, "string(documentation)");
583
584 if (doc != NULL) {
585 printf("Suite %s\n", doc);
586 xmlFree(doc);
587 }
588 }
589 cur = getNext(cur, "./testCase[1]");
590 while (cur != NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000591 xsdTestCase(verbose, cur);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000592 cur = getNext(cur, "following-sibling::testCase[1]");
593 }
594
595 return(0);
596}
597
598static int
599xsdTest(int verbose) {
600 xmlDocPtr doc;
601 xmlNodePtr cur;
602 const char *filename = "test/xsdtest/xsdtestsuite.xml";
603 int ret = 0;
604
605 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
606 if (doc == NULL) {
607 fprintf(stderr, "Failed to parse %s\n", filename);
608 return(-1);
609 }
610 printf("## XML Schemas datatypes test suite from James Clark\n");
611
612 cur = xmlDocGetRootElement(doc);
613 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
614 fprintf(stderr, "Unexpected format %s\n", filename);
615 ret = -1;
616 goto done;
617 }
618
619 cur = getNext(cur, "./testSuite[1]");
620 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
621 fprintf(stderr, "Unexpected format %s\n", filename);
622 ret = -1;
623 goto done;
624 }
625 while (cur != NULL) {
626 xsdTestSuite(verbose, cur);
627 cur = getNext(cur, "following-sibling::testSuite[1]");
628 }
629
630done:
631 if (doc != NULL)
632 xmlFreeDoc(doc);
633 return(ret);
634}
635
636static int
637rngTestSuite(int verbose, xmlNodePtr cur) {
638 if (verbose) {
639 xmlChar *doc = getString(cur, "string(documentation)");
640
641 if (doc != NULL) {
642 printf("Suite %s\n", doc);
643 xmlFree(doc);
644 } else {
645 doc = getString(cur, "string(section)");
646 if (doc != NULL) {
647 printf("Section %s\n", doc);
648 xmlFree(doc);
649 }
650 }
651 }
652 cur = getNext(cur, "./testSuite[1]");
653 while (cur != NULL) {
654 xsdTestSuite(verbose, cur);
655 cur = getNext(cur, "following-sibling::testSuite[1]");
656 }
657
658 return(0);
659}
660
661static int
662rngTest1(int verbose) {
663 xmlDocPtr doc;
664 xmlNodePtr cur;
665 const char *filename = "test/relaxng/OASIS/spectest.xml";
666 int ret = 0;
667
668 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
669 if (doc == NULL) {
670 fprintf(stderr, "Failed to parse %s\n", filename);
671 return(-1);
672 }
Daniel Veillarde84f2312005-07-02 07:31:28 +0000673 printf("## Relax NG test suite from James Clark\n");
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000674
675 cur = xmlDocGetRootElement(doc);
676 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
677 fprintf(stderr, "Unexpected format %s\n", filename);
678 ret = -1;
679 goto done;
680 }
681
682 cur = getNext(cur, "./testSuite[1]");
683 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
684 fprintf(stderr, "Unexpected format %s\n", filename);
685 ret = -1;
686 goto done;
687 }
688 while (cur != NULL) {
689 rngTestSuite(verbose, cur);
690 cur = getNext(cur, "following-sibling::testSuite[1]");
691 }
692
693done:
694 if (doc != NULL)
695 xmlFreeDoc(doc);
696 return(ret);
697}
698
Daniel Veillarde84f2312005-07-02 07:31:28 +0000699static int
700rngTest2(int verbose) {
701 xmlDocPtr doc;
702 xmlNodePtr cur;
703 const char *filename = "test/relaxng/testsuite.xml";
704 int ret = 0;
705
706 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
707 if (doc == NULL) {
708 fprintf(stderr, "Failed to parse %s\n", filename);
709 return(-1);
710 }
711 printf("## Relax NG test suite for libxml2\n");
712
713 cur = xmlDocGetRootElement(doc);
714 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
715 fprintf(stderr, "Unexpected format %s\n", filename);
716 ret = -1;
717 goto done;
718 }
719
720 cur = getNext(cur, "./testSuite[1]");
721 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
722 fprintf(stderr, "Unexpected format %s\n", filename);
723 ret = -1;
724 goto done;
725 }
726 while (cur != NULL) {
727 xsdTestSuite(verbose, cur);
728 cur = getNext(cur, "following-sibling::testSuite[1]");
729 }
730
731done:
732 if (doc != NULL)
733 xmlFreeDoc(doc);
734 return(ret);
735}
736
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000737/************************************************************************
738 * *
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000739 * Schemas test suites from W3C/NIST/MS/Sun *
740 * *
741 ************************************************************************/
742
743static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000744xstcTestInstance(int verbose, xmlNodePtr cur, xmlSchemaPtr schemas,
745 const xmlChar *spath, const xmlChar *base) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000746 xmlChar *href = NULL;
747 xmlChar *path = NULL;
Daniel Veillardde0e4982005-07-03 14:35:44 +0000748 xmlChar *validity = NULL;
749 xmlSchemaValidCtxtPtr ctxt = NULL;
750 xmlDocPtr doc = NULL;
751 int ret = 0, mem;
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000752
Daniel Veillardde0e4982005-07-03 14:35:44 +0000753 xmlResetLastError();
754 mem = xmlMemUsed();
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000755 href = getString(cur,
Daniel Veillardde0e4982005-07-03 14:35:44 +0000756 "string(ts:instanceDocument/@xlink:href)");
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000757 if ((href == NULL) || (href[0] == 0)) {
758 if (verbose)
759 fprintf(stderr,
760 "testGroup line %ld misses href for schemaDocument\n",
761 xmlGetLineNo(cur));
762 ret = -1;
763 goto done;
764 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000765 path = xmlBuildURI(href, BAD_CAST base);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000766 if (path == NULL) {
767 fprintf(stderr,
768 "Failed to build path to schemas testGroup line %ld : %s\n",
769 xmlGetLineNo(cur), href);
770 ret = -1;
771 goto done;
772 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000773 if (checkTestFile((const char *) path) <= 0) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000774 fprintf(stderr,
775 "schemas for testGroup line %ld is missing: %s\n",
776 xmlGetLineNo(cur), path);
777 ret = -1;
778 goto done;
779 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000780 validity = getString(cur,
781 "string(ts:expected/@validity)");
782 if (validity == NULL) {
783 fprintf(stderr, "instanceDocument line %ld misses expected validity\n",
784 xmlGetLineNo(cur));
785 ret = -1;
786 goto done;
787 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000788 nb_tests++;
Daniel Veillardde0e4982005-07-03 14:35:44 +0000789 doc = xmlReadFile((const char *) path, NULL, XML_PARSE_NOENT);
790 if (doc == NULL) {
791 fprintf(stderr, "instance %s fails to parse\n", path);
792 ret = -1;
793 nb_errors++;
794 goto done;
795 }
796
797 ctxt = xmlSchemaNewValidCtxt(schemas);
798 xmlSchemaSetValidErrors(ctxt,
799 (xmlSchemaValidityErrorFunc) testErrorHandler,
800 (xmlSchemaValidityWarningFunc) testErrorHandler,
801 ctxt);
802 ret = xmlSchemaValidateDoc(ctxt, doc);
803
804 if (xmlStrEqual(validity, BAD_CAST "valid")) {
805 if (ret != 0) {
806 if (verbose)
807 fprintf(stderr,
808 "valid instance %s failed to validate against %s\n",
809 path, spath);
810 nb_errors++;
811 }
812 } else if (xmlStrEqual(validity, BAD_CAST "invalid")) {
813 if (ret == 0) {
814 if (verbose)
815 fprintf(stderr,
816 "Failed to detect invalid instance %s against %s\n",
817 path, spath);
818 nb_errors++;
819 }
820 } else {
821 fprintf(stderr,
822 "instanceDocument line %ld has unexpected validity value%s\n",
823 xmlGetLineNo(cur), validity);
824 ret = -1;
825 goto done;
826 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000827
828done:
829 if (href != NULL) xmlFree(href);
830 if (path != NULL) xmlFree(path);
Daniel Veillardde0e4982005-07-03 14:35:44 +0000831 if (validity != NULL) xmlFree(validity);
832 if (ctxt != NULL) xmlSchemaFreeValidCtxt(ctxt);
833 if (doc != NULL) xmlFreeDoc(doc);
834 xmlResetLastError();
835 if (mem != xmlMemUsed()) {
836 fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
837 xmlGetLineNo(cur), xmlMemUsed() - mem);
838 nb_leaks++;
839 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000840 return(ret);
841}
Daniel Veillardde0e4982005-07-03 14:35:44 +0000842
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000843static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000844xstcTestGroup(int verbose, xmlNodePtr cur, const char *base) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000845 xmlChar *href = NULL;
846 xmlChar *path = NULL;
847 xmlChar *validity = NULL;
848 xmlSchemaPtr schemas = NULL;
849 xmlSchemaParserCtxtPtr ctxt;
850 xmlNodePtr instance;
Daniel Veillardde0e4982005-07-03 14:35:44 +0000851 int ret = 0, mem;
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000852
Daniel Veillardde0e4982005-07-03 14:35:44 +0000853 xmlResetLastError();
854 mem = xmlMemUsed();
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000855 href = getString(cur,
856 "string(ts:schemaTest/ts:schemaDocument/@xlink:href)");
857 if ((href == NULL) || (href[0] == 0)) {
858 if (verbose)
859 fprintf(stderr,
860 "testGroup line %ld misses href for schemaDocument\n",
861 xmlGetLineNo(cur));
862 ret = -1;
863 goto done;
864 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000865 path = xmlBuildURI(href, BAD_CAST base);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000866 if (path == NULL) {
867 fprintf(stderr,
868 "Failed to build path to schemas testGroup line %ld : %s\n",
869 xmlGetLineNo(cur), href);
870 ret = -1;
871 goto done;
872 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000873 if (checkTestFile((const char *) path) <= 0) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000874 fprintf(stderr,
875 "schemas for testGroup line %ld is missing: %s\n",
876 xmlGetLineNo(cur), path);
877 ret = -1;
878 goto done;
879 }
880 validity = getString(cur,
881 "string(ts:schemaTest/ts:expected/@validity)");
882 if (validity == NULL) {
883 fprintf(stderr, "testGroup line %ld misses expected validity\n",
884 xmlGetLineNo(cur));
885 ret = -1;
886 goto done;
887 }
888 if (xmlStrEqual(validity, BAD_CAST "valid")) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000889 ctxt = xmlSchemaNewParserCtxt((const char *) path);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000890 xmlSchemaSetParserErrors(ctxt,
891 (xmlSchemaValidityErrorFunc) testErrorHandler,
892 (xmlSchemaValidityWarningFunc) testErrorHandler,
893 ctxt);
894 schemas = xmlSchemaParse(ctxt);
895 xmlSchemaFreeParserCtxt(ctxt);
896 if (schemas == NULL) {
897 if (verbose)
898 fprintf(stderr, "valid schemas %s failed to parse\n",
899 path);
900 nb_errors++;
901 }
902 instance = getNext(cur, "./ts:instanceTest[1]");
903 if (instance == NULL) {
904 nb_tests++;
905 }
906 while (instance != NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000907 xstcTestInstance(verbose, instance, schemas, path, base);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000908 instance = getNext(instance,
909 "following-sibling::ts:instanceTest[1]");
910 }
911 } else if (xmlStrEqual(validity, BAD_CAST "invalid")) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000912 ctxt = xmlSchemaNewParserCtxt((const char *) path);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000913 xmlSchemaSetParserErrors(ctxt,
914 (xmlSchemaValidityErrorFunc) testErrorHandler,
915 (xmlSchemaValidityWarningFunc) testErrorHandler,
916 ctxt);
917 schemas = xmlSchemaParse(ctxt);
918 xmlSchemaFreeParserCtxt(ctxt);
919 if (schemas == NULL) {
920 if (verbose)
921 fprintf(stderr, "Failed to detect error in schemas %s\n",
922 path);
923 nb_errors++;
924 }
925 nb_tests++;
926 } else {
927 fprintf(stderr,
928 "testGroup line %ld misses unexpected validity value%s\n",
929 xmlGetLineNo(cur), validity);
930 ret = -1;
931 goto done;
932 }
933
934done:
935 if (href != NULL) xmlFree(href);
936 if (path != NULL) xmlFree(path);
937 if (validity != NULL) xmlFree(validity);
938 if (schemas != NULL) xmlSchemaFree(schemas);
Daniel Veillardde0e4982005-07-03 14:35:44 +0000939 xmlResetLastError();
940 if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
941 fprintf(stderr, "Processing test line %ld leaked %d\n",
942 xmlGetLineNo(cur), xmlMemUsed() - mem);
943 nb_leaks++;
944 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000945 return(ret);
946}
947
948static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000949xstcMetadata(int verbose, const char *metadata, const char *base) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000950 xmlDocPtr doc;
951 xmlNodePtr cur;
952 xmlChar *contributor;
953 xmlChar *name;
954 int ret;
955
956 doc = xmlReadFile(metadata, NULL, XML_PARSE_NOENT);
957 if (doc == NULL) {
958 fprintf(stderr, "Failed to parse %s\n", metadata);
959 return(-1);
960 }
961
962 cur = xmlDocGetRootElement(doc);
963 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSet"))) {
964 fprintf(stderr, "Unexpected format %s\n", metadata);
965 return(-1);
966 }
967 contributor = xmlGetProp(cur, BAD_CAST "contributor");
968 if (contributor == NULL) {
969 contributor = xmlStrdup(BAD_CAST "Unknown");
970 }
971 name = xmlGetProp(cur, BAD_CAST "name");
972 if (name == NULL) {
973 name = xmlStrdup(BAD_CAST "Unknown");
974 }
975 printf("## %s test suite for Schemas version %s\n", contributor, name);
976 xmlFree(contributor);
977 xmlFree(name);
978
979 cur = getNext(cur, "./ts:testGroup[1]");
980 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testGroup"))) {
981 fprintf(stderr, "Unexpected format %s\n", metadata);
982 ret = -1;
983 goto done;
984 }
985 while (cur != NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000986 xstcTestGroup(verbose, cur, base);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000987 cur = getNext(cur, "following-sibling::ts:testGroup[1]");
988 }
989
990done:
991 xmlFreeDoc(doc);
992 return(ret);
993}
994
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000995/************************************************************************
996 * *
997 * The driver for the tests *
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000998 * *
999 ************************************************************************/
1000
1001int
1002main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1003 int res, ret = 0;
1004 int verbose = 0;
1005 int old_errors, old_tests, old_leaks;
1006
1007 initializeLibxml2();
1008
1009 if ((argc >= 2) && (!strcmp(argv[1], "-v")))
1010 verbose = 1;
1011
1012
Daniel Veillarde84f2312005-07-02 07:31:28 +00001013 old_errors = nb_errors;
1014 old_tests = nb_tests;
1015 old_leaks = nb_leaks;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001016 res = xsdTest(verbose);
1017 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1018 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1019 else
1020 printf("Ran %d tests, %d errors, %d leaks\n",
1021 nb_tests - old_tests,
1022 nb_errors - old_errors,
1023 nb_leaks - old_leaks);
1024 old_errors = nb_errors;
1025 old_tests = nb_tests;
1026 old_leaks = nb_leaks;
1027 res = rngTest1(verbose);
1028 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1029 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1030 else
1031 printf("Ran %d tests, %d errors, %d leaks\n",
1032 nb_tests - old_tests,
1033 nb_errors - old_errors,
1034 nb_leaks - old_leaks);
1035 old_errors = nb_errors;
1036 old_tests = nb_tests;
1037 old_leaks = nb_leaks;
Daniel Veillarde84f2312005-07-02 07:31:28 +00001038 res = rngTest2(verbose);
1039 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1040 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1041 else
1042 printf("Ran %d tests, %d errors, %d leaks\n",
1043 nb_tests - old_tests,
1044 nb_errors - old_errors,
1045 nb_leaks - old_leaks);
1046 old_errors = nb_errors;
1047 old_tests = nb_tests;
1048 old_leaks = nb_leaks;
Daniel Veillardde0e4982005-07-03 14:35:44 +00001049 res = xstcMetadata(verbose,
1050 "xstc/Tests/Metadata/NISTXMLSchemaDatatypes.testSet",
1051 "xstc/Tests/Metadata/");
1052 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1053 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1054 else
1055 printf("Ran %d tests, %d errors, %d leaks\n",
1056 nb_tests - old_tests,
1057 nb_errors - old_errors,
1058 nb_leaks - old_leaks);
1059 old_errors = nb_errors;
1060 old_tests = nb_tests;
1061 old_leaks = nb_leaks;
1062 res = xstcMetadata(verbose,
1063 "xstc/Tests/Metadata/SunXMLSchema1-0-20020116.testSet",
1064 "xstc/");
1065 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1066 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1067 else
1068 printf("Ran %d tests, %d errors, %d leaks\n",
1069 nb_tests - old_tests,
1070 nb_errors - old_errors,
1071 nb_leaks - old_leaks);
1072 old_errors = nb_errors;
1073 old_tests = nb_tests;
1074 old_leaks = nb_leaks;
1075 res = xstcMetadata(verbose,
1076 "xstc/Tests/Metadata/MSXMLSchema1-0-20020116.testSet",
1077 "xstc/Tests/");
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +00001078 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1079 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1080 else
1081 printf("Ran %d tests, %d errors, %d leaks\n",
1082 nb_tests - old_tests,
1083 nb_errors - old_errors,
1084 nb_leaks - old_leaks);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001085
1086 if ((nb_errors == 0) && (nb_leaks == 0)) {
1087 ret = 0;
1088 printf("Total %d tests, no errors\n",
1089 nb_tests);
1090 } else {
1091 ret = 1;
1092 printf("Total %d tests, %d errors, %d leaks\n",
1093 nb_tests, nb_errors, nb_leaks);
1094 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +00001095
1096 xmlXPathFreeContext(ctxtXPath);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001097 xmlCleanupParser();
1098 xmlMemoryDump();
1099
1100 return(ret);
1101}