📄 runsuite.c
字号:
/*
* runsuite.c: C program to run libxml2 againts published testsuites
*
* See Copyright for the status of this software.
*
* daniel@veillard.com
*/
#if !defined(_WIN32) || defined(__CYGWIN__)
#include <unistd.h>
#endif
#include <string.h>
#include <stdio.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"
FILE *logfile = NULL;
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 long libxmlMemoryAllocatedBase = 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
char *testEntitiesName[MAX_ENTITIES];
char *testEntitiesValue[MAX_ENTITIES];
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;
}
xmlXPathContextPtr ctxtXPath;
static void
initializeLibxml2(void) {
xmlGetWarningsDefaultValue = 0;
xmlPedanticParserDefault(0);
xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
xmlInitParser();
xmlSetExternalEntityLoader(testExternalEntityLoader);
ctxtXPath = xmlXPathNewContext(NULL);
/* 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
libxmlMemoryAllocatedBase = xmlMemUsed();
}
static xmlNodePtr
getNext(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 void
installResources(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);
}
}
tst = getNext(tst, "following-sibling::resource[1]");
}
if (buf != NULL)
xmlBufferFree(buf);
}
static void
installDirs(xmlNodePtr tst, const xmlChar *base) {
xmlNodePtr test;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -