runsuite.c 31 KB

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