libxml2 r3757 - trunk



Author: veillard
Date: Tue Jul 29 16:12:31 2008
New Revision: 3757
URL: http://svn.gnome.org/viewvc/libxml2?rev=3757&view=rev

Log:
* runxmlconf.c Makefile.am: add a C program to run the W3C test
  suite, work in progress
* xmllint.c: add a new option --oldxml10 to use the old parser
* parser.c: fix the XML_PARSE_OLD10 processing of the new option
  and a bug in version parsing
Daniel


Added:
   trunk/runxmlconf.c
Modified:
   trunk/ChangeLog
   trunk/Makefile.am
   trunk/parser.c
   trunk/xmllint.c

Modified: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am	(original)
+++ trunk/Makefile.am	Tue Jul 29 16:12:31 2008
@@ -8,7 +8,8 @@
 
 noinst_PROGRAMS=testSchemas testRelax testSAX testHTML testXPath testURI \
                 testThreads testC14N testAutomata testRegexp \
-                testReader testapi testModule runtest runsuite testchar
+                testReader testapi testModule runtest runsuite testchar \
+		runxmlconf
 
 bin_PROGRAMS = xmllint xmlcatalog
 
@@ -155,6 +156,11 @@
 testapi_DEPENDENCIES = $(DEPS)
 testapi_LDADD= $(LDADDS)
 
+runxmlconf_SOURCES=runxmlconf.c
+runxmlconf_LDFLAGS = 
+runxmlconf_DEPENDENCIES = $(DEPS)
+runxmlconf_LDADD= $(LDADDS)
+
 #testOOM_SOURCES=testOOM.c testOOMlib.h testOOMlib.c
 #testOOM_LDFLAGS = 
 #testOOM_DEPENDENCIES = $(DEPS)

Modified: trunk/parser.c
==============================================================================
--- trunk/parser.c	(original)
+++ trunk/parser.c	Tue Jul 29 16:12:31 2008
@@ -9168,14 +9168,14 @@
     }
     cur = CUR;
     if (!((cur >= '0') && (cur <= '9'))) {
-	free(buf);
+	xmlFree(buf);
 	return(NULL);
     }
     buf[len++] = cur;
     NEXT;
     cur=CUR;
     if (cur != '.') {
-	free(buf);
+	xmlFree(buf);
 	return(NULL);
     }
     buf[len++] = cur;
@@ -13753,6 +13753,10 @@
 	ctxt->options |= XML_PARSE_COMPACT;
         options -= XML_PARSE_COMPACT;
     }
+    if (options & XML_PARSE_OLD10) {
+	ctxt->options |= XML_PARSE_OLD10;
+        options -= XML_PARSE_OLD10;
+    }
     ctxt->linenumbers = 1;
     return (options);
 }

Added: trunk/runxmlconf.c
==============================================================================
--- (empty file)
+++ trunk/runxmlconf.c	Tue Jul 29 16:12:31 2008
@@ -0,0 +1,549 @@
+/*
+ * runsuite.c: C program to run libxml2 againts published testsuites
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel veillard com
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "libxml.h"
+#else
+#include <stdio.h>
+#endif
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/tree.h>
+#include <libxml/uri.h>
+#include <libxml/xmlreader.h>
+
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#define LOGFILE "runsuite.log"
+static FILE *logfile = NULL;
+static int verbose = 0;
+
+
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+
+#define vsnprintf _vsnprintf
+
+#define snprintf _snprintf
+
+#endif
+
+/************************************************************************
+ *									*
+ *		File name and path utilities				*
+ *									*
+ ************************************************************************/
+
+static int checkTestFile(const char *filename) {
+    struct stat buf;
+
+    if (stat(filename, &buf) == -1)
+        return(0);
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+    if (!(buf.st_mode & _S_IFREG))
+        return(0);
+#else
+    if (!S_ISREG(buf.st_mode))
+        return(0);
+#endif
+
+    return(1);
+}
+
+static xmlChar *composeDir(const xmlChar *dir, const xmlChar *path) {
+    char buf[500];
+
+    if (dir == NULL) return(xmlStrdup(path));
+    if (path == NULL) return(NULL);
+
+    snprintf(buf, 500, "%s/%s", (const char *) dir, (const char *) path);
+    return(xmlStrdup((const xmlChar *) buf));
+}
+
+/************************************************************************
+ *									*
+ *		Libxml2 specific routines				*
+ *									*
+ ************************************************************************/
+
+static int nb_skipped = 0;
+static int nb_tests = 0;
+static int nb_errors = 0;
+static int nb_leaks = 0;
+static int extraMemoryFromResolver = 0;
+
+static int
+fatalError(void) {
+    fprintf(stderr, "Exitting tests on fatal error\n");
+    exit(1);
+}
+
+/*
+ * that's needed to implement <resource>
+ */
+#define MAX_ENTITIES 20
+static char *testEntitiesName[MAX_ENTITIES];
+static char *testEntitiesValue[MAX_ENTITIES];
+static int nb_entities = 0;
+static void resetEntities(void) {
+    int i;
+
+    for (i = 0;i < nb_entities;i++) {
+        if (testEntitiesName[i] != NULL)
+	    xmlFree(testEntitiesName[i]);
+        if (testEntitiesValue[i] != NULL)
+	    xmlFree(testEntitiesValue[i]);
+    }
+    nb_entities = 0;
+}
+static int addEntity(char *name, char *content) {
+    if (nb_entities >= MAX_ENTITIES) {
+	fprintf(stderr, "Too many entities defined\n");
+	return(-1);
+    }
+    testEntitiesName[nb_entities] = name;
+    testEntitiesValue[nb_entities] = content;
+    nb_entities++;
+    return(0);
+}
+
+/*
+ * 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;
+    int i;
+
+    for (i = 0;i < nb_entities;i++) {
+        if (!strcmp(testEntitiesName[i], URL)) {
+	    ret = xmlNewStringInputStream(ctxt,
+	                (const xmlChar *) testEntitiesValue[i]);
+	    if (ret != NULL) {
+	        ret->filename = (const char *)
+		                xmlStrdup((xmlChar *)testEntitiesName[i]);
+	    }
+	    return(ret);
+	}
+    }
+    if (checkTestFile(URL)) {
+	ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
+    } else {
+	int memused = xmlMemUsed();
+	ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
+	extraMemoryFromResolver += xmlMemUsed() - memused;
+    }
+#if 0
+    if (ret == NULL) {
+        fprintf(stderr, "Failed to find resource %s\n", URL);
+    }
+#endif
+
+    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 test_log(const char *msg, ...) {
+    va_list args;
+    if (logfile != NULL) {
+        fprintf(logfile, "\n------------\n");
+	va_start(args, msg);
+	vfprintf(logfile, msg, args);
+	va_end(args);
+	fprintf(logfile, "%s", testErrors);
+	testErrorsSize = 0; testErrors[0] = 0;
+    }
+    if (verbose) {
+	va_start(args, msg);
+	vfprintf(stderr, msg, args);
+	va_end(args);
+    }
+}
+
+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 xmlXPathContextPtr ctxtXPath;
+
+static void
+initializeLibxml2(void) {
+    xmlGetWarningsDefaultValue = 0;
+    xmlPedanticParserDefault(0);
+
+    xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
+    xmlInitParser();
+    xmlSetExternalEntityLoader(testExternalEntityLoader);
+    ctxtXPath = xmlXPathNewContext(NULL);
+    /*
+    * Deactivate the cache if created; otherwise we have to create/free it
+    * for every test, since it will confuse the memory leak detection.
+    * Note that normally this need not be done, since the cache is not
+    * created until set explicitely with xmlXPathContextSetCache();
+    * but for test purposes it is sometimes usefull to activate the
+    * cache by default for the whole library.
+    */
+    if (ctxtXPath->cache != NULL)
+	xmlXPathContextSetCache(ctxtXPath, 0, -1, 0);
+    xmlSetGenericErrorFunc(NULL, testErrorHandler);
+}
+
+/************************************************************************
+ *									*
+ *		Run the xmlconf test if found				*
+ *									*
+ ************************************************************************/
+
+static int
+xmlconfTestNotNSWF(const char *id, const char *filename, int options) {
+    xmlDocPtr doc;
+    int ret = 1;
+
+    /*
+     * In case of Namespace errors, libxml2 will still parse the document
+     * but log a Namesapce error.
+     */
+    doc = xmlReadFile(filename, NULL, options);
+    if (doc == NULL) {
+        test_log("test %s : %s failed to parse the XML\n",
+	         id, filename);
+        nb_errors++;
+	ret = 0;
+    } else {
+	if ((xmlLastError.code == XML_ERR_OK) ||
+	    (xmlLastError.domain != XML_FROM_NAMESPACE)) {
+	    test_log("test %s : %s failed to detect namespace error\n",
+		     id, filename);
+	    nb_errors++;
+	    ret = 0;
+	}
+	xmlFreeDoc(doc);
+    }
+    return(ret);
+}
+
+static int
+xmlconfTestNotWF(const char *id, const char *filename, int options) {
+    xmlDocPtr doc;
+    int ret = 1;
+
+    doc = xmlReadFile(filename, NULL, options);
+    if (doc != NULL) {
+        test_log("test %s : %s failed to detect not well formedness\n",
+	         id, filename);
+        nb_errors++;
+	xmlFreeDoc(doc);
+	ret = 0;
+    }
+    return(ret);
+}
+
+static int
+xmlconfTestItem(xmlDocPtr doc, xmlNodePtr cur) {
+    int ret = -1;
+    xmlChar *type = NULL;
+    xmlChar *filename = NULL;
+    xmlChar *uri = NULL;
+    xmlChar *base = NULL;
+    xmlChar *id = NULL;
+    xmlChar *rec = NULL;
+    xmlChar *entities = NULL;
+    xmlChar *edition = NULL;
+    int options = 0;
+    int nstest = 0;
+    int mem, final;
+
+    id = xmlGetProp(cur, BAD_CAST "ID");
+    if (id == NULL) {
+        test_log("test missing ID, line %ld\n", xmlGetLineNo(cur));
+	goto error;
+    }
+    type = xmlGetProp(cur, BAD_CAST "TYPE");
+    if (type == NULL) {
+        test_log("test %s missing TYPE\n", (char *) id);
+	goto error;
+    }
+    uri = xmlGetProp(cur, BAD_CAST "URI");
+    if (uri == NULL) {
+        test_log("test %s missing URI\n", (char *) id);
+	goto error;
+    }
+    base = xmlNodeGetBase(doc, cur);
+    filename = composeDir(base, uri);
+    if (!checkTestFile((char *) filename)) {
+        test_log("test %s missing file %s \n", id,
+	         (filename ? (char *)filename : "NULL"));
+	goto error;
+    }
+
+    entities = xmlGetProp(cur, BAD_CAST "ENTITIES");
+    if (!xmlStrEqual(entities, BAD_CAST "none")) {
+        options |= XML_PARSE_DTDLOAD;
+    }
+    rec = xmlGetProp(cur, BAD_CAST "RECOMMENDATION");
+    if ((rec == NULL) ||
+        (xmlStrEqual(rec, BAD_CAST "XML1.0")) ||
+	(xmlStrEqual(rec, BAD_CAST "XML1.0-errata2e")) ||
+	(xmlStrEqual(rec, BAD_CAST "XML1.0-errata3e")) ||
+	(xmlStrEqual(rec, BAD_CAST "XML1.0-errata4e"))) {
+	ret = 1;
+    } else if ((xmlStrEqual(rec, BAD_CAST "NS1.0")) ||
+	       (xmlStrEqual(rec, BAD_CAST "NS1.0-errata1e"))) {
+	ret = 1;
+	nstest = 1;
+    } else {
+        test_log("Skipping test %s for REC %s\n", (char *) id, (char *) rec);
+	ret = 0;
+	nb_skipped++;
+	goto error;
+    }
+    edition = xmlGetProp(cur, BAD_CAST "EDITION");
+    if ((edition != NULL) && (xmlStrchr(edition, '5') == NULL)) {
+        /* test limited to all versions before 5th */
+	options |= XML_PARSE_OLD10;
+    }
+
+    /*
+     * Reset errors and check memory usage before the test
+     */
+    xmlResetLastError();
+    testErrorsSize = 0; testErrors[0] = 0;
+    mem = xmlMemUsed();
+
+    if (xmlStrEqual(type, BAD_CAST "not-wf")) {
+        if (nstest == 0)
+	    xmlconfTestNotWF((char *) id, (char *) filename, options);
+        else 
+	    xmlconfTestNotNSWF((char *) id, (char *) filename, options);
+    } else if (xmlStrEqual(type, BAD_CAST "valid")) {
+    } else if (xmlStrEqual(type, BAD_CAST "invalid")) {
+    } else if (xmlStrEqual(type, BAD_CAST "error")) {
+    } else {
+        test_log("test %s unknown TYPE value %s\n", (char *) id, (char *)type);
+	ret = -1;
+	goto error;
+    }
+
+    /*
+     * Reset errors and check memory usage after the test
+     */
+    xmlResetLastError();
+    final = xmlMemUsed();
+    if (final > mem) {
+        test_log("test %s : %s leaked %d bytes\n",
+	         id, filename, final - mem);
+        nb_leaks++;
+    }
+    nb_tests++;
+
+error:
+    if (type != NULL)
+        xmlFree(type);
+    if (entities != NULL)
+        xmlFree(entities);
+    if (edition != NULL)
+        xmlFree(edition);
+    if (filename != NULL)
+        xmlFree(filename);
+    if (uri != NULL)
+        xmlFree(uri);
+    if (base != NULL)
+        xmlFree(base);
+    if (id != NULL)
+        xmlFree(id);
+    if (rec != NULL)
+        xmlFree(rec);
+    return(ret);
+}
+
+static int
+xmlconfTestCases(xmlDocPtr doc, xmlNodePtr cur) {
+    xmlChar *profile;
+    int ret = 0;
+    int tests = 0;
+
+    profile = xmlGetProp(cur, BAD_CAST "PROFILE");
+    if (profile != NULL) {
+        printf("Test cases: %s\n", (char *) profile);
+	xmlFree(profile);
+    }
+    cur = cur->children;
+    while (cur != NULL) {
+        /* look only at elements we ignore everything else */
+        if (cur->type == XML_ELEMENT_NODE) {
+	    if (xmlStrEqual(cur->name, BAD_CAST "TESTCASES")) {
+	        ret += xmlconfTestCases(doc, cur);
+	    } else if (xmlStrEqual(cur->name, BAD_CAST "TEST")) {
+	        if (xmlconfTestItem(doc, cur) >= 0)
+		    ret++;
+		tests++;
+	    } else {
+	        fprintf(stderr, "Unhandled element %s\n", (char *)cur->name);
+	    }
+	}
+        cur = cur->next;
+    }
+    if (tests > 0)
+	printf("Test cases: %d tests\n", tests);
+    return(ret);
+}
+
+static int
+xmlconfTestSuite(xmlDocPtr doc, xmlNodePtr cur) {
+    xmlChar *profile;
+    int ret = 0;
+
+    profile = xmlGetProp(cur, BAD_CAST "PROFILE");
+    if (profile != NULL) {
+        printf("Test suite: %s\n", (char *) profile);
+	xmlFree(profile);
+    } else
+        printf("Test suite\n");
+    cur = cur->children;
+    while (cur != NULL) {
+        /* look only at elements we ignore everything else */
+        if (cur->type == XML_ELEMENT_NODE) {
+	    if (xmlStrEqual(cur->name, BAD_CAST "TESTCASES")) {
+	        ret += xmlconfTestCases(doc, cur);
+	    } else {
+	        fprintf(stderr, "Unhandled element %s\n", (char *)cur->name);
+	    }
+	}
+        cur = cur->next;
+    }
+    return(ret);
+}
+
+static void
+xmlconfInfo(void) {
+    fprintf(stderr, "  you need to fetch and extract the\n");
+    fprintf(stderr, "  latest XML Conformance Test Suites\n");
+    fprintf(stderr, "  http://www.w3.org/XML/Test/xmlts20080205.tar.gz\n";);
+    fprintf(stderr, "  see http://www.w3.org/XML/Test/ for informations\n");
+}
+
+static int
+xmlconfTest(void) {
+    const char *confxml = "xmlconf/xmlconf.xml";
+    xmlDocPtr doc;
+    xmlNodePtr cur;
+    int ret = 0;
+
+    if (!checkTestFile(confxml)) {
+        fprintf(stderr, "%s is missing \n", confxml);
+	xmlconfInfo();
+	return(-1);
+    }
+    doc = xmlReadFile(confxml, NULL, XML_PARSE_NOENT);
+    if (doc == NULL) {
+        fprintf(stderr, "%s is corrupted \n", confxml);
+	xmlconfInfo();
+	return(-1);
+    }
+
+    cur = xmlDocGetRootElement(doc);
+    if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "TESTSUITE"))) {
+        fprintf(stderr, "Unexpected format %s\n", confxml);
+	xmlconfInfo();
+	ret = -1;
+    } else {
+        ret = xmlconfTestSuite(doc, cur);
+    }
+    xmlFreeDoc(doc);
+    return(ret);
+}
+
+/************************************************************************
+ *									*
+ *		The driver for the tests				*
+ *									*
+ ************************************************************************/
+
+int
+main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
+    int ret = 0;
+    int old_errors, old_tests, old_leaks;
+
+    logfile = fopen(LOGFILE, "w");
+    if (logfile == NULL) {
+        fprintf(stderr,
+	        "Could not open the log file, running in verbose mode\n");
+	verbose = 1;
+    }
+    initializeLibxml2();
+
+    if ((argc >= 2) && (!strcmp(argv[1], "-v")))
+        verbose = 1;
+
+
+    old_errors = nb_errors;
+    old_tests = nb_tests;
+    old_leaks = nb_leaks;
+    xmlconfTest();
+    if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
+	printf("Ran %d tests, no errors\n", nb_tests - old_tests);
+    else
+	printf("Ran %d tests, %d errors, %d leaks\n",
+	       nb_tests - old_tests,
+	       nb_errors - old_errors,
+	       nb_leaks - old_leaks);
+    if ((nb_errors == 0) && (nb_leaks == 0)) {
+        ret = 0;
+	printf("Total %d tests, no errors\n",
+	       nb_tests);
+    } else {
+        ret = 1;
+	printf("Total %d tests, %d errors, %d leaks\n",
+	       nb_tests, nb_errors, nb_leaks);
+    }
+    xmlXPathFreeContext(ctxtXPath);
+    xmlCleanupParser();
+    xmlMemoryDump();
+
+    if (logfile != NULL)
+        fclose(logfile);
+    return(ret);
+}

Modified: trunk/xmllint.c
==============================================================================
--- trunk/xmllint.c	(original)
+++ trunk/xmllint.c	Tue Jul 29 16:12:31 2008
@@ -202,6 +202,7 @@
 #endif
 static int options = XML_PARSE_COMPACT;
 static int sax = 0;
+static int oldxml10 = 0;
 
 /************************************************************************
  *									*
@@ -2912,6 +2913,7 @@
     printf("\t--sax1: use the old SAX1 interfaces for processing\n");
 #endif
     printf("\t--sax: do not build a tree but work just at the SAX level\n");
+    printf("\t--oldxml10: use XML-1.0 parsing rules before the 5th edition\n");
 
     printf("\nLibxml project home page: http://xmlsoft.org/\n";);
     printf("To report bugs or get some help check: http://xmlsoft.org/bugs.html\n";);
@@ -3237,6 +3239,10 @@
 	    i++;
 	    pattern = argv[i];
 #endif
+	} else if ((!strcmp(argv[i], "-oldxml10")) ||
+	           (!strcmp(argv[i], "--oldxml10"))) {
+	    oldxml10++;
+	    options |= XML_PARSE_OLD10;
 	} else {
 	    fprintf(stderr, "Unknown option %s\n", argv[i]);
 	    usage(argv[0]);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]