📄 runsuite.c
字号:
/* * 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>#if defined(LIBXML_SCHEMAS_ENABLED) && defined(LIBXML_XPATH_ENABLED)#include <libxml/xmlreader.h>#include <libxml/xpath.h>#include <libxml/xpathInternals.h>#include <libxml/relaxng.h>#include <libxml/xmlschemas.h>#include <libxml/xmlschemastypes.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_tests = 0;static int nb_errors = 0;static int nb_internals = 0;static int nb_schematas = 0;static int nb_unimplemented = 0;static int nb_leaks = 0;static int extraMemoryFromResolver = 0;static intfatalError(void) { fprintf(stderr, "Exitting tests on fatal error\n"); exit(1);}/* * that's needed to implement <resource> */#define MAX_ENTITIES 20static 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 voidtestErrorHandler(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 voidinitializeLibxml2(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); /* used as default nanemspace in xstc tests */ xmlXPathRegisterNs(ctxtXPath, BAD_CAST "ts", BAD_CAST "TestSuite"); xmlXPathRegisterNs(ctxtXPath, BAD_CAST "xlink", BAD_CAST "http://www.w3.org/1999/xlink"); xmlSetGenericErrorFunc(NULL, testErrorHandler);#ifdef LIBXML_SCHEMAS_ENABLED xmlSchemaInitTypes(); xmlRelaxNGInitTypes();#endif}static xmlNodePtrgetNext(xmlNodePtr cur, const char *xpath) { xmlNodePtr ret = NULL; xmlXPathObjectPtr res; xmlXPathCompExprPtr comp; if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL)) return(NULL); ctxtXPath->doc = cur->doc; ctxtXPath->node = cur; comp = xmlXPathCompile(BAD_CAST xpath); if (comp == NULL) { fprintf(stderr, "Failed to compile %s\n", xpath); return(NULL); } res = xmlXPathCompiledEval(comp, ctxtXPath); xmlXPathFreeCompExpr(comp); 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; xmlXPathCompExprPtr comp; if ((cur == NULL) || (cur->doc == NULL) || (xpath == NULL)) return(NULL); ctxtXPath->doc = cur->doc; ctxtXPath->node = cur; comp = xmlXPathCompile(BAD_CAST xpath); if (comp == NULL) { fprintf(stderr, "Failed to compile %s\n", xpath); return(NULL); } res = xmlXPathCompiledEval(comp, ctxtXPath); xmlXPathFreeCompExpr(comp); 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(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) { test_log("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) { test_log("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)) { test_log("Validation of tests starting line %ld leaked %d\n", xmlGetLineNo(cur), xmlMemUsed() - memt); nb_leaks++; } return(ret);}static voidinstallResources(xmlNodePtr tst, const xmlChar *base) { xmlNodePtr test; xmlBufferPtr buf; xmlChar *name, *content, *res; buf = xmlBufferCreate(); if (buf == NULL) { fprintf(stderr, "out of memory !\n"); fatalError(); } xmlNodeDump(buf, tst->doc, tst, 0, 0); while (tst != NULL) { test = getNext(tst, "./*"); if (test != NULL) { xmlBufferEmpty(buf); xmlNodeDump(buf, test->doc, test, 0, 0); name = getString(tst, "string(@name)"); content = xmlStrdup(buf->content); if ((name != NULL) && (content != NULL)) { res = composeDir(base, name); xmlFree(name); addEntity((char *) res, (char *) content); } else { if (name != NULL) xmlFree(name); if (content != NULL) xmlFree(content);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -