From 0357a308b8e1cc37e5527f27047dc725a4ae17e1 Mon Sep 17 00:00:00 2001 From: "William M. Brack" Date: Wed, 6 Jul 2005 17:39:14 +0000 Subject: excluded content string check for XML_ELEMENT_DECL in * debugXML.c: excluded content string check for XML_ELEMENT_DECL in xmlCtxtGenericNodeCheck * runtest.c: changed "open" calls to include O_BINARY for Windows --- runtest.c | 8417 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 4211 insertions(+), 4206 deletions(-) (limited to 'runtest.c') diff --git a/runtest.c b/runtest.c index 63cf0d52..88c39b85 100644 --- a/runtest.c +++ b/runtest.c @@ -1,4207 +1,4212 @@ -/* - * runtest.c: C program to run libxml2 regression tests without - * requiring make or Python, and reducing platform dependancies - * to a strict minimum. - * - * To compile on Unixes: - * cc -o runtest `xml2-config --cflags` runtest.c `xml2-config --libs` -lpthread - * - * See Copyright for the status of this software. - * - * daniel@veillard.com - */ - -#if !defined(_WIN32) || defined(__CYGWIN__) -#include -#endif -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef LIBXML_OUTPUT_ENABLED -#ifdef LIBXML_READER_ENABLED -#include -#endif - -#ifdef LIBXML_XINCLUDE_ENABLED -#include -#endif - -#ifdef LIBXML_XPATH_ENABLED -#include -#include -#ifdef LIBXML_XPTR_ENABLED -#include -#endif -#endif - -#ifdef LIBXML_SCHEMAS_ENABLED -#include -#include -#include -#endif - -#ifdef LIBXML_PATTERN_ENABLED -#include -#endif - -#ifdef LIBXML_C14N_ENABLED -#include -#endif - -#ifdef LIBXML_HTML_ENABLED -#include -#include - -/* - * pseudo flag for the unification of HTML and XML tests - */ -#define XML_PARSE_HTML 1 << 24 -#endif - -#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) -#include -#include -#include -#include -#include -#endif - -typedef int (*functest) (const char *filename, const char *result, - const char *error, int options); - -typedef struct testDesc testDesc; -typedef testDesc *testDescPtr; -struct testDesc { - const char *desc; /* descripton of the test */ - functest func; /* function implementing the test */ - const char *in; /* glob to path for input files */ - const char *out; /* output directory */ - const char *suffix;/* suffix for output files */ - const char *err; /* suffix for error output files */ - int options; /* parser options for the test */ -}; - -static int checkTestFile(const char *filename); - -#if defined(_WIN32) && !defined(__CYGWIN__) - -#include -#include - -typedef struct -{ - size_t gl_pathc; /* Count of paths matched so far */ - char **gl_pathv; /* List of matched pathnames. */ - size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */ -} glob_t; - -#define GLOB_DOOFFS 0 -static int glob(const char *pattern, int flags, - int errfunc(const char *epath, int eerrno), - glob_t *pglob) { - glob_t *ret; - WIN32_FIND_DATA FindFileData; - HANDLE hFind; - unsigned int nb_paths = 0; - char directory[500]; - int len; - - if ((pattern == NULL) || (pglob == NULL)) return(-1); - - strncpy(directory, pattern, 499); - for (len = strlen(directory);len >= 0;len--) { - if (directory[len] == '/') { - len++; - directory[len] = 0; - break; - } - } - if (len <= 0) - len = 0; - - - ret = pglob; - memset(ret, 0, sizeof(glob_t)); - - hFind = FindFirstFileA(pattern, &FindFileData); - if (hFind == INVALID_HANDLE_VALUE) - return(0); - nb_paths = 20; - ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *)); - if (ret->gl_pathv == NULL) { - FindClose(hFind); - return(-1); - } - strncpy(directory + len, FindFileData.cFileName, 499 - len); - ret->gl_pathv[ret->gl_pathc] = strdup(directory); - if (ret->gl_pathv[ret->gl_pathc] == NULL) - goto done; - ret->gl_pathc++; - while(FindNextFileA(hFind, &FindFileData)) { - if (FindFileData.cFileName[0] == '.') - continue; - if (ret->gl_pathc + 2 > nb_paths) { - char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *)); - if (tmp == NULL) - break; - ret->gl_pathv = tmp; - nb_paths *= 2; - } - strncpy(directory + len, FindFileData.cFileName, 499 - len); - ret->gl_pathv[ret->gl_pathc] = strdup(directory); - if (ret->gl_pathv[ret->gl_pathc] == NULL) - break; - ret->gl_pathc++; - } - ret->gl_pathv[ret->gl_pathc] = NULL; - -done: - FindClose(hFind); - return(0); -} - - - -static void globfree(glob_t *pglob) { - unsigned int i; - if (pglob == NULL) - return; - - for (i = 0;i < pglob->gl_pathc;i++) { - if (pglob->gl_pathv[i] != NULL) - free(pglob->gl_pathv[i]); - } -} -#define vsnprintf _vsnprintf -#define snprintf _snprintf -#else -#include -#endif - -/************************************************************************ - * * - * 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 -channel(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; -} - -/** - * xmlParserPrintFileContext: - * @input: an xmlParserInputPtr input - * - * Displays current context within the input content for error tracking - */ - -static void -xmlParserPrintFileContextInternal(xmlParserInputPtr input , - xmlGenericErrorFunc chanl, void *data ) { - const xmlChar *cur, *base; - unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ - xmlChar content[81]; /* space for 80 chars + line terminator */ - xmlChar *ctnt; - - if (input == NULL) return; - cur = input->cur; - base = input->base; - /* skip backwards over any end-of-lines */ - while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) { - cur--; - } - n = 0; - /* search backwards for beginning-of-line (to max buff size) */ - while ((n++ < (sizeof(content)-1)) && (cur > base) && - (*(cur) != '\n') && (*(cur) != '\r')) - cur--; - if ((*(cur) == '\n') || (*(cur) == '\r')) cur++; - /* calculate the error position in terms of the current position */ - col = input->cur - cur; - /* search forward for end-of-line (to max buff size) */ - n = 0; - ctnt = content; - /* copy selected text to our buffer */ - while ((*cur != 0) && (*(cur) != '\n') && - (*(cur) != '\r') && (n < sizeof(content)-1)) { - *ctnt++ = *cur++; - n++; - } - *ctnt = 0; - /* print out the selected text */ - chanl(data ,"%s\n", content); - /* create blank line with problem pointer */ - n = 0; - ctnt = content; - /* (leave buffer space for pointer + line terminator) */ - while ((nfile; - line = err->line; - code = err->code; - domain = err->domain; - level = err->level; - node = err->node; - if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || - (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || - (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { - ctxt = err->ctxt; - } - str = err->message; - - if (code == XML_ERR_OK) - return; - - if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) - name = node->name; - - /* - * Maintain the compatibility with the legacy error handling - */ - if (ctxt != NULL) { - input = ctxt->input; - if ((input != NULL) && (input->filename == NULL) && - (ctxt->inputNr > 1)) { - cur = input; - input = ctxt->inputTab[ctxt->inputNr - 2]; - } - if (input != NULL) { - if (input->filename) - channel(data, "%s:%d: ", input->filename, input->line); - else if ((line != 0) && (domain == XML_FROM_PARSER)) - channel(data, "Entity: line %d: ", input->line); - } - } else { - if (file != NULL) - channel(data, "%s:%d: ", file, line); - else if ((line != 0) && (domain == XML_FROM_PARSER)) - channel(data, "Entity: line %d: ", line); - } - if (name != NULL) { - channel(data, "element %s: ", name); - } - if (code == XML_ERR_OK) - return; - switch (domain) { - case XML_FROM_PARSER: - channel(data, "parser "); - break; - case XML_FROM_NAMESPACE: - channel(data, "namespace "); - break; - case XML_FROM_DTD: - case XML_FROM_VALID: - channel(data, "validity "); - break; - case XML_FROM_HTML: - channel(data, "HTML parser "); - break; - case XML_FROM_MEMORY: - channel(data, "memory "); - break; - case XML_FROM_OUTPUT: - channel(data, "output "); - break; - case XML_FROM_IO: - channel(data, "I/O "); - break; - case XML_FROM_XINCLUDE: - channel(data, "XInclude "); - break; - case XML_FROM_XPATH: - channel(data, "XPath "); - break; - case XML_FROM_XPOINTER: - channel(data, "parser "); - break; - case XML_FROM_REGEXP: - channel(data, "regexp "); - break; - case XML_FROM_MODULE: - channel(data, "module "); - break; - case XML_FROM_SCHEMASV: - channel(data, "Schemas validity "); - break; - case XML_FROM_SCHEMASP: - channel(data, "Schemas parser "); - break; - case XML_FROM_RELAXNGP: - channel(data, "Relax-NG parser "); - break; - case XML_FROM_RELAXNGV: - channel(data, "Relax-NG validity "); - break; - case XML_FROM_CATALOG: - channel(data, "Catalog "); - break; - case XML_FROM_C14N: - channel(data, "C14N "); - break; - case XML_FROM_XSLT: - channel(data, "XSLT "); - break; - default: - break; - } - if (code == XML_ERR_OK) - return; - switch (level) { - case XML_ERR_NONE: - channel(data, ": "); - break; - case XML_ERR_WARNING: - channel(data, "warning : "); - break; - case XML_ERR_ERROR: - channel(data, "error : "); - break; - case XML_ERR_FATAL: - channel(data, "error : "); - break; - } - if (code == XML_ERR_OK) - return; - if (str != NULL) { - int len; - len = xmlStrlen((const xmlChar *)str); - if ((len > 0) && (str[len - 1] != '\n')) - channel(data, "%s\n", str); - else - channel(data, "%s", str); - } else { - channel(data, "%s\n", "out of memory error"); - } - if (code == XML_ERR_OK) - return; - - if (ctxt != NULL) { - xmlParserPrintFileContextInternal(input, channel, data); - if (cur != NULL) { - if (cur->filename) - channel(data, "%s:%d: \n", cur->filename, cur->line); - else if ((line != 0) && (domain == XML_FROM_PARSER)) - channel(data, "Entity: line %d: \n", cur->line); - xmlParserPrintFileContextInternal(cur, channel, data); - } - } - if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) && - (err->int1 < 100) && - (err->int1 < xmlStrlen((const xmlChar *)err->str1))) { - xmlChar buf[150]; - int i; - - channel(data, "%s\n", err->str1); - for (i=0;i < err->int1;i++) - buf[i] = ' '; - buf[i++] = '^'; - buf[i] = 0; - channel(data, "%s\n", buf); - } -} - -static void -initializeLibxml2(void) { - xmlGetWarningsDefaultValue = 0; - xmlPedanticParserDefault(0); - - xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup); - xmlInitParser(); - xmlSetExternalEntityLoader(testExternalEntityLoader); - xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler); -#ifdef LIBXML_SCHEMAS_ENABLED - xmlSchemaInitTypes(); - xmlRelaxNGInitTypes(); -#endif - libxmlMemoryAllocatedBase = xmlMemUsed(); -} - - -/************************************************************************ - * * - * File name and path utilities * - * * - ************************************************************************/ - -static const char *baseFilename(const char *filename) { - const char *cur; - if (filename == NULL) - return(NULL); - cur = &filename[strlen(filename)]; - while ((cur > filename) && (*cur != '/')) - cur--; - if (*cur == '/') - return(cur + 1); - return(cur); -} - -static char *resultFilename(const char *filename, const char *out, - const char *suffix) { - const char *base; - char res[500]; - -/************* - if ((filename[0] == 't') && (filename[1] == 'e') && - (filename[2] == 's') && (filename[3] == 't') && - (filename[4] == '/')) - filename = &filename[5]; - *************/ - - base = baseFilename(filename); - if (suffix == NULL) - suffix = ".tmp"; - if (out == NULL) - out = ""; - snprintf(res, 499, "%s%s%s", out, base, suffix); - res[499] = 0; - return(strdup(res)); -} - -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 int compareFiles(const char *r1, const char *r2) { - int res1, res2; - int fd1, fd2; - char bytes1[4096]; - char bytes2[4096]; - - fd1 = open(r1, O_RDONLY); - if (fd1 < 0) - return(-1); - fd2 = open(r2, O_RDONLY); - if (fd2 < 0) { - close(fd1); - return(-1); - } - while (1) { - res1 = read(fd1, bytes1, 4096); - res2 = read(fd2, bytes2, 4096); - if (res1 != res2) { - close(fd1); - close(fd2); - return(1); - } - if (res1 == 0) - break; - if (memcmp(bytes1, bytes2, res1) != 0) { - close(fd1); - close(fd2); - return(1); - } - } - close(fd1); - close(fd2); - return(0); -} - -static int compareFileMem(const char *filename, const char *mem, int size) { - int res; - int fd; - char bytes[4096]; - int idx = 0; - struct stat info; - - if (stat(filename, &info) < 0) - return(-1); - if (info.st_size != size) - return(-1); - fd = open(filename, O_RDONLY); - if (fd < 0) - return(-1); - while (idx < size) { - res = read(fd, bytes, 4096); - if (res <= 0) - break; - if (res + idx > size) - break; - if (memcmp(bytes, &mem[idx], res) != 0) { - close(fd); - return(1); - } - idx += res; - } - close(fd); - return(idx != size); -} - -static int loadMem(const char *filename, const char **mem, int *size) { - int fd, res; - struct stat info; - char *base; - int siz = 0; - if (stat(filename, &info) < 0) - return(-1); - base = malloc(info.st_size + 1); - if (base == NULL) - return(-1); - if ((fd = open(filename, O_RDONLY)) < 0) { - free(base); - return(-1); - } - while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) { - siz += res; - } +/* + * runtest.c: C program to run libxml2 regression tests without + * requiring make or Python, and reducing platform dependancies + * to a strict minimum. + * + * To compile on Unixes: + * cc -o runtest `xml2-config --cflags` runtest.c `xml2-config --libs` -lpthread + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#if !defined(_WIN32) || defined(__CYGWIN__) +#include +#endif +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef LIBXML_OUTPUT_ENABLED +#ifdef LIBXML_READER_ENABLED +#include +#endif + +#ifdef LIBXML_XINCLUDE_ENABLED +#include +#endif + +#ifdef LIBXML_XPATH_ENABLED +#include +#include +#ifdef LIBXML_XPTR_ENABLED +#include +#endif +#endif + +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#include +#endif + +#ifdef LIBXML_PATTERN_ENABLED +#include +#endif + +#ifdef LIBXML_C14N_ENABLED +#include +#endif + +#ifdef LIBXML_HTML_ENABLED +#include +#include + +/* + * pseudo flag for the unification of HTML and XML tests + */ +#define XML_PARSE_HTML 1 << 24 +#endif + +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) +#include +#include +#include +#include +#include +#endif + +typedef int (*functest) (const char *filename, const char *result, + const char *error, int options); + +typedef struct testDesc testDesc; +typedef testDesc *testDescPtr; +struct testDesc { + const char *desc; /* descripton of the test */ + functest func; /* function implementing the test */ + const char *in; /* glob to path for input files */ + const char *out; /* output directory */ + const char *suffix;/* suffix for output files */ + const char *err; /* suffix for error output files */ + int options; /* parser options for the test */ +}; + +static int checkTestFile(const char *filename); + +#if defined(_WIN32) && !defined(__CYGWIN__) + +#include +#include + +typedef struct +{ + size_t gl_pathc; /* Count of paths matched so far */ + char **gl_pathv; /* List of matched pathnames. */ + size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */ +} glob_t; + +#define GLOB_DOOFFS 0 +static int glob(const char *pattern, int flags, + int errfunc(const char *epath, int eerrno), + glob_t *pglob) { + glob_t *ret; + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + unsigned int nb_paths = 0; + char directory[500]; + int len; + + if ((pattern == NULL) || (pglob == NULL)) return(-1); + + strncpy(directory, pattern, 499); + for (len = strlen(directory);len >= 0;len--) { + if (directory[len] == '/') { + len++; + directory[len] = 0; + break; + } + } + if (len <= 0) + len = 0; + + + ret = pglob; + memset(ret, 0, sizeof(glob_t)); + + hFind = FindFirstFileA(pattern, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) + return(0); + nb_paths = 20; + ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *)); + if (ret->gl_pathv == NULL) { + FindClose(hFind); + return(-1); + } + strncpy(directory + len, FindFileData.cFileName, 499 - len); + ret->gl_pathv[ret->gl_pathc] = strdup(directory); + if (ret->gl_pathv[ret->gl_pathc] == NULL) + goto done; + ret->gl_pathc++; + while(FindNextFileA(hFind, &FindFileData)) { + if (FindFileData.cFileName[0] == '.') + continue; + if (ret->gl_pathc + 2 > nb_paths) { + char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *)); + if (tmp == NULL) + break; + ret->gl_pathv = tmp; + nb_paths *= 2; + } + strncpy(directory + len, FindFileData.cFileName, 499 - len); + ret->gl_pathv[ret->gl_pathc] = strdup(directory); + if (ret->gl_pathv[ret->gl_pathc] == NULL) + break; + ret->gl_pathc++; + } + ret->gl_pathv[ret->gl_pathc] = NULL; + +done: + FindClose(hFind); + return(0); +} + + + +static void globfree(glob_t *pglob) { + unsigned int i; + if (pglob == NULL) + return; + + for (i = 0;i < pglob->gl_pathc;i++) { + if (pglob->gl_pathv[i] != NULL) + free(pglob->gl_pathv[i]); + } +} +#define vsnprintf _vsnprintf +#define snprintf _snprintf +#else +#include +#endif + +/************************************************************************ + * * + * 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 +channel(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; +} + +/** + * xmlParserPrintFileContext: + * @input: an xmlParserInputPtr input + * + * Displays current context within the input content for error tracking + */ + +static void +xmlParserPrintFileContextInternal(xmlParserInputPtr input , + xmlGenericErrorFunc chanl, void *data ) { + const xmlChar *cur, *base; + unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ + xmlChar content[81]; /* space for 80 chars + line terminator */ + xmlChar *ctnt; + + if (input == NULL) return; + cur = input->cur; + base = input->base; + /* skip backwards over any end-of-lines */ + while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) { + cur--; + } + n = 0; + /* search backwards for beginning-of-line (to max buff size) */ + while ((n++ < (sizeof(content)-1)) && (cur > base) && + (*(cur) != '\n') && (*(cur) != '\r')) + cur--; + if ((*(cur) == '\n') || (*(cur) == '\r')) cur++; + /* calculate the error position in terms of the current position */ + col = input->cur - cur; + /* search forward for end-of-line (to max buff size) */ + n = 0; + ctnt = content; + /* copy selected text to our buffer */ + while ((*cur != 0) && (*(cur) != '\n') && + (*(cur) != '\r') && (n < sizeof(content)-1)) { + *ctnt++ = *cur++; + n++; + } + *ctnt = 0; + /* print out the selected text */ + chanl(data ,"%s\n", content); + /* create blank line with problem pointer */ + n = 0; + ctnt = content; + /* (leave buffer space for pointer + line terminator) */ + while ((nfile; + line = err->line; + code = err->code; + domain = err->domain; + level = err->level; + node = err->node; + if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || + (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || + (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { + ctxt = err->ctxt; + } + str = err->message; + + if (code == XML_ERR_OK) + return; + + if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) + name = node->name; + + /* + * Maintain the compatibility with the legacy error handling + */ + if (ctxt != NULL) { + input = ctxt->input; + if ((input != NULL) && (input->filename == NULL) && + (ctxt->inputNr > 1)) { + cur = input; + input = ctxt->inputTab[ctxt->inputNr - 2]; + } + if (input != NULL) { + if (input->filename) + channel(data, "%s:%d: ", input->filename, input->line); + else if ((line != 0) && (domain == XML_FROM_PARSER)) + channel(data, "Entity: line %d: ", input->line); + } + } else { + if (file != NULL) + channel(data, "%s:%d: ", file, line); + else if ((line != 0) && (domain == XML_FROM_PARSER)) + channel(data, "Entity: line %d: ", line); + } + if (name != NULL) { + channel(data, "element %s: ", name); + } + if (code == XML_ERR_OK) + return; + switch (domain) { + case XML_FROM_PARSER: + channel(data, "parser "); + break; + case XML_FROM_NAMESPACE: + channel(data, "namespace "); + break; + case XML_FROM_DTD: + case XML_FROM_VALID: + channel(data, "validity "); + break; + case XML_FROM_HTML: + channel(data, "HTML parser "); + break; + case XML_FROM_MEMORY: + channel(data, "memory "); + break; + case XML_FROM_OUTPUT: + channel(data, "output "); + break; + case XML_FROM_IO: + channel(data, "I/O "); + break; + case XML_FROM_XINCLUDE: + channel(data, "XInclude "); + break; + case XML_FROM_XPATH: + channel(data, "XPath "); + break; + case XML_FROM_XPOINTER: + channel(data, "parser "); + break; + case XML_FROM_REGEXP: + channel(data, "regexp "); + break; + case XML_FROM_MODULE: + channel(data, "module "); + break; + case XML_FROM_SCHEMASV: + channel(data, "Schemas validity "); + break; + case XML_FROM_SCHEMASP: + channel(data, "Schemas parser "); + break; + case XML_FROM_RELAXNGP: + channel(data, "Relax-NG parser "); + break; + case XML_FROM_RELAXNGV: + channel(data, "Relax-NG validity "); + break; + case XML_FROM_CATALOG: + channel(data, "Catalog "); + break; + case XML_FROM_C14N: + channel(data, "C14N "); + break; + case XML_FROM_XSLT: + channel(data, "XSLT "); + break; + default: + break; + } + if (code == XML_ERR_OK) + return; + switch (level) { + case XML_ERR_NONE: + channel(data, ": "); + break; + case XML_ERR_WARNING: + channel(data, "warning : "); + break; + case XML_ERR_ERROR: + channel(data, "error : "); + break; + case XML_ERR_FATAL: + channel(data, "error : "); + break; + } + if (code == XML_ERR_OK) + return; + if (str != NULL) { + int len; + len = xmlStrlen((const xmlChar *)str); + if ((len > 0) && (str[len - 1] != '\n')) + channel(data, "%s\n", str); + else + channel(data, "%s", str); + } else { + channel(data, "%s\n", "out of memory error"); + } + if (code == XML_ERR_OK) + return; + + if (ctxt != NULL) { + xmlParserPrintFileContextInternal(input, channel, data); + if (cur != NULL) { + if (cur->filename) + channel(data, "%s:%d: \n", cur->filename, cur->line); + else if ((line != 0) && (domain == XML_FROM_PARSER)) + channel(data, "Entity: line %d: \n", cur->line); + xmlParserPrintFileContextInternal(cur, channel, data); + } + } + if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) && + (err->int1 < 100) && + (err->int1 < xmlStrlen((const xmlChar *)err->str1))) { + xmlChar buf[150]; + int i; + + channel(data, "%s\n", err->str1); + for (i=0;i < err->int1;i++) + buf[i] = ' '; + buf[i++] = '^'; + buf[i] = 0; + channel(data, "%s\n", buf); + } +} + +static void +initializeLibxml2(void) { + xmlGetWarningsDefaultValue = 0; + xmlPedanticParserDefault(0); + + xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup); + xmlInitParser(); + xmlSetExternalEntityLoader(testExternalEntityLoader); + xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler); +#ifdef LIBXML_SCHEMAS_ENABLED + xmlSchemaInitTypes(); + xmlRelaxNGInitTypes(); +#endif + libxmlMemoryAllocatedBase = xmlMemUsed(); +} + + +/************************************************************************ + * * + * File name and path utilities * + * * + ************************************************************************/ + +static const char *baseFilename(const char *filename) { + const char *cur; + if (filename == NULL) + return(NULL); + cur = &filename[strlen(filename)]; + while ((cur > filename) && (*cur != '/')) + cur--; + if (*cur == '/') + return(cur + 1); + return(cur); +} + +static char *resultFilename(const char *filename, const char *out, + const char *suffix) { + const char *base; + char res[500]; + +/************* + if ((filename[0] == 't') && (filename[1] == 'e') && + (filename[2] == 's') && (filename[3] == 't') && + (filename[4] == '/')) + filename = &filename[5]; + *************/ + + base = baseFilename(filename); + if (suffix == NULL) + suffix = ".tmp"; + if (out == NULL) + out = ""; + snprintf(res, 499, "%s%s%s", out, base, suffix); + res[499] = 0; + return(strdup(res)); +} + +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 int compareFiles(const char *r1, const char *r2) { + int res1, res2; + int fd1, fd2; + char bytes1[4096]; + char bytes2[4096]; + + fd1 = open(r1, O_RDONLY | O_BINARY); + if (fd1 < 0) + return(-1); + fd2 = open(r2, O_RDONLY | O_BINARY); + if (fd2 < 0) { + close(fd1); + return(-1); + } + while (1) { + res1 = read(fd1, bytes1, 4096); + res2 = read(fd2, bytes2, 4096); + if (res1 != res2) { + close(fd1); + close(fd2); + return(1); + } + if (res1 == 0) + break; + if (memcmp(bytes1, bytes2, res1) != 0) { + close(fd1); + close(fd2); + return(1); + } + } + close(fd1); + close(fd2); + return(0); +} + +static int compareFileMem(const char *filename, const char *mem, int size) { + int res; + int fd; + char bytes[4096]; + int idx = 0; + struct stat info; + + if (stat(filename, &info) < 0) + return(-1); + if (info.st_size != size) + return(-1); + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) + return(-1); + while (idx < size) { + res = read(fd, bytes, 4096); + if (res <= 0) + break; + if (res + idx > size) + break; + if (memcmp(bytes, &mem[idx], res) != 0) { + int ix; + for (ix=0; ix 0) { + siz += res; + } close(fd); -#if !defined(_WIN32) - if (siz != info.st_size) { - free(base); - return(-1); - } -#endif - base[siz] = 0; - *mem = base; - *size = siz; - return(0); -} - -static int unloadMem(const char *mem) { - free((char *)mem); - return(0); -} - -/************************************************************************ - * * - * Tests implementations * - * * - ************************************************************************/ - -/************************************************************************ - * * - * Parse to SAX based tests * - * * - ************************************************************************/ - -FILE *SAXdebug = NULL; - -/* - * empty SAX block - */ -xmlSAXHandler emptySAXHandlerStruct = { - NULL, /* internalSubset */ - NULL, /* isStandalone */ - NULL, /* hasInternalSubset */ - NULL, /* hasExternalSubset */ - NULL, /* resolveEntity */ - NULL, /* getEntity */ - NULL, /* entityDecl */ - NULL, /* notationDecl */ - NULL, /* attributeDecl */ - NULL, /* elementDecl */ - NULL, /* unparsedEntityDecl */ - NULL, /* setDocumentLocator */ - NULL, /* startDocument */ - NULL, /* endDocument */ - NULL, /* startElement */ - NULL, /* endElement */ - NULL, /* reference */ - NULL, /* characters */ - NULL, /* ignorableWhitespace */ - NULL, /* processingInstruction */ - NULL, /* comment */ - NULL, /* xmlParserWarning */ - NULL, /* xmlParserError */ - NULL, /* xmlParserError */ - NULL, /* getParameterEntity */ - NULL, /* cdataBlock; */ - NULL, /* externalSubset; */ - 1, - NULL, - NULL, /* startElementNs */ - NULL, /* endElementNs */ - NULL /* xmlStructuredErrorFunc */ -}; - -static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct; -int callbacks = 0; -int quiet = 0; - -/** - * isStandaloneDebug: - * @ctxt: An XML parser context - * - * Is this document tagged standalone ? - * - * Returns 1 if true - */ -static int -isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED) -{ - callbacks++; - if (quiet) - return(0); - fprintf(SAXdebug, "SAX.isStandalone()\n"); - return(0); -} - -/** - * hasInternalSubsetDebug: - * @ctxt: An XML parser context - * - * Does this document has an internal subset - * - * Returns 1 if true - */ -static int -hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) -{ - callbacks++; - if (quiet) - return(0); - fprintf(SAXdebug, "SAX.hasInternalSubset()\n"); - return(0); -} - -/** - * hasExternalSubsetDebug: - * @ctxt: An XML parser context - * - * Does this document has an external subset - * - * Returns 1 if true - */ -static int -hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) -{ - callbacks++; - if (quiet) - return(0); - fprintf(SAXdebug, "SAX.hasExternalSubset()\n"); - return(0); -} - -/** - * internalSubsetDebug: - * @ctxt: An XML parser context - * - * Does this document has an internal subset - */ -static void -internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, - const xmlChar *ExternalID, const xmlChar *SystemID) -{ - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.internalSubset(%s,", name); - if (ExternalID == NULL) - fprintf(SAXdebug, " ,"); - else - fprintf(SAXdebug, " %s,", ExternalID); - if (SystemID == NULL) - fprintf(SAXdebug, " )\n"); - else - fprintf(SAXdebug, " %s)\n", SystemID); -} - -/** - * externalSubsetDebug: - * @ctxt: An XML parser context - * - * Does this document has an external subset - */ -static void -externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, - const xmlChar *ExternalID, const xmlChar *SystemID) -{ - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.externalSubset(%s,", name); - if (ExternalID == NULL) - fprintf(SAXdebug, " ,"); - else - fprintf(SAXdebug, " %s,", ExternalID); - if (SystemID == NULL) - fprintf(SAXdebug, " )\n"); - else - fprintf(SAXdebug, " %s)\n", SystemID); -} - -/** - * resolveEntityDebug: - * @ctxt: An XML parser context - * @publicId: The public ID of the entity - * @systemId: The system ID of the entity - * - * Special entity resolver, better left to the parser, it has - * more context than the application layer. - * The default behaviour is to NOT resolve the entities, in that case - * the ENTITY_REF nodes are built in the structure (and the parameter - * values). - * - * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. - */ -static xmlParserInputPtr -resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId) -{ - callbacks++; - if (quiet) - return(NULL); - /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ - - - fprintf(SAXdebug, "SAX.resolveEntity("); - if (publicId != NULL) - fprintf(SAXdebug, "%s", (char *)publicId); - else - fprintf(SAXdebug, " "); - if (systemId != NULL) - fprintf(SAXdebug, ", %s)\n", (char *)systemId); - else - fprintf(SAXdebug, ", )\n"); -/********* - if (systemId != NULL) { - return(xmlNewInputFromFile(ctxt, (char *) systemId)); - } - *********/ - return(NULL); -} - -/** - * getEntityDebug: - * @ctxt: An XML parser context - * @name: The entity name - * - * Get an entity by name - * - * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. - */ -static xmlEntityPtr -getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) -{ - callbacks++; - if (quiet) - return(NULL); - fprintf(SAXdebug, "SAX.getEntity(%s)\n", name); - return(NULL); -} - -/** - * getParameterEntityDebug: - * @ctxt: An XML parser context - * @name: The entity name - * - * Get a parameter entity by name - * - * Returns the xmlParserInputPtr - */ -static xmlEntityPtr -getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) -{ - callbacks++; - if (quiet) - return(NULL); - fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name); - return(NULL); -} - - -/** - * entityDeclDebug: - * @ctxt: An XML parser context - * @name: the entity name - * @type: the entity type - * @publicId: The public ID of the entity - * @systemId: The system ID of the entity - * @content: the entity value (without processing). - * - * An entity definition has been parsed - */ -static void -entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, - const xmlChar *publicId, const xmlChar *systemId, xmlChar *content) -{ -const xmlChar *nullstr = BAD_CAST "(null)"; - /* not all libraries handle printing null pointers nicely */ - if (publicId == NULL) - publicId = nullstr; - if (systemId == NULL) - systemId = nullstr; - if (content == NULL) - content = (xmlChar *)nullstr; - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n", - name, type, publicId, systemId, content); -} - -/** - * attributeDeclDebug: - * @ctxt: An XML parser context - * @name: the attribute name - * @type: the attribute type - * - * An attribute definition has been parsed - */ -static void -attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem, - const xmlChar * name, int type, int def, - const xmlChar * defaultValue, xmlEnumerationPtr tree) -{ - callbacks++; - if (quiet) - return; - if (defaultValue == NULL) - fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n", - elem, name, type, def); - else - fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n", - elem, name, type, def, defaultValue); - xmlFreeEnumeration(tree); -} - -/** - * elementDeclDebug: - * @ctxt: An XML parser context - * @name: the element name - * @type: the element type - * @content: the element value (without processing). - * - * An element definition has been parsed - */ -static void -elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, - xmlElementContentPtr content ATTRIBUTE_UNUSED) -{ - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n", - name, type); -} - -/** - * notationDeclDebug: - * @ctxt: An XML parser context - * @name: The name of the notation - * @publicId: The public ID of the entity - * @systemId: The system ID of the entity - * - * What to do when a notation declaration has been parsed. - */ -static void -notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, - const xmlChar *publicId, const xmlChar *systemId) -{ - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n", - (char *) name, (char *) publicId, (char *) systemId); -} - -/** - * unparsedEntityDeclDebug: - * @ctxt: An XML parser context - * @name: The name of the entity - * @publicId: The public ID of the entity - * @systemId: The system ID of the entity - * @notationName: the name of the notation - * - * What to do when an unparsed entity declaration is parsed - */ -static void -unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, - const xmlChar *publicId, const xmlChar *systemId, - const xmlChar *notationName) -{ -const xmlChar *nullstr = BAD_CAST "(null)"; - - if (publicId == NULL) - publicId = nullstr; - if (systemId == NULL) - systemId = nullstr; - if (notationName == NULL) - notationName = nullstr; - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n", - (char *) name, (char *) publicId, (char *) systemId, - (char *) notationName); -} - -/** - * setDocumentLocatorDebug: - * @ctxt: An XML parser context - * @loc: A SAX Locator - * - * Receive the document locator at startup, actually xmlDefaultSAXLocator - * Everything is available on the context, so this is useless in our case. - */ -static void -setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED) -{ - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.setDocumentLocator()\n"); -} - -/** - * startDocumentDebug: - * @ctxt: An XML parser context - * - * called when the document start being processed. - */ -static void -startDocumentDebug(void *ctx ATTRIBUTE_UNUSED) -{ - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.startDocument()\n"); -} - -/** - * endDocumentDebug: - * @ctxt: An XML parser context - * - * called when the document end has been detected. - */ -static void -endDocumentDebug(void *ctx ATTRIBUTE_UNUSED) -{ - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.endDocument()\n"); -} - -/** - * startElementDebug: - * @ctxt: An XML parser context - * @name: The element name - * - * called when an opening tag has been processed. - */ -static void -startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts) -{ - int i; - - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.startElement(%s", (char *) name); - if (atts != NULL) { - for (i = 0;(atts[i] != NULL);i++) { - fprintf(SAXdebug, ", %s='", atts[i++]); - if (atts[i] != NULL) - fprintf(SAXdebug, "%s'", atts[i]); - } - } - fprintf(SAXdebug, ")\n"); -} - -/** - * endElementDebug: - * @ctxt: An XML parser context - * @name: The element name - * - * called when the end of an element has been detected. - */ -static void -endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) -{ - callbacks++; - if (quiet) - return; - fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name); -} - -/** - * charactersDebug: - * @ctxt: An XML parser context - * @ch: a xmlChar string - * @len: the number of xmlChar - * - * receiving some chars from the parser. - * Question: how much at a time ??? - */ -static void -charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) -{ - char output[40]; - int i; - - callbacks++; - if (quiet) - return; - for (i = 0;(i= size) { -#ifdef LIBXML_HTML_ENABLED - if (options & XML_PARSE_HTML) - htmlParseChunk(ctxt, base + cur, size - cur, 1); - else -#endif - xmlParseChunk(ctxt, base + cur, size - cur, 1); - break; - } else { -#ifdef LIBXML_HTML_ENABLED - if (options & XML_PARSE_HTML) - htmlParseChunk(ctxt, base + cur, 1024, 0); - else -#endif - xmlParseChunk(ctxt, base + cur, 1024, 0); - cur += 1024; - } - } - doc = ctxt->myDoc; -#ifdef LIBXML_HTML_ENABLED - if (options & XML_PARSE_HTML) - res = 1; - else -#endif - res = ctxt->wellFormed; - xmlFreeParserCtxt(ctxt); - free((char *)base); - if (!res) { - xmlFreeDoc(doc); - fprintf(stderr, "Failed to parse %s\n", filename); - return(-1); - } -#ifdef LIBXML_HTML_ENABLED - if (options & XML_PARSE_HTML) - htmlDocDumpMemory(doc, (xmlChar **) &base, &size); - else -#endif - xmlDocDumpMemory(doc, (xmlChar **) &base, &size); - xmlFreeDoc(doc); - res = compareFileMem(result, base, size); - if ((base == NULL) || (res != 0)) { - if (base != NULL) - xmlFree((char *)base); - fprintf(stderr, "Result for %s failed\n", filename); - return(-1); - } - xmlFree((char *)base); - if (err != NULL) { - res = compareFileMem(err, testErrors, testErrorsSize); - if (res != 0) { - fprintf(stderr, "Error for %s failed\n", filename); - return(-1); - } - } - return(0); -} -#endif - -/** - * memParseTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages: unused - * - * Parse a file using the old xmlReadMemory API, then serialize back - * reparse the result and serialize again, then check for deviation - * in serialization. - * - * Returns 0 in case of success, an error code otherwise - */ -static int -memParseTest(const char *filename, const char *result, - const char *err ATTRIBUTE_UNUSED, - int options ATTRIBUTE_UNUSED) { - xmlDocPtr doc; - const char *base; - int size, res; - - nb_tests++; - /* - * load and parse the memory - */ - if (loadMem(filename, &base, &size) != 0) { - fprintf(stderr, "Failed to load %s\n", filename); - return(-1); - } - - doc = xmlReadMemory(base, size, filename, NULL, 0); - unloadMem(base); - if (doc == NULL) { - return(1); - } - xmlDocDumpMemory(doc, (xmlChar **) &base, &size); - xmlFreeDoc(doc); - res = compareFileMem(result, base, size); - if ((base == NULL) || (res != 0)) { - if (base != NULL) - xmlFree((char *)base); - fprintf(stderr, "Result for %s failed\n", filename); - return(-1); - } - xmlFree((char *)base); - return(0); -} - -/** - * noentParseTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages: unused - * - * Parse a file with entity resolution, then serialize back - * reparse the result and serialize again, then check for deviation - * in serialization. - * - * Returns 0 in case of success, an error code otherwise - */ -static int -noentParseTest(const char *filename, const char *result, - const char *err ATTRIBUTE_UNUSED, - int options) { - xmlDocPtr doc; - char *temp; - int res = 0; - - nb_tests++; - /* - * base of the test, parse with the old API - */ - doc = xmlReadFile(filename, NULL, options); - if (doc == NULL) - return(1); - temp = resultFilename(filename, "", ".res"); - if (temp == NULL) { - fprintf(stderr, "Out of memory\n"); - fatalError(); - } - xmlSaveFile(temp, doc); - if (compareFiles(temp, result)) { - res = 1; - } - xmlFreeDoc(doc); - - /* - * Parse the saved result to make sure the round trip is okay - */ - doc = xmlReadFile(filename, NULL, options); - if (doc == NULL) - return(1); - xmlSaveFile(temp, doc); - if (compareFiles(temp, result)) { - res = 1; - } - xmlFreeDoc(doc); - - unlink(temp); - free(temp); - return(res); -} - -/** - * errParseTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file using the xmlReadFile API and check for errors. - * - * Returns 0 in case of success, an error code otherwise - */ -static int -errParseTest(const char *filename, const char *result, const char *err, - int options) { - xmlDocPtr doc; - const char *base = NULL; - int size, res = 0; - - nb_tests++; -#ifdef LIBXML_HTML_ENABLED - if (options & XML_PARSE_HTML) { - doc = htmlReadFile(filename, NULL, options); - } else -#endif -#ifdef LIBXML_XINCLUDE_ENABLED - if (options & XML_PARSE_XINCLUDE) { - doc = xmlReadFile(filename, NULL, options); - xmlXIncludeProcessFlags(doc, options); - } else -#endif - { - xmlGetWarningsDefaultValue = 1; - doc = xmlReadFile(filename, NULL, options); - } - xmlGetWarningsDefaultValue = 0; - if (result) { - if (doc == NULL) { - base = ""; - size = 0; - } else { -#ifdef LIBXML_HTML_ENABLED - if (options & XML_PARSE_HTML) { - htmlDocDumpMemory(doc, (xmlChar **) &base, &size); - } else -#endif - xmlDocDumpMemory(doc, (xmlChar **) &base, &size); - } - res = compareFileMem(result, base, size); - } - if (doc != NULL) { - if (base != NULL) - xmlFree((char *)base); - xmlFreeDoc(doc); - } - if (res != 0) { - fprintf(stderr, "Result for %s failed\n", filename); - return(-1); - } - if (err != NULL) { - res = compareFileMem(err, testErrors, testErrorsSize); - if (res != 0) { - fprintf(stderr, "Error for %s failed\n", filename); - return(-1); - } - } else if (options & XML_PARSE_DTDVALID) { - if (testErrorsSize != 0) - fprintf(stderr, "Validation for %s failed\n", filename); - } - - return(0); -} - -#ifdef LIBXML_READER_ENABLED -/************************************************************************ - * * - * Reader based tests * - * * - ************************************************************************/ - -static void processNode(FILE *out, xmlTextReaderPtr reader) { - const xmlChar *name, *value; - int type, empty; - - type = xmlTextReaderNodeType(reader); - empty = xmlTextReaderIsEmptyElement(reader); - - name = xmlTextReaderConstName(reader); - if (name == NULL) - name = BAD_CAST "--"; - - value = xmlTextReaderConstValue(reader); - - - fprintf(out, "%d %d %s %d %d", - xmlTextReaderDepth(reader), - type, - name, - empty, - xmlTextReaderHasValue(reader)); - if (value == NULL) - fprintf(out, "\n"); - else { - fprintf(out, " %s\n", value); - } -} -static int -streamProcessTest(const char *filename, const char *result, const char *err, - xmlTextReaderPtr reader, const char *rng) { - int ret; - char *temp = NULL; - FILE *t = NULL; - - if (reader == NULL) - return(-1); - - nb_tests++; - if (result != NULL) { - temp = resultFilename(filename, "", ".res"); - if (temp == NULL) { - fprintf(stderr, "Out of memory\n"); - fatalError(); - } - t = fopen(temp, "wb"); - if (t == NULL) { - fprintf(stderr, "Can't open temp file %s\n", temp); - free(temp); - return(-1); - } - } -#ifdef LIBXML_SCHEMAS_ENABLED - if (rng != NULL) { - ret = xmlTextReaderRelaxNGValidate(reader, rng); - if (ret < 0) { - testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n", - rng); - fclose(t); - unlink(temp); - free(temp); - return(0); - } - } -#endif - xmlGetWarningsDefaultValue = 1; - ret = xmlTextReaderRead(reader); - while (ret == 1) { - if ((t != NULL) && (rng == NULL)) - processNode(t, reader); - ret = xmlTextReaderRead(reader); - } - if (ret != 0) { - testErrorHandler(NULL, "%s : failed to parse\n", filename); - } - if (rng != NULL) { - if (xmlTextReaderIsValid(reader) != 1) { - testErrorHandler(NULL, "%s fails to validate\n", filename); - } else { - testErrorHandler(NULL, "%s validates\n", filename); - } - } - xmlGetWarningsDefaultValue = 0; - if (t != NULL) { - fclose(t); - ret = compareFiles(temp, result); - unlink(temp); - free(temp); - if (ret) { - fprintf(stderr, "Result for %s failed\n", filename); - return(-1); - } - } - if (err != NULL) { - ret = compareFileMem(err, testErrors, testErrorsSize); - if (ret != 0) { - fprintf(stderr, "Error for %s failed\n", filename); - printf("%s", testErrors); - return(-1); - } - } - - return(0); -} - -/** - * streamParseTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file using the reader API and check for errors. - * - * Returns 0 in case of success, an error code otherwise - */ -static int -streamParseTest(const char *filename, const char *result, const char *err, - int options) { - xmlTextReaderPtr reader; - int ret; - - reader = xmlReaderForFile(filename, NULL, options); - ret = streamProcessTest(filename, result, err, reader, NULL); - xmlFreeTextReader(reader); - return(ret); -} - -/** - * walkerParseTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file using the walker, i.e. a reader built from a atree. - * - * Returns 0 in case of success, an error code otherwise - */ -static int -walkerParseTest(const char *filename, const char *result, const char *err, - int options) { - xmlDocPtr doc; - xmlTextReaderPtr reader; - int ret; - - doc = xmlReadFile(filename, NULL, options); - if (doc == NULL) { - fprintf(stderr, "Failed to parse %s\n", filename); - return(-1); - } - reader = xmlReaderWalker(doc); - ret = streamProcessTest(filename, result, err, reader, NULL); - xmlFreeTextReader(reader); - xmlFreeDoc(doc); - return(ret); -} - -/** - * streamMemParseTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file using the reader API from memory and check for errors. - * - * Returns 0 in case of success, an error code otherwise - */ -static int -streamMemParseTest(const char *filename, const char *result, const char *err, - int options) { - xmlTextReaderPtr reader; - int ret; - const char *base; - int size; - - /* - * load and parse the memory - */ - if (loadMem(filename, &base, &size) != 0) { - fprintf(stderr, "Failed to load %s\n", filename); - return(-1); - } - reader = xmlReaderForMemory(base, size, filename, NULL, options); - ret = streamProcessTest(filename, result, err, reader, NULL); - free((char *)base); - xmlFreeTextReader(reader); - return(ret); -} -#endif - -#ifdef LIBXML_XPATH_ENABLED -#ifdef LIBXML_DEBUG_ENABLED -/************************************************************************ - * * - * XPath and XPointer based tests * - * * - ************************************************************************/ - -FILE *xpathOutput; -xmlDocPtr xpathDocument; - -static void -testXPath(const char *str, int xptr, int expr) { - xmlXPathObjectPtr res; - xmlXPathContextPtr ctxt; - - nb_tests++; -#if defined(LIBXML_XPTR_ENABLED) - if (xptr) { - ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL); - res = xmlXPtrEval(BAD_CAST str, ctxt); - } else { -#endif - ctxt = xmlXPathNewContext(xpathDocument); - ctxt->node = xmlDocGetRootElement(xpathDocument); - if (expr) - res = xmlXPathEvalExpression(BAD_CAST str, ctxt); - else { - /* res = xmlXPathEval(BAD_CAST str, ctxt); */ - xmlXPathCompExprPtr comp; - - comp = xmlXPathCompile(BAD_CAST str); - if (comp != NULL) { - res = xmlXPathCompiledEval(comp, ctxt); - xmlXPathFreeCompExpr(comp); - } else - res = NULL; - } -#if defined(LIBXML_XPTR_ENABLED) - } -#endif - xmlXPathDebugDumpObject(xpathOutput, res, 0); - xmlXPathFreeObject(res); - xmlXPathFreeContext(ctxt); -} - -/** - * xpathExprTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file containing XPath standalone expressions and evaluate them - * - * Returns 0 in case of success, an error code otherwise - */ -static int -xpathCommonTest(const char *filename, const char *result, - int xptr, int expr) { - FILE *input; - char expression[5000]; - int len, ret = 0; - char *temp; - - temp = resultFilename(filename, "", ".res"); - if (temp == NULL) { - fprintf(stderr, "Out of memory\n"); - fatalError(); - } - xpathOutput = fopen(temp, "wb"); - if (xpathOutput == NULL) { - fprintf(stderr, "failed to open output file %s\n", temp); - free(temp); - return(-1); - } - - input = fopen(filename, "rb"); - if (input == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Cannot open %s for reading\n", filename); - free(temp); - return(-1); - } - while (fgets(expression, 4500, input) != NULL) { - len = strlen(expression); - len--; - while ((len >= 0) && - ((expression[len] == '\n') || (expression[len] == '\t') || - (expression[len] == '\r') || (expression[len] == ' '))) len--; - expression[len + 1] = 0; - if (len >= 0) { - fprintf(xpathOutput, - "\n========================\nExpression: %s\n", - expression) ; - testXPath(expression, xptr, expr); - } - } - - fclose(input); - fclose(xpathOutput); - if (result != NULL) { - ret = compareFiles(temp, result); - if (ret) { - fprintf(stderr, "Result for %s failed\n", filename); - } - } - - unlink(temp); - free(temp); - return(ret); -} - -/** - * xpathExprTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file containing XPath standalone expressions and evaluate them - * - * Returns 0 in case of success, an error code otherwise - */ -static int -xpathExprTest(const char *filename, const char *result, - const char *err ATTRIBUTE_UNUSED, - int options ATTRIBUTE_UNUSED) { - return(xpathCommonTest(filename, result, 0, 1)); -} - -/** - * xpathDocTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file containing XPath expressions and evaluate them against - * a set of corresponding documents. - * - * Returns 0 in case of success, an error code otherwise - */ -static int -xpathDocTest(const char *filename, - const char *resul ATTRIBUTE_UNUSED, - const char *err ATTRIBUTE_UNUSED, - int options) { - - char pattern[500]; - char result[500]; - glob_t globbuf; - size_t i; - int ret = 0, res; - - xpathDocument = xmlReadFile(filename, NULL, - options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); - if (xpathDocument == NULL) { - fprintf(stderr, "Failed to load %s\n", filename); - return(-1); - } - - snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename)); - pattern[499] = 0; - globbuf.gl_offs = 0; - glob(pattern, GLOB_DOOFFS, NULL, &globbuf); - for (i = 0;i < globbuf.gl_pathc;i++) { - snprintf(result, 499, "result/XPath/tests/%s", - baseFilename(globbuf.gl_pathv[i])); - res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0); - if (res != 0) - ret = res; - } - globfree(&globbuf); - - xmlFreeDoc(xpathDocument); - return(ret); -} - -#ifdef LIBXML_XPTR_ENABLED -/** - * xptrDocTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file containing XPath expressions and evaluate them against - * a set of corresponding documents. - * - * Returns 0 in case of success, an error code otherwise - */ -static int -xptrDocTest(const char *filename, - const char *resul ATTRIBUTE_UNUSED, - const char *err ATTRIBUTE_UNUSED, - int options) { - - char pattern[500]; - char result[500]; - glob_t globbuf; - size_t i; - int ret = 0, res; - - xpathDocument = xmlReadFile(filename, NULL, - options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); - if (xpathDocument == NULL) { - fprintf(stderr, "Failed to load %s\n", filename); - return(-1); - } - - snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename)); - pattern[499] = 0; - globbuf.gl_offs = 0; - glob(pattern, GLOB_DOOFFS, NULL, &globbuf); - for (i = 0;i < globbuf.gl_pathc;i++) { - snprintf(result, 499, "result/XPath/xptr/%s", - baseFilename(globbuf.gl_pathv[i])); - res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0); - if (res != 0) - ret = res; - } - globfree(&globbuf); - - xmlFreeDoc(xpathDocument); - return(ret); -} -#endif /* LIBXML_XPTR_ENABLED */ - -/** - * xmlidDocTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file containing xml:id and check for errors and verify - * that XPath queries will work on them as expected. - * - * Returns 0 in case of success, an error code otherwise - */ -static int -xmlidDocTest(const char *filename, - const char *result, - const char *err, - int options) { - - int res = 0; - int ret = 0; - char *temp; - - xpathDocument = xmlReadFile(filename, NULL, - options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); - if (xpathDocument == NULL) { - fprintf(stderr, "Failed to load %s\n", filename); - return(-1); - } - - temp = resultFilename(filename, "", ".res"); - if (temp == NULL) { - fprintf(stderr, "Out of memory\n"); - fatalError(); - } - xpathOutput = fopen(temp, "wb"); - if (xpathOutput == NULL) { - fprintf(stderr, "failed to open output file %s\n", temp); - xmlFreeDoc(xpathDocument); - free(temp); - return(-1); - } - - testXPath("id('bar')", 0, 0); - - fclose(xpathOutput); - if (result != NULL) { - ret = compareFiles(temp, result); - if (ret) { - fprintf(stderr, "Result for %s failed\n", filename); - res = 1; - } - } - - unlink(temp); - free(temp); - xmlFreeDoc(xpathDocument); - - if (err != NULL) { - ret = compareFileMem(err, testErrors, testErrorsSize); - if (ret != 0) { - fprintf(stderr, "Error for %s failed\n", filename); - res = 1; - } - } - return(res); -} - -#endif /* LIBXML_DEBUG_ENABLED */ -#endif /* XPATH */ -/************************************************************************ - * * - * URI based tests * - * * - ************************************************************************/ - -static void -handleURI(const char *str, const char *base, FILE *o) { - int ret; - xmlURIPtr uri; - xmlChar *res = NULL, *parsed = NULL; - - uri = xmlCreateURI(); - - if (base == NULL) { - ret = xmlParseURIReference(uri, str); - if (ret != 0) - fprintf(o, "%s : error %d\n", str, ret); - else { - xmlNormalizeURIPath(uri->path); - xmlPrintURI(o, uri); - fprintf(o, "\n"); - } - } else { - res = xmlBuildURI((xmlChar *)str, (xmlChar *) base); - if (res != NULL) { - fprintf(o, "%s\n", (char *) res); - } - else - fprintf(o, "::ERROR::\n"); - } - if (res != NULL) - xmlFree(res); - if (parsed != NULL) - xmlFree(parsed); - xmlFreeURI(uri); -} - -/** - * uriCommonTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file containing URI and check for errors - * - * Returns 0 in case of success, an error code otherwise - */ -static int -uriCommonTest(const char *filename, - const char *result, - const char *err, - const char *base) { - char *temp; - FILE *o, *f; - char str[1024]; - int res = 0, i, ret; - - temp = resultFilename(filename, "", ".res"); - if (temp == NULL) { - fprintf(stderr, "Out of memory\n"); - fatalError(); - } - o = fopen(temp, "wb"); - if (o == NULL) { - fprintf(stderr, "failed to open output file %s\n", temp); - free(temp); - return(-1); - } - f = fopen(filename, "rb"); - if (f == NULL) { - fprintf(stderr, "failed to open input file %s\n", filename); - fclose(o); - unlink(temp); - free(temp); - return(-1); - } - - while (1) { - /* - * read one line in string buffer. - */ - if (fgets (&str[0], sizeof (str) - 1, f) == NULL) - break; - - /* - * remove the ending spaces - */ - i = strlen(str); - while ((i > 0) && - ((str[i - 1] == '\n') || (str[i - 1] == '\r') || - (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { - i--; - str[i] = 0; - } - nb_tests++; - handleURI(str, base, o); - } - - fclose(f); - fclose(o); - - if (result != NULL) { - ret = compareFiles(temp, result); - if (ret) { - fprintf(stderr, "Result for %s failed\n", filename); - res = 1; - } - } - if (err != NULL) { - ret = compareFileMem(err, testErrors, testErrorsSize); - if (ret != 0) { - fprintf(stderr, "Error for %s failed\n", filename); - res = 1; - } - } - - unlink(temp); - free(temp); - return(res); -} - -/** - * uriParseTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file containing URI and check for errors - * - * Returns 0 in case of success, an error code otherwise - */ -static int -uriParseTest(const char *filename, - const char *result, - const char *err, - int options ATTRIBUTE_UNUSED) { - return(uriCommonTest(filename, result, err, NULL)); -} - -/** - * uriBaseTest: - * @filename: the file to parse - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file containing URI, compose them against a fixed base and - * check for errors - * - * Returns 0 in case of success, an error code otherwise - */ -static int -uriBaseTest(const char *filename, - const char *result, - const char *err, - int options ATTRIBUTE_UNUSED) { - return(uriCommonTest(filename, result, err, - "http://foo.com/path/to/index.html?orig#help")); -} - -#ifdef LIBXML_SCHEMAS_ENABLED -/************************************************************************ - * * - * Schemas tests * - * * - ************************************************************************/ -static int -schemasOneTest(const char *sch, - const char *filename, - const char *result, - const char *err, - int options, - xmlSchemaPtr schemas) { - xmlDocPtr doc; - xmlSchemaValidCtxtPtr ctxt; - int ret = 0; - char *temp; - FILE *schemasOutput; - - doc = xmlReadFile(filename, NULL, options); - if (doc == NULL) { - fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); - return(-1); - } - - temp = resultFilename(result, "", ".res"); - if (temp == NULL) { - fprintf(stderr, "Out of memory\n"); - fatalError(); - } - schemasOutput = fopen(temp, "wb"); - if (schemasOutput == NULL) { - fprintf(stderr, "failed to open output file %s\n", temp); - xmlFreeDoc(doc); - free(temp); - return(-1); - } - - ctxt = xmlSchemaNewValidCtxt(schemas); - xmlSchemaSetValidErrors(ctxt, - (xmlSchemaValidityErrorFunc) testErrorHandler, - (xmlSchemaValidityWarningFunc) testErrorHandler, - ctxt); - ret = xmlSchemaValidateDoc(ctxt, doc); - if (ret == 0) { - fprintf(schemasOutput, "%s validates\n", filename); - } else if (ret > 0) { - fprintf(schemasOutput, "%s fails to validate\n", filename); - } else { - fprintf(schemasOutput, "%s validation generated an internal error\n", - filename); - } - fclose(schemasOutput); - if (result) { - if (compareFiles(temp, result)) { - fprintf(stderr, "Result for %s on %s failed\n", filename, sch); - ret = 1; - } - } - unlink(temp); - free(temp); - - if (err != NULL) { - if (compareFileMem(err, testErrors, testErrorsSize)) { - fprintf(stderr, "Error for %s on %s failed\n", filename, sch); - ret = 1; - } - } - - - xmlSchemaFreeValidCtxt(ctxt); - xmlFreeDoc(doc); - return(ret); -} -/** - * schemasTest: - * @filename: the schemas file - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a file containing URI, compose them against a fixed base and - * check for errors - * - * Returns 0 in case of success, an error code otherwise - */ -static int -schemasTest(const char *filename, - const char *resul ATTRIBUTE_UNUSED, - const char *errr ATTRIBUTE_UNUSED, - int options) { - const char *base = baseFilename(filename); - const char *base2; - const char *instance; - xmlSchemaParserCtxtPtr ctxt; - xmlSchemaPtr schemas; - int res = 0, len, ret; - char pattern[500]; - char prefix[500]; - char result[500]; - char err[500]; - glob_t globbuf; - size_t i; - char count = 0; - - /* first compile the schemas if possible */ - ctxt = xmlSchemaNewParserCtxt(filename); - xmlSchemaSetParserErrors(ctxt, - (xmlSchemaValidityErrorFunc) testErrorHandler, - (xmlSchemaValidityWarningFunc) testErrorHandler, - ctxt); - schemas = xmlSchemaParse(ctxt); - xmlSchemaFreeParserCtxt(ctxt); - - /* - * most of the mess is about the output filenames generated by the Makefile - */ - len = strlen(base); - if ((len > 499) || (len < 5)) { - xmlSchemaFree(schemas); - return(-1); - } - len -= 4; /* remove trailing .xsd */ - if (base[len - 2] == '_') { - len -= 2; /* remove subtest number */ - } - if (base[len - 2] == '_') { - len -= 2; /* remove subtest number */ - } - memcpy(prefix, base, len); - prefix[len] = 0; - - snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix); - pattern[499] = 0; - - if (base[len] == '_') { - len += 2; - memcpy(prefix, base, len); - prefix[len] = 0; - } - - globbuf.gl_offs = 0; - glob(pattern, GLOB_DOOFFS, NULL, &globbuf); - for (i = 0;i < globbuf.gl_pathc;i++) { - testErrorsSize = 0; - testErrors[0] = 0; - instance = globbuf.gl_pathv[i]; - base2 = baseFilename(instance); - len = strlen(base2); - if ((len > 6) && (base2[len - 6] == '_')) { - count = base2[len - 5]; - snprintf(result, 499, "result/schemas/%s_%c", - prefix, count); - result[499] = 0; - snprintf(err, 499, "result/schemas/%s_%c.err", - prefix, count); - err[499] = 0; - } else { - fprintf(stderr, "don't know how to process %s\n", instance); - continue; - } - if (schemas == NULL) { - } else { - nb_tests++; - ret = schemasOneTest(filename, instance, result, err, - options, schemas); - if (res != 0) - ret = res; - } - } - globfree(&globbuf); - xmlSchemaFree(schemas); - - return(res); -} - -/************************************************************************ - * * - * Schemas tests * - * * - ************************************************************************/ -static int -rngOneTest(const char *sch, - const char *filename, - const char *result, - const char *err, - int options, - xmlRelaxNGPtr schemas) { - xmlDocPtr doc; - xmlRelaxNGValidCtxtPtr ctxt; - int ret = 0; - char *temp; - FILE *schemasOutput; - - doc = xmlReadFile(filename, NULL, options); - if (doc == NULL) { - fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); - return(-1); - } - - temp = resultFilename(result, "", ".res"); - if (temp == NULL) { - fprintf(stderr, "Out of memory\n"); - fatalError(); - } - schemasOutput = fopen(temp, "wb"); - if (schemasOutput == NULL) { - fprintf(stderr, "failed to open output file %s\n", temp); - xmlFreeDoc(doc); - free(temp); - return(-1); - } - - ctxt = xmlRelaxNGNewValidCtxt(schemas); - xmlRelaxNGSetValidErrors(ctxt, - (xmlRelaxNGValidityErrorFunc) testErrorHandler, - (xmlRelaxNGValidityWarningFunc) testErrorHandler, - ctxt); - ret = xmlRelaxNGValidateDoc(ctxt, doc); - if (ret == 0) { - testErrorHandler(NULL, "%s validates\n", filename); - } else if (ret > 0) { - testErrorHandler(NULL, "%s fails to validate\n", filename); - } else { - testErrorHandler(NULL, "%s validation generated an internal error\n", - filename); - } - fclose(schemasOutput); - if (result) { - if (compareFiles(temp, result)) { - fprintf(stderr, "Result for %s on %s failed\n", filename, sch); - ret = 1; - } - } - unlink(temp); - free(temp); - - if (err != NULL) { - if (compareFileMem(err, testErrors, testErrorsSize)) { - fprintf(stderr, "Error for %s on %s failed\n", filename, sch); - ret = 1; - printf("%s", testErrors); - } - } - - - xmlRelaxNGFreeValidCtxt(ctxt); - xmlFreeDoc(doc); - return(ret); -} -/** - * rngTest: - * @filename: the schemas file - * @result: the file with expected result - * @err: the file with error messages - * - * Parse an RNG schemas and then apply it to the related .xml - * - * Returns 0 in case of success, an error code otherwise - */ -static int -rngTest(const char *filename, - const char *resul ATTRIBUTE_UNUSED, - const char *errr ATTRIBUTE_UNUSED, - int options) { - const char *base = baseFilename(filename); - const char *base2; - const char *instance; - xmlRelaxNGParserCtxtPtr ctxt; - xmlRelaxNGPtr schemas; - int res = 0, len, ret; - char pattern[500]; - char prefix[500]; - char result[500]; - char err[500]; - glob_t globbuf; - size_t i; - char count = 0; - - /* first compile the schemas if possible */ - ctxt = xmlRelaxNGNewParserCtxt(filename); - xmlRelaxNGSetParserErrors(ctxt, - (xmlRelaxNGValidityErrorFunc) testErrorHandler, - (xmlRelaxNGValidityWarningFunc) testErrorHandler, - ctxt); - schemas = xmlRelaxNGParse(ctxt); - xmlRelaxNGFreeParserCtxt(ctxt); - - /* - * most of the mess is about the output filenames generated by the Makefile - */ - len = strlen(base); - if ((len > 499) || (len < 5)) { - xmlRelaxNGFree(schemas); - return(-1); - } - len -= 4; /* remove trailing .rng */ - memcpy(prefix, base, len); - prefix[len] = 0; - - snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix); - pattern[499] = 0; - - globbuf.gl_offs = 0; - glob(pattern, GLOB_DOOFFS, NULL, &globbuf); - for (i = 0;i < globbuf.gl_pathc;i++) { - testErrorsSize = 0; - testErrors[0] = 0; - instance = globbuf.gl_pathv[i]; - base2 = baseFilename(instance); - len = strlen(base2); - if ((len > 6) && (base2[len - 6] == '_')) { - count = base2[len - 5]; - snprintf(result, 499, "result/relaxng/%s_%c", - prefix, count); - result[499] = 0; - snprintf(err, 499, "result/relaxng/%s_%c.err", - prefix, count); - err[499] = 0; - } else { - fprintf(stderr, "don't know how to process %s\n", instance); - continue; - } - if (schemas == NULL) { - } else { - nb_tests++; - ret = rngOneTest(filename, instance, result, err, - options, schemas); - if (res != 0) - ret = res; - } - } - globfree(&globbuf); - xmlRelaxNGFree(schemas); - - return(res); -} - -#ifdef LIBXML_READER_ENABLED -/** - * rngStreamTest: - * @filename: the schemas file - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a set of files with streaming, applying an RNG schemas - * - * Returns 0 in case of success, an error code otherwise - */ -static int -rngStreamTest(const char *filename, - const char *resul ATTRIBUTE_UNUSED, - const char *errr ATTRIBUTE_UNUSED, - int options) { - const char *base = baseFilename(filename); - const char *base2; - const char *instance; - int res = 0, len, ret; - char pattern[500]; - char prefix[500]; - char result[500]; - char err[500]; - glob_t globbuf; - size_t i; - char count = 0; - xmlTextReaderPtr reader; - int disable_err = 0; - - /* - * most of the mess is about the output filenames generated by the Makefile - */ - len = strlen(base); - if ((len > 499) || (len < 5)) { - fprintf(stderr, "len(base) == %d !\n", len); - return(-1); - } - len -= 4; /* remove trailing .rng */ - memcpy(prefix, base, len); - prefix[len] = 0; - - /* - * strictly unifying the error messages is nearly impossible this - * hack is also done in the Makefile - */ - if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) || - (!strcmp(prefix, "tutor3_2"))) - disable_err = 1; - - snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix); - pattern[499] = 0; - - globbuf.gl_offs = 0; - glob(pattern, GLOB_DOOFFS, NULL, &globbuf); - for (i = 0;i < globbuf.gl_pathc;i++) { - testErrorsSize = 0; - testErrors[0] = 0; - instance = globbuf.gl_pathv[i]; - base2 = baseFilename(instance); - len = strlen(base2); - if ((len > 6) && (base2[len - 6] == '_')) { - count = base2[len - 5]; - snprintf(result, 499, "result/relaxng/%s_%c", - prefix, count); - result[499] = 0; - snprintf(err, 499, "result/relaxng/%s_%c.err", - prefix, count); - err[499] = 0; - } else { - fprintf(stderr, "don't know how to process %s\n", instance); - continue; - } - reader = xmlReaderForFile(instance, NULL, options); - if (reader == NULL) { - fprintf(stderr, "Failed to build reder for %s\n", instance); - } - if (disable_err == 1) - ret = streamProcessTest(instance, result, NULL, reader, filename); - else - ret = streamProcessTest(instance, result, err, reader, filename); - xmlFreeTextReader(reader); - if (ret != 0) { - fprintf(stderr, "instance %s failed\n", instance); - res = ret; - } - } - globfree(&globbuf); - - return(res); -} -#endif /* READER */ - -#endif - -#ifdef LIBXML_PATTERN_ENABLED -#ifdef LIBXML_READER_ENABLED -/************************************************************************ - * * - * Patterns tests * - * * - ************************************************************************/ -static void patternNode(FILE *out, xmlTextReaderPtr reader, - const char *pattern, xmlPatternPtr patternc, - xmlStreamCtxtPtr patstream) { - xmlChar *path = NULL; - int match = -1; - int type, empty; - - type = xmlTextReaderNodeType(reader); - empty = xmlTextReaderIsEmptyElement(reader); - - if (type == XML_READER_TYPE_ELEMENT) { - /* do the check only on element start */ - match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader)); - - if (match) { - path = xmlGetNodePath(xmlTextReaderCurrentNode(reader)); - fprintf(out, "Node %s matches pattern %s\n", path, pattern); - } - } - if (patstream != NULL) { - int ret; - - if (type == XML_READER_TYPE_ELEMENT) { - ret = xmlStreamPush(patstream, - xmlTextReaderConstLocalName(reader), - xmlTextReaderConstNamespaceUri(reader)); - if (ret < 0) { - fprintf(out, "xmlStreamPush() failure\n"); - xmlFreeStreamCtxt(patstream); - patstream = NULL; - } else if (ret != match) { - if (path == NULL) { - path = xmlGetNodePath( - xmlTextReaderCurrentNode(reader)); - } - fprintf(out, - "xmlPatternMatch and xmlStreamPush disagree\n"); - fprintf(out, - " pattern %s node %s\n", - pattern, path); - } - - - } - if ((type == XML_READER_TYPE_END_ELEMENT) || - ((type == XML_READER_TYPE_ELEMENT) && (empty))) { - ret = xmlStreamPop(patstream); - if (ret < 0) { - fprintf(out, "xmlStreamPop() failure\n"); - xmlFreeStreamCtxt(patstream); - patstream = NULL; - } - } - } - if (path != NULL) - xmlFree(path); -} - -/** - * patternTest: - * @filename: the schemas file - * @result: the file with expected result - * @err: the file with error messages - * - * Parse a set of files with streaming, applying an RNG schemas - * - * Returns 0 in case of success, an error code otherwise - */ -static int -patternTest(const char *filename, - const char *resul ATTRIBUTE_UNUSED, - const char *err ATTRIBUTE_UNUSED, - int options) { - xmlPatternPtr patternc = NULL; - xmlStreamCtxtPtr patstream = NULL; - FILE *o, *f; - char str[1024]; - char xml[500]; - char result[500]; - int len, i; - int ret = 0, res; - char *temp; - xmlTextReaderPtr reader; - xmlDocPtr doc; - - len = strlen(filename); - len -= 4; - memcpy(xml, filename, len); - xml[len] = 0; - snprintf(result, 499, "result/pattern/%s", baseFilename(xml)); - result[499] = 0; - memcpy(xml + len, ".xml", 5); - - if (!checkTestFile(xml)) { - fprintf(stderr, "Missing xml file %s\n", xml); - return(-1); - } - if (!checkTestFile(result)) { - fprintf(stderr, "Missing result file %s\n", result); - return(-1); - } - f = fopen(filename, "rb"); - if (f == NULL) { - fprintf(stderr, "Failed to open %s\n", filename); - return(-1); - } - temp = resultFilename(filename, "", ".res"); - if (temp == NULL) { - fprintf(stderr, "Out of memory\n"); - fatalError(); - } - o = fopen(temp, "wb"); - if (o == NULL) { - fprintf(stderr, "failed to open output file %s\n", temp); - fclose(f); - free(temp); - return(-1); - } - while (1) { - /* - * read one line in string buffer. - */ - if (fgets (&str[0], sizeof (str) - 1, f) == NULL) - break; - - /* - * remove the ending spaces - */ - i = strlen(str); - while ((i > 0) && - ((str[i - 1] == '\n') || (str[i - 1] == '\r') || - (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { - i--; - str[i] = 0; - } - doc = xmlReadFile(xml, NULL, options); - if (doc == NULL) { - fprintf(stderr, "Failed to parse %s\n", xml); - ret = 1; - } else { - xmlNodePtr root; - const xmlChar *namespaces[22]; - int j; - xmlNsPtr ns; - - root = xmlDocGetRootElement(doc); - for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) { - namespaces[j++] = ns->href; - namespaces[j++] = ns->prefix; - } - namespaces[j++] = NULL; - namespaces[j++] = NULL; - - patternc = xmlPatterncompile((const xmlChar *) str, doc->dict, - 0, &namespaces[0]); - if (patternc == NULL) { - testErrorHandler(NULL, - "Pattern %s failed to compile\n", str); - xmlFreeDoc(doc); - ret = 1; - continue; - } - patstream = xmlPatternGetStreamCtxt(patternc); - if (patstream != NULL) { - ret = xmlStreamPush(patstream, NULL, NULL); - if (ret < 0) { - fprintf(stderr, "xmlStreamPush() failure\n"); - xmlFreeStreamCtxt(patstream); - patstream = NULL; - } - } - nb_tests++; - - reader = xmlReaderWalker(doc); - res = xmlTextReaderRead(reader); - while (res == 1) { - patternNode(o, reader, str, patternc, patstream); - res = xmlTextReaderRead(reader); - } - if (res != 0) { - fprintf(o, "%s : failed to parse\n", filename); - } - xmlFreeTextReader(reader); - xmlFreeDoc(doc); - xmlFreeStreamCtxt(patstream); - patstream = NULL; - xmlFreePattern(patternc); - - } - } - - fclose(f); - fclose(o); - - ret = compareFiles(temp, result); - if (ret) { - fprintf(stderr, "Result for %s failed\n", filename); - ret = 1; - } - unlink(temp); - free(temp); - return(ret); -} -#endif /* READER */ -#endif /* PATTERN */ -#ifdef LIBXML_C14N_ENABLED -/************************************************************************ - * * - * Canonicalization tests * - * * - ************************************************************************/ -static xmlXPathObjectPtr -load_xpath_expr (xmlDocPtr parent_doc, const char* filename) { - xmlXPathObjectPtr xpath; - xmlDocPtr doc; - xmlChar *expr; - xmlXPathContextPtr ctx; - xmlNodePtr node; - xmlNsPtr ns; - - /* - * load XPath expr as a file - */ - xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; - xmlSubstituteEntitiesDefault(1); - - doc = xmlParseFile(filename); - if (doc == NULL) { - fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename); - return(NULL); - } - - /* - * Check the document is of the right kind - */ - if(xmlDocGetRootElement(doc) == NULL) { - fprintf(stderr,"Error: empty document for file \"%s\"\n", filename); - xmlFreeDoc(doc); - return(NULL); - } - - node = doc->children; - while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) { - node = node->next; - } - - if(node == NULL) { - fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename); - xmlFreeDoc(doc); - return(NULL); - } - - expr = xmlNodeGetContent(node); - if(expr == NULL) { - fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename); - xmlFreeDoc(doc); - return(NULL); - } - - ctx = xmlXPathNewContext(parent_doc); - if(ctx == NULL) { - fprintf(stderr,"Error: unable to create new context\n"); - xmlFree(expr); - xmlFreeDoc(doc); - return(NULL); - } - - /* - * Register namespaces - */ - ns = node->nsDef; - while(ns != NULL) { - if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) { - fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href); - xmlFree(expr); - xmlXPathFreeContext(ctx); - xmlFreeDoc(doc); - return(NULL); - } - ns = ns->next; - } - - /* - * Evaluate xpath - */ - xpath = xmlXPathEvalExpression(expr, ctx); - if(xpath == NULL) { - fprintf(stderr,"Error: unable to evaluate xpath expression\n"); - xmlFree(expr); - xmlXPathFreeContext(ctx); - xmlFreeDoc(doc); - return(NULL); - } - - /* print_xpath_nodes(xpath->nodesetval); */ - - xmlFree(expr); - xmlXPathFreeContext(ctx); - xmlFreeDoc(doc); - return(xpath); -} - -/* - * Macro used to grow the current buffer. - */ -#define xxx_growBufferReentrant() { \ - buffer_size *= 2; \ - buffer = (xmlChar **) \ - xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \ - if (buffer == NULL) { \ - perror("realloc failed"); \ - return(NULL); \ - } \ -} - -static xmlChar ** -parse_list(xmlChar *str) { - xmlChar **buffer; - xmlChar **out = NULL; - int buffer_size = 0; - int len; - - if(str == NULL) { - return(NULL); - } - - len = xmlStrlen(str); - if((str[0] == '\'') && (str[len - 1] == '\'')) { - str[len - 1] = '\0'; - str++; - len -= 2; - } - /* - * allocate an translation buffer. - */ - buffer_size = 1000; - buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*)); - if (buffer == NULL) { - perror("malloc failed"); - return(NULL); - } - out = buffer; - - while(*str != '\0') { - if (out - buffer > buffer_size - 10) { - int indx = out - buffer; - - xxx_growBufferReentrant(); - out = &buffer[indx]; - } - (*out++) = str; - while(*str != ',' && *str != '\0') ++str; - if(*str == ',') *(str++) = '\0'; - } - (*out) = NULL; - return buffer; -} - -static int -c14nRunTest(const char* xml_filename, int with_comments, int exclusive, - const char* xpath_filename, const char *ns_filename, - const char* result_file) { - xmlDocPtr doc; - xmlXPathObjectPtr xpath = NULL; - xmlChar *result = NULL; - int ret; - xmlChar **inclusive_namespaces = NULL; - const char *nslist = NULL; - int nssize; - - - /* - * build an XML tree from a the file; we need to add default - * attributes and resolve all character and entities references - */ - xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; - xmlSubstituteEntitiesDefault(1); - - doc = xmlParseFile(xml_filename); - if (doc == NULL) { - fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename); - return(-1); - } - - /* - * Check the document is of the right kind - */ - if(xmlDocGetRootElement(doc) == NULL) { - fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename); - xmlFreeDoc(doc); - return(-1); - } - - /* - * load xpath file if specified - */ - if(xpath_filename) { - xpath = load_xpath_expr(doc, xpath_filename); - if(xpath == NULL) { - fprintf(stderr,"Error: unable to evaluate xpath expression\n"); - xmlFreeDoc(doc); - return(-1); - } - } - - if (ns_filename != NULL) { - if (loadMem(ns_filename, &nslist, &nssize)) { - fprintf(stderr,"Error: unable to evaluate xpath expression\n"); - if(xpath != NULL) xmlXPathFreeObject(xpath); - xmlFreeDoc(doc); - return(-1); - } - inclusive_namespaces = parse_list((xmlChar *) nslist); - } - - /* - * Canonical form - */ - /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */ - ret = xmlC14NDocDumpMemory(doc, - (xpath) ? xpath->nodesetval : NULL, - exclusive, inclusive_namespaces, - with_comments, &result); - if (ret >= 0) { - if(result != NULL) { - if (compareFileMem(result_file, (const char *) result, ret)) { - fprintf(stderr, "Result mismatch for %s\n", xml_filename); - ret = -1; - } - } - } else { - fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret); - ret = -1; - } - - /* - * Cleanup - */ - if (result != NULL) xmlFree(result); - if(xpath != NULL) xmlXPathFreeObject(xpath); - if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces); - if (nslist != NULL) free((char *) nslist); - xmlFreeDoc(doc); - - return(ret); -} - -static int -c14nCommonTest(const char *filename, int with_comments, int exclusive, - const char *subdir) { - char buf[500]; - char prefix[500]; - const char *base; - int len; - char *result = NULL; - char *xpath = NULL; - char *ns = NULL; - int ret = 0; - - base = baseFilename(filename); - len = strlen(base); - len -= 4; - memcpy(prefix, base, len); - prefix[len] = 0; - - snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix); - if (!checkTestFile(buf)) { - fprintf(stderr, "Missing result file %s", buf); - return(-1); - } - result = strdup(buf); - snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix); - if (checkTestFile(buf)) { - xpath = strdup(buf); - } - snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix); - if (checkTestFile(buf)) { - ns = strdup(buf); - } - - nb_tests++; - if (c14nRunTest(filename, with_comments, exclusive, - xpath, ns, result) < 0) - ret = 1; - - if (result != NULL) free(result); - if (xpath != NULL) free(xpath); - if (ns != NULL) free(ns); - return(ret); -} - -static int -c14nWithCommentTest(const char *filename, - const char *resul ATTRIBUTE_UNUSED, - const char *err ATTRIBUTE_UNUSED, - int options ATTRIBUTE_UNUSED) { - return(c14nCommonTest(filename, 1, 0, "with-comments")); -} -static int -c14nWithoutCommentTest(const char *filename, - const char *resul ATTRIBUTE_UNUSED, - const char *err ATTRIBUTE_UNUSED, - int options ATTRIBUTE_UNUSED) { - return(c14nCommonTest(filename, 0, 0, "without-comments")); -} -static int -c14nExcWithoutCommentTest(const char *filename, - const char *resul ATTRIBUTE_UNUSED, - const char *err ATTRIBUTE_UNUSED, - int options ATTRIBUTE_UNUSED) { - return(c14nCommonTest(filename, 0, 1, "exc-without-comments")); -} -#endif -#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) -/************************************************************************ - * * - * Catalog and threads test * - * * - ************************************************************************/ - -/* - * mostly a cut and paste from testThreads.c - */ -#define MAX_ARGC 20 - -static const char *catalog = "test/threads/complex.xml"; -static const char *testfiles[] = { - "test/threads/abc.xml", - "test/threads/acb.xml", - "test/threads/bac.xml", - "test/threads/bca.xml", - "test/threads/cab.xml", - "test/threads/cba.xml", - "test/threads/invalid.xml", -}; - -const char *Okay = "OK"; -const char *Failed = "Failed"; - -#ifndef xmlDoValidityCheckingDefaultValue -#error xmlDoValidityCheckingDefaultValue is not a macro -#endif -#ifndef xmlGenericErrorContext -#error xmlGenericErrorContext is not a macro -#endif - -static void * -thread_specific_data(void *private_data) -{ - xmlDocPtr myDoc; - const char *filename = (const char *) private_data; - int okay = 1; - - if (!strcmp(filename, "test/threads/invalid.xml")) { - xmlDoValidityCheckingDefaultValue = 0; - xmlGenericErrorContext = stdout; - } else { - xmlDoValidityCheckingDefaultValue = 1; - xmlGenericErrorContext = stderr; - } - myDoc = xmlParseFile(filename); - if (myDoc) { - xmlFreeDoc(myDoc); - } else { - printf("parse failed\n"); - okay = 0; - } - if (!strcmp(filename, "test/threads/invalid.xml")) { - if (xmlDoValidityCheckingDefaultValue != 0) { - printf("ValidityCheckingDefaultValue override failed\n"); - okay = 0; - } - if (xmlGenericErrorContext != stdout) { - printf("xmlGenericErrorContext override failed\n"); - okay = 0; - } - } else { - if (xmlDoValidityCheckingDefaultValue != 1) { - printf("ValidityCheckingDefaultValue override failed\n"); - okay = 0; - } - if (xmlGenericErrorContext != stderr) { - printf("xmlGenericErrorContext override failed\n"); - okay = 0; - } - } - if (okay == 0) - return ((void *) Failed); - return ((void *) Okay); -} - -#if defined(linux) || defined(solaris) - -#include - -static pthread_t tid[MAX_ARGC]; - -static int -testThread(void) -{ - unsigned int i, repeat; - unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); - void *results[MAX_ARGC]; - int ret; - int res = 0; - - xmlInitParser(); - - for (repeat = 0; repeat < 500; repeat++) { - xmlLoadCatalog(catalog); - nb_tests++; - - for (i = 0; i < num_threads; i++) { - results[i] = NULL; - tid[i] = (pthread_t) - 1; - } - - for (i = 0; i < num_threads; i++) { - ret = pthread_create(&tid[i], 0, thread_specific_data, - (void *) testfiles[i]); - if (ret != 0) { - fprintf(stderr, "pthread_create failed\n"); - return (1); - } - } - for (i = 0; i < num_threads; i++) { - ret = pthread_join(tid[i], &results[i]); - if (ret != 0) { - fprintf(stderr, "pthread_join failed\n"); - return (1); - } - } - - xmlCatalogCleanup(); - for (i = 0; i < num_threads; i++) - if (results[i] != (void *) Okay) { - fprintf(stderr, "Thread %d handling %s failed\n", - i, testfiles[i]); - res = 1; - } - } - return (res); -} - -#elif defined WIN32 -#include -#include - -#define TEST_REPEAT_COUNT 500 - -static HANDLE tid[MAX_ARGC]; - -static DWORD WINAPI -win32_thread_specific_data(void *private_data) -{ - return((DWORD) thread_specific_data(private_data)); -} - -static int -testThread(void) -{ - unsigned int i, repeat; - unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); - DWORD results[MAX_ARGC]; - BOOL ret; - int res = 0; - - xmlInitParser(); - for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) { - xmlLoadCatalog(catalog); - nb_tests++; - - for (i = 0; i < num_threads; i++) { - results[i] = 0; - tid[i] = (HANDLE) - 1; - } - - for (i = 0; i < num_threads; i++) { - DWORD useless; - - tid[i] = CreateThread(NULL, 0, - win32_thread_specific_data, - (void *) testfiles[i], 0, - &useless); - if (tid[i] == NULL) { - fprintf(stderr, "CreateThread failed\n"); - return(1); - } - } - - if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) == - WAIT_FAILED) { - fprintf(stderr, "WaitForMultipleObjects failed\n"); - return(1); - } - - for (i = 0; i < num_threads; i++) { - ret = GetExitCodeThread(tid[i], &results[i]); - if (ret == 0) { - fprintf(stderr, "GetExitCodeThread failed\n"); - return(1); - } - CloseHandle(tid[i]); - } - - xmlCatalogCleanup(); - for (i = 0; i < num_threads; i++) { - if (results[i] != (DWORD) Okay) { - fprintf(stderr, "Thread %d handling %s failed\n", - i, testfiles[i]); - res = 1; - } - } - } - - return (res); -} - -#elif defined __BEOS__ -#include - -static thread_id tid[MAX_ARGC]; - -static int -testThread(void) -{ - unsigned int i, repeat; - unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); - void *results[MAX_ARGC]; - status_t ret; - int res = 0; - - xmlInitParser(); - for (repeat = 0; repeat < 500; repeat++) { - xmlLoadCatalog(catalog); - for (i = 0; i < num_threads; i++) { - results[i] = NULL; - tid[i] = (thread_id) - 1; - } - for (i = 0; i < num_threads; i++) { - tid[i] = - spawn_thread(thread_specific_data, "xmlTestThread", - B_NORMAL_PRIORITY, (void *) testfiles[i]); - if (tid[i] < B_OK) { - fprintf(stderr, "beos_thread_create failed\n"); - return (1); - } - printf("beos_thread_create %d -> %d\n", i, tid[i]); - } - for (i = 0; i < num_threads; i++) { - ret = wait_for_thread(tid[i], &results[i]); - printf("beos_thread_wait %d -> %d\n", i, ret); - if (ret != B_OK) { - fprintf(stderr, "beos_thread_wait failed\n"); - return (1); - } - } - - xmlCatalogCleanup(); - ret = B_OK; - for (i = 0; i < num_threads; i++) - if (results[i] != (void *) Okay) { - printf("Thread %d handling %s failed\n", i, testfiles[i]); - ret = B_ERROR; - } - } - if (ret != B_OK) - return(1); - return (0); -} -#else -static int -testThread(void) -{ - fprintf(stderr, - "Specific platform thread support not detected\n"); - return (-1); -} -#endif -static int -threadsTest(const char *filename ATTRIBUTE_UNUSED, - const char *resul ATTRIBUTE_UNUSED, - const char *err ATTRIBUTE_UNUSED, - int options ATTRIBUTE_UNUSED) { - return(testThread()); -} -#endif -/************************************************************************ - * * - * Tests Descriptions * - * * - ************************************************************************/ - -static -testDesc testDescriptions[] = { - { "XML regression tests" , - oldParseTest, "./test/*", "result/", "", NULL, - 0 }, - { "XML regression tests on memory" , - memParseTest, "./test/*", "result/", "", NULL, - 0 }, - { "XML entity subst regression tests" , - noentParseTest, "./test/*", "result/noent/", "", NULL, - XML_PARSE_NOENT }, - { "XML Namespaces regression tests", - errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err", - 0 }, - { "Error cases regression tests", - errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err", - 0 }, -#ifdef LIBXML_READER_ENABLED - { "Error cases stream regression tests", - streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str", - 0 }, - { "Reader regression tests", - streamParseTest, "./test/*", "result/", ".rdr", NULL, - 0 }, - { "Reader entities substitution regression tests", - streamParseTest, "./test/*", "result/", ".rde", NULL, - XML_PARSE_NOENT }, - { "Reader on memory regression tests", - streamMemParseTest, "./test/*", "result/", ".rdr", NULL, - 0 }, - { "Walker regression tests", - walkerParseTest, "./test/*", "result/", ".rdr", NULL, - 0 }, -#endif -#ifdef LIBXML_SAX1_ENABLED - { "SAX1 callbacks regression tests" , - saxParseTest, "./test/*", "result/", ".sax", NULL, - XML_PARSE_SAX1 }, - { "SAX2 callbacks regression tests" , - saxParseTest, "./test/*", "result/", ".sax2", NULL, - 0 }, -#endif -#ifdef LIBXML_PUSH_ENABLED - { "XML push regression tests" , - pushParseTest, "./test/*", "result/", "", NULL, - 0 }, -#endif -#ifdef LIBXML_HTML_ENABLED - { "HTML regression tests" , - errParseTest, "./test/HTML/*", "result/HTML/", "", ".err", - XML_PARSE_HTML }, -#ifdef LIBXML_PUSH_ENABLED - { "Push HTML regression tests" , - pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err", - XML_PARSE_HTML }, -#endif -#ifdef LIBXML_SAX1_ENABLED - { "HTML SAX regression tests" , - saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL, - XML_PARSE_HTML }, -#endif -#endif -#ifdef LIBXML_VALID_ENABLED - { "Valid documents regression tests" , - errParseTest, "./test/VCM/*", NULL, NULL, NULL, - XML_PARSE_DTDVALID }, - { "Validity checking regression tests" , - errParseTest, "./test/VC/*", "result/VC/", NULL, "", - XML_PARSE_DTDVALID }, - { "General documents valid regression tests" , - errParseTest, "./test/valid/*", "result/valid/", "", ".err", - XML_PARSE_DTDVALID }, -#endif -#ifdef LIBXML_XINCLUDE_ENABLED - { "XInclude regression tests" , - errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL, - /* Ignore errors at this point ".err", */ - XML_PARSE_XINCLUDE }, - { "XInclude xmlReader regression tests", - streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", - /* Ignore errors at this point ".err", */ - NULL, XML_PARSE_XINCLUDE }, - { "XInclude regression tests stripping include nodes" , - errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL, - /* Ignore errors at this point ".err", */ - XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, - { "XInclude xmlReader regression tests stripping include nodes", - streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", - /* Ignore errors at this point ".err", */ - NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, -#endif -#ifdef LIBXML_XPATH_ENABLED -#ifdef LIBXML_DEBUG_ENABLED - { "XPath expressions regression tests" , - xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL, - 0 }, - { "XPath document queries regression tests" , - xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, - 0 }, -#ifdef LIBXML_XPTR_ENABLED - { "XPointer document queries regression tests" , - xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, - 0 }, -#endif - { "xml:id regression tests" , - xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err", - 0 }, -#endif -#endif - { "URI parsing tests" , - uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL, - 0 }, - { "URI base composition tests" , - uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL, - 0 }, -#ifdef LIBXML_SCHEMAS_ENABLED - { "Schemas regression tests" , - schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL, - 0 }, - { "Relax-NG regression tests" , - rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL, - XML_PARSE_DTDATTR | XML_PARSE_NOENT }, -#ifdef LIBXML_READER_ENABLED - { "Relax-NG streaming regression tests" , - rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL, - XML_PARSE_DTDATTR | XML_PARSE_NOENT }, -#endif -#endif -#ifdef LIBXML_PATTERN_ENABLED -#ifdef LIBXML_READER_ENABLED - { "Pattern regression tests" , - patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL, - 0 }, -#endif -#endif -#ifdef LIBXML_C14N_ENABLED - { "C14N with comments regression tests" , - c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL, - 0 }, - { "C14N without comments regression tests" , - c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL, - 0 }, - { "C14N exclusive without comments regression tests" , - c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL, - 0 }, -#endif -#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) - { "Catalog and Threads regression tests" , - threadsTest, NULL, NULL, NULL, NULL, - 0 }, -#endif - {NULL, NULL, NULL, NULL, NULL, NULL, 0} -}; - -/************************************************************************ - * * - * The main code driving the tests * - * * - ************************************************************************/ - -static int -launchTests(testDescPtr tst) { - int res = 0, err = 0; - size_t i; - char *result; - char *error; - int mem; - - if (tst == NULL) return(-1); - if (tst->in != NULL) { - glob_t globbuf; - - globbuf.gl_offs = 0; - glob(tst->in, GLOB_DOOFFS, NULL, &globbuf); - for (i = 0;i < globbuf.gl_pathc;i++) { - if (!checkTestFile(globbuf.gl_pathv[i])) - continue; - if (tst->suffix != NULL) { - result = resultFilename(globbuf.gl_pathv[i], tst->out, - tst->suffix); - if (result == NULL) { - fprintf(stderr, "Out of memory !\n"); - fatalError(); - } - } else { - result = NULL; - } - if (tst->err != NULL) { - error = resultFilename(globbuf.gl_pathv[i], tst->out, - tst->err); - if (error == NULL) { - fprintf(stderr, "Out of memory !\n"); - fatalError(); - } - } else { - error = NULL; - } - if ((result) &&(!checkTestFile(result))) { - fprintf(stderr, "Missing result file %s\n", result); - } else if ((error) &&(!checkTestFile(error))) { - fprintf(stderr, "Missing error file %s\n", error); - } else { - mem = xmlMemUsed(); - extraMemoryFromResolver = 0; - testErrorsSize = 0; - testErrors[0] = 0; - res = tst->func(globbuf.gl_pathv[i], result, error, - tst->options); - xmlResetLastError(); - if (res != 0) { - fprintf(stderr, "File %s generated an error\n", - globbuf.gl_pathv[i]); - nb_errors++; - err++; - } - else if (xmlMemUsed() != mem) { - if ((xmlMemUsed() != mem) && - (extraMemoryFromResolver == 0)) { - fprintf(stderr, "File %s leaked %d bytes\n", - globbuf.gl_pathv[i], xmlMemUsed() - mem); - nb_leaks++; - err++; - } - } - testErrorsSize = 0; - } - if (result) - free(result); - if (error) - free(error); - } - globfree(&globbuf); - } else { - testErrorsSize = 0; - testErrors[0] = 0; - extraMemoryFromResolver = 0; - res = tst->func(NULL, NULL, NULL, tst->options); - if (res != 0) { - nb_errors++; - err++; - } - } - return(err); -} - -int -main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { - int i = 0, res, ret = 0; - int verbose = 0; - int old_errors, old_tests, old_leaks; - - initializeLibxml2(); - - if ((argc >= 2) && (!strcmp(argv[1], "-v"))) - verbose = 1; - for (i = 0; testDescriptions[i].func != NULL; i++) { - old_errors = nb_errors; - old_tests = nb_tests; - old_leaks = nb_leaks; - if (testDescriptions[i].desc != NULL) - printf("## %s\n", testDescriptions[i].desc); - res = launchTests(&testDescriptions[i]); - if (res != 0) - ret++; - if (verbose) { - 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); - } - xmlCleanupParser(); - xmlMemoryDump(); - - return(ret); -} - -#else /* ! LIBXML_OUTPUT_ENABLED */ -int -main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { - fprintf(stderr, "runtest requires output to be enabled in libxml2\n"); - return(1); -} -#endif +#if !defined(_WIN32) + if (siz != info.st_size) { + free(base); + return(-1); + } +#endif + base[siz] = 0; + *mem = base; + *size = siz; + return(0); +} + +static int unloadMem(const char *mem) { + free((char *)mem); + return(0); +} + +/************************************************************************ + * * + * Tests implementations * + * * + ************************************************************************/ + +/************************************************************************ + * * + * Parse to SAX based tests * + * * + ************************************************************************/ + +FILE *SAXdebug = NULL; + +/* + * empty SAX block + */ +xmlSAXHandler emptySAXHandlerStruct = { + NULL, /* internalSubset */ + NULL, /* isStandalone */ + NULL, /* hasInternalSubset */ + NULL, /* hasExternalSubset */ + NULL, /* resolveEntity */ + NULL, /* getEntity */ + NULL, /* entityDecl */ + NULL, /* notationDecl */ + NULL, /* attributeDecl */ + NULL, /* elementDecl */ + NULL, /* unparsedEntityDecl */ + NULL, /* setDocumentLocator */ + NULL, /* startDocument */ + NULL, /* endDocument */ + NULL, /* startElement */ + NULL, /* endElement */ + NULL, /* reference */ + NULL, /* characters */ + NULL, /* ignorableWhitespace */ + NULL, /* processingInstruction */ + NULL, /* comment */ + NULL, /* xmlParserWarning */ + NULL, /* xmlParserError */ + NULL, /* xmlParserError */ + NULL, /* getParameterEntity */ + NULL, /* cdataBlock; */ + NULL, /* externalSubset; */ + 1, + NULL, + NULL, /* startElementNs */ + NULL, /* endElementNs */ + NULL /* xmlStructuredErrorFunc */ +}; + +static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct; +int callbacks = 0; +int quiet = 0; + +/** + * isStandaloneDebug: + * @ctxt: An XML parser context + * + * Is this document tagged standalone ? + * + * Returns 1 if true + */ +static int +isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (quiet) + return(0); + fprintf(SAXdebug, "SAX.isStandalone()\n"); + return(0); +} + +/** + * hasInternalSubsetDebug: + * @ctxt: An XML parser context + * + * Does this document has an internal subset + * + * Returns 1 if true + */ +static int +hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (quiet) + return(0); + fprintf(SAXdebug, "SAX.hasInternalSubset()\n"); + return(0); +} + +/** + * hasExternalSubsetDebug: + * @ctxt: An XML parser context + * + * Does this document has an external subset + * + * Returns 1 if true + */ +static int +hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (quiet) + return(0); + fprintf(SAXdebug, "SAX.hasExternalSubset()\n"); + return(0); +} + +/** + * internalSubsetDebug: + * @ctxt: An XML parser context + * + * Does this document has an internal subset + */ +static void +internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.internalSubset(%s,", name); + if (ExternalID == NULL) + fprintf(SAXdebug, " ,"); + else + fprintf(SAXdebug, " %s,", ExternalID); + if (SystemID == NULL) + fprintf(SAXdebug, " )\n"); + else + fprintf(SAXdebug, " %s)\n", SystemID); +} + +/** + * externalSubsetDebug: + * @ctxt: An XML parser context + * + * Does this document has an external subset + */ +static void +externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.externalSubset(%s,", name); + if (ExternalID == NULL) + fprintf(SAXdebug, " ,"); + else + fprintf(SAXdebug, " %s,", ExternalID); + if (SystemID == NULL) + fprintf(SAXdebug, " )\n"); + else + fprintf(SAXdebug, " %s)\n", SystemID); +} + +/** + * resolveEntityDebug: + * @ctxt: An XML parser context + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * Special entity resolver, better left to the parser, it has + * more context than the application layer. + * The default behaviour is to NOT resolve the entities, in that case + * the ENTITY_REF nodes are built in the structure (and the parameter + * values). + * + * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. + */ +static xmlParserInputPtr +resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId) +{ + callbacks++; + if (quiet) + return(NULL); + /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ + + + fprintf(SAXdebug, "SAX.resolveEntity("); + if (publicId != NULL) + fprintf(SAXdebug, "%s", (char *)publicId); + else + fprintf(SAXdebug, " "); + if (systemId != NULL) + fprintf(SAXdebug, ", %s)\n", (char *)systemId); + else + fprintf(SAXdebug, ", )\n"); +/********* + if (systemId != NULL) { + return(xmlNewInputFromFile(ctxt, (char *) systemId)); + } + *********/ + return(NULL); +} + +/** + * getEntityDebug: + * @ctxt: An XML parser context + * @name: The entity name + * + * Get an entity by name + * + * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. + */ +static xmlEntityPtr +getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) +{ + callbacks++; + if (quiet) + return(NULL); + fprintf(SAXdebug, "SAX.getEntity(%s)\n", name); + return(NULL); +} + +/** + * getParameterEntityDebug: + * @ctxt: An XML parser context + * @name: The entity name + * + * Get a parameter entity by name + * + * Returns the xmlParserInputPtr + */ +static xmlEntityPtr +getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) +{ + callbacks++; + if (quiet) + return(NULL); + fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name); + return(NULL); +} + + +/** + * entityDeclDebug: + * @ctxt: An XML parser context + * @name: the entity name + * @type: the entity type + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @content: the entity value (without processing). + * + * An entity definition has been parsed + */ +static void +entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, + const xmlChar *publicId, const xmlChar *systemId, xmlChar *content) +{ +const xmlChar *nullstr = BAD_CAST "(null)"; + /* not all libraries handle printing null pointers nicely */ + if (publicId == NULL) + publicId = nullstr; + if (systemId == NULL) + systemId = nullstr; + if (content == NULL) + content = (xmlChar *)nullstr; + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n", + name, type, publicId, systemId, content); +} + +/** + * attributeDeclDebug: + * @ctxt: An XML parser context + * @name: the attribute name + * @type: the attribute type + * + * An attribute definition has been parsed + */ +static void +attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem, + const xmlChar * name, int type, int def, + const xmlChar * defaultValue, xmlEnumerationPtr tree) +{ + callbacks++; + if (quiet) + return; + if (defaultValue == NULL) + fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n", + elem, name, type, def); + else + fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n", + elem, name, type, def, defaultValue); + xmlFreeEnumeration(tree); +} + +/** + * elementDeclDebug: + * @ctxt: An XML parser context + * @name: the element name + * @type: the element type + * @content: the element value (without processing). + * + * An element definition has been parsed + */ +static void +elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, + xmlElementContentPtr content ATTRIBUTE_UNUSED) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n", + name, type); +} + +/** + * notationDeclDebug: + * @ctxt: An XML parser context + * @name: The name of the notation + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * What to do when a notation declaration has been parsed. + */ +static void +notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n", + (char *) name, (char *) publicId, (char *) systemId); +} + +/** + * unparsedEntityDeclDebug: + * @ctxt: An XML parser context + * @name: The name of the entity + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @notationName: the name of the notation + * + * What to do when an unparsed entity declaration is parsed + */ +static void +unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId, + const xmlChar *notationName) +{ +const xmlChar *nullstr = BAD_CAST "(null)"; + + if (publicId == NULL) + publicId = nullstr; + if (systemId == NULL) + systemId = nullstr; + if (notationName == NULL) + notationName = nullstr; + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n", + (char *) name, (char *) publicId, (char *) systemId, + (char *) notationName); +} + +/** + * setDocumentLocatorDebug: + * @ctxt: An XML parser context + * @loc: A SAX Locator + * + * Receive the document locator at startup, actually xmlDefaultSAXLocator + * Everything is available on the context, so this is useless in our case. + */ +static void +setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.setDocumentLocator()\n"); +} + +/** + * startDocumentDebug: + * @ctxt: An XML parser context + * + * called when the document start being processed. + */ +static void +startDocumentDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.startDocument()\n"); +} + +/** + * endDocumentDebug: + * @ctxt: An XML parser context + * + * called when the document end has been detected. + */ +static void +endDocumentDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.endDocument()\n"); +} + +/** + * startElementDebug: + * @ctxt: An XML parser context + * @name: The element name + * + * called when an opening tag has been processed. + */ +static void +startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts) +{ + int i; + + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.startElement(%s", (char *) name); + if (atts != NULL) { + for (i = 0;(atts[i] != NULL);i++) { + fprintf(SAXdebug, ", %s='", atts[i++]); + if (atts[i] != NULL) + fprintf(SAXdebug, "%s'", atts[i]); + } + } + fprintf(SAXdebug, ")\n"); +} + +/** + * endElementDebug: + * @ctxt: An XML parser context + * @name: The element name + * + * called when the end of an element has been detected. + */ +static void +endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) +{ + callbacks++; + if (quiet) + return; + fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name); +} + +/** + * charactersDebug: + * @ctxt: An XML parser context + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * receiving some chars from the parser. + * Question: how much at a time ??? + */ +static void +charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) +{ + char output[40]; + int i; + + callbacks++; + if (quiet) + return; + for (i = 0;(i= size) { +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + htmlParseChunk(ctxt, base + cur, size - cur, 1); + else +#endif + xmlParseChunk(ctxt, base + cur, size - cur, 1); + break; + } else { +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + htmlParseChunk(ctxt, base + cur, 1024, 0); + else +#endif + xmlParseChunk(ctxt, base + cur, 1024, 0); + cur += 1024; + } + } + doc = ctxt->myDoc; +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + res = 1; + else +#endif + res = ctxt->wellFormed; + xmlFreeParserCtxt(ctxt); + free((char *)base); + if (!res) { + xmlFreeDoc(doc); + fprintf(stderr, "Failed to parse %s\n", filename); + return(-1); + } +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) + htmlDocDumpMemory(doc, (xmlChar **) &base, &size); + else +#endif + xmlDocDumpMemory(doc, (xmlChar **) &base, &size); + xmlFreeDoc(doc); + res = compareFileMem(result, base, size); + if ((base == NULL) || (res != 0)) { + if (base != NULL) + xmlFree((char *)base); + fprintf(stderr, "Result for %s failed\n", filename); + return(-1); + } + xmlFree((char *)base); + if (err != NULL) { + res = compareFileMem(err, testErrors, testErrorsSize); + if (res != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + return(-1); + } + } + return(0); +} +#endif + +/** + * memParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages: unused + * + * Parse a file using the old xmlReadMemory API, then serialize back + * reparse the result and serialize again, then check for deviation + * in serialization. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +memParseTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + xmlDocPtr doc; + const char *base; + int size, res; + + nb_tests++; + /* + * load and parse the memory + */ + if (loadMem(filename, &base, &size) != 0) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + + doc = xmlReadMemory(base, size, filename, NULL, 0); + unloadMem(base); + if (doc == NULL) { + return(1); + } + xmlDocDumpMemory(doc, (xmlChar **) &base, &size); + xmlFreeDoc(doc); + res = compareFileMem(result, base, size); + if ((base == NULL) || (res != 0)) { + if (base != NULL) + xmlFree((char *)base); + fprintf(stderr, "Result for %s failed\n", filename); + return(-1); + } + xmlFree((char *)base); + return(0); +} + +/** + * noentParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages: unused + * + * Parse a file with entity resolution, then serialize back + * reparse the result and serialize again, then check for deviation + * in serialization. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +noentParseTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options) { + xmlDocPtr doc; + char *temp; + int res = 0; + + nb_tests++; + /* + * base of the test, parse with the old API + */ + doc = xmlReadFile(filename, NULL, options); + if (doc == NULL) + return(1); + temp = resultFilename(filename, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + xmlSaveFile(temp, doc); + if (compareFiles(temp, result)) { + res = 1; + } + xmlFreeDoc(doc); + + /* + * Parse the saved result to make sure the round trip is okay + */ + doc = xmlReadFile(filename, NULL, options); + if (doc == NULL) + return(1); + xmlSaveFile(temp, doc); + if (compareFiles(temp, result)) { + res = 1; + } + xmlFreeDoc(doc); + + unlink(temp); + free(temp); + return(res); +} + +/** + * errParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the xmlReadFile API and check for errors. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +errParseTest(const char *filename, const char *result, const char *err, + int options) { + xmlDocPtr doc; + const char *base = NULL; + int size, res = 0; + + nb_tests++; +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) { + doc = htmlReadFile(filename, NULL, options); + } else +#endif +#ifdef LIBXML_XINCLUDE_ENABLED + if (options & XML_PARSE_XINCLUDE) { + doc = xmlReadFile(filename, NULL, options); + xmlXIncludeProcessFlags(doc, options); + } else +#endif + { + xmlGetWarningsDefaultValue = 1; + doc = xmlReadFile(filename, NULL, options); + } + xmlGetWarningsDefaultValue = 0; + if (result) { + if (doc == NULL) { + base = ""; + size = 0; + } else { +#ifdef LIBXML_HTML_ENABLED + if (options & XML_PARSE_HTML) { + htmlDocDumpMemory(doc, (xmlChar **) &base, &size); + } else +#endif + xmlDocDumpMemory(doc, (xmlChar **) &base, &size); + } + res = compareFileMem(result, base, size); + } + if (doc != NULL) { + if (base != NULL) + xmlFree((char *)base); + xmlFreeDoc(doc); + } + if (res != 0) { + fprintf(stderr, "Result for %s failed\n", filename); + return(-1); + } + if (err != NULL) { + res = compareFileMem(err, testErrors, testErrorsSize); + if (res != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + return(-1); + } + } else if (options & XML_PARSE_DTDVALID) { + if (testErrorsSize != 0) + fprintf(stderr, "Validation for %s failed\n", filename); + } + + return(0); +} + +#ifdef LIBXML_READER_ENABLED +/************************************************************************ + * * + * Reader based tests * + * * + ************************************************************************/ + +static void processNode(FILE *out, xmlTextReaderPtr reader) { + const xmlChar *name, *value; + int type, empty; + + type = xmlTextReaderNodeType(reader); + empty = xmlTextReaderIsEmptyElement(reader); + + name = xmlTextReaderConstName(reader); + if (name == NULL) + name = BAD_CAST "--"; + + value = xmlTextReaderConstValue(reader); + + + fprintf(out, "%d %d %s %d %d", + xmlTextReaderDepth(reader), + type, + name, + empty, + xmlTextReaderHasValue(reader)); + if (value == NULL) + fprintf(out, "\n"); + else { + fprintf(out, " %s\n", value); + } +} +static int +streamProcessTest(const char *filename, const char *result, const char *err, + xmlTextReaderPtr reader, const char *rng) { + int ret; + char *temp = NULL; + FILE *t = NULL; + + if (reader == NULL) + return(-1); + + nb_tests++; + if (result != NULL) { + temp = resultFilename(filename, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + t = fopen(temp, "wb"); + if (t == NULL) { + fprintf(stderr, "Can't open temp file %s\n", temp); + free(temp); + return(-1); + } + } +#ifdef LIBXML_SCHEMAS_ENABLED + if (rng != NULL) { + ret = xmlTextReaderRelaxNGValidate(reader, rng); + if (ret < 0) { + testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n", + rng); + fclose(t); + unlink(temp); + free(temp); + return(0); + } + } +#endif + xmlGetWarningsDefaultValue = 1; + ret = xmlTextReaderRead(reader); + while (ret == 1) { + if ((t != NULL) && (rng == NULL)) + processNode(t, reader); + ret = xmlTextReaderRead(reader); + } + if (ret != 0) { + testErrorHandler(NULL, "%s : failed to parse\n", filename); + } + if (rng != NULL) { + if (xmlTextReaderIsValid(reader) != 1) { + testErrorHandler(NULL, "%s fails to validate\n", filename); + } else { + testErrorHandler(NULL, "%s validates\n", filename); + } + } + xmlGetWarningsDefaultValue = 0; + if (t != NULL) { + fclose(t); + ret = compareFiles(temp, result); + unlink(temp); + free(temp); + if (ret) { + fprintf(stderr, "Result for %s failed\n", filename); + return(-1); + } + } + if (err != NULL) { + ret = compareFileMem(err, testErrors, testErrorsSize); + if (ret != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + printf("%s", testErrors); + return(-1); + } + } + + return(0); +} + +/** + * streamParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the reader API and check for errors. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +streamParseTest(const char *filename, const char *result, const char *err, + int options) { + xmlTextReaderPtr reader; + int ret; + + reader = xmlReaderForFile(filename, NULL, options); + ret = streamProcessTest(filename, result, err, reader, NULL); + xmlFreeTextReader(reader); + return(ret); +} + +/** + * walkerParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the walker, i.e. a reader built from a atree. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +walkerParseTest(const char *filename, const char *result, const char *err, + int options) { + xmlDocPtr doc; + xmlTextReaderPtr reader; + int ret; + + doc = xmlReadFile(filename, NULL, options); + if (doc == NULL) { + fprintf(stderr, "Failed to parse %s\n", filename); + return(-1); + } + reader = xmlReaderWalker(doc); + ret = streamProcessTest(filename, result, err, reader, NULL); + xmlFreeTextReader(reader); + xmlFreeDoc(doc); + return(ret); +} + +/** + * streamMemParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file using the reader API from memory and check for errors. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +streamMemParseTest(const char *filename, const char *result, const char *err, + int options) { + xmlTextReaderPtr reader; + int ret; + const char *base; + int size; + + /* + * load and parse the memory + */ + if (loadMem(filename, &base, &size) != 0) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + reader = xmlReaderForMemory(base, size, filename, NULL, options); + ret = streamProcessTest(filename, result, err, reader, NULL); + free((char *)base); + xmlFreeTextReader(reader); + return(ret); +} +#endif + +#ifdef LIBXML_XPATH_ENABLED +#ifdef LIBXML_DEBUG_ENABLED +/************************************************************************ + * * + * XPath and XPointer based tests * + * * + ************************************************************************/ + +FILE *xpathOutput; +xmlDocPtr xpathDocument; + +static void +testXPath(const char *str, int xptr, int expr) { + xmlXPathObjectPtr res; + xmlXPathContextPtr ctxt; + + nb_tests++; +#if defined(LIBXML_XPTR_ENABLED) + if (xptr) { + ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL); + res = xmlXPtrEval(BAD_CAST str, ctxt); + } else { +#endif + ctxt = xmlXPathNewContext(xpathDocument); + ctxt->node = xmlDocGetRootElement(xpathDocument); + if (expr) + res = xmlXPathEvalExpression(BAD_CAST str, ctxt); + else { + /* res = xmlXPathEval(BAD_CAST str, ctxt); */ + xmlXPathCompExprPtr comp; + + comp = xmlXPathCompile(BAD_CAST str); + if (comp != NULL) { + res = xmlXPathCompiledEval(comp, ctxt); + xmlXPathFreeCompExpr(comp); + } else + res = NULL; + } +#if defined(LIBXML_XPTR_ENABLED) + } +#endif + xmlXPathDebugDumpObject(xpathOutput, res, 0); + xmlXPathFreeObject(res); + xmlXPathFreeContext(ctxt); +} + +/** + * xpathExprTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing XPath standalone expressions and evaluate them + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xpathCommonTest(const char *filename, const char *result, + int xptr, int expr) { + FILE *input; + char expression[5000]; + int len, ret = 0; + char *temp; + + temp = resultFilename(filename, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + xpathOutput = fopen(temp, "wb"); + if (xpathOutput == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + free(temp); + return(-1); + } + + input = fopen(filename, "rb"); + if (input == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Cannot open %s for reading\n", filename); + free(temp); + return(-1); + } + while (fgets(expression, 4500, input) != NULL) { + len = strlen(expression); + len--; + while ((len >= 0) && + ((expression[len] == '\n') || (expression[len] == '\t') || + (expression[len] == '\r') || (expression[len] == ' '))) len--; + expression[len + 1] = 0; + if (len >= 0) { + fprintf(xpathOutput, + "\n========================\nExpression: %s\n", + expression) ; + testXPath(expression, xptr, expr); + } + } + + fclose(input); + fclose(xpathOutput); + if (result != NULL) { + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed\n", filename); + } + } + + unlink(temp); + free(temp); + return(ret); +} + +/** + * xpathExprTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing XPath standalone expressions and evaluate them + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xpathExprTest(const char *filename, const char *result, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(xpathCommonTest(filename, result, 0, 1)); +} + +/** + * xpathDocTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing XPath expressions and evaluate them against + * a set of corresponding documents. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xpathDocTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options) { + + char pattern[500]; + char result[500]; + glob_t globbuf; + size_t i; + int ret = 0, res; + + xpathDocument = xmlReadFile(filename, NULL, + options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); + if (xpathDocument == NULL) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + + snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename)); + pattern[499] = 0; + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + snprintf(result, 499, "result/XPath/tests/%s", + baseFilename(globbuf.gl_pathv[i])); + res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0); + if (res != 0) + ret = res; + } + globfree(&globbuf); + + xmlFreeDoc(xpathDocument); + return(ret); +} + +#ifdef LIBXML_XPTR_ENABLED +/** + * xptrDocTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing XPath expressions and evaluate them against + * a set of corresponding documents. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xptrDocTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options) { + + char pattern[500]; + char result[500]; + glob_t globbuf; + size_t i; + int ret = 0, res; + + xpathDocument = xmlReadFile(filename, NULL, + options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); + if (xpathDocument == NULL) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + + snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename)); + pattern[499] = 0; + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + snprintf(result, 499, "result/XPath/xptr/%s", + baseFilename(globbuf.gl_pathv[i])); + res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0); + if (res != 0) + ret = res; + } + globfree(&globbuf); + + xmlFreeDoc(xpathDocument); + return(ret); +} +#endif /* LIBXML_XPTR_ENABLED */ + +/** + * xmlidDocTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing xml:id and check for errors and verify + * that XPath queries will work on them as expected. + * + * Returns 0 in case of success, an error code otherwise + */ +static int +xmlidDocTest(const char *filename, + const char *result, + const char *err, + int options) { + + int res = 0; + int ret = 0; + char *temp; + + xpathDocument = xmlReadFile(filename, NULL, + options | XML_PARSE_DTDATTR | XML_PARSE_NOENT); + if (xpathDocument == NULL) { + fprintf(stderr, "Failed to load %s\n", filename); + return(-1); + } + + temp = resultFilename(filename, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + xpathOutput = fopen(temp, "wb"); + if (xpathOutput == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + xmlFreeDoc(xpathDocument); + free(temp); + return(-1); + } + + testXPath("id('bar')", 0, 0); + + fclose(xpathOutput); + if (result != NULL) { + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed\n", filename); + res = 1; + } + } + + unlink(temp); + free(temp); + xmlFreeDoc(xpathDocument); + + if (err != NULL) { + ret = compareFileMem(err, testErrors, testErrorsSize); + if (ret != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + res = 1; + } + } + return(res); +} + +#endif /* LIBXML_DEBUG_ENABLED */ +#endif /* XPATH */ +/************************************************************************ + * * + * URI based tests * + * * + ************************************************************************/ + +static void +handleURI(const char *str, const char *base, FILE *o) { + int ret; + xmlURIPtr uri; + xmlChar *res = NULL, *parsed = NULL; + + uri = xmlCreateURI(); + + if (base == NULL) { + ret = xmlParseURIReference(uri, str); + if (ret != 0) + fprintf(o, "%s : error %d\n", str, ret); + else { + xmlNormalizeURIPath(uri->path); + xmlPrintURI(o, uri); + fprintf(o, "\n"); + } + } else { + res = xmlBuildURI((xmlChar *)str, (xmlChar *) base); + if (res != NULL) { + fprintf(o, "%s\n", (char *) res); + } + else + fprintf(o, "::ERROR::\n"); + } + if (res != NULL) + xmlFree(res); + if (parsed != NULL) + xmlFree(parsed); + xmlFreeURI(uri); +} + +/** + * uriCommonTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing URI and check for errors + * + * Returns 0 in case of success, an error code otherwise + */ +static int +uriCommonTest(const char *filename, + const char *result, + const char *err, + const char *base) { + char *temp; + FILE *o, *f; + char str[1024]; + int res = 0, i, ret; + + temp = resultFilename(filename, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + o = fopen(temp, "wb"); + if (o == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + free(temp); + return(-1); + } + f = fopen(filename, "rb"); + if (f == NULL) { + fprintf(stderr, "failed to open input file %s\n", filename); + fclose(o); + unlink(temp); + free(temp); + return(-1); + } + + while (1) { + /* + * read one line in string buffer. + */ + if (fgets (&str[0], sizeof (str) - 1, f) == NULL) + break; + + /* + * remove the ending spaces + */ + i = strlen(str); + while ((i > 0) && + ((str[i - 1] == '\n') || (str[i - 1] == '\r') || + (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { + i--; + str[i] = 0; + } + nb_tests++; + handleURI(str, base, o); + } + + fclose(f); + fclose(o); + + if (result != NULL) { + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed\n", filename); + res = 1; + } + } + if (err != NULL) { + ret = compareFileMem(err, testErrors, testErrorsSize); + if (ret != 0) { + fprintf(stderr, "Error for %s failed\n", filename); + res = 1; + } + } + + unlink(temp); + free(temp); + return(res); +} + +/** + * uriParseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing URI and check for errors + * + * Returns 0 in case of success, an error code otherwise + */ +static int +uriParseTest(const char *filename, + const char *result, + const char *err, + int options ATTRIBUTE_UNUSED) { + return(uriCommonTest(filename, result, err, NULL)); +} + +/** + * uriBaseTest: + * @filename: the file to parse + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing URI, compose them against a fixed base and + * check for errors + * + * Returns 0 in case of success, an error code otherwise + */ +static int +uriBaseTest(const char *filename, + const char *result, + const char *err, + int options ATTRIBUTE_UNUSED) { + return(uriCommonTest(filename, result, err, + "http://foo.com/path/to/index.html?orig#help")); +} + +#ifdef LIBXML_SCHEMAS_ENABLED +/************************************************************************ + * * + * Schemas tests * + * * + ************************************************************************/ +static int +schemasOneTest(const char *sch, + const char *filename, + const char *result, + const char *err, + int options, + xmlSchemaPtr schemas) { + xmlDocPtr doc; + xmlSchemaValidCtxtPtr ctxt; + int ret = 0; + char *temp; + FILE *schemasOutput; + + doc = xmlReadFile(filename, NULL, options); + if (doc == NULL) { + fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); + return(-1); + } + + temp = resultFilename(result, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + schemasOutput = fopen(temp, "wb"); + if (schemasOutput == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + xmlFreeDoc(doc); + free(temp); + return(-1); + } + + ctxt = xmlSchemaNewValidCtxt(schemas); + xmlSchemaSetValidErrors(ctxt, + (xmlSchemaValidityErrorFunc) testErrorHandler, + (xmlSchemaValidityWarningFunc) testErrorHandler, + ctxt); + ret = xmlSchemaValidateDoc(ctxt, doc); + if (ret == 0) { + fprintf(schemasOutput, "%s validates\n", filename); + } else if (ret > 0) { + fprintf(schemasOutput, "%s fails to validate\n", filename); + } else { + fprintf(schemasOutput, "%s validation generated an internal error\n", + filename); + } + fclose(schemasOutput); + if (result) { + if (compareFiles(temp, result)) { + fprintf(stderr, "Result for %s on %s failed\n", filename, sch); + ret = 1; + } + } + unlink(temp); + free(temp); + + if (err != NULL) { + if (compareFileMem(err, testErrors, testErrorsSize)) { + fprintf(stderr, "Error for %s on %s failed\n", filename, sch); + ret = 1; + } + } + + + xmlSchemaFreeValidCtxt(ctxt); + xmlFreeDoc(doc); + return(ret); +} +/** + * schemasTest: + * @filename: the schemas file + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a file containing URI, compose them against a fixed base and + * check for errors + * + * Returns 0 in case of success, an error code otherwise + */ +static int +schemasTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *errr ATTRIBUTE_UNUSED, + int options) { + const char *base = baseFilename(filename); + const char *base2; + const char *instance; + xmlSchemaParserCtxtPtr ctxt; + xmlSchemaPtr schemas; + int res = 0, len, ret; + char pattern[500]; + char prefix[500]; + char result[500]; + char err[500]; + glob_t globbuf; + size_t i; + char count = 0; + + /* first compile the schemas if possible */ + ctxt = xmlSchemaNewParserCtxt(filename); + xmlSchemaSetParserErrors(ctxt, + (xmlSchemaValidityErrorFunc) testErrorHandler, + (xmlSchemaValidityWarningFunc) testErrorHandler, + ctxt); + schemas = xmlSchemaParse(ctxt); + xmlSchemaFreeParserCtxt(ctxt); + + /* + * most of the mess is about the output filenames generated by the Makefile + */ + len = strlen(base); + if ((len > 499) || (len < 5)) { + xmlSchemaFree(schemas); + return(-1); + } + len -= 4; /* remove trailing .xsd */ + if (base[len - 2] == '_') { + len -= 2; /* remove subtest number */ + } + if (base[len - 2] == '_') { + len -= 2; /* remove subtest number */ + } + memcpy(prefix, base, len); + prefix[len] = 0; + + snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix); + pattern[499] = 0; + + if (base[len] == '_') { + len += 2; + memcpy(prefix, base, len); + prefix[len] = 0; + } + + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + testErrorsSize = 0; + testErrors[0] = 0; + instance = globbuf.gl_pathv[i]; + base2 = baseFilename(instance); + len = strlen(base2); + if ((len > 6) && (base2[len - 6] == '_')) { + count = base2[len - 5]; + snprintf(result, 499, "result/schemas/%s_%c", + prefix, count); + result[499] = 0; + snprintf(err, 499, "result/schemas/%s_%c.err", + prefix, count); + err[499] = 0; + } else { + fprintf(stderr, "don't know how to process %s\n", instance); + continue; + } + if (schemas == NULL) { + } else { + nb_tests++; + ret = schemasOneTest(filename, instance, result, err, + options, schemas); + if (res != 0) + ret = res; + } + } + globfree(&globbuf); + xmlSchemaFree(schemas); + + return(res); +} + +/************************************************************************ + * * + * Schemas tests * + * * + ************************************************************************/ +static int +rngOneTest(const char *sch, + const char *filename, + const char *result, + const char *err, + int options, + xmlRelaxNGPtr schemas) { + xmlDocPtr doc; + xmlRelaxNGValidCtxtPtr ctxt; + int ret = 0; + char *temp; + FILE *schemasOutput; + + doc = xmlReadFile(filename, NULL, options); + if (doc == NULL) { + fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch); + return(-1); + } + + temp = resultFilename(result, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + schemasOutput = fopen(temp, "wb"); + if (schemasOutput == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + xmlFreeDoc(doc); + free(temp); + return(-1); + } + + ctxt = xmlRelaxNGNewValidCtxt(schemas); + xmlRelaxNGSetValidErrors(ctxt, + (xmlRelaxNGValidityErrorFunc) testErrorHandler, + (xmlRelaxNGValidityWarningFunc) testErrorHandler, + ctxt); + ret = xmlRelaxNGValidateDoc(ctxt, doc); + if (ret == 0) { + testErrorHandler(NULL, "%s validates\n", filename); + } else if (ret > 0) { + testErrorHandler(NULL, "%s fails to validate\n", filename); + } else { + testErrorHandler(NULL, "%s validation generated an internal error\n", + filename); + } + fclose(schemasOutput); + if (result) { + if (compareFiles(temp, result)) { + fprintf(stderr, "Result for %s on %s failed\n", filename, sch); + ret = 1; + } + } + unlink(temp); + free(temp); + + if (err != NULL) { + if (compareFileMem(err, testErrors, testErrorsSize)) { + fprintf(stderr, "Error for %s on %s failed\n", filename, sch); + ret = 1; + printf("%s", testErrors); + } + } + + + xmlRelaxNGFreeValidCtxt(ctxt); + xmlFreeDoc(doc); + return(ret); +} +/** + * rngTest: + * @filename: the schemas file + * @result: the file with expected result + * @err: the file with error messages + * + * Parse an RNG schemas and then apply it to the related .xml + * + * Returns 0 in case of success, an error code otherwise + */ +static int +rngTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *errr ATTRIBUTE_UNUSED, + int options) { + const char *base = baseFilename(filename); + const char *base2; + const char *instance; + xmlRelaxNGParserCtxtPtr ctxt; + xmlRelaxNGPtr schemas; + int res = 0, len, ret; + char pattern[500]; + char prefix[500]; + char result[500]; + char err[500]; + glob_t globbuf; + size_t i; + char count = 0; + + /* first compile the schemas if possible */ + ctxt = xmlRelaxNGNewParserCtxt(filename); + xmlRelaxNGSetParserErrors(ctxt, + (xmlRelaxNGValidityErrorFunc) testErrorHandler, + (xmlRelaxNGValidityWarningFunc) testErrorHandler, + ctxt); + schemas = xmlRelaxNGParse(ctxt); + xmlRelaxNGFreeParserCtxt(ctxt); + + /* + * most of the mess is about the output filenames generated by the Makefile + */ + len = strlen(base); + if ((len > 499) || (len < 5)) { + xmlRelaxNGFree(schemas); + return(-1); + } + len -= 4; /* remove trailing .rng */ + memcpy(prefix, base, len); + prefix[len] = 0; + + snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix); + pattern[499] = 0; + + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + testErrorsSize = 0; + testErrors[0] = 0; + instance = globbuf.gl_pathv[i]; + base2 = baseFilename(instance); + len = strlen(base2); + if ((len > 6) && (base2[len - 6] == '_')) { + count = base2[len - 5]; + snprintf(result, 499, "result/relaxng/%s_%c", + prefix, count); + result[499] = 0; + snprintf(err, 499, "result/relaxng/%s_%c.err", + prefix, count); + err[499] = 0; + } else { + fprintf(stderr, "don't know how to process %s\n", instance); + continue; + } + if (schemas == NULL) { + } else { + nb_tests++; + ret = rngOneTest(filename, instance, result, err, + options, schemas); + if (res != 0) + ret = res; + } + } + globfree(&globbuf); + xmlRelaxNGFree(schemas); + + return(res); +} + +#ifdef LIBXML_READER_ENABLED +/** + * rngStreamTest: + * @filename: the schemas file + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a set of files with streaming, applying an RNG schemas + * + * Returns 0 in case of success, an error code otherwise + */ +static int +rngStreamTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *errr ATTRIBUTE_UNUSED, + int options) { + const char *base = baseFilename(filename); + const char *base2; + const char *instance; + int res = 0, len, ret; + char pattern[500]; + char prefix[500]; + char result[500]; + char err[500]; + glob_t globbuf; + size_t i; + char count = 0; + xmlTextReaderPtr reader; + int disable_err = 0; + + /* + * most of the mess is about the output filenames generated by the Makefile + */ + len = strlen(base); + if ((len > 499) || (len < 5)) { + fprintf(stderr, "len(base) == %d !\n", len); + return(-1); + } + len -= 4; /* remove trailing .rng */ + memcpy(prefix, base, len); + prefix[len] = 0; + + /* + * strictly unifying the error messages is nearly impossible this + * hack is also done in the Makefile + */ + if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) || + (!strcmp(prefix, "tutor3_2"))) + disable_err = 1; + + snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix); + pattern[499] = 0; + + globbuf.gl_offs = 0; + glob(pattern, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + testErrorsSize = 0; + testErrors[0] = 0; + instance = globbuf.gl_pathv[i]; + base2 = baseFilename(instance); + len = strlen(base2); + if ((len > 6) && (base2[len - 6] == '_')) { + count = base2[len - 5]; + snprintf(result, 499, "result/relaxng/%s_%c", + prefix, count); + result[499] = 0; + snprintf(err, 499, "result/relaxng/%s_%c.err", + prefix, count); + err[499] = 0; + } else { + fprintf(stderr, "don't know how to process %s\n", instance); + continue; + } + reader = xmlReaderForFile(instance, NULL, options); + if (reader == NULL) { + fprintf(stderr, "Failed to build reder for %s\n", instance); + } + if (disable_err == 1) + ret = streamProcessTest(instance, result, NULL, reader, filename); + else + ret = streamProcessTest(instance, result, err, reader, filename); + xmlFreeTextReader(reader); + if (ret != 0) { + fprintf(stderr, "instance %s failed\n", instance); + res = ret; + } + } + globfree(&globbuf); + + return(res); +} +#endif /* READER */ + +#endif + +#ifdef LIBXML_PATTERN_ENABLED +#ifdef LIBXML_READER_ENABLED +/************************************************************************ + * * + * Patterns tests * + * * + ************************************************************************/ +static void patternNode(FILE *out, xmlTextReaderPtr reader, + const char *pattern, xmlPatternPtr patternc, + xmlStreamCtxtPtr patstream) { + xmlChar *path = NULL; + int match = -1; + int type, empty; + + type = xmlTextReaderNodeType(reader); + empty = xmlTextReaderIsEmptyElement(reader); + + if (type == XML_READER_TYPE_ELEMENT) { + /* do the check only on element start */ + match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader)); + + if (match) { + path = xmlGetNodePath(xmlTextReaderCurrentNode(reader)); + fprintf(out, "Node %s matches pattern %s\n", path, pattern); + } + } + if (patstream != NULL) { + int ret; + + if (type == XML_READER_TYPE_ELEMENT) { + ret = xmlStreamPush(patstream, + xmlTextReaderConstLocalName(reader), + xmlTextReaderConstNamespaceUri(reader)); + if (ret < 0) { + fprintf(out, "xmlStreamPush() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } else if (ret != match) { + if (path == NULL) { + path = xmlGetNodePath( + xmlTextReaderCurrentNode(reader)); + } + fprintf(out, + "xmlPatternMatch and xmlStreamPush disagree\n"); + fprintf(out, + " pattern %s node %s\n", + pattern, path); + } + + + } + if ((type == XML_READER_TYPE_END_ELEMENT) || + ((type == XML_READER_TYPE_ELEMENT) && (empty))) { + ret = xmlStreamPop(patstream); + if (ret < 0) { + fprintf(out, "xmlStreamPop() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } + } + } + if (path != NULL) + xmlFree(path); +} + +/** + * patternTest: + * @filename: the schemas file + * @result: the file with expected result + * @err: the file with error messages + * + * Parse a set of files with streaming, applying an RNG schemas + * + * Returns 0 in case of success, an error code otherwise + */ +static int +patternTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options) { + xmlPatternPtr patternc = NULL; + xmlStreamCtxtPtr patstream = NULL; + FILE *o, *f; + char str[1024]; + char xml[500]; + char result[500]; + int len, i; + int ret = 0, res; + char *temp; + xmlTextReaderPtr reader; + xmlDocPtr doc; + + len = strlen(filename); + len -= 4; + memcpy(xml, filename, len); + xml[len] = 0; + snprintf(result, 499, "result/pattern/%s", baseFilename(xml)); + result[499] = 0; + memcpy(xml + len, ".xml", 5); + + if (!checkTestFile(xml)) { + fprintf(stderr, "Missing xml file %s\n", xml); + return(-1); + } + if (!checkTestFile(result)) { + fprintf(stderr, "Missing result file %s\n", result); + return(-1); + } + f = fopen(filename, "rb"); + if (f == NULL) { + fprintf(stderr, "Failed to open %s\n", filename); + return(-1); + } + temp = resultFilename(filename, "", ".res"); + if (temp == NULL) { + fprintf(stderr, "Out of memory\n"); + fatalError(); + } + o = fopen(temp, "wb"); + if (o == NULL) { + fprintf(stderr, "failed to open output file %s\n", temp); + fclose(f); + free(temp); + return(-1); + } + while (1) { + /* + * read one line in string buffer. + */ + if (fgets (&str[0], sizeof (str) - 1, f) == NULL) + break; + + /* + * remove the ending spaces + */ + i = strlen(str); + while ((i > 0) && + ((str[i - 1] == '\n') || (str[i - 1] == '\r') || + (str[i - 1] == ' ') || (str[i - 1] == '\t'))) { + i--; + str[i] = 0; + } + doc = xmlReadFile(xml, NULL, options); + if (doc == NULL) { + fprintf(stderr, "Failed to parse %s\n", xml); + ret = 1; + } else { + xmlNodePtr root; + const xmlChar *namespaces[22]; + int j; + xmlNsPtr ns; + + root = xmlDocGetRootElement(doc); + for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) { + namespaces[j++] = ns->href; + namespaces[j++] = ns->prefix; + } + namespaces[j++] = NULL; + namespaces[j++] = NULL; + + patternc = xmlPatterncompile((const xmlChar *) str, doc->dict, + 0, &namespaces[0]); + if (patternc == NULL) { + testErrorHandler(NULL, + "Pattern %s failed to compile\n", str); + xmlFreeDoc(doc); + ret = 1; + continue; + } + patstream = xmlPatternGetStreamCtxt(patternc); + if (patstream != NULL) { + ret = xmlStreamPush(patstream, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "xmlStreamPush() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } + } + nb_tests++; + + reader = xmlReaderWalker(doc); + res = xmlTextReaderRead(reader); + while (res == 1) { + patternNode(o, reader, str, patternc, patstream); + res = xmlTextReaderRead(reader); + } + if (res != 0) { + fprintf(o, "%s : failed to parse\n", filename); + } + xmlFreeTextReader(reader); + xmlFreeDoc(doc); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + xmlFreePattern(patternc); + + } + } + + fclose(f); + fclose(o); + + ret = compareFiles(temp, result); + if (ret) { + fprintf(stderr, "Result for %s failed\n", filename); + ret = 1; + } + unlink(temp); + free(temp); + return(ret); +} +#endif /* READER */ +#endif /* PATTERN */ +#ifdef LIBXML_C14N_ENABLED +/************************************************************************ + * * + * Canonicalization tests * + * * + ************************************************************************/ +static xmlXPathObjectPtr +load_xpath_expr (xmlDocPtr parent_doc, const char* filename) { + xmlXPathObjectPtr xpath; + xmlDocPtr doc; + xmlChar *expr; + xmlXPathContextPtr ctx; + xmlNodePtr node; + xmlNsPtr ns; + + /* + * load XPath expr as a file + */ + xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + xmlSubstituteEntitiesDefault(1); + + doc = xmlParseFile(filename); + if (doc == NULL) { + fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename); + return(NULL); + } + + /* + * Check the document is of the right kind + */ + if(xmlDocGetRootElement(doc) == NULL) { + fprintf(stderr,"Error: empty document for file \"%s\"\n", filename); + xmlFreeDoc(doc); + return(NULL); + } + + node = doc->children; + while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) { + node = node->next; + } + + if(node == NULL) { + fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename); + xmlFreeDoc(doc); + return(NULL); + } + + expr = xmlNodeGetContent(node); + if(expr == NULL) { + fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename); + xmlFreeDoc(doc); + return(NULL); + } + + ctx = xmlXPathNewContext(parent_doc); + if(ctx == NULL) { + fprintf(stderr,"Error: unable to create new context\n"); + xmlFree(expr); + xmlFreeDoc(doc); + return(NULL); + } + + /* + * Register namespaces + */ + ns = node->nsDef; + while(ns != NULL) { + if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) { + fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href); + xmlFree(expr); + xmlXPathFreeContext(ctx); + xmlFreeDoc(doc); + return(NULL); + } + ns = ns->next; + } + + /* + * Evaluate xpath + */ + xpath = xmlXPathEvalExpression(expr, ctx); + if(xpath == NULL) { + fprintf(stderr,"Error: unable to evaluate xpath expression\n"); + xmlFree(expr); + xmlXPathFreeContext(ctx); + xmlFreeDoc(doc); + return(NULL); + } + + /* print_xpath_nodes(xpath->nodesetval); */ + + xmlFree(expr); + xmlXPathFreeContext(ctx); + xmlFreeDoc(doc); + return(xpath); +} + +/* + * Macro used to grow the current buffer. + */ +#define xxx_growBufferReentrant() { \ + buffer_size *= 2; \ + buffer = (xmlChar **) \ + xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \ + if (buffer == NULL) { \ + perror("realloc failed"); \ + return(NULL); \ + } \ +} + +static xmlChar ** +parse_list(xmlChar *str) { + xmlChar **buffer; + xmlChar **out = NULL; + int buffer_size = 0; + int len; + + if(str == NULL) { + return(NULL); + } + + len = xmlStrlen(str); + if((str[0] == '\'') && (str[len - 1] == '\'')) { + str[len - 1] = '\0'; + str++; + len -= 2; + } + /* + * allocate an translation buffer. + */ + buffer_size = 1000; + buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*)); + if (buffer == NULL) { + perror("malloc failed"); + return(NULL); + } + out = buffer; + + while(*str != '\0') { + if (out - buffer > buffer_size - 10) { + int indx = out - buffer; + + xxx_growBufferReentrant(); + out = &buffer[indx]; + } + (*out++) = str; + while(*str != ',' && *str != '\0') ++str; + if(*str == ',') *(str++) = '\0'; + } + (*out) = NULL; + return buffer; +} + +static int +c14nRunTest(const char* xml_filename, int with_comments, int exclusive, + const char* xpath_filename, const char *ns_filename, + const char* result_file) { + xmlDocPtr doc; + xmlXPathObjectPtr xpath = NULL; + xmlChar *result = NULL; + int ret; + xmlChar **inclusive_namespaces = NULL; + const char *nslist = NULL; + int nssize; + + + /* + * build an XML tree from a the file; we need to add default + * attributes and resolve all character and entities references + */ + xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + xmlSubstituteEntitiesDefault(1); + + doc = xmlParseFile(xml_filename); + if (doc == NULL) { + fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename); + return(-1); + } + + /* + * Check the document is of the right kind + */ + if(xmlDocGetRootElement(doc) == NULL) { + fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename); + xmlFreeDoc(doc); + return(-1); + } + + /* + * load xpath file if specified + */ + if(xpath_filename) { + xpath = load_xpath_expr(doc, xpath_filename); + if(xpath == NULL) { + fprintf(stderr,"Error: unable to evaluate xpath expression\n"); + xmlFreeDoc(doc); + return(-1); + } + } + + if (ns_filename != NULL) { + if (loadMem(ns_filename, &nslist, &nssize)) { + fprintf(stderr,"Error: unable to evaluate xpath expression\n"); + if(xpath != NULL) xmlXPathFreeObject(xpath); + xmlFreeDoc(doc); + return(-1); + } + inclusive_namespaces = parse_list((xmlChar *) nslist); + } + + /* + * Canonical form + */ + /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */ + ret = xmlC14NDocDumpMemory(doc, + (xpath) ? xpath->nodesetval : NULL, + exclusive, inclusive_namespaces, + with_comments, &result); + if (ret >= 0) { + if(result != NULL) { + if (compareFileMem(result_file, (const char *) result, ret)) { + fprintf(stderr, "Result mismatch for %s\n", xml_filename); + ret = -1; + } + } + } else { + fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret); + ret = -1; + } + + /* + * Cleanup + */ + if (result != NULL) xmlFree(result); + if(xpath != NULL) xmlXPathFreeObject(xpath); + if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces); + if (nslist != NULL) free((char *) nslist); + xmlFreeDoc(doc); + + return(ret); +} + +static int +c14nCommonTest(const char *filename, int with_comments, int exclusive, + const char *subdir) { + char buf[500]; + char prefix[500]; + const char *base; + int len; + char *result = NULL; + char *xpath = NULL; + char *ns = NULL; + int ret = 0; + + base = baseFilename(filename); + len = strlen(base); + len -= 4; + memcpy(prefix, base, len); + prefix[len] = 0; + + snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix); + if (!checkTestFile(buf)) { + fprintf(stderr, "Missing result file %s", buf); + return(-1); + } + result = strdup(buf); + snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix); + if (checkTestFile(buf)) { + xpath = strdup(buf); + } + snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix); + if (checkTestFile(buf)) { + ns = strdup(buf); + } + + nb_tests++; + if (c14nRunTest(filename, with_comments, exclusive, + xpath, ns, result) < 0) + ret = 1; + + if (result != NULL) free(result); + if (xpath != NULL) free(xpath); + if (ns != NULL) free(ns); + return(ret); +} + +static int +c14nWithCommentTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(c14nCommonTest(filename, 1, 0, "with-comments")); +} +static int +c14nWithoutCommentTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(c14nCommonTest(filename, 0, 0, "without-comments")); +} +static int +c14nExcWithoutCommentTest(const char *filename, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(c14nCommonTest(filename, 0, 1, "exc-without-comments")); +} +#endif +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) +/************************************************************************ + * * + * Catalog and threads test * + * * + ************************************************************************/ + +/* + * mostly a cut and paste from testThreads.c + */ +#define MAX_ARGC 20 + +static const char *catalog = "test/threads/complex.xml"; +static const char *testfiles[] = { + "test/threads/abc.xml", + "test/threads/acb.xml", + "test/threads/bac.xml", + "test/threads/bca.xml", + "test/threads/cab.xml", + "test/threads/cba.xml", + "test/threads/invalid.xml", +}; + +const char *Okay = "OK"; +const char *Failed = "Failed"; + +#ifndef xmlDoValidityCheckingDefaultValue +#error xmlDoValidityCheckingDefaultValue is not a macro +#endif +#ifndef xmlGenericErrorContext +#error xmlGenericErrorContext is not a macro +#endif + +static void * +thread_specific_data(void *private_data) +{ + xmlDocPtr myDoc; + const char *filename = (const char *) private_data; + int okay = 1; + + if (!strcmp(filename, "test/threads/invalid.xml")) { + xmlDoValidityCheckingDefaultValue = 0; + xmlGenericErrorContext = stdout; + } else { + xmlDoValidityCheckingDefaultValue = 1; + xmlGenericErrorContext = stderr; + } + myDoc = xmlParseFile(filename); + if (myDoc) { + xmlFreeDoc(myDoc); + } else { + printf("parse failed\n"); + okay = 0; + } + if (!strcmp(filename, "test/threads/invalid.xml")) { + if (xmlDoValidityCheckingDefaultValue != 0) { + printf("ValidityCheckingDefaultValue override failed\n"); + okay = 0; + } + if (xmlGenericErrorContext != stdout) { + printf("xmlGenericErrorContext override failed\n"); + okay = 0; + } + } else { + if (xmlDoValidityCheckingDefaultValue != 1) { + printf("ValidityCheckingDefaultValue override failed\n"); + okay = 0; + } + if (xmlGenericErrorContext != stderr) { + printf("xmlGenericErrorContext override failed\n"); + okay = 0; + } + } + if (okay == 0) + return ((void *) Failed); + return ((void *) Okay); +} + +#if defined(linux) || defined(solaris) + +#include + +static pthread_t tid[MAX_ARGC]; + +static int +testThread(void) +{ + unsigned int i, repeat; + unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); + void *results[MAX_ARGC]; + int ret; + int res = 0; + + xmlInitParser(); + + for (repeat = 0; repeat < 500; repeat++) { + xmlLoadCatalog(catalog); + nb_tests++; + + for (i = 0; i < num_threads; i++) { + results[i] = NULL; + tid[i] = (pthread_t) - 1; + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_create(&tid[i], 0, thread_specific_data, + (void *) testfiles[i]); + if (ret != 0) { + fprintf(stderr, "pthread_create failed\n"); + return (1); + } + } + for (i = 0; i < num_threads; i++) { + ret = pthread_join(tid[i], &results[i]); + if (ret != 0) { + fprintf(stderr, "pthread_join failed\n"); + return (1); + } + } + + xmlCatalogCleanup(); + for (i = 0; i < num_threads; i++) + if (results[i] != (void *) Okay) { + fprintf(stderr, "Thread %d handling %s failed\n", + i, testfiles[i]); + res = 1; + } + } + return (res); +} + +#elif defined WIN32 +#include +#include + +#define TEST_REPEAT_COUNT 500 + +static HANDLE tid[MAX_ARGC]; + +static DWORD WINAPI +win32_thread_specific_data(void *private_data) +{ + return((DWORD) thread_specific_data(private_data)); +} + +static int +testThread(void) +{ + unsigned int i, repeat; + unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); + DWORD results[MAX_ARGC]; + BOOL ret; + int res = 0; + + xmlInitParser(); + for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) { + xmlLoadCatalog(catalog); + nb_tests++; + + for (i = 0; i < num_threads; i++) { + results[i] = 0; + tid[i] = (HANDLE) - 1; + } + + for (i = 0; i < num_threads; i++) { + DWORD useless; + + tid[i] = CreateThread(NULL, 0, + win32_thread_specific_data, + (void *) testfiles[i], 0, + &useless); + if (tid[i] == NULL) { + fprintf(stderr, "CreateThread failed\n"); + return(1); + } + } + + if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) == + WAIT_FAILED) { + fprintf(stderr, "WaitForMultipleObjects failed\n"); + return(1); + } + + for (i = 0; i < num_threads; i++) { + ret = GetExitCodeThread(tid[i], &results[i]); + if (ret == 0) { + fprintf(stderr, "GetExitCodeThread failed\n"); + return(1); + } + CloseHandle(tid[i]); + } + + xmlCatalogCleanup(); + for (i = 0; i < num_threads; i++) { + if (results[i] != (DWORD) Okay) { + fprintf(stderr, "Thread %d handling %s failed\n", + i, testfiles[i]); + res = 1; + } + } + } + + return (res); +} + +#elif defined __BEOS__ +#include + +static thread_id tid[MAX_ARGC]; + +static int +testThread(void) +{ + unsigned int i, repeat; + unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]); + void *results[MAX_ARGC]; + status_t ret; + int res = 0; + + xmlInitParser(); + for (repeat = 0; repeat < 500; repeat++) { + xmlLoadCatalog(catalog); + for (i = 0; i < num_threads; i++) { + results[i] = NULL; + tid[i] = (thread_id) - 1; + } + for (i = 0; i < num_threads; i++) { + tid[i] = + spawn_thread(thread_specific_data, "xmlTestThread", + B_NORMAL_PRIORITY, (void *) testfiles[i]); + if (tid[i] < B_OK) { + fprintf(stderr, "beos_thread_create failed\n"); + return (1); + } + printf("beos_thread_create %d -> %d\n", i, tid[i]); + } + for (i = 0; i < num_threads; i++) { + ret = wait_for_thread(tid[i], &results[i]); + printf("beos_thread_wait %d -> %d\n", i, ret); + if (ret != B_OK) { + fprintf(stderr, "beos_thread_wait failed\n"); + return (1); + } + } + + xmlCatalogCleanup(); + ret = B_OK; + for (i = 0; i < num_threads; i++) + if (results[i] != (void *) Okay) { + printf("Thread %d handling %s failed\n", i, testfiles[i]); + ret = B_ERROR; + } + } + if (ret != B_OK) + return(1); + return (0); +} +#else +static int +testThread(void) +{ + fprintf(stderr, + "Specific platform thread support not detected\n"); + return (-1); +} +#endif +static int +threadsTest(const char *filename ATTRIBUTE_UNUSED, + const char *resul ATTRIBUTE_UNUSED, + const char *err ATTRIBUTE_UNUSED, + int options ATTRIBUTE_UNUSED) { + return(testThread()); +} +#endif +/************************************************************************ + * * + * Tests Descriptions * + * * + ************************************************************************/ + +static +testDesc testDescriptions[] = { + { "XML regression tests" , + oldParseTest, "./test/*", "result/", "", NULL, + 0 }, + { "XML regression tests on memory" , + memParseTest, "./test/*", "result/", "", NULL, + 0 }, + { "XML entity subst regression tests" , + noentParseTest, "./test/*", "result/noent/", "", NULL, + XML_PARSE_NOENT }, + { "XML Namespaces regression tests", + errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err", + 0 }, + { "Error cases regression tests", + errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err", + 0 }, +#ifdef LIBXML_READER_ENABLED + { "Error cases stream regression tests", + streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str", + 0 }, + { "Reader regression tests", + streamParseTest, "./test/*", "result/", ".rdr", NULL, + 0 }, + { "Reader entities substitution regression tests", + streamParseTest, "./test/*", "result/", ".rde", NULL, + XML_PARSE_NOENT }, + { "Reader on memory regression tests", + streamMemParseTest, "./test/*", "result/", ".rdr", NULL, + 0 }, + { "Walker regression tests", + walkerParseTest, "./test/*", "result/", ".rdr", NULL, + 0 }, +#endif +#ifdef LIBXML_SAX1_ENABLED + { "SAX1 callbacks regression tests" , + saxParseTest, "./test/*", "result/", ".sax", NULL, + XML_PARSE_SAX1 }, + { "SAX2 callbacks regression tests" , + saxParseTest, "./test/*", "result/", ".sax2", NULL, + 0 }, +#endif +#ifdef LIBXML_PUSH_ENABLED + { "XML push regression tests" , + pushParseTest, "./test/*", "result/", "", NULL, + 0 }, +#endif +#ifdef LIBXML_HTML_ENABLED + { "HTML regression tests" , + errParseTest, "./test/HTML/*", "result/HTML/", "", ".err", + XML_PARSE_HTML }, +#ifdef LIBXML_PUSH_ENABLED + { "Push HTML regression tests" , + pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err", + XML_PARSE_HTML }, +#endif +#ifdef LIBXML_SAX1_ENABLED + { "HTML SAX regression tests" , + saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL, + XML_PARSE_HTML }, +#endif +#endif +#ifdef LIBXML_VALID_ENABLED + { "Valid documents regression tests" , + errParseTest, "./test/VCM/*", NULL, NULL, NULL, + XML_PARSE_DTDVALID }, + { "Validity checking regression tests" , + errParseTest, "./test/VC/*", "result/VC/", NULL, "", + XML_PARSE_DTDVALID }, + { "General documents valid regression tests" , + errParseTest, "./test/valid/*", "result/valid/", "", ".err", + XML_PARSE_DTDVALID }, +#endif +#ifdef LIBXML_XINCLUDE_ENABLED + { "XInclude regression tests" , + errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL, + /* Ignore errors at this point ".err", */ + XML_PARSE_XINCLUDE }, + { "XInclude xmlReader regression tests", + streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", + /* Ignore errors at this point ".err", */ + NULL, XML_PARSE_XINCLUDE }, + { "XInclude regression tests stripping include nodes" , + errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL, + /* Ignore errors at this point ".err", */ + XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, + { "XInclude xmlReader regression tests stripping include nodes", + streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr", + /* Ignore errors at this point ".err", */ + NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE }, +#endif +#ifdef LIBXML_XPATH_ENABLED +#ifdef LIBXML_DEBUG_ENABLED + { "XPath expressions regression tests" , + xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL, + 0 }, + { "XPath document queries regression tests" , + xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, + 0 }, +#ifdef LIBXML_XPTR_ENABLED + { "XPointer document queries regression tests" , + xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL, + 0 }, +#endif + { "xml:id regression tests" , + xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err", + 0 }, +#endif +#endif + { "URI parsing tests" , + uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL, + 0 }, + { "URI base composition tests" , + uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL, + 0 }, +#ifdef LIBXML_SCHEMAS_ENABLED + { "Schemas regression tests" , + schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL, + 0 }, + { "Relax-NG regression tests" , + rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL, + XML_PARSE_DTDATTR | XML_PARSE_NOENT }, +#ifdef LIBXML_READER_ENABLED + { "Relax-NG streaming regression tests" , + rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL, + XML_PARSE_DTDATTR | XML_PARSE_NOENT }, +#endif +#endif +#ifdef LIBXML_PATTERN_ENABLED +#ifdef LIBXML_READER_ENABLED + { "Pattern regression tests" , + patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL, + 0 }, +#endif +#endif +#ifdef LIBXML_C14N_ENABLED + { "C14N with comments regression tests" , + c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL, + 0 }, + { "C14N without comments regression tests" , + c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL, + 0 }, + { "C14N exclusive without comments regression tests" , + c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL, + 0 }, +#endif +#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) + { "Catalog and Threads regression tests" , + threadsTest, NULL, NULL, NULL, NULL, + 0 }, +#endif + {NULL, NULL, NULL, NULL, NULL, NULL, 0} +}; + +/************************************************************************ + * * + * The main code driving the tests * + * * + ************************************************************************/ + +static int +launchTests(testDescPtr tst) { + int res = 0, err = 0; + size_t i; + char *result; + char *error; + int mem; + + if (tst == NULL) return(-1); + if (tst->in != NULL) { + glob_t globbuf; + + globbuf.gl_offs = 0; + glob(tst->in, GLOB_DOOFFS, NULL, &globbuf); + for (i = 0;i < globbuf.gl_pathc;i++) { + if (!checkTestFile(globbuf.gl_pathv[i])) + continue; + if (tst->suffix != NULL) { + result = resultFilename(globbuf.gl_pathv[i], tst->out, + tst->suffix); + if (result == NULL) { + fprintf(stderr, "Out of memory !\n"); + fatalError(); + } + } else { + result = NULL; + } + if (tst->err != NULL) { + error = resultFilename(globbuf.gl_pathv[i], tst->out, + tst->err); + if (error == NULL) { + fprintf(stderr, "Out of memory !\n"); + fatalError(); + } + } else { + error = NULL; + } + if ((result) &&(!checkTestFile(result))) { + fprintf(stderr, "Missing result file %s\n", result); + } else if ((error) &&(!checkTestFile(error))) { + fprintf(stderr, "Missing error file %s\n", error); + } else { + mem = xmlMemUsed(); + extraMemoryFromResolver = 0; + testErrorsSize = 0; + testErrors[0] = 0; + res = tst->func(globbuf.gl_pathv[i], result, error, + tst->options); + xmlResetLastError(); + if (res != 0) { + fprintf(stderr, "File %s generated an error\n", + globbuf.gl_pathv[i]); + nb_errors++; + err++; + } + else if (xmlMemUsed() != mem) { + if ((xmlMemUsed() != mem) && + (extraMemoryFromResolver == 0)) { + fprintf(stderr, "File %s leaked %d bytes\n", + globbuf.gl_pathv[i], xmlMemUsed() - mem); + nb_leaks++; + err++; + } + } + testErrorsSize = 0; + } + if (result) + free(result); + if (error) + free(error); + } + globfree(&globbuf); + } else { + testErrorsSize = 0; + testErrors[0] = 0; + extraMemoryFromResolver = 0; + res = tst->func(NULL, NULL, NULL, tst->options); + if (res != 0) { + nb_errors++; + err++; + } + } + return(err); +} + +int +main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + int i = 0, res, ret = 0; + int verbose = 0; + int old_errors, old_tests, old_leaks; + + initializeLibxml2(); + + if ((argc >= 2) && (!strcmp(argv[1], "-v"))) + verbose = 1; + for (i = 0; testDescriptions[i].func != NULL; i++) { + old_errors = nb_errors; + old_tests = nb_tests; + old_leaks = nb_leaks; + if (testDescriptions[i].desc != NULL) + printf("## %s\n", testDescriptions[i].desc); + res = launchTests(&testDescriptions[i]); + if (res != 0) + ret++; + if (verbose) { + 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); + } + xmlCleanupParser(); + xmlMemoryDump(); + + return(ret); +} + +#else /* ! LIBXML_OUTPUT_ENABLED */ +int +main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + fprintf(stderr, "runtest requires output to be enabled in libxml2\n"); + return(1); +} +#endif -- cgit v1.2.3