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