blob: f2d9a5789919459da820e6dba579c7e229d37614 [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 Veillard3fe1e8a2005-07-02 21:39:06 +0000257xsdIncorectTestCase(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) {
295 fprintf(stderr, "Failed to detect incorect RNG line %ld\n",
296 xmlGetLineNo(test));
297 ret = 1;
298 goto done;
299 }
300
301done:
302 if (buf != NULL)
303 xmlBufferFree(buf);
304 if (rng != NULL)
305 xmlRelaxNGFree(rng);
306 xmlResetLastError();
307 if ((memt != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
308 fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
309 xmlGetLineNo(cur), xmlMemUsed() - memt);
310 nb_leaks++;
311 }
312 return(ret);
313}
314
Daniel Veillarde84f2312005-07-02 07:31:28 +0000315static void
316installResources(xmlNodePtr tst, const xmlChar *base) {
317 xmlNodePtr test;
318 xmlBufferPtr buf;
319 xmlChar *name, *content, *res;
320 buf = xmlBufferCreate();
321 if (buf == NULL) {
322 fprintf(stderr, "out of memory !\n");
323 fatalError();
324 }
325 xmlNodeDump(buf, tst->doc, tst, 0, 0);
326
327 while (tst != NULL) {
328 test = getNext(tst, "./*");
329 if (test != NULL) {
330 xmlBufferEmpty(buf);
331 xmlNodeDump(buf, test->doc, test, 0, 0);
332 name = getString(tst, "string(@name)");
333 content = xmlStrdup(buf->content);
334 if ((name != NULL) && (content != NULL)) {
335 res = composeDir(base, name);
336 xmlFree(name);
337 addEntity((char *) res, (char *) content);
338 } else {
339 if (name != NULL) xmlFree(name);
340 if (content != NULL) xmlFree(content);
341 }
342 }
343 tst = getNext(tst, "following-sibling::resource[1]");
344 }
345 if (buf != NULL)
346 xmlBufferFree(buf);
347}
348
349static void
350installDirs(xmlNodePtr tst, const xmlChar *base) {
351 xmlNodePtr test;
352 xmlChar *name, *res;
353
354 name = getString(tst, "string(@name)");
355 if (name == NULL)
356 return;
357 res = composeDir(base, name);
358 xmlFree(name);
359 if (res == NULL) {
360 return;
361 }
362 /* Now process resources and subdir recursively */
363 test = getNext(tst, "./resource[1]");
364 if (test != NULL) {
365 installResources(test, res);
366 }
367 test = getNext(tst, "./dir[1]");
368 while (test != NULL) {
369 installDirs(test, res);
370 test = getNext(test, "following-sibling::dir[1]");
371 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000372 xmlFree(res);
Daniel Veillarde84f2312005-07-02 07:31:28 +0000373}
374
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000375static int
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000376xsdTestCase(xmlNodePtr tst) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000377 xmlNodePtr test, tmp, cur;
378 xmlBufferPtr buf;
379 xmlDocPtr doc = NULL;
380 xmlRelaxNGParserCtxtPtr pctxt;
381 xmlRelaxNGValidCtxtPtr ctxt;
382 xmlRelaxNGPtr rng = NULL;
383 int ret = 0, mem, memt;
Daniel Veillarde84f2312005-07-02 07:31:28 +0000384 xmlChar *dtd;
385
386 resetEntities();
387
388 tmp = getNext(tst, "./dir[1]");
389 if (tmp != NULL) {
390 installDirs(tmp, NULL);
391 }
392 tmp = getNext(tst, "./resource[1]");
393 if (tmp != NULL) {
394 installResources(tmp, NULL);
395 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000396
397 cur = getNext(tst, "./correct[1]");
398 if (cur == NULL) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000399 return(xsdIncorectTestCase(tst));
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000400 }
401
402 test = getNext(cur, "./*");
403 if (test == NULL) {
404 fprintf(stderr, "Failed to find test in correct line %ld\n",
405 xmlGetLineNo(cur));
406 return(1);
407 }
408
409 memt = xmlMemUsed();
410 extraMemoryFromResolver = 0;
411 /*
412 * dump the schemas to a buffer, then reparse it and compile the schemas
413 */
414 buf = xmlBufferCreate();
415 if (buf == NULL) {
416 fprintf(stderr, "out of memory !\n");
417 fatalError();
418 }
419 xmlNodeDump(buf, test->doc, test, 0, 0);
420 pctxt = xmlRelaxNGNewMemParserCtxt((const char *)buf->content, buf->use);
421 xmlRelaxNGSetParserErrors(pctxt,
422 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
423 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
424 pctxt);
425 rng = xmlRelaxNGParse(pctxt);
426 xmlRelaxNGFreeParserCtxt(pctxt);
427 if (extraMemoryFromResolver)
428 memt = 0;
429
430 if (rng == NULL) {
431 fprintf(stderr, "Failed to parse RNGtest line %ld\n",
432 xmlGetLineNo(test));
433 nb_errors++;
434 ret = 1;
435 goto done;
436 }
437 /*
438 * now scan all the siblings of correct to process the <valid> tests
439 */
440 tmp = getNext(cur, "following-sibling::valid[1]");
441 while (tmp != NULL) {
Daniel Veillarde84f2312005-07-02 07:31:28 +0000442 dtd = xmlGetProp(tmp, BAD_CAST "dtd");
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000443 test = getNext(tmp, "./*");
444 if (test == NULL) {
445 fprintf(stderr, "Failed to find test in <valid> line %ld\n",
446 xmlGetLineNo(tmp));
447
448 } else {
449 xmlBufferEmpty(buf);
Daniel Veillarde84f2312005-07-02 07:31:28 +0000450 if (dtd != NULL)
451 xmlBufferAdd(buf, dtd, -1);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000452 xmlNodeDump(buf, test->doc, test, 0, 0);
453
454 /*
455 * We are ready to run the test
456 */
457 mem = xmlMemUsed();
458 extraMemoryFromResolver = 0;
459 doc = xmlReadMemory((const char *)buf->content, buf->use,
460 "test", NULL, 0);
461 if (doc == NULL) {
462 fprintf(stderr,
463 "Failed to parse valid instance line %ld\n",
464 xmlGetLineNo(tmp));
465 nb_errors++;
466 } else {
467 nb_tests++;
468 ctxt = xmlRelaxNGNewValidCtxt(rng);
469 xmlRelaxNGSetValidErrors(ctxt,
470 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
471 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
472 ctxt);
473 ret = xmlRelaxNGValidateDoc(ctxt, doc);
474 xmlRelaxNGFreeValidCtxt(ctxt);
475 if (ret > 0) {
476 fprintf(stderr,
477 "Failed to validate valid instance line %ld\n",
478 xmlGetLineNo(tmp));
479 nb_errors++;
480 } else if (ret < 0) {
481 fprintf(stderr,
482 "Internal error validating instance line %ld\n",
483 xmlGetLineNo(tmp));
484 nb_errors++;
485 }
486 xmlFreeDoc(doc);
487 }
488 xmlResetLastError();
489 if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
490 fprintf(stderr, "Validation of instance line %ld leaked %d\n",
491 xmlGetLineNo(tmp), xmlMemUsed() - mem);
492 xmlMemoryDump();
493 nb_leaks++;
494 }
495 }
Daniel Veillarde84f2312005-07-02 07:31:28 +0000496 if (dtd != NULL)
497 xmlFree(dtd);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000498 tmp = getNext(tmp, "following-sibling::valid[1]");
499 }
500 /*
501 * now scan all the siblings of correct to process the <invalid> tests
502 */
503 tmp = getNext(cur, "following-sibling::invalid[1]");
504 while (tmp != NULL) {
505 test = getNext(tmp, "./*");
506 if (test == NULL) {
507 fprintf(stderr, "Failed to find test in <invalid> line %ld\n",
508 xmlGetLineNo(tmp));
509
510 } else {
511 xmlBufferEmpty(buf);
512 xmlNodeDump(buf, test->doc, test, 0, 0);
513
514 /*
515 * We are ready to run the test
516 */
517 mem = xmlMemUsed();
518 extraMemoryFromResolver = 0;
519 doc = xmlReadMemory((const char *)buf->content, buf->use,
520 "test", NULL, 0);
521 if (doc == NULL) {
522 fprintf(stderr,
523 "Failed to parse valid instance line %ld\n",
524 xmlGetLineNo(tmp));
525 nb_errors++;
526 } else {
527 nb_tests++;
528 ctxt = xmlRelaxNGNewValidCtxt(rng);
529 xmlRelaxNGSetValidErrors(ctxt,
530 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
531 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
532 ctxt);
533 ret = xmlRelaxNGValidateDoc(ctxt, doc);
534 xmlRelaxNGFreeValidCtxt(ctxt);
535 if (ret == 0) {
536 fprintf(stderr,
537 "Failed to detect invalid instance line %ld\n",
538 xmlGetLineNo(tmp));
539 nb_errors++;
540 } else if (ret < 0) {
541 fprintf(stderr,
542 "Internal error validating instance line %ld\n",
543 xmlGetLineNo(tmp));
544 nb_errors++;
545 }
546 xmlFreeDoc(doc);
547 }
548 xmlResetLastError();
549 if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
550 fprintf(stderr, "Validation of instance line %ld leaked %d\n",
551 xmlGetLineNo(tmp), xmlMemUsed() - mem);
552 xmlMemoryDump();
553 nb_leaks++;
554 }
555 }
556 tmp = getNext(tmp, "following-sibling::invalid[1]");
557 }
558
559done:
560 if (buf != NULL)
561 xmlBufferFree(buf);
562 if (rng != NULL)
563 xmlRelaxNGFree(rng);
564 xmlResetLastError();
565 if ((memt != xmlMemUsed()) && (memt != 0)) {
566 fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
567 xmlGetLineNo(cur), xmlMemUsed() - memt);
568 nb_leaks++;
569 }
570 return(ret);
571}
572
573static int
574xsdTestSuite(int verbose, xmlNodePtr cur) {
575 if (verbose) {
576 xmlChar *doc = getString(cur, "string(documentation)");
577
578 if (doc != NULL) {
579 printf("Suite %s\n", doc);
580 xmlFree(doc);
581 }
582 }
583 cur = getNext(cur, "./testCase[1]");
584 while (cur != NULL) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000585 xsdTestCase(cur);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000586 cur = getNext(cur, "following-sibling::testCase[1]");
587 }
588
589 return(0);
590}
591
592static int
593xsdTest(int verbose) {
594 xmlDocPtr doc;
595 xmlNodePtr cur;
596 const char *filename = "test/xsdtest/xsdtestsuite.xml";
597 int ret = 0;
598
599 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
600 if (doc == NULL) {
601 fprintf(stderr, "Failed to parse %s\n", filename);
602 return(-1);
603 }
604 printf("## XML Schemas datatypes test suite from James Clark\n");
605
606 cur = xmlDocGetRootElement(doc);
607 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
608 fprintf(stderr, "Unexpected format %s\n", filename);
609 ret = -1;
610 goto done;
611 }
612
613 cur = getNext(cur, "./testSuite[1]");
614 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
615 fprintf(stderr, "Unexpected format %s\n", filename);
616 ret = -1;
617 goto done;
618 }
619 while (cur != NULL) {
620 xsdTestSuite(verbose, cur);
621 cur = getNext(cur, "following-sibling::testSuite[1]");
622 }
623
624done:
625 if (doc != NULL)
626 xmlFreeDoc(doc);
627 return(ret);
628}
629
630static int
631rngTestSuite(int verbose, xmlNodePtr cur) {
632 if (verbose) {
633 xmlChar *doc = getString(cur, "string(documentation)");
634
635 if (doc != NULL) {
636 printf("Suite %s\n", doc);
637 xmlFree(doc);
638 } else {
639 doc = getString(cur, "string(section)");
640 if (doc != NULL) {
641 printf("Section %s\n", doc);
642 xmlFree(doc);
643 }
644 }
645 }
646 cur = getNext(cur, "./testSuite[1]");
647 while (cur != NULL) {
648 xsdTestSuite(verbose, cur);
649 cur = getNext(cur, "following-sibling::testSuite[1]");
650 }
651
652 return(0);
653}
654
655static int
656rngTest1(int verbose) {
657 xmlDocPtr doc;
658 xmlNodePtr cur;
659 const char *filename = "test/relaxng/OASIS/spectest.xml";
660 int ret = 0;
661
662 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
663 if (doc == NULL) {
664 fprintf(stderr, "Failed to parse %s\n", filename);
665 return(-1);
666 }
Daniel Veillarde84f2312005-07-02 07:31:28 +0000667 printf("## Relax NG test suite from James Clark\n");
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000668
669 cur = xmlDocGetRootElement(doc);
670 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
671 fprintf(stderr, "Unexpected format %s\n", filename);
672 ret = -1;
673 goto done;
674 }
675
676 cur = getNext(cur, "./testSuite[1]");
677 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
678 fprintf(stderr, "Unexpected format %s\n", filename);
679 ret = -1;
680 goto done;
681 }
682 while (cur != NULL) {
683 rngTestSuite(verbose, cur);
684 cur = getNext(cur, "following-sibling::testSuite[1]");
685 }
686
687done:
688 if (doc != NULL)
689 xmlFreeDoc(doc);
690 return(ret);
691}
692
Daniel Veillarde84f2312005-07-02 07:31:28 +0000693static int
694rngTest2(int verbose) {
695 xmlDocPtr doc;
696 xmlNodePtr cur;
697 const char *filename = "test/relaxng/testsuite.xml";
698 int ret = 0;
699
700 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
701 if (doc == NULL) {
702 fprintf(stderr, "Failed to parse %s\n", filename);
703 return(-1);
704 }
705 printf("## Relax NG test suite for libxml2\n");
706
707 cur = xmlDocGetRootElement(doc);
708 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
709 fprintf(stderr, "Unexpected format %s\n", filename);
710 ret = -1;
711 goto done;
712 }
713
714 cur = getNext(cur, "./testSuite[1]");
715 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
716 fprintf(stderr, "Unexpected format %s\n", filename);
717 ret = -1;
718 goto done;
719 }
720 while (cur != NULL) {
721 xsdTestSuite(verbose, cur);
722 cur = getNext(cur, "following-sibling::testSuite[1]");
723 }
724
725done:
726 if (doc != NULL)
727 xmlFreeDoc(doc);
728 return(ret);
729}
730
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000731/************************************************************************
732 * *
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000733 * Schemas test suites from W3C/NIST/MS/Sun *
734 * *
735 ************************************************************************/
736
737static int
738xstcTestInstance(int verbose, xmlNodePtr cur, xmlSchemaPtr schemas) {
739 xmlChar *href = NULL;
740 xmlChar *path = NULL;
741 int ret = 0;
742
743 href = getString(cur,
744 "string(ts:schemaTest/ts:schemaDocument/@xlink:href)");
745 if ((href == NULL) || (href[0] == 0)) {
746 if (verbose)
747 fprintf(stderr,
748 "testGroup line %ld misses href for schemaDocument\n",
749 xmlGetLineNo(cur));
750 ret = -1;
751 goto done;
752 }
753 path = xmlBuildURI(href, BAD_CAST "./xstc/Tests/");
754 if (path == NULL) {
755 fprintf(stderr,
756 "Failed to build path to schemas testGroup line %ld : %s\n",
757 xmlGetLineNo(cur), href);
758 ret = -1;
759 goto done;
760 }
761 if (checkTestFile(path) <= 0) {
762 fprintf(stderr,
763 "schemas for testGroup line %ld is missing: %s\n",
764 xmlGetLineNo(cur), path);
765 ret = -1;
766 goto done;
767 }
768 nb_tests++;
769
770done:
771 if (href != NULL) xmlFree(href);
772 if (path != NULL) xmlFree(path);
773 return(ret);
774}
775static int
776xstcTestGroup(int verbose, xmlNodePtr cur) {
777 xmlChar *href = NULL;
778 xmlChar *path = NULL;
779 xmlChar *validity = NULL;
780 xmlSchemaPtr schemas = NULL;
781 xmlSchemaParserCtxtPtr ctxt;
782 xmlNodePtr instance;
783 int ret = 0;
784
785 href = getString(cur,
786 "string(ts:schemaTest/ts:schemaDocument/@xlink:href)");
787 if ((href == NULL) || (href[0] == 0)) {
788 if (verbose)
789 fprintf(stderr,
790 "testGroup line %ld misses href for schemaDocument\n",
791 xmlGetLineNo(cur));
792 ret = -1;
793 goto done;
794 }
795 path = xmlBuildURI(href, BAD_CAST "./xstc/Tests/");
796 if (path == NULL) {
797 fprintf(stderr,
798 "Failed to build path to schemas testGroup line %ld : %s\n",
799 xmlGetLineNo(cur), href);
800 ret = -1;
801 goto done;
802 }
803 if (checkTestFile(path) <= 0) {
804 fprintf(stderr,
805 "schemas for testGroup line %ld is missing: %s\n",
806 xmlGetLineNo(cur), path);
807 ret = -1;
808 goto done;
809 }
810 validity = getString(cur,
811 "string(ts:schemaTest/ts:expected/@validity)");
812 if (validity == NULL) {
813 fprintf(stderr, "testGroup line %ld misses expected validity\n",
814 xmlGetLineNo(cur));
815 ret = -1;
816 goto done;
817 }
818 if (xmlStrEqual(validity, BAD_CAST "valid")) {
819 ctxt = xmlSchemaNewParserCtxt(path);
820 xmlSchemaSetParserErrors(ctxt,
821 (xmlSchemaValidityErrorFunc) testErrorHandler,
822 (xmlSchemaValidityWarningFunc) testErrorHandler,
823 ctxt);
824 schemas = xmlSchemaParse(ctxt);
825 xmlSchemaFreeParserCtxt(ctxt);
826 if (schemas == NULL) {
827 if (verbose)
828 fprintf(stderr, "valid schemas %s failed to parse\n",
829 path);
830 nb_errors++;
831 }
832 instance = getNext(cur, "./ts:instanceTest[1]");
833 if (instance == NULL) {
834 nb_tests++;
835 }
836 while (instance != NULL) {
837 xstcTestInstance(verbose, instance, schemas);
838 instance = getNext(instance,
839 "following-sibling::ts:instanceTest[1]");
840 }
841 } else if (xmlStrEqual(validity, BAD_CAST "invalid")) {
842 ctxt = xmlSchemaNewParserCtxt(path);
843 xmlSchemaSetParserErrors(ctxt,
844 (xmlSchemaValidityErrorFunc) testErrorHandler,
845 (xmlSchemaValidityWarningFunc) testErrorHandler,
846 ctxt);
847 schemas = xmlSchemaParse(ctxt);
848 xmlSchemaFreeParserCtxt(ctxt);
849 if (schemas == NULL) {
850 if (verbose)
851 fprintf(stderr, "Failed to detect error in schemas %s\n",
852 path);
853 nb_errors++;
854 }
855 nb_tests++;
856 } else {
857 fprintf(stderr,
858 "testGroup line %ld misses unexpected validity value%s\n",
859 xmlGetLineNo(cur), validity);
860 ret = -1;
861 goto done;
862 }
863
864done:
865 if (href != NULL) xmlFree(href);
866 if (path != NULL) xmlFree(path);
867 if (validity != NULL) xmlFree(validity);
868 if (schemas != NULL) xmlSchemaFree(schemas);
869 return(ret);
870}
871
872static int
873xstcMetadata(int verbose, const char *metadata) {
874 xmlDocPtr doc;
875 xmlNodePtr cur;
876 xmlChar *contributor;
877 xmlChar *name;
878 int ret;
879
880 doc = xmlReadFile(metadata, NULL, XML_PARSE_NOENT);
881 if (doc == NULL) {
882 fprintf(stderr, "Failed to parse %s\n", metadata);
883 return(-1);
884 }
885
886 cur = xmlDocGetRootElement(doc);
887 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSet"))) {
888 fprintf(stderr, "Unexpected format %s\n", metadata);
889 return(-1);
890 }
891 contributor = xmlGetProp(cur, BAD_CAST "contributor");
892 if (contributor == NULL) {
893 contributor = xmlStrdup(BAD_CAST "Unknown");
894 }
895 name = xmlGetProp(cur, BAD_CAST "name");
896 if (name == NULL) {
897 name = xmlStrdup(BAD_CAST "Unknown");
898 }
899 printf("## %s test suite for Schemas version %s\n", contributor, name);
900 xmlFree(contributor);
901 xmlFree(name);
902
903 cur = getNext(cur, "./ts:testGroup[1]");
904 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testGroup"))) {
905 fprintf(stderr, "Unexpected format %s\n", metadata);
906 ret = -1;
907 goto done;
908 }
909 while (cur != NULL) {
910 xstcTestGroup(verbose, cur);
911 cur = getNext(cur, "following-sibling::ts:testGroup[1]");
912 }
913
914done:
915 xmlFreeDoc(doc);
916 return(ret);
917}
918
919static int
920xstcTests(int verbose) {
921 int ret;
922
923 ret = xstcMetadata(verbose,
924 "xstc/Tests/Metadata/MSXMLSchema1-0-20020116.testSet");
925 return(ret);
926}
927
928/************************************************************************
929 * *
930 * The driver for the tests *
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000931 * *
932 ************************************************************************/
933
934int
935main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
936 int res, ret = 0;
937 int verbose = 0;
938 int old_errors, old_tests, old_leaks;
939
940 initializeLibxml2();
941
942 if ((argc >= 2) && (!strcmp(argv[1], "-v")))
943 verbose = 1;
944
945
Daniel Veillarde84f2312005-07-02 07:31:28 +0000946 old_errors = nb_errors;
947 old_tests = nb_tests;
948 old_leaks = nb_leaks;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000949 res = xsdTest(verbose);
950 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
951 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
952 else
953 printf("Ran %d tests, %d errors, %d leaks\n",
954 nb_tests - old_tests,
955 nb_errors - old_errors,
956 nb_leaks - old_leaks);
957 old_errors = nb_errors;
958 old_tests = nb_tests;
959 old_leaks = nb_leaks;
960 res = rngTest1(verbose);
961 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
962 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
963 else
964 printf("Ran %d tests, %d errors, %d leaks\n",
965 nb_tests - old_tests,
966 nb_errors - old_errors,
967 nb_leaks - old_leaks);
968 old_errors = nb_errors;
969 old_tests = nb_tests;
970 old_leaks = nb_leaks;
Daniel Veillarde84f2312005-07-02 07:31:28 +0000971 res = rngTest2(verbose);
972 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
973 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
974 else
975 printf("Ran %d tests, %d errors, %d leaks\n",
976 nb_tests - old_tests,
977 nb_errors - old_errors,
978 nb_leaks - old_leaks);
979 old_errors = nb_errors;
980 old_tests = nb_tests;
981 old_leaks = nb_leaks;
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000982 res = xstcTests(verbose);
983 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
984 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
985 else
986 printf("Ran %d tests, %d errors, %d leaks\n",
987 nb_tests - old_tests,
988 nb_errors - old_errors,
989 nb_leaks - old_leaks);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000990
991 if ((nb_errors == 0) && (nb_leaks == 0)) {
992 ret = 0;
993 printf("Total %d tests, no errors\n",
994 nb_tests);
995 } else {
996 ret = 1;
997 printf("Total %d tests, %d errors, %d leaks\n",
998 nb_tests, nb_errors, nb_leaks);
999 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +00001000
1001 xmlXPathFreeContext(ctxtXPath);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001002 xmlCleanupParser();
1003 xmlMemoryDump();
1004
1005 return(ret);
1006}