ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

runxmlconf.c
Go to the documentation of this file.
00001 /*
00002  * runsuite.c: C program to run libxml2 againts published testsuites
00003  *
00004  * See Copyright for the status of this software.
00005  *
00006  * daniel@veillard.com
00007  */
00008 
00009 #ifdef HAVE_CONFIG_H
00010 #include "libxml.h"
00011 #else
00012 #include <stdio.h>
00013 #endif
00014 
00015 #ifdef LIBXML_XPATH_ENABLED
00016 
00017 #if !defined(_WIN32) || defined(__CYGWIN__)
00018 #include <unistd.h>
00019 #endif
00020 #include <string.h>
00021 #include <sys/types.h>
00022 #include <sys/stat.h>
00023 #include <fcntl.h>
00024 
00025 #include <libxml/parser.h>
00026 #include <libxml/parserInternals.h>
00027 #include <libxml/tree.h>
00028 #include <libxml/uri.h>
00029 #include <libxml/xmlreader.h>
00030 
00031 #include <libxml/xpath.h>
00032 #include <libxml/xpathInternals.h>
00033 
00034 #define LOGFILE "runxmlconf.log"
00035 static FILE *logfile = NULL;
00036 static int verbose = 0;
00037 
00038 #define NB_EXPECTED_ERRORS 15
00039 
00040 #if defined(_WIN32) && !defined(__CYGWIN__)
00041 
00042 #define vsnprintf _vsnprintf
00043 
00044 #define snprintf _snprintf
00045 
00046 #endif
00047 
00048 const char *skipped_tests[] = {
00049 /* http://lists.w3.org/Archives/Public/public-xml-testsuite/2008Jul/0000.html */
00050     "rmt-ns10-035",
00051     NULL
00052 };
00053 
00054 /************************************************************************
00055  *                                  *
00056  *      File name and path utilities                *
00057  *                                  *
00058  ************************************************************************/
00059 
00060 static int checkTestFile(const char *filename) {
00061     struct stat buf;
00062 
00063     if (stat(filename, &buf) == -1)
00064         return(0);
00065 
00066 #if defined(_WIN32) && !defined(__CYGWIN__)
00067     if (!(buf.st_mode & _S_IFREG))
00068         return(0);
00069 #else
00070     if (!S_ISREG(buf.st_mode))
00071         return(0);
00072 #endif
00073 
00074     return(1);
00075 }
00076 
00077 static xmlChar *composeDir(const xmlChar *dir, const xmlChar *path) {
00078     char buf[500];
00079 
00080     if (dir == NULL) return(xmlStrdup(path));
00081     if (path == NULL) return(NULL);
00082 
00083     snprintf(buf, 500, "%s/%s", (const char *) dir, (const char *) path);
00084     return(xmlStrdup((const xmlChar *) buf));
00085 }
00086 
00087 /************************************************************************
00088  *                                  *
00089  *      Libxml2 specific routines               *
00090  *                                  *
00091  ************************************************************************/
00092 
00093 static int nb_skipped = 0;
00094 static int nb_tests = 0;
00095 static int nb_errors = 0;
00096 static int nb_leaks = 0;
00097 
00098 /*
00099  * We need to trap calls to the resolver to not account memory for the catalog
00100  * and not rely on any external resources.
00101  */
00102 static xmlParserInputPtr
00103 testExternalEntityLoader(const char *URL, const char *ID ATTRIBUTE_UNUSED,
00104              xmlParserCtxtPtr ctxt) {
00105     xmlParserInputPtr ret;
00106 
00107     ret = xmlNewInputFromFile(ctxt, (const char *) URL);
00108 
00109     return(ret);
00110 }
00111 
00112 /*
00113  * Trapping the error messages at the generic level to grab the equivalent of
00114  * stderr messages on CLI tools.
00115  */
00116 static char testErrors[32769];
00117 static int testErrorsSize = 0;
00118 static int nbError = 0;
00119 static int nbFatal = 0;
00120 
00121 static void test_log(const char *msg, ...) {
00122     va_list args;
00123     if (logfile != NULL) {
00124         fprintf(logfile, "\n------------\n");
00125     va_start(args, msg);
00126     vfprintf(logfile, msg, args);
00127     va_end(args);
00128     fprintf(logfile, "%s", testErrors);
00129     testErrorsSize = 0; testErrors[0] = 0;
00130     }
00131     if (verbose) {
00132     va_start(args, msg);
00133     vfprintf(stderr, msg, args);
00134     va_end(args);
00135     }
00136 }
00137 
00138 static void
00139 testErrorHandler(void *userData ATTRIBUTE_UNUSED, xmlErrorPtr error) {
00140     int res;
00141 
00142     if (testErrorsSize >= 32768)
00143         return;
00144     res = snprintf(&testErrors[testErrorsSize],
00145                     32768 - testErrorsSize,
00146            "%s:%d: %s\n", (error->file ? error->file : "entity"),
00147            error->line, error->message);
00148     if (error->level == XML_ERR_FATAL)
00149         nbFatal++;
00150     else if (error->level == XML_ERR_ERROR)
00151         nbError++;
00152     if (testErrorsSize + res >= 32768) {
00153         /* buffer is full */
00154     testErrorsSize = 32768;
00155     testErrors[testErrorsSize] = 0;
00156     } else {
00157         testErrorsSize += res;
00158     }
00159     testErrors[testErrorsSize] = 0;
00160 }
00161 
00162 static xmlXPathContextPtr ctxtXPath;
00163 
00164 static void
00165 initializeLibxml2(void) {
00166     xmlGetWarningsDefaultValue = 0;
00167     xmlPedanticParserDefault(0);
00168 
00169     xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
00170     xmlInitParser();
00171     xmlSetExternalEntityLoader(testExternalEntityLoader);
00172     ctxtXPath = xmlXPathNewContext(NULL);
00173     /*
00174     * Deactivate the cache if created; otherwise we have to create/free it
00175     * for every test, since it will confuse the memory leak detection.
00176     * Note that normally this need not be done, since the cache is not
00177     * created until set explicitely with xmlXPathContextSetCache();
00178     * but for test purposes it is sometimes usefull to activate the
00179     * cache by default for the whole library.
00180     */
00181     if (ctxtXPath->cache != NULL)
00182     xmlXPathContextSetCache(ctxtXPath, 0, -1, 0);
00183     xmlSetStructuredErrorFunc(NULL, testErrorHandler);
00184 }
00185 
00186 /************************************************************************
00187  *                                  *
00188  *      Run the xmlconf test if found               *
00189  *                                  *
00190  ************************************************************************/
00191 
00192 static int
00193 xmlconfTestInvalid(const char *id, const char *filename, int options) {
00194     xmlDocPtr doc;
00195     xmlParserCtxtPtr ctxt;
00196     int ret = 1;
00197 
00198     ctxt = xmlNewParserCtxt();
00199     if (ctxt == NULL) {
00200         test_log("test %s : %s out of memory\n",
00201              id, filename);
00202         return(0);
00203     }
00204     doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
00205     if (doc == NULL) {
00206         test_log("test %s : %s invalid document turned not well-formed too\n",
00207              id, filename);
00208     } else {
00209     /* invalidity should be reported both in the context and in the document */
00210         if ((ctxt->valid != 0) || (doc->properties & XML_DOC_DTDVALID)) {
00211         test_log("test %s : %s failed to detect invalid document\n",
00212              id, filename);
00213         nb_errors++;
00214         ret = 0;
00215     }
00216     xmlFreeDoc(doc);
00217     }
00218     xmlFreeParserCtxt(ctxt);
00219     return(ret);
00220 }
00221 
00222 static int
00223 xmlconfTestValid(const char *id, const char *filename, int options) {
00224     xmlDocPtr doc;
00225     xmlParserCtxtPtr ctxt;
00226     int ret = 1;
00227 
00228     ctxt = xmlNewParserCtxt();
00229     if (ctxt == NULL) {
00230         test_log("test %s : %s out of memory\n",
00231              id, filename);
00232         return(0);
00233     }
00234     doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
00235     if (doc == NULL) {
00236         test_log("test %s : %s failed to parse a valid document\n",
00237              id, filename);
00238         nb_errors++;
00239     ret = 0;
00240     } else {
00241     /* validity should be reported both in the context and in the document */
00242         if ((ctxt->valid == 0) || ((doc->properties & XML_DOC_DTDVALID) == 0)) {
00243         test_log("test %s : %s failed to validate a valid document\n",
00244              id, filename);
00245         nb_errors++;
00246         ret = 0;
00247     }
00248     xmlFreeDoc(doc);
00249     }
00250     xmlFreeParserCtxt(ctxt);
00251     return(ret);
00252 }
00253 
00254 static int
00255 xmlconfTestNotNSWF(const char *id, const char *filename, int options) {
00256     xmlDocPtr doc;
00257     int ret = 1;
00258 
00259     /*
00260      * In case of Namespace errors, libxml2 will still parse the document
00261      * but log a Namesapce error.
00262      */
00263     doc = xmlReadFile(filename, NULL, options);
00264     if (doc == NULL) {
00265         test_log("test %s : %s failed to parse the XML\n",
00266              id, filename);
00267         nb_errors++;
00268     ret = 0;
00269     } else {
00270     if ((xmlLastError.code == XML_ERR_OK) ||
00271         (xmlLastError.domain != XML_FROM_NAMESPACE)) {
00272         test_log("test %s : %s failed to detect namespace error\n",
00273              id, filename);
00274         nb_errors++;
00275         ret = 0;
00276     }
00277     xmlFreeDoc(doc);
00278     }
00279     return(ret);
00280 }
00281 
00282 static int
00283 xmlconfTestNotWF(const char *id, const char *filename, int options) {
00284     xmlDocPtr doc;
00285     int ret = 1;
00286 
00287     doc = xmlReadFile(filename, NULL, options);
00288     if (doc != NULL) {
00289         test_log("test %s : %s failed to detect not well formedness\n",
00290              id, filename);
00291         nb_errors++;
00292     xmlFreeDoc(doc);
00293     ret = 0;
00294     }
00295     return(ret);
00296 }
00297 
00298 static int
00299 xmlconfTestItem(xmlDocPtr doc, xmlNodePtr cur) {
00300     int ret = -1;
00301     xmlChar *type = NULL;
00302     xmlChar *filename = NULL;
00303     xmlChar *uri = NULL;
00304     xmlChar *base = NULL;
00305     xmlChar *id = NULL;
00306     xmlChar *rec = NULL;
00307     xmlChar *version = NULL;
00308     xmlChar *entities = NULL;
00309     xmlChar *edition = NULL;
00310     int options = 0;
00311     int nstest = 0;
00312     int mem, final;
00313     int i;
00314 
00315     testErrorsSize = 0; testErrors[0] = 0;
00316     nbError = 0;
00317     nbFatal = 0;
00318     id = xmlGetProp(cur, BAD_CAST "ID");
00319     if (id == NULL) {
00320         test_log("test missing ID, line %ld\n", xmlGetLineNo(cur));
00321     goto error;
00322     }
00323     for (i = 0;skipped_tests[i] != NULL;i++) {
00324         if (!strcmp(skipped_tests[i], (char *) id)) {
00325         test_log("Skipping test %s from skipped list\n", (char *) id);
00326         ret = 0;
00327         nb_skipped++;
00328         goto error;
00329     }
00330     }
00331     type = xmlGetProp(cur, BAD_CAST "TYPE");
00332     if (type == NULL) {
00333         test_log("test %s missing TYPE\n", (char *) id);
00334     goto error;
00335     }
00336     uri = xmlGetProp(cur, BAD_CAST "URI");
00337     if (uri == NULL) {
00338         test_log("test %s missing URI\n", (char *) id);
00339     goto error;
00340     }
00341     base = xmlNodeGetBase(doc, cur);
00342     filename = composeDir(base, uri);
00343     if (!checkTestFile((char *) filename)) {
00344         test_log("test %s missing file %s \n", id,
00345              (filename ? (char *)filename : "NULL"));
00346     goto error;
00347     }
00348 
00349     version = xmlGetProp(cur, BAD_CAST "VERSION");
00350 
00351     entities = xmlGetProp(cur, BAD_CAST "ENTITIES");
00352     if (!xmlStrEqual(entities, BAD_CAST "none")) {
00353         options |= XML_PARSE_DTDLOAD;
00354         options |= XML_PARSE_NOENT;
00355     }
00356     rec = xmlGetProp(cur, BAD_CAST "RECOMMENDATION");
00357     if ((rec == NULL) ||
00358         (xmlStrEqual(rec, BAD_CAST "XML1.0")) ||
00359     (xmlStrEqual(rec, BAD_CAST "XML1.0-errata2e")) ||
00360     (xmlStrEqual(rec, BAD_CAST "XML1.0-errata3e")) ||
00361     (xmlStrEqual(rec, BAD_CAST "XML1.0-errata4e"))) {
00362     if ((version != NULL) && (!xmlStrEqual(version, BAD_CAST "1.0"))) {
00363         test_log("Skipping test %s for %s\n", (char *) id,
00364                  (char *) version);
00365         ret = 0;
00366         nb_skipped++;
00367         goto error;
00368     }
00369     ret = 1;
00370     } else if ((xmlStrEqual(rec, BAD_CAST "NS1.0")) ||
00371            (xmlStrEqual(rec, BAD_CAST "NS1.0-errata1e"))) {
00372     ret = 1;
00373     nstest = 1;
00374     } else {
00375         test_log("Skipping test %s for REC %s\n", (char *) id, (char *) rec);
00376     ret = 0;
00377     nb_skipped++;
00378     goto error;
00379     }
00380     edition = xmlGetProp(cur, BAD_CAST "EDITION");
00381     if ((edition != NULL) && (xmlStrchr(edition, '5') == NULL)) {
00382         /* test limited to all versions before 5th */
00383     options |= XML_PARSE_OLD10;
00384     }
00385 
00386     /*
00387      * Reset errors and check memory usage before the test
00388      */
00389     xmlResetLastError();
00390     testErrorsSize = 0; testErrors[0] = 0;
00391     mem = xmlMemUsed();
00392 
00393     if (xmlStrEqual(type, BAD_CAST "not-wf")) {
00394         if (nstest == 0)
00395         xmlconfTestNotWF((char *) id, (char *) filename, options);
00396         else 
00397         xmlconfTestNotNSWF((char *) id, (char *) filename, options);
00398     } else if (xmlStrEqual(type, BAD_CAST "valid")) {
00399         options |= XML_PARSE_DTDVALID;
00400     xmlconfTestValid((char *) id, (char *) filename, options);
00401     } else if (xmlStrEqual(type, BAD_CAST "invalid")) {
00402         options |= XML_PARSE_DTDVALID;
00403     xmlconfTestInvalid((char *) id, (char *) filename, options);
00404     } else if (xmlStrEqual(type, BAD_CAST "error")) {
00405         test_log("Skipping error test %s \n", (char *) id);
00406     ret = 0;
00407     nb_skipped++;
00408     goto error;
00409     } else {
00410         test_log("test %s unknown TYPE value %s\n", (char *) id, (char *)type);
00411     ret = -1;
00412     goto error;
00413     }
00414 
00415     /*
00416      * Reset errors and check memory usage after the test
00417      */
00418     xmlResetLastError();
00419     final = xmlMemUsed();
00420     if (final > mem) {
00421         test_log("test %s : %s leaked %d bytes\n",
00422              id, filename, final - mem);
00423         nb_leaks++;
00424     xmlMemDisplayLast(logfile, final - mem);
00425     }
00426     nb_tests++;
00427 
00428 error:
00429     if (type != NULL)
00430         xmlFree(type);
00431     if (entities != NULL)
00432         xmlFree(entities);
00433     if (edition != NULL)
00434         xmlFree(edition);
00435     if (version != NULL)
00436         xmlFree(version);
00437     if (filename != NULL)
00438         xmlFree(filename);
00439     if (uri != NULL)
00440         xmlFree(uri);
00441     if (base != NULL)
00442         xmlFree(base);
00443     if (id != NULL)
00444         xmlFree(id);
00445     if (rec != NULL)
00446         xmlFree(rec);
00447     return(ret);
00448 }
00449 
00450 static int
00451 xmlconfTestCases(xmlDocPtr doc, xmlNodePtr cur, int level) {
00452     xmlChar *profile;
00453     int ret = 0;
00454     int tests = 0;
00455     int output = 0;
00456 
00457     if (level == 1) {
00458     profile = xmlGetProp(cur, BAD_CAST "PROFILE");
00459     if (profile != NULL) {
00460         output = 1;
00461         level++;
00462         printf("Test cases: %s\n", (char *) profile);
00463         xmlFree(profile);
00464     }
00465     }
00466     cur = cur->children;
00467     while (cur != NULL) {
00468         /* look only at elements we ignore everything else */
00469         if (cur->type == XML_ELEMENT_NODE) {
00470         if (xmlStrEqual(cur->name, BAD_CAST "TESTCASES")) {
00471             ret += xmlconfTestCases(doc, cur, level);
00472         } else if (xmlStrEqual(cur->name, BAD_CAST "TEST")) {
00473             if (xmlconfTestItem(doc, cur) >= 0)
00474             ret++;
00475         tests++;
00476         } else {
00477             fprintf(stderr, "Unhandled element %s\n", (char *)cur->name);
00478         }
00479     }
00480         cur = cur->next;
00481     }
00482     if (output == 1) {
00483     if (tests > 0)
00484         printf("Test cases: %d tests\n", tests);
00485     }
00486     return(ret);
00487 }
00488 
00489 static int
00490 xmlconfTestSuite(xmlDocPtr doc, xmlNodePtr cur) {
00491     xmlChar *profile;
00492     int ret = 0;
00493 
00494     profile = xmlGetProp(cur, BAD_CAST "PROFILE");
00495     if (profile != NULL) {
00496         printf("Test suite: %s\n", (char *) profile);
00497     xmlFree(profile);
00498     } else
00499         printf("Test suite\n");
00500     cur = cur->children;
00501     while (cur != NULL) {
00502         /* look only at elements we ignore everything else */
00503         if (cur->type == XML_ELEMENT_NODE) {
00504         if (xmlStrEqual(cur->name, BAD_CAST "TESTCASES")) {
00505             ret += xmlconfTestCases(doc, cur, 1);
00506         } else {
00507             fprintf(stderr, "Unhandled element %s\n", (char *)cur->name);
00508         }
00509     }
00510         cur = cur->next;
00511     }
00512     return(ret);
00513 }
00514 
00515 static void
00516 xmlconfInfo(void) {
00517     fprintf(stderr, "  you need to fetch and extract the\n");
00518     fprintf(stderr, "  latest XML Conformance Test Suites\n");
00519     fprintf(stderr, "  http://www.w3.org/XML/Test/xmlts20080205.tar.gz\n");
00520     fprintf(stderr, "  see http://www.w3.org/XML/Test/ for informations\n");
00521 }
00522 
00523 static int
00524 xmlconfTest(void) {
00525     const char *confxml = "xmlconf/xmlconf.xml";
00526     xmlDocPtr doc;
00527     xmlNodePtr cur;
00528     int ret = 0;
00529 
00530     if (!checkTestFile(confxml)) {
00531         fprintf(stderr, "%s is missing \n", confxml);
00532     xmlconfInfo();
00533     return(-1);
00534     }
00535     doc = xmlReadFile(confxml, NULL, XML_PARSE_NOENT);
00536     if (doc == NULL) {
00537         fprintf(stderr, "%s is corrupted \n", confxml);
00538     xmlconfInfo();
00539     return(-1);
00540     }
00541 
00542     cur = xmlDocGetRootElement(doc);
00543     if ((cur == NULL) || (!xmlStrEqual(cur->name, BAD_CAST "TESTSUITE"))) {
00544         fprintf(stderr, "Unexpected format %s\n", confxml);
00545     xmlconfInfo();
00546     ret = -1;
00547     } else {
00548         ret = xmlconfTestSuite(doc, cur);
00549     }
00550     xmlFreeDoc(doc);
00551     return(ret);
00552 }
00553 
00554 /************************************************************************
00555  *                                  *
00556  *      The driver for the tests                *
00557  *                                  *
00558  ************************************************************************/
00559 
00560 int
00561 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
00562     int ret = 0;
00563     int old_errors, old_tests, old_leaks;
00564 
00565     logfile = fopen(LOGFILE, "w");
00566     if (logfile == NULL) {
00567         fprintf(stderr,
00568             "Could not open the log file, running in verbose mode\n");
00569     verbose = 1;
00570     }
00571     initializeLibxml2();
00572 
00573     if ((argc >= 2) && (!strcmp(argv[1], "-v")))
00574         verbose = 1;
00575 
00576 
00577     old_errors = nb_errors;
00578     old_tests = nb_tests;
00579     old_leaks = nb_leaks;
00580     xmlconfTest();
00581     if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
00582     printf("Ran %d tests, no errors\n", nb_tests - old_tests);
00583     else
00584     printf("Ran %d tests, %d errors, %d leaks\n",
00585            nb_tests - old_tests,
00586            nb_errors - old_errors,
00587            nb_leaks - old_leaks);
00588     if ((nb_errors == 0) && (nb_leaks == 0)) {
00589         ret = 0;
00590     printf("Total %d tests, no errors\n",
00591            nb_tests);
00592     } else {
00593     ret = 1;
00594     printf("Total %d tests, %d errors, %d leaks\n",
00595            nb_tests, nb_errors, nb_leaks);
00596     printf("See %s for detailed output\n", LOGFILE);
00597     if ((nb_leaks == 0) && (nb_errors == NB_EXPECTED_ERRORS)) {
00598         printf("%d errors were expected\n", nb_errors);
00599         ret = 0;
00600     }
00601     }
00602     xmlXPathFreeContext(ctxtXPath);
00603     xmlCleanupParser();
00604     xmlMemoryDump();
00605 
00606     if (logfile != NULL)
00607         fclose(logfile);
00608     return(ret);
00609 }
00610 
00611 #else /* ! LIBXML_XPATH_ENABLED */
00612 #include <stdio.h>
00613 int
00614 main(int argc, char **argv) {
00615     fprintf(stderr, "%s need XPath support\n", argv[0]);
00616 }
00617 #endif

Generated on Fri May 25 2012 04:32:58 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.