blob: e9fcc0c45d208db16fea2d8419dd263f16c6f9cd [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>
Daniel Veillard95175012005-07-03 16:09:51 +000022#if defined(LIBXML_SCHEMAS_ENABLED) && defined(LIBXML_XPATH_ENABLED)
Daniel Veillardf2e066a2005-06-30 13:04:44 +000023#include <libxml/xmlreader.h>
24
25#include <libxml/xpath.h>
26#include <libxml/xpathInternals.h>
27
28#include <libxml/relaxng.h>
29#include <libxml/xmlschemas.h>
30#include <libxml/xmlschemastypes.h>
31
32/************************************************************************
33 * *
34 * File name and path utilities *
35 * *
36 ************************************************************************/
37
38static int checkTestFile(const char *filename) {
39 struct stat buf;
40
41 if (stat(filename, &buf) == -1)
42 return(0);
43
44 if (!S_ISREG(buf.st_mode))
45 return(0);
46
47 return(1);
48}
Daniel Veillarde84f2312005-07-02 07:31:28 +000049static xmlChar *composeDir(const xmlChar *dir, const xmlChar *path) {
50 char buf[500];
51
52 if (dir == NULL) return(xmlStrdup(path));
53 if (path == NULL) return(NULL);
54
55 snprintf(buf, 500, "%s/%s", (const char *) dir, (const char *) path);
56 return(xmlStrdup((const xmlChar *) buf));
57}
Daniel Veillardf2e066a2005-06-30 13:04:44 +000058
59/************************************************************************
60 * *
61 * Libxml2 specific routines *
62 * *
63 ************************************************************************/
64
65static int nb_tests = 0;
66static int nb_errors = 0;
67static int nb_leaks = 0;
68static long libxmlMemoryAllocatedBase = 0;
69static int extraMemoryFromResolver = 0;
70
71static int
72fatalError(void) {
73 fprintf(stderr, "Exitting tests on fatal error\n");
74 exit(1);
75}
76
77/*
Daniel Veillarde84f2312005-07-02 07:31:28 +000078 * that's needed to implement <resource>
79 */
80#define MAX_ENTITIES 20
81char *testEntitiesName[MAX_ENTITIES];
82char *testEntitiesValue[MAX_ENTITIES];
83int nb_entities = 0;
84static void resetEntities(void) {
85 int i;
86
87 for (i = 0;i < nb_entities;i++) {
88 if (testEntitiesName[i] != NULL)
89 xmlFree(testEntitiesName[i]);
90 if (testEntitiesValue[i] != NULL)
91 xmlFree(testEntitiesValue[i]);
92 }
93 nb_entities = 0;
94}
95static int addEntity(char *name, char *content) {
96 if (nb_entities >= MAX_ENTITIES) {
97 fprintf(stderr, "Too many entities defined\n");
98 return(-1);
99 }
100 testEntitiesName[nb_entities] = name;
101 testEntitiesValue[nb_entities] = content;
102 nb_entities++;
103 return(0);
104}
105
106/*
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000107 * We need to trap calls to the resolver to not account memory for the catalog
108 * which is shared to the current running test. We also don't want to have
109 * network downloads modifying tests.
110 */
111static xmlParserInputPtr
112testExternalEntityLoader(const char *URL, const char *ID,
113 xmlParserCtxtPtr ctxt) {
114 xmlParserInputPtr ret;
Daniel Veillarde84f2312005-07-02 07:31:28 +0000115 int i;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000116
Daniel Veillarde84f2312005-07-02 07:31:28 +0000117 for (i = 0;i < nb_entities;i++) {
118 if (!strcmp(testEntitiesName[i], URL)) {
119 ret = xmlNewStringInputStream(ctxt,
120 (const xmlChar *) testEntitiesValue[i]);
121 if (ret != NULL) {
122 ret->filename = (const char *)
123 xmlStrdup((xmlChar *)testEntitiesName[i]);
124 }
125 return(ret);
126 }
127 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000128 if (checkTestFile(URL)) {
129 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
130 } else {
131 int memused = xmlMemUsed();
132 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
133 extraMemoryFromResolver += xmlMemUsed() - memused;
134 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000135#if 0
Daniel Veillarde84f2312005-07-02 07:31:28 +0000136 if (ret == NULL) {
137 fprintf(stderr, "Failed to find resource %s\n", URL);
138 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000139#endif
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000140
141 return(ret);
142}
143
144/*
145 * Trapping the error messages at the generic level to grab the equivalent of
146 * stderr messages on CLI tools.
147 */
148static char testErrors[32769];
149static int testErrorsSize = 0;
150
151static void
152testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
153 va_list args;
154 int res;
155
156 if (testErrorsSize >= 32768)
157 return;
158 va_start(args, msg);
159 res = vsnprintf(&testErrors[testErrorsSize],
160 32768 - testErrorsSize,
161 msg, args);
162 va_end(args);
163 if (testErrorsSize + res >= 32768) {
164 /* buffer is full */
165 testErrorsSize = 32768;
166 testErrors[testErrorsSize] = 0;
167 } else {
168 testErrorsSize += res;
169 }
170 testErrors[testErrorsSize] = 0;
171}
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000172
173xmlXPathContextPtr ctxtXPath;
174
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000175static void
176initializeLibxml2(void) {
177 xmlGetWarningsDefaultValue = 0;
178 xmlPedanticParserDefault(0);
179
180 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
181 xmlInitParser();
182 xmlSetExternalEntityLoader(testExternalEntityLoader);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000183 ctxtXPath = xmlXPathNewContext(NULL);
184 /* used as default nanemspace in xstc tests */
185 xmlXPathRegisterNs(ctxtXPath, BAD_CAST "ts", BAD_CAST "TestSuite");
186 xmlXPathRegisterNs(ctxtXPath, BAD_CAST "xlink",
187 BAD_CAST "http://www.w3.org/1999/xlink");
188 xmlSetGenericErrorFunc(NULL, testErrorHandler);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000189#ifdef LIBXML_SCHEMAS_ENABLED
190 xmlSchemaInitTypes();
191 xmlRelaxNGInitTypes();
192#endif
193 libxmlMemoryAllocatedBase = xmlMemUsed();
194}
195
196static xmlNodePtr
197getNext(xmlNodePtr cur, const char *xpath) {
198 xmlNodePtr ret = NULL;
199 xmlXPathObjectPtr res;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000200 xmlXPathCompExprPtr comp;
201
202 if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL))
203 return(NULL);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000204 ctxtXPath->doc = cur->doc;
205 ctxtXPath->node = cur;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000206 comp = xmlXPathCompile(BAD_CAST xpath);
207 if (comp == NULL) {
208 fprintf(stderr, "Failed to compile %s\n", xpath);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000209 return(NULL);
210 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000211 res = xmlXPathCompiledEval(comp, ctxtXPath);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000212 xmlXPathFreeCompExpr(comp);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000213 if (res == NULL)
214 return(NULL);
215 if ((res->type == XPATH_NODESET) &&
216 (res->nodesetval != NULL) &&
217 (res->nodesetval->nodeNr > 0) &&
218 (res->nodesetval->nodeTab != NULL))
219 ret = res->nodesetval->nodeTab[0];
220 xmlXPathFreeObject(res);
221 return(ret);
222}
223
224static xmlChar *
225getString(xmlNodePtr cur, const char *xpath) {
226 xmlChar *ret = NULL;
227 xmlXPathObjectPtr res;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000228 xmlXPathCompExprPtr comp;
229
230 if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL))
231 return(NULL);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000232 ctxtXPath->doc = cur->doc;
233 ctxtXPath->node = cur;
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000234 comp = xmlXPathCompile(BAD_CAST xpath);
235 if (comp == NULL) {
236 fprintf(stderr, "Failed to compile %s\n", xpath);
237 return(NULL);
238 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000239 res = xmlXPathCompiledEval(comp, ctxtXPath);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000240 xmlXPathFreeCompExpr(comp);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000241 if (res == NULL)
242 return(NULL);
243 if (res->type == XPATH_STRING) {
244 ret = res->stringval;
245 res->stringval = NULL;
246 }
247 xmlXPathFreeObject(res);
248 return(ret);
249}
250
251/************************************************************************
252 * *
253 * Test test/xsdtest/xsdtestsuite.xml *
254 * *
255 ************************************************************************/
256
257static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000258xsdIncorectTestCase(int verbose, xmlNodePtr cur) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000259 xmlNodePtr test;
260 xmlBufferPtr buf;
261 xmlRelaxNGParserCtxtPtr pctxt;
262 xmlRelaxNGPtr rng = NULL;
263 int ret = 0, memt;
264
265 cur = getNext(cur, "./incorrect[1]");
266 if (cur == NULL) {
267 return(0);
268 }
269
270 test = getNext(cur, "./*");
271 if (test == NULL) {
272 fprintf(stderr, "Failed to find test in correct line %ld\n",
273 xmlGetLineNo(cur));
274 return(1);
275 }
276
277 memt = xmlMemUsed();
278 extraMemoryFromResolver = 0;
279 /*
280 * dump the schemas to a buffer, then reparse it and compile the schemas
281 */
282 buf = xmlBufferCreate();
283 if (buf == NULL) {
284 fprintf(stderr, "out of memory !\n");
285 fatalError();
286 }
287 xmlNodeDump(buf, test->doc, test, 0, 0);
288 pctxt = xmlRelaxNGNewMemParserCtxt((const char *)buf->content, buf->use);
289 xmlRelaxNGSetParserErrors(pctxt,
290 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
291 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
292 pctxt);
293 rng = xmlRelaxNGParse(pctxt);
294 xmlRelaxNGFreeParserCtxt(pctxt);
295 if (rng != NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000296 if (verbose) {
297 fprintf(stderr, "Failed to detect incorect RNG line %ld\n",
298 xmlGetLineNo(test));
299 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000300 ret = 1;
301 goto done;
302 }
303
304done:
305 if (buf != NULL)
306 xmlBufferFree(buf);
307 if (rng != NULL)
308 xmlRelaxNGFree(rng);
309 xmlResetLastError();
310 if ((memt != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
311 fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
312 xmlGetLineNo(cur), xmlMemUsed() - memt);
313 nb_leaks++;
314 }
315 return(ret);
316}
317
Daniel Veillarde84f2312005-07-02 07:31:28 +0000318static void
319installResources(xmlNodePtr tst, const xmlChar *base) {
320 xmlNodePtr test;
321 xmlBufferPtr buf;
322 xmlChar *name, *content, *res;
323 buf = xmlBufferCreate();
324 if (buf == NULL) {
325 fprintf(stderr, "out of memory !\n");
326 fatalError();
327 }
328 xmlNodeDump(buf, tst->doc, tst, 0, 0);
329
330 while (tst != NULL) {
331 test = getNext(tst, "./*");
332 if (test != NULL) {
333 xmlBufferEmpty(buf);
334 xmlNodeDump(buf, test->doc, test, 0, 0);
335 name = getString(tst, "string(@name)");
336 content = xmlStrdup(buf->content);
337 if ((name != NULL) && (content != NULL)) {
338 res = composeDir(base, name);
339 xmlFree(name);
340 addEntity((char *) res, (char *) content);
341 } else {
342 if (name != NULL) xmlFree(name);
343 if (content != NULL) xmlFree(content);
344 }
345 }
346 tst = getNext(tst, "following-sibling::resource[1]");
347 }
348 if (buf != NULL)
349 xmlBufferFree(buf);
350}
351
352static void
353installDirs(xmlNodePtr tst, const xmlChar *base) {
354 xmlNodePtr test;
355 xmlChar *name, *res;
356
357 name = getString(tst, "string(@name)");
358 if (name == NULL)
359 return;
360 res = composeDir(base, name);
361 xmlFree(name);
362 if (res == NULL) {
363 return;
364 }
365 /* Now process resources and subdir recursively */
366 test = getNext(tst, "./resource[1]");
367 if (test != NULL) {
368 installResources(test, res);
369 }
370 test = getNext(tst, "./dir[1]");
371 while (test != NULL) {
372 installDirs(test, res);
373 test = getNext(test, "following-sibling::dir[1]");
374 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000375 xmlFree(res);
Daniel Veillarde84f2312005-07-02 07:31:28 +0000376}
377
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000378static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000379xsdTestCase(int verbose, xmlNodePtr tst) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000380 xmlNodePtr test, tmp, cur;
381 xmlBufferPtr buf;
382 xmlDocPtr doc = NULL;
383 xmlRelaxNGParserCtxtPtr pctxt;
384 xmlRelaxNGValidCtxtPtr ctxt;
385 xmlRelaxNGPtr rng = NULL;
386 int ret = 0, mem, memt;
Daniel Veillarde84f2312005-07-02 07:31:28 +0000387 xmlChar *dtd;
388
389 resetEntities();
390
391 tmp = getNext(tst, "./dir[1]");
392 if (tmp != NULL) {
393 installDirs(tmp, NULL);
394 }
395 tmp = getNext(tst, "./resource[1]");
396 if (tmp != NULL) {
397 installResources(tmp, NULL);
398 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000399
400 cur = getNext(tst, "./correct[1]");
401 if (cur == NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000402 return(xsdIncorectTestCase(verbose, tst));
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000403 }
404
405 test = getNext(cur, "./*");
406 if (test == NULL) {
407 fprintf(stderr, "Failed to find test in correct line %ld\n",
408 xmlGetLineNo(cur));
409 return(1);
410 }
411
412 memt = xmlMemUsed();
413 extraMemoryFromResolver = 0;
414 /*
415 * dump the schemas to a buffer, then reparse it and compile the schemas
416 */
417 buf = xmlBufferCreate();
418 if (buf == NULL) {
419 fprintf(stderr, "out of memory !\n");
420 fatalError();
421 }
422 xmlNodeDump(buf, test->doc, test, 0, 0);
423 pctxt = xmlRelaxNGNewMemParserCtxt((const char *)buf->content, buf->use);
424 xmlRelaxNGSetParserErrors(pctxt,
425 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
426 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
427 pctxt);
428 rng = xmlRelaxNGParse(pctxt);
429 xmlRelaxNGFreeParserCtxt(pctxt);
430 if (extraMemoryFromResolver)
431 memt = 0;
432
433 if (rng == NULL) {
434 fprintf(stderr, "Failed to parse RNGtest line %ld\n",
435 xmlGetLineNo(test));
436 nb_errors++;
437 ret = 1;
438 goto done;
439 }
440 /*
441 * now scan all the siblings of correct to process the <valid> tests
442 */
443 tmp = getNext(cur, "following-sibling::valid[1]");
444 while (tmp != NULL) {
Daniel Veillarde84f2312005-07-02 07:31:28 +0000445 dtd = xmlGetProp(tmp, BAD_CAST "dtd");
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000446 test = getNext(tmp, "./*");
447 if (test == NULL) {
448 fprintf(stderr, "Failed to find test in <valid> line %ld\n",
449 xmlGetLineNo(tmp));
450
451 } else {
452 xmlBufferEmpty(buf);
Daniel Veillarde84f2312005-07-02 07:31:28 +0000453 if (dtd != NULL)
454 xmlBufferAdd(buf, dtd, -1);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000455 xmlNodeDump(buf, test->doc, test, 0, 0);
456
457 /*
458 * We are ready to run the test
459 */
460 mem = xmlMemUsed();
461 extraMemoryFromResolver = 0;
462 doc = xmlReadMemory((const char *)buf->content, buf->use,
463 "test", NULL, 0);
464 if (doc == NULL) {
465 fprintf(stderr,
466 "Failed to parse valid instance line %ld\n",
467 xmlGetLineNo(tmp));
468 nb_errors++;
469 } else {
470 nb_tests++;
471 ctxt = xmlRelaxNGNewValidCtxt(rng);
472 xmlRelaxNGSetValidErrors(ctxt,
473 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
474 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
475 ctxt);
476 ret = xmlRelaxNGValidateDoc(ctxt, doc);
477 xmlRelaxNGFreeValidCtxt(ctxt);
478 if (ret > 0) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000479 if (verbose) {
480 fprintf(stderr,
481 "Failed to validate valid instance line %ld\n",
482 xmlGetLineNo(tmp));
483 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000484 nb_errors++;
485 } else if (ret < 0) {
486 fprintf(stderr,
487 "Internal error validating instance line %ld\n",
488 xmlGetLineNo(tmp));
489 nb_errors++;
490 }
491 xmlFreeDoc(doc);
492 }
493 xmlResetLastError();
494 if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
495 fprintf(stderr, "Validation of instance line %ld leaked %d\n",
496 xmlGetLineNo(tmp), xmlMemUsed() - mem);
497 xmlMemoryDump();
498 nb_leaks++;
499 }
500 }
Daniel Veillarde84f2312005-07-02 07:31:28 +0000501 if (dtd != NULL)
502 xmlFree(dtd);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000503 tmp = getNext(tmp, "following-sibling::valid[1]");
504 }
505 /*
506 * now scan all the siblings of correct to process the <invalid> tests
507 */
508 tmp = getNext(cur, "following-sibling::invalid[1]");
509 while (tmp != NULL) {
510 test = getNext(tmp, "./*");
511 if (test == NULL) {
512 fprintf(stderr, "Failed to find test in <invalid> line %ld\n",
513 xmlGetLineNo(tmp));
514
515 } else {
516 xmlBufferEmpty(buf);
517 xmlNodeDump(buf, test->doc, test, 0, 0);
518
519 /*
520 * We are ready to run the test
521 */
522 mem = xmlMemUsed();
523 extraMemoryFromResolver = 0;
524 doc = xmlReadMemory((const char *)buf->content, buf->use,
525 "test", NULL, 0);
526 if (doc == NULL) {
527 fprintf(stderr,
528 "Failed to parse valid instance line %ld\n",
529 xmlGetLineNo(tmp));
530 nb_errors++;
531 } else {
532 nb_tests++;
533 ctxt = xmlRelaxNGNewValidCtxt(rng);
534 xmlRelaxNGSetValidErrors(ctxt,
535 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
536 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
537 ctxt);
538 ret = xmlRelaxNGValidateDoc(ctxt, doc);
539 xmlRelaxNGFreeValidCtxt(ctxt);
540 if (ret == 0) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000541 if (verbose) {
542 fprintf(stderr,
543 "Failed to detect invalid instance line %ld\n",
544 xmlGetLineNo(tmp));
545 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000546 nb_errors++;
547 } else if (ret < 0) {
548 fprintf(stderr,
549 "Internal error validating instance line %ld\n",
550 xmlGetLineNo(tmp));
551 nb_errors++;
552 }
553 xmlFreeDoc(doc);
554 }
555 xmlResetLastError();
556 if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
557 fprintf(stderr, "Validation of instance line %ld leaked %d\n",
558 xmlGetLineNo(tmp), xmlMemUsed() - mem);
559 xmlMemoryDump();
560 nb_leaks++;
561 }
562 }
563 tmp = getNext(tmp, "following-sibling::invalid[1]");
564 }
565
566done:
567 if (buf != NULL)
568 xmlBufferFree(buf);
569 if (rng != NULL)
570 xmlRelaxNGFree(rng);
571 xmlResetLastError();
572 if ((memt != xmlMemUsed()) && (memt != 0)) {
573 fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
574 xmlGetLineNo(cur), xmlMemUsed() - memt);
575 nb_leaks++;
576 }
577 return(ret);
578}
579
580static int
581xsdTestSuite(int verbose, xmlNodePtr cur) {
582 if (verbose) {
583 xmlChar *doc = getString(cur, "string(documentation)");
584
585 if (doc != NULL) {
586 printf("Suite %s\n", doc);
587 xmlFree(doc);
588 }
589 }
590 cur = getNext(cur, "./testCase[1]");
591 while (cur != NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000592 xsdTestCase(verbose, cur);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000593 cur = getNext(cur, "following-sibling::testCase[1]");
594 }
595
596 return(0);
597}
598
599static int
600xsdTest(int verbose) {
601 xmlDocPtr doc;
602 xmlNodePtr cur;
603 const char *filename = "test/xsdtest/xsdtestsuite.xml";
604 int ret = 0;
605
606 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
607 if (doc == NULL) {
608 fprintf(stderr, "Failed to parse %s\n", filename);
609 return(-1);
610 }
611 printf("## XML Schemas datatypes test suite from James Clark\n");
612
613 cur = xmlDocGetRootElement(doc);
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
620 cur = getNext(cur, "./testSuite[1]");
621 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
622 fprintf(stderr, "Unexpected format %s\n", filename);
623 ret = -1;
624 goto done;
625 }
626 while (cur != NULL) {
627 xsdTestSuite(verbose, cur);
628 cur = getNext(cur, "following-sibling::testSuite[1]");
629 }
630
631done:
632 if (doc != NULL)
633 xmlFreeDoc(doc);
634 return(ret);
635}
636
637static int
638rngTestSuite(int verbose, xmlNodePtr cur) {
639 if (verbose) {
640 xmlChar *doc = getString(cur, "string(documentation)");
641
642 if (doc != NULL) {
643 printf("Suite %s\n", doc);
644 xmlFree(doc);
645 } else {
646 doc = getString(cur, "string(section)");
647 if (doc != NULL) {
648 printf("Section %s\n", doc);
649 xmlFree(doc);
650 }
651 }
652 }
653 cur = getNext(cur, "./testSuite[1]");
654 while (cur != NULL) {
655 xsdTestSuite(verbose, cur);
656 cur = getNext(cur, "following-sibling::testSuite[1]");
657 }
658
659 return(0);
660}
661
662static int
663rngTest1(int verbose) {
664 xmlDocPtr doc;
665 xmlNodePtr cur;
666 const char *filename = "test/relaxng/OASIS/spectest.xml";
667 int ret = 0;
668
669 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
670 if (doc == NULL) {
671 fprintf(stderr, "Failed to parse %s\n", filename);
672 return(-1);
673 }
Daniel Veillarde84f2312005-07-02 07:31:28 +0000674 printf("## Relax NG test suite from James Clark\n");
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000675
676 cur = xmlDocGetRootElement(doc);
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
683 cur = getNext(cur, "./testSuite[1]");
684 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
685 fprintf(stderr, "Unexpected format %s\n", filename);
686 ret = -1;
687 goto done;
688 }
689 while (cur != NULL) {
690 rngTestSuite(verbose, cur);
691 cur = getNext(cur, "following-sibling::testSuite[1]");
692 }
693
694done:
695 if (doc != NULL)
696 xmlFreeDoc(doc);
697 return(ret);
698}
699
Daniel Veillarde84f2312005-07-02 07:31:28 +0000700static int
701rngTest2(int verbose) {
702 xmlDocPtr doc;
703 xmlNodePtr cur;
704 const char *filename = "test/relaxng/testsuite.xml";
705 int ret = 0;
706
707 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
708 if (doc == NULL) {
709 fprintf(stderr, "Failed to parse %s\n", filename);
710 return(-1);
711 }
712 printf("## Relax NG test suite for libxml2\n");
713
714 cur = xmlDocGetRootElement(doc);
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
721 cur = getNext(cur, "./testSuite[1]");
722 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
723 fprintf(stderr, "Unexpected format %s\n", filename);
724 ret = -1;
725 goto done;
726 }
727 while (cur != NULL) {
728 xsdTestSuite(verbose, cur);
729 cur = getNext(cur, "following-sibling::testSuite[1]");
730 }
731
732done:
733 if (doc != NULL)
734 xmlFreeDoc(doc);
735 return(ret);
736}
737
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000738/************************************************************************
739 * *
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000740 * Schemas test suites from W3C/NIST/MS/Sun *
741 * *
742 ************************************************************************/
743
744static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000745xstcTestInstance(int verbose, xmlNodePtr cur, xmlSchemaPtr schemas,
Daniel Veillard6b6d6802005-07-03 21:00:34 +0000746 const xmlChar *spath, const char *base) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000747 xmlChar *href = NULL;
748 xmlChar *path = NULL;
Daniel Veillardde0e4982005-07-03 14:35:44 +0000749 xmlChar *validity = NULL;
750 xmlSchemaValidCtxtPtr ctxt = NULL;
751 xmlDocPtr doc = NULL;
752 int ret = 0, mem;
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000753
Daniel Veillardde0e4982005-07-03 14:35:44 +0000754 xmlResetLastError();
755 mem = xmlMemUsed();
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000756 href = getString(cur,
Daniel Veillardde0e4982005-07-03 14:35:44 +0000757 "string(ts:instanceDocument/@xlink:href)");
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000758 if ((href == NULL) || (href[0] == 0)) {
759 if (verbose)
760 fprintf(stderr,
761 "testGroup line %ld misses href for schemaDocument\n",
762 xmlGetLineNo(cur));
763 ret = -1;
764 goto done;
765 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000766 path = xmlBuildURI(href, BAD_CAST base);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000767 if (path == NULL) {
768 fprintf(stderr,
769 "Failed to build path to schemas testGroup line %ld : %s\n",
770 xmlGetLineNo(cur), href);
771 ret = -1;
772 goto done;
773 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000774 if (checkTestFile((const char *) path) <= 0) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000775 fprintf(stderr,
776 "schemas for testGroup line %ld is missing: %s\n",
777 xmlGetLineNo(cur), path);
778 ret = -1;
779 goto done;
780 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000781 validity = getString(cur,
782 "string(ts:expected/@validity)");
783 if (validity == NULL) {
784 fprintf(stderr, "instanceDocument line %ld misses expected validity\n",
785 xmlGetLineNo(cur));
786 ret = -1;
787 goto done;
788 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000789 nb_tests++;
Daniel Veillardde0e4982005-07-03 14:35:44 +0000790 doc = xmlReadFile((const char *) path, NULL, XML_PARSE_NOENT);
791 if (doc == NULL) {
792 fprintf(stderr, "instance %s fails to parse\n", path);
793 ret = -1;
794 nb_errors++;
795 goto done;
796 }
797
798 ctxt = xmlSchemaNewValidCtxt(schemas);
799 xmlSchemaSetValidErrors(ctxt,
800 (xmlSchemaValidityErrorFunc) testErrorHandler,
801 (xmlSchemaValidityWarningFunc) testErrorHandler,
802 ctxt);
803 ret = xmlSchemaValidateDoc(ctxt, doc);
804
805 if (xmlStrEqual(validity, BAD_CAST "valid")) {
806 if (ret != 0) {
807 if (verbose)
808 fprintf(stderr,
809 "valid instance %s failed to validate against %s\n",
810 path, spath);
811 nb_errors++;
812 }
813 } else if (xmlStrEqual(validity, BAD_CAST "invalid")) {
814 if (ret == 0) {
815 if (verbose)
816 fprintf(stderr,
817 "Failed to detect invalid instance %s against %s\n",
818 path, spath);
819 nb_errors++;
820 }
821 } else {
822 fprintf(stderr,
823 "instanceDocument line %ld has unexpected validity value%s\n",
824 xmlGetLineNo(cur), validity);
825 ret = -1;
826 goto done;
827 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000828
829done:
830 if (href != NULL) xmlFree(href);
831 if (path != NULL) xmlFree(path);
Daniel Veillardde0e4982005-07-03 14:35:44 +0000832 if (validity != NULL) xmlFree(validity);
833 if (ctxt != NULL) xmlSchemaFreeValidCtxt(ctxt);
834 if (doc != NULL) xmlFreeDoc(doc);
835 xmlResetLastError();
836 if (mem != xmlMemUsed()) {
837 fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
838 xmlGetLineNo(cur), xmlMemUsed() - mem);
839 nb_leaks++;
840 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000841 return(ret);
842}
Daniel Veillardde0e4982005-07-03 14:35:44 +0000843
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000844static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000845xstcTestGroup(int verbose, xmlNodePtr cur, const char *base) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000846 xmlChar *href = NULL;
847 xmlChar *path = NULL;
848 xmlChar *validity = NULL;
849 xmlSchemaPtr schemas = NULL;
850 xmlSchemaParserCtxtPtr ctxt;
851 xmlNodePtr instance;
Daniel Veillardde0e4982005-07-03 14:35:44 +0000852 int ret = 0, mem;
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000853
Daniel Veillardde0e4982005-07-03 14:35:44 +0000854 xmlResetLastError();
855 mem = xmlMemUsed();
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000856 href = getString(cur,
857 "string(ts:schemaTest/ts:schemaDocument/@xlink:href)");
858 if ((href == NULL) || (href[0] == 0)) {
859 if (verbose)
860 fprintf(stderr,
861 "testGroup line %ld misses href for schemaDocument\n",
862 xmlGetLineNo(cur));
863 ret = -1;
864 goto done;
865 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000866 path = xmlBuildURI(href, BAD_CAST base);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000867 if (path == NULL) {
868 fprintf(stderr,
869 "Failed to build path to schemas testGroup line %ld : %s\n",
870 xmlGetLineNo(cur), href);
871 ret = -1;
872 goto done;
873 }
Daniel Veillardde0e4982005-07-03 14:35:44 +0000874 if (checkTestFile((const char *) path) <= 0) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000875 fprintf(stderr,
876 "schemas for testGroup line %ld is missing: %s\n",
877 xmlGetLineNo(cur), path);
878 ret = -1;
879 goto done;
880 }
881 validity = getString(cur,
882 "string(ts:schemaTest/ts:expected/@validity)");
883 if (validity == NULL) {
884 fprintf(stderr, "testGroup line %ld misses expected validity\n",
885 xmlGetLineNo(cur));
886 ret = -1;
887 goto done;
888 }
889 if (xmlStrEqual(validity, BAD_CAST "valid")) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000890 ctxt = xmlSchemaNewParserCtxt((const char *) path);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000891 xmlSchemaSetParserErrors(ctxt,
892 (xmlSchemaValidityErrorFunc) testErrorHandler,
893 (xmlSchemaValidityWarningFunc) testErrorHandler,
894 ctxt);
895 schemas = xmlSchemaParse(ctxt);
896 xmlSchemaFreeParserCtxt(ctxt);
897 if (schemas == NULL) {
898 if (verbose)
899 fprintf(stderr, "valid schemas %s failed to parse\n",
900 path);
901 nb_errors++;
902 }
903 instance = getNext(cur, "./ts:instanceTest[1]");
904 if (instance == NULL) {
905 nb_tests++;
906 }
907 while (instance != NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000908 xstcTestInstance(verbose, instance, schemas, path, base);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000909 instance = getNext(instance,
910 "following-sibling::ts:instanceTest[1]");
911 }
912 } else if (xmlStrEqual(validity, BAD_CAST "invalid")) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000913 ctxt = xmlSchemaNewParserCtxt((const char *) path);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000914 xmlSchemaSetParserErrors(ctxt,
915 (xmlSchemaValidityErrorFunc) testErrorHandler,
916 (xmlSchemaValidityWarningFunc) testErrorHandler,
917 ctxt);
918 schemas = xmlSchemaParse(ctxt);
919 xmlSchemaFreeParserCtxt(ctxt);
920 if (schemas == NULL) {
921 if (verbose)
922 fprintf(stderr, "Failed to detect error in schemas %s\n",
923 path);
924 nb_errors++;
925 }
926 nb_tests++;
927 } else {
928 fprintf(stderr,
929 "testGroup line %ld misses unexpected validity value%s\n",
930 xmlGetLineNo(cur), validity);
931 ret = -1;
932 goto done;
933 }
934
935done:
936 if (href != NULL) xmlFree(href);
937 if (path != NULL) xmlFree(path);
938 if (validity != NULL) xmlFree(validity);
939 if (schemas != NULL) xmlSchemaFree(schemas);
Daniel Veillardde0e4982005-07-03 14:35:44 +0000940 xmlResetLastError();
941 if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
942 fprintf(stderr, "Processing test line %ld leaked %d\n",
943 xmlGetLineNo(cur), xmlMemUsed() - mem);
944 nb_leaks++;
945 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000946 return(ret);
947}
948
949static int
Daniel Veillardde0e4982005-07-03 14:35:44 +0000950xstcMetadata(int verbose, const char *metadata, const char *base) {
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000951 xmlDocPtr doc;
952 xmlNodePtr cur;
953 xmlChar *contributor;
954 xmlChar *name;
Daniel Veillard6b6d6802005-07-03 21:00:34 +0000955 int ret = 0;
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000956
957 doc = xmlReadFile(metadata, NULL, XML_PARSE_NOENT);
958 if (doc == NULL) {
959 fprintf(stderr, "Failed to parse %s\n", metadata);
960 return(-1);
961 }
962
963 cur = xmlDocGetRootElement(doc);
964 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSet"))) {
965 fprintf(stderr, "Unexpected format %s\n", metadata);
966 return(-1);
967 }
968 contributor = xmlGetProp(cur, BAD_CAST "contributor");
969 if (contributor == NULL) {
970 contributor = xmlStrdup(BAD_CAST "Unknown");
971 }
972 name = xmlGetProp(cur, BAD_CAST "name");
973 if (name == NULL) {
974 name = xmlStrdup(BAD_CAST "Unknown");
975 }
976 printf("## %s test suite for Schemas version %s\n", contributor, name);
977 xmlFree(contributor);
978 xmlFree(name);
979
980 cur = getNext(cur, "./ts:testGroup[1]");
981 if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testGroup"))) {
982 fprintf(stderr, "Unexpected format %s\n", metadata);
983 ret = -1;
984 goto done;
985 }
986 while (cur != NULL) {
Daniel Veillardde0e4982005-07-03 14:35:44 +0000987 xstcTestGroup(verbose, cur, base);
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000988 cur = getNext(cur, "following-sibling::ts:testGroup[1]");
989 }
990
991done:
992 xmlFreeDoc(doc);
993 return(ret);
994}
995
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +0000996/************************************************************************
997 * *
998 * The driver for the tests *
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000999 * *
1000 ************************************************************************/
1001
1002int
1003main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1004 int res, ret = 0;
1005 int verbose = 0;
1006 int old_errors, old_tests, old_leaks;
1007
1008 initializeLibxml2();
1009
1010 if ((argc >= 2) && (!strcmp(argv[1], "-v")))
1011 verbose = 1;
1012
1013
Daniel Veillarde84f2312005-07-02 07:31:28 +00001014 old_errors = nb_errors;
1015 old_tests = nb_tests;
1016 old_leaks = nb_leaks;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001017 res = xsdTest(verbose);
1018 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1019 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1020 else
1021 printf("Ran %d tests, %d errors, %d leaks\n",
1022 nb_tests - old_tests,
1023 nb_errors - old_errors,
1024 nb_leaks - old_leaks);
1025 old_errors = nb_errors;
1026 old_tests = nb_tests;
1027 old_leaks = nb_leaks;
1028 res = rngTest1(verbose);
1029 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1030 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1031 else
1032 printf("Ran %d tests, %d errors, %d leaks\n",
1033 nb_tests - old_tests,
1034 nb_errors - old_errors,
1035 nb_leaks - old_leaks);
1036 old_errors = nb_errors;
1037 old_tests = nb_tests;
1038 old_leaks = nb_leaks;
Daniel Veillarde84f2312005-07-02 07:31:28 +00001039 res = rngTest2(verbose);
1040 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1041 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1042 else
1043 printf("Ran %d tests, %d errors, %d leaks\n",
1044 nb_tests - old_tests,
1045 nb_errors - old_errors,
1046 nb_leaks - old_leaks);
1047 old_errors = nb_errors;
1048 old_tests = nb_tests;
1049 old_leaks = nb_leaks;
Daniel Veillardde0e4982005-07-03 14:35:44 +00001050 res = xstcMetadata(verbose,
1051 "xstc/Tests/Metadata/NISTXMLSchemaDatatypes.testSet",
1052 "xstc/Tests/Metadata/");
1053 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1054 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1055 else
1056 printf("Ran %d tests, %d errors, %d leaks\n",
1057 nb_tests - old_tests,
1058 nb_errors - old_errors,
1059 nb_leaks - old_leaks);
1060 old_errors = nb_errors;
1061 old_tests = nb_tests;
1062 old_leaks = nb_leaks;
1063 res = xstcMetadata(verbose,
1064 "xstc/Tests/Metadata/SunXMLSchema1-0-20020116.testSet",
1065 "xstc/");
1066 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1067 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1068 else
1069 printf("Ran %d tests, %d errors, %d leaks\n",
1070 nb_tests - old_tests,
1071 nb_errors - old_errors,
1072 nb_leaks - old_leaks);
1073 old_errors = nb_errors;
1074 old_tests = nb_tests;
1075 old_leaks = nb_leaks;
1076 res = xstcMetadata(verbose,
1077 "xstc/Tests/Metadata/MSXMLSchema1-0-20020116.testSet",
1078 "xstc/Tests/");
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +00001079 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1080 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1081 else
1082 printf("Ran %d tests, %d errors, %d leaks\n",
1083 nb_tests - old_tests,
1084 nb_errors - old_errors,
1085 nb_leaks - old_leaks);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001086
1087 if ((nb_errors == 0) && (nb_leaks == 0)) {
1088 ret = 0;
1089 printf("Total %d tests, no errors\n",
1090 nb_tests);
1091 } else {
1092 ret = 1;
1093 printf("Total %d tests, %d errors, %d leaks\n",
1094 nb_tests, nb_errors, nb_leaks);
1095 }
Daniel Veillard3fe1e8a2005-07-02 21:39:06 +00001096
1097 xmlXPathFreeContext(ctxtXPath);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001098 xmlCleanupParser();
1099 xmlMemoryDump();
1100
1101 return(ret);
1102}
Daniel Veillard95175012005-07-03 16:09:51 +00001103#else /* !SCHEMAS */
1104int
1105main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1106 fprintf(stderr, "runsuite requires support for schemas and xpath in libxml2\n");
1107}
1108#endif