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