Commit f2e066ac authored by Daniel Veillard's avatar Daniel Veillard

complete, checking on other platforms is needed updated fix a bug raised

* runtest.c: complete, checking on other platforms is needed
* README: updated
* debugXML.c: fix a bug raised by bill on IRC
* relaxng.c: fix a leak in weird circumstances
* runsuite.c Makefile.am: standalone test tool agaisnt
  the regression suites, work in progress
Daniel
parent 3056404d
Thu Jun 30 15:01:52 CEST 2005 Daniel Veillard <daniel@veillard.com>
* runtest.c: complete, checking on other platforms is needed
* README: updated
* debugXML.c: fix a bug raised by bill on IRC
* relaxng.c: fix a leak in weird circumstances
* runsuite.c Makefile.am: standalone test tool agaisnt
the regression suites, work in progress
Tue Jun 28 08:30:26 CEST 2005 Daniel Veillard <daniel@veillard.com>
* runtest.c: adding URI tests
......
......@@ -8,7 +8,7 @@ INCLUDES = -I$(top_builddir)/include -I@srcdir@/include @THREAD_CFLAGS@ @Z_CFLAG
noinst_PROGRAMS=testSchemas testRelax testSAX testHTML testXPath testURI \
testThreads testC14N testAutomata testRegexp \
testReader testapi testModule runtest
testReader testapi testModule runtest runsuite
bin_PROGRAMS = xmllint xmlcatalog
......@@ -52,7 +52,12 @@ m4data_DATA = libxml.m4
runtest_SOURCES=runtest.c
runtest_LDFLAGS =
runtest_DEPENDENCIES = $(DEPS)
runtest_LDADD= @RDL_LIBS@ $(LDADDS)
runtest_LDADD= @BASE_THREAD_LIBS@ @RDL_LIBS@ $(LDADDS)
runsuite_SOURCES=runsuite.c
runsuite_LDFLAGS =
runsuite_DEPENDENCIES = $(DEPS)
runsuite_LDADD= @RDL_LIBS@ $(LDADDS)
xmllint_SOURCES=xmllint.c
xmllint_LDFLAGS =
......
......@@ -6,6 +6,21 @@ Full documentation is available on-line at
This code is released under the MIT Licence see the Copyright file.
To build on an Unixised setup:
./configure ; make ; make install
To build on Windows:
see instructions on win32/Readme.txt
To assert build quality:
on an Unixised setup:
run make tests
otherwise:
There is 2 standalone tools runtest.c and testapi.c, which should
compile as part of the build or as any application would.
Launch them from this directory to get results, runtest checks
the proper functionning of libxml2 main APIs while testapi does
a full coverage check. Report failures to the list.
To report bugs, follow the instructions at:
http://xmlsoft.org/bugs.html
......
......@@ -344,6 +344,7 @@ xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
if ((node->type != XML_ELEMENT_NODE) &&
(node->type != XML_ATTRIBUTE_NODE) &&
(node->type != XML_ELEMENT_DECL) &&
(node->type != XML_ATTRIBUTE_DECL) &&
(node->type != XML_DTD_NODE) &&
(node->type != XML_HTML_DOCUMENT_NODE) &&
......
......@@ -6908,6 +6908,8 @@ xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
"xmlRelaxNGParse: externalRef has no href attribute\n",
NULL, NULL);
if (ns != NULL)
xmlFree(ns);
delete = cur;
goto skip_children;
}
......@@ -6916,6 +6918,8 @@ xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
"Incorrect URI for externalRef %s\n",
href, NULL);
if (ns != NULL)
xmlFree(ns);
if (href != NULL)
xmlFree(href);
delete = cur;
......@@ -6925,6 +6929,8 @@ xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
"Fragment forbidden in URI for externalRef %s\n",
href, NULL);
if (ns != NULL)
xmlFree(ns);
xmlFreeURI(uri);
if (href != NULL)
xmlFree(href);
......@@ -6938,6 +6944,8 @@ xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
"Failed to compute URL for externalRef %s\n",
href, NULL);
if (ns != NULL)
xmlFree(ns);
if (href != NULL)
xmlFree(href);
if (base != NULL)
......@@ -6954,6 +6962,8 @@ xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
"Failed to load externalRef %s\n", URL,
NULL);
if (ns != NULL)
xmlFree(ns);
xmlFree(URL);
delete = cur;
goto skip_children;
......
/*
* runsuite.c: C program to run libxml2 againts external published testsuites
*
* See Copyright for the status of this software.
*
* daniel@veillard.com
*/
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <glob.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/uri.h>
#include <libxml/xmlreader.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/relaxng.h>
#include <libxml/xmlschemas.h>
#include <libxml/xmlschemastypes.h>
/************************************************************************
* *
* File name and path utilities *
* *
************************************************************************/
static int checkTestFile(const char *filename) {
struct stat buf;
if (stat(filename, &buf) == -1)
return(0);
if (!S_ISREG(buf.st_mode))
return(0);
return(1);
}
/************************************************************************
* *
* Libxml2 specific routines *
* *
************************************************************************/
static int nb_tests = 0;
static int nb_errors = 0;
static int nb_leaks = 0;
static long libxmlMemoryAllocatedBase = 0;
static int extraMemoryFromResolver = 0;
static int
fatalError(void) {
fprintf(stderr, "Exitting tests on fatal error\n");
exit(1);
}
/*
* We need to trap calls to the resolver to not account memory for the catalog
* which is shared to the current running test. We also don't want to have
* network downloads modifying tests.
*/
static xmlParserInputPtr
testExternalEntityLoader(const char *URL, const char *ID,
xmlParserCtxtPtr ctxt) {
xmlParserInputPtr ret;
if (checkTestFile(URL)) {
ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
} else {
int memused = xmlMemUsed();
ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
extraMemoryFromResolver += xmlMemUsed() - memused;
}
return(ret);
}
/*
* Trapping the error messages at the generic level to grab the equivalent of
* stderr messages on CLI tools.
*/
static char testErrors[32769];
static int testErrorsSize = 0;
static void
testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
va_list args;
int res;
if (testErrorsSize >= 32768)
return;
va_start(args, msg);
res = vsnprintf(&testErrors[testErrorsSize],
32768 - testErrorsSize,
msg, args);
va_end(args);
if (testErrorsSize + res >= 32768) {
/* buffer is full */
testErrorsSize = 32768;
testErrors[testErrorsSize] = 0;
} else {
testErrorsSize += res;
}
testErrors[testErrorsSize] = 0;
}
static void
initializeLibxml2(void) {
xmlGetWarningsDefaultValue = 0;
xmlPedanticParserDefault(0);
xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
xmlInitParser();
xmlSetExternalEntityLoader(testExternalEntityLoader);
#ifdef LIBXML_SCHEMAS_ENABLED
xmlSchemaInitTypes();
xmlRelaxNGInitTypes();
#endif
libxmlMemoryAllocatedBase = xmlMemUsed();
}
static xmlNodePtr
getNext(xmlNodePtr cur, const char *xpath) {
xmlNodePtr ret = NULL;
xmlXPathObjectPtr res;
xmlXPathContextPtr ctxt;
xmlXPathCompExprPtr comp;
if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL))
return(NULL);
ctxt = xmlXPathNewContext(cur->doc);
ctxt->node = cur;
comp = xmlXPathCompile(BAD_CAST xpath);
if (comp == NULL) {
fprintf(stderr, "Failed to compile %s\n", xpath);
xmlXPathFreeContext(ctxt);
return(NULL);
}
res = xmlXPathCompiledEval(comp, ctxt);
xmlXPathFreeCompExpr(comp);
xmlXPathFreeContext(ctxt);
if (res == NULL)
return(NULL);
if ((res->type == XPATH_NODESET) &&
(res->nodesetval != NULL) &&
(res->nodesetval->nodeNr > 0) &&
(res->nodesetval->nodeTab != NULL))
ret = res->nodesetval->nodeTab[0];
xmlXPathFreeObject(res);
return(ret);
}
static xmlChar *
getString(xmlNodePtr cur, const char *xpath) {
xmlChar *ret = NULL;
xmlXPathObjectPtr res;
xmlXPathContextPtr ctxt;
xmlXPathCompExprPtr comp;
if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL))
return(NULL);
ctxt = xmlXPathNewContext(cur->doc);
ctxt->node = cur;
comp = xmlXPathCompile(BAD_CAST xpath);
if (comp == NULL) {
fprintf(stderr, "Failed to compile %s\n", xpath);
return(NULL);
}
res = xmlXPathCompiledEval(comp, ctxt);
xmlXPathFreeCompExpr(comp);
xmlXPathFreeContext(ctxt);
if (res == NULL)
return(NULL);
if (res->type == XPATH_STRING) {
ret = res->stringval;
res->stringval = NULL;
}
xmlXPathFreeObject(res);
return(ret);
}
/************************************************************************
* *
* Test test/xsdtest/xsdtestsuite.xml *
* *
************************************************************************/
static int
xsdIncorectTestCase(int verbose, xmlNodePtr cur) {
xmlNodePtr test;
xmlBufferPtr buf;
xmlRelaxNGParserCtxtPtr pctxt;
xmlRelaxNGPtr rng = NULL;
int ret = 0, memt;
cur = getNext(cur, "./incorrect[1]");
if (cur == NULL) {
return(0);
}
test = getNext(cur, "./*");
if (test == NULL) {
fprintf(stderr, "Failed to find test in correct line %ld\n",
xmlGetLineNo(cur));
return(1);
}
memt = xmlMemUsed();
extraMemoryFromResolver = 0;
/*
* dump the schemas to a buffer, then reparse it and compile the schemas
*/
buf = xmlBufferCreate();
if (buf == NULL) {
fprintf(stderr, "out of memory !\n");
fatalError();
}
xmlNodeDump(buf, test->doc, test, 0, 0);
pctxt = xmlRelaxNGNewMemParserCtxt((const char *)buf->content, buf->use);
xmlRelaxNGSetParserErrors(pctxt,
(xmlRelaxNGValidityErrorFunc) testErrorHandler,
(xmlRelaxNGValidityWarningFunc) testErrorHandler,
pctxt);
rng = xmlRelaxNGParse(pctxt);
xmlRelaxNGFreeParserCtxt(pctxt);
if (rng != NULL) {
fprintf(stderr, "Failed to detect incorect RNG line %ld\n",
xmlGetLineNo(test));
ret = 1;
goto done;
}
done:
if (buf != NULL)
xmlBufferFree(buf);
if (rng != NULL)
xmlRelaxNGFree(rng);
xmlResetLastError();
if ((memt != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
xmlGetLineNo(cur), xmlMemUsed() - memt);
nb_leaks++;
}
return(ret);
}
static int
xsdTestCase(int verbose, xmlNodePtr tst) {
xmlNodePtr test, tmp, cur;
xmlBufferPtr buf;
xmlDocPtr doc = NULL;
xmlRelaxNGParserCtxtPtr pctxt;
xmlRelaxNGValidCtxtPtr ctxt;
xmlRelaxNGPtr rng = NULL;
int ret = 0, mem, memt;
cur = getNext(tst, "./correct[1]");
if (cur == NULL) {
return(xsdIncorectTestCase(verbose, tst));
}
test = getNext(cur, "./*");
if (test == NULL) {
fprintf(stderr, "Failed to find test in correct line %ld\n",
xmlGetLineNo(cur));
return(1);
}
memt = xmlMemUsed();
extraMemoryFromResolver = 0;
/*
* dump the schemas to a buffer, then reparse it and compile the schemas
*/
buf = xmlBufferCreate();
if (buf == NULL) {
fprintf(stderr, "out of memory !\n");
fatalError();
}
xmlNodeDump(buf, test->doc, test, 0, 0);
pctxt = xmlRelaxNGNewMemParserCtxt((const char *)buf->content, buf->use);
xmlRelaxNGSetParserErrors(pctxt,
(xmlRelaxNGValidityErrorFunc) testErrorHandler,
(xmlRelaxNGValidityWarningFunc) testErrorHandler,
pctxt);
rng = xmlRelaxNGParse(pctxt);
xmlRelaxNGFreeParserCtxt(pctxt);
if (extraMemoryFromResolver)
memt = 0;
if (rng == NULL) {
fprintf(stderr, "Failed to parse RNGtest line %ld\n",
xmlGetLineNo(test));
nb_errors++;
ret = 1;
goto done;
}
/*
* now scan all the siblings of correct to process the <valid> tests
*/
tmp = getNext(cur, "following-sibling::valid[1]");
while (tmp != NULL) {
test = getNext(tmp, "./*");
if (test == NULL) {
fprintf(stderr, "Failed to find test in <valid> line %ld\n",
xmlGetLineNo(tmp));
} else {
xmlBufferEmpty(buf);
xmlNodeDump(buf, test->doc, test, 0, 0);
/*
* We are ready to run the test
*/
mem = xmlMemUsed();
extraMemoryFromResolver = 0;
doc = xmlReadMemory((const char *)buf->content, buf->use,
"test", NULL, 0);
if (doc == NULL) {
fprintf(stderr,
"Failed to parse valid instance line %ld\n",
xmlGetLineNo(tmp));
nb_errors++;
} else {
nb_tests++;
ctxt = xmlRelaxNGNewValidCtxt(rng);
xmlRelaxNGSetValidErrors(ctxt,
(xmlRelaxNGValidityErrorFunc) testErrorHandler,
(xmlRelaxNGValidityWarningFunc) testErrorHandler,
ctxt);
ret = xmlRelaxNGValidateDoc(ctxt, doc);
xmlRelaxNGFreeValidCtxt(ctxt);
if (ret > 0) {
fprintf(stderr,
"Failed to validate valid instance line %ld\n",
xmlGetLineNo(tmp));
nb_errors++;
} else if (ret < 0) {
fprintf(stderr,
"Internal error validating instance line %ld\n",
xmlGetLineNo(tmp));
nb_errors++;
}
xmlFreeDoc(doc);
}
xmlResetLastError();
if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
fprintf(stderr, "Validation of instance line %ld leaked %d\n",
xmlGetLineNo(tmp), xmlMemUsed() - mem);
xmlMemoryDump();
nb_leaks++;
}
}
tmp = getNext(tmp, "following-sibling::valid[1]");
}
/*
* now scan all the siblings of correct to process the <invalid> tests
*/
tmp = getNext(cur, "following-sibling::invalid[1]");
while (tmp != NULL) {
test = getNext(tmp, "./*");
if (test == NULL) {
fprintf(stderr, "Failed to find test in <invalid> line %ld\n",
xmlGetLineNo(tmp));
} else {
xmlBufferEmpty(buf);
xmlNodeDump(buf, test->doc, test, 0, 0);
/*
* We are ready to run the test
*/
mem = xmlMemUsed();
extraMemoryFromResolver = 0;
doc = xmlReadMemory((const char *)buf->content, buf->use,
"test", NULL, 0);
if (doc == NULL) {
fprintf(stderr,
"Failed to parse valid instance line %ld\n",
xmlGetLineNo(tmp));
nb_errors++;
} else {
nb_tests++;
ctxt = xmlRelaxNGNewValidCtxt(rng);
xmlRelaxNGSetValidErrors(ctxt,
(xmlRelaxNGValidityErrorFunc) testErrorHandler,
(xmlRelaxNGValidityWarningFunc) testErrorHandler,
ctxt);
ret = xmlRelaxNGValidateDoc(ctxt, doc);
xmlRelaxNGFreeValidCtxt(ctxt);
if (ret == 0) {
fprintf(stderr,
"Failed to detect invalid instance line %ld\n",
xmlGetLineNo(tmp));
nb_errors++;
} else if (ret < 0) {
fprintf(stderr,
"Internal error validating instance line %ld\n",
xmlGetLineNo(tmp));
nb_errors++;
}
xmlFreeDoc(doc);
}
xmlResetLastError();
if ((mem != xmlMemUsed()) && (extraMemoryFromResolver == 0)) {
fprintf(stderr, "Validation of instance line %ld leaked %d\n",
xmlGetLineNo(tmp), xmlMemUsed() - mem);
xmlMemoryDump();
nb_leaks++;
}
}
tmp = getNext(tmp, "following-sibling::invalid[1]");
}
done:
if (buf != NULL)
xmlBufferFree(buf);
if (rng != NULL)
xmlRelaxNGFree(rng);
xmlResetLastError();
if ((memt != xmlMemUsed()) && (memt != 0)) {
fprintf(stderr, "Validation of tests starting line %ld leaked %d\n",
xmlGetLineNo(cur), xmlMemUsed() - memt);
nb_leaks++;
}
return(ret);
}
static int
xsdTestSuite(int verbose, xmlNodePtr cur) {
if (verbose) {
xmlChar *doc = getString(cur, "string(documentation)");
if (doc != NULL) {
printf("Suite %s\n", doc);
xmlFree(doc);
}
}
cur = getNext(cur, "./testCase[1]");
while (cur != NULL) {
xsdTestCase(verbose, cur);
cur = getNext(cur, "following-sibling::testCase[1]");
}
return(0);
}
static int
xsdTest(int verbose) {
xmlDocPtr doc;
xmlNodePtr cur;
const char *filename = "test/xsdtest/xsdtestsuite.xml";
int ret = 0;
doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
if (doc == NULL) {
fprintf(stderr, "Failed to parse %s\n", filename);
return(-1);
}
printf("## XML Schemas datatypes test suite from James Clark\n");
cur = xmlDocGetRootElement(doc);
if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
fprintf(stderr, "Unexpected format %s\n", filename);
ret = -1;
goto done;
}
cur = getNext(cur, "./testSuite[1]");
if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
fprintf(stderr, "Unexpected format %s\n", filename);
ret = -1;
goto done;
}
while (cur != NULL) {
xsdTestSuite(verbose, cur);
cur = getNext(cur, "following-sibling::testSuite[1]");
}
done:
if (doc != NULL)
xmlFreeDoc(doc);
return(ret);
}
static int
rngTestSuite(int verbose, xmlNodePtr cur) {
if (verbose) {
xmlChar *doc = getString(cur, "string(documentation)");
if (doc != NULL) {
printf("Suite %s\n", doc);
xmlFree(doc);
} else {
doc = getString(cur, "string(section)");
if (doc != NULL) {
printf("Section %s\n", doc);
xmlFree(doc);
}
}
}
cur = getNext(cur, "./testSuite[1]");
while (cur != NULL) {
xsdTestSuite(verbose, cur);
cur = getNext(cur, "following-sibling::testSuite[1]");
}
return(0);
}
static int
rngTest1(int verbose) {
xmlDocPtr doc;
xmlNodePtr cur;
const char *filename = "test/relaxng/OASIS/spectest.xml";
int ret = 0;
doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
if (doc == NULL) {
fprintf(stderr, "Failed to parse %s\n", filename);
return(-1);
}
printf("## Relax NG test suite 1 from James Clark\n");
cur = xmlDocGetRootElement(doc);
if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
fprintf(stderr, "Unexpected format %s\n", filename);
ret = -1;
goto done;
}
cur = getNext(cur, "./testSuite[1]");
if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "testSuite"))) {
fprintf(stderr, "Unexpected format %s\n", filename);
ret = -1;
goto done;
}
while (cur != NULL) {
rngTestSuite(verbose, cur);
cur = getNext(cur, "following-sibling::testSuite[1]");