blob: 63cf0d521d0d65779c4e9ac46053b83b3623b037 [file] [log] [blame]
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001/*
2 * runtest.c: C program to run libxml2 regression tests without
3 * requiring make or Python, and reducing platform dependancies
4 * to a strict minimum.
5 *
Daniel Veillard89074392005-07-04 16:24:31 +00006 * To compile on Unixes:
7 * cc -o runtest `xml2-config --cflags` runtest.c `xml2-config --libs` -lpthread
8 *
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00009 * See Copyright for the status of this software.
10 *
11 * daniel@veillard.com
12 */
13
Daniel Veillardc9352532005-07-04 14:25:34 +000014#if !defined(_WIN32) || defined(__CYGWIN__)
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000015#include <unistd.h>
Daniel Veillardc9352532005-07-04 14:25:34 +000016#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000017#include <string.h>
18#include <stdio.h>
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000019#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000022
23#include <libxml/parser.h>
24#include <libxml/tree.h>
Daniel Veillard30564042005-06-28 07:30:41 +000025#include <libxml/uri.h>
Daniel Veillard6b6d6802005-07-03 21:00:34 +000026
27#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardc111c152005-06-27 08:22:10 +000028#ifdef LIBXML_READER_ENABLED
29#include <libxml/xmlreader.h>
30#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000031
Daniel Veillard970adf52005-06-27 16:40:10 +000032#ifdef LIBXML_XINCLUDE_ENABLED
33#include <libxml/xinclude.h>
34#endif
35
36#ifdef LIBXML_XPATH_ENABLED
37#include <libxml/xpath.h>
38#include <libxml/xpathInternals.h>
39#ifdef LIBXML_XPTR_ENABLED
40#include <libxml/xpointer.h>
41#endif
42#endif
43
Daniel Veillardf2e066a2005-06-30 13:04:44 +000044#ifdef LIBXML_SCHEMAS_ENABLED
45#include <libxml/relaxng.h>
46#include <libxml/xmlschemas.h>
47#include <libxml/xmlschemastypes.h>
48#endif
49
50#ifdef LIBXML_PATTERN_ENABLED
51#include <libxml/pattern.h>
52#endif
53
54#ifdef LIBXML_C14N_ENABLED
55#include <libxml/c14n.h>
56#endif
57
Daniel Veillardfc319af2005-06-27 12:44:55 +000058#ifdef LIBXML_HTML_ENABLED
59#include <libxml/HTMLparser.h>
60#include <libxml/HTMLtree.h>
61
62/*
63 * pseudo flag for the unification of HTML and XML tests
64 */
65#define XML_PARSE_HTML 1 << 24
66#endif
67
Daniel Veillardf2e066a2005-06-30 13:04:44 +000068#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
69#include <libxml/globals.h>
70#include <libxml/threads.h>
71#include <libxml/parser.h>
72#include <libxml/catalog.h>
73#include <string.h>
Daniel Veillardf2e066a2005-06-30 13:04:44 +000074#endif
75
Daniel Veillardfd110d22005-06-27 00:02:02 +000076typedef int (*functest) (const char *filename, const char *result,
Daniel Veillardc111c152005-06-27 08:22:10 +000077 const char *error, int options);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000078
79typedef struct testDesc testDesc;
80typedef testDesc *testDescPtr;
81struct testDesc {
82 const char *desc; /* descripton of the test */
83 functest func; /* function implementing the test */
84 const char *in; /* glob to path for input files */
85 const char *out; /* output directory */
86 const char *suffix;/* suffix for output files */
Daniel Veillardfd110d22005-06-27 00:02:02 +000087 const char *err; /* suffix for error output files */
Daniel Veillardc111c152005-06-27 08:22:10 +000088 int options; /* parser options for the test */
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000089};
90
91static int checkTestFile(const char *filename);
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +000092
93#if defined(_WIN32) && !defined(__CYGWIN__)
94
Daniel Veillard90837782005-07-04 15:45:10 +000095#include <windows.h>
Daniel Veillard25450d02005-07-04 16:02:38 +000096#include <io.h>
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +000097
98typedef struct
99{
100 size_t gl_pathc; /* Count of paths matched so far */
101 char **gl_pathv; /* List of matched pathnames. */
102 size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
103} glob_t;
104
105#define GLOB_DOOFFS 0
106static int glob(const char *pattern, int flags,
107 int errfunc(const char *epath, int eerrno),
108 glob_t *pglob) {
109 glob_t *ret;
110 WIN32_FIND_DATA FindFileData;
111 HANDLE hFind;
Daniel Veillard25450d02005-07-04 16:02:38 +0000112 unsigned int nb_paths = 0;
Kasimier T. Buchcik87db1cf2005-07-05 10:40:52 +0000113 char directory[500];
Daniel Veillardf7d16602005-07-04 16:47:58 +0000114 int len;
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000115
116 if ((pattern == NULL) || (pglob == NULL)) return(-1);
117
Daniel Veillard73c0f712005-07-04 16:53:16 +0000118 strncpy(directory, pattern, 499);
Daniel Veillardf7d16602005-07-04 16:47:58 +0000119 for (len = strlen(directory);len >= 0;len--) {
120 if (directory[len] == '/') {
Daniel Veillard73c0f712005-07-04 16:53:16 +0000121 len++;
122 directory[len] = 0;
Daniel Veillardf7d16602005-07-04 16:47:58 +0000123 break;
124 }
125 }
126 if (len <= 0)
127 len = 0;
128
129
Daniel Veillard25450d02005-07-04 16:02:38 +0000130 ret = pglob;
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000131 memset(ret, 0, sizeof(glob_t));
132
133 hFind = FindFirstFileA(pattern, &FindFileData);
134 if (hFind == INVALID_HANDLE_VALUE)
135 return(0);
136 nb_paths = 20;
137 ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
138 if (ret->gl_pathv == NULL) {
139 FindClose(hFind);
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000140 return(-1);
141 }
Daniel Veillard73c0f712005-07-04 16:53:16 +0000142 strncpy(directory + len, FindFileData.cFileName, 499 - len);
Daniel Veillardf7d16602005-07-04 16:47:58 +0000143 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000144 if (ret->gl_pathv[ret->gl_pathc] == NULL)
145 goto done;
146 ret->gl_pathc++;
147 while(FindNextFileA(hFind, &FindFileData)) {
Daniel Veillard91fe3ed2005-07-04 18:13:15 +0000148 if (FindFileData.cFileName[0] == '.')
Daniel Veillard89074392005-07-04 16:24:31 +0000149 continue;
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000150 if (ret->gl_pathc + 2 > nb_paths) {
151 char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
152 if (tmp == NULL)
153 break;
154 ret->gl_pathv = tmp;
155 nb_paths *= 2;
156 }
Daniel Veillard73c0f712005-07-04 16:53:16 +0000157 strncpy(directory + len, FindFileData.cFileName, 499 - len);
Daniel Veillardf7d16602005-07-04 16:47:58 +0000158 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000159 if (ret->gl_pathv[ret->gl_pathc] == NULL)
160 break;
161 ret->gl_pathc++;
162 }
163 ret->gl_pathv[ret->gl_pathc] = NULL;
164
165done:
166 FindClose(hFind);
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000167 return(0);
168}
Daniel Veillard90837782005-07-04 15:45:10 +0000169
170
171
172static void globfree(glob_t *pglob) {
173 unsigned int i;
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000174 if (pglob == NULL)
175 return;
176
177 for (i = 0;i < pglob->gl_pathc;i++) {
178 if (pglob->gl_pathv[i] != NULL)
179 free(pglob->gl_pathv[i]);
180 }
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000181}
182#define vsnprintf _vsnprintf
Daniel Veillard90837782005-07-04 15:45:10 +0000183#define snprintf _snprintf
Daniel Veillard4ac5f9a2005-07-04 15:20:27 +0000184#else
185#include <glob.h>
186#endif
187
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000188/************************************************************************
189 * *
190 * Libxml2 specific routines *
191 * *
192 ************************************************************************/
193
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000194static int nb_tests = 0;
195static int nb_errors = 0;
196static int nb_leaks = 0;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000197static long libxmlMemoryAllocatedBase = 0;
198static int extraMemoryFromResolver = 0;
199
200static int
201fatalError(void) {
202 fprintf(stderr, "Exitting tests on fatal error\n");
203 exit(1);
204}
205
206/*
207 * We need to trap calls to the resolver to not account memory for the catalog
208 * which is shared to the current running test. We also don't want to have
209 * network downloads modifying tests.
210 */
211static xmlParserInputPtr
212testExternalEntityLoader(const char *URL, const char *ID,
213 xmlParserCtxtPtr ctxt) {
214 xmlParserInputPtr ret;
215
216 if (checkTestFile(URL)) {
217 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
218 } else {
219 int memused = xmlMemUsed();
220 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
221 extraMemoryFromResolver += xmlMemUsed() - memused;
222 }
223
224 return(ret);
225}
226
Daniel Veillardfd110d22005-06-27 00:02:02 +0000227/*
228 * Trapping the error messages at the generic level to grab the equivalent of
229 * stderr messages on CLI tools.
230 */
231static char testErrors[32769];
232static int testErrorsSize = 0;
233
234static void
Daniel Veillardc111c152005-06-27 08:22:10 +0000235testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
Daniel Veillardfd110d22005-06-27 00:02:02 +0000236 va_list args;
237 int res;
238
239 if (testErrorsSize >= 32768)
240 return;
241 va_start(args, msg);
242 res = vsnprintf(&testErrors[testErrorsSize],
243 32768 - testErrorsSize,
244 msg, args);
245 va_end(args);
246 if (testErrorsSize + res >= 32768) {
247 /* buffer is full */
248 testErrorsSize = 32768;
249 testErrors[testErrorsSize] = 0;
250 } else {
251 testErrorsSize += res;
252 }
253 testErrors[testErrorsSize] = 0;
254}
255
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000256static void
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000257channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
258 va_list args;
259 int res;
260
261 if (testErrorsSize >= 32768)
262 return;
263 va_start(args, msg);
264 res = vsnprintf(&testErrors[testErrorsSize],
265 32768 - testErrorsSize,
266 msg, args);
267 va_end(args);
268 if (testErrorsSize + res >= 32768) {
269 /* buffer is full */
270 testErrorsSize = 32768;
271 testErrors[testErrorsSize] = 0;
272 } else {
273 testErrorsSize += res;
274 }
275 testErrors[testErrorsSize] = 0;
276}
277
278/**
279 * xmlParserPrintFileContext:
280 * @input: an xmlParserInputPtr input
281 *
282 * Displays current context within the input content for error tracking
283 */
284
285static void
286xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
287 xmlGenericErrorFunc chanl, void *data ) {
288 const xmlChar *cur, *base;
289 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
290 xmlChar content[81]; /* space for 80 chars + line terminator */
291 xmlChar *ctnt;
292
293 if (input == NULL) return;
294 cur = input->cur;
295 base = input->base;
296 /* skip backwards over any end-of-lines */
297 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
298 cur--;
299 }
300 n = 0;
301 /* search backwards for beginning-of-line (to max buff size) */
302 while ((n++ < (sizeof(content)-1)) && (cur > base) &&
303 (*(cur) != '\n') && (*(cur) != '\r'))
304 cur--;
305 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
306 /* calculate the error position in terms of the current position */
307 col = input->cur - cur;
308 /* search forward for end-of-line (to max buff size) */
309 n = 0;
310 ctnt = content;
311 /* copy selected text to our buffer */
312 while ((*cur != 0) && (*(cur) != '\n') &&
313 (*(cur) != '\r') && (n < sizeof(content)-1)) {
314 *ctnt++ = *cur++;
315 n++;
316 }
317 *ctnt = 0;
318 /* print out the selected text */
319 chanl(data ,"%s\n", content);
320 /* create blank line with problem pointer */
321 n = 0;
322 ctnt = content;
323 /* (leave buffer space for pointer + line terminator) */
324 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
325 if (*(ctnt) != '\t')
326 *(ctnt) = ' ';
327 ctnt++;
328 }
329 *ctnt++ = '^';
330 *ctnt = 0;
331 chanl(data ,"%s\n", content);
332}
333
334static void
335testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
336 char *file = NULL;
337 int line = 0;
338 int code = -1;
339 int domain;
340 void *data = NULL;
341 const char *str;
342 const xmlChar *name = NULL;
343 xmlNodePtr node;
344 xmlErrorLevel level;
345 xmlParserInputPtr input = NULL;
346 xmlParserInputPtr cur = NULL;
347 xmlParserCtxtPtr ctxt = NULL;
348
349 if (err == NULL)
350 return;
351
352 file = err->file;
353 line = err->line;
354 code = err->code;
355 domain = err->domain;
356 level = err->level;
357 node = err->node;
358 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
359 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
360 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
361 ctxt = err->ctxt;
362 }
363 str = err->message;
364
365 if (code == XML_ERR_OK)
366 return;
367
368 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
369 name = node->name;
370
371 /*
372 * Maintain the compatibility with the legacy error handling
373 */
374 if (ctxt != NULL) {
375 input = ctxt->input;
376 if ((input != NULL) && (input->filename == NULL) &&
377 (ctxt->inputNr > 1)) {
378 cur = input;
379 input = ctxt->inputTab[ctxt->inputNr - 2];
380 }
381 if (input != NULL) {
382 if (input->filename)
383 channel(data, "%s:%d: ", input->filename, input->line);
384 else if ((line != 0) && (domain == XML_FROM_PARSER))
385 channel(data, "Entity: line %d: ", input->line);
386 }
387 } else {
388 if (file != NULL)
389 channel(data, "%s:%d: ", file, line);
390 else if ((line != 0) && (domain == XML_FROM_PARSER))
391 channel(data, "Entity: line %d: ", line);
392 }
393 if (name != NULL) {
394 channel(data, "element %s: ", name);
395 }
396 if (code == XML_ERR_OK)
397 return;
398 switch (domain) {
399 case XML_FROM_PARSER:
400 channel(data, "parser ");
401 break;
402 case XML_FROM_NAMESPACE:
403 channel(data, "namespace ");
404 break;
405 case XML_FROM_DTD:
406 case XML_FROM_VALID:
407 channel(data, "validity ");
408 break;
409 case XML_FROM_HTML:
410 channel(data, "HTML parser ");
411 break;
412 case XML_FROM_MEMORY:
413 channel(data, "memory ");
414 break;
415 case XML_FROM_OUTPUT:
416 channel(data, "output ");
417 break;
418 case XML_FROM_IO:
419 channel(data, "I/O ");
420 break;
421 case XML_FROM_XINCLUDE:
422 channel(data, "XInclude ");
423 break;
424 case XML_FROM_XPATH:
425 channel(data, "XPath ");
426 break;
427 case XML_FROM_XPOINTER:
428 channel(data, "parser ");
429 break;
430 case XML_FROM_REGEXP:
431 channel(data, "regexp ");
432 break;
433 case XML_FROM_MODULE:
434 channel(data, "module ");
435 break;
436 case XML_FROM_SCHEMASV:
437 channel(data, "Schemas validity ");
438 break;
439 case XML_FROM_SCHEMASP:
440 channel(data, "Schemas parser ");
441 break;
442 case XML_FROM_RELAXNGP:
443 channel(data, "Relax-NG parser ");
444 break;
445 case XML_FROM_RELAXNGV:
446 channel(data, "Relax-NG validity ");
447 break;
448 case XML_FROM_CATALOG:
449 channel(data, "Catalog ");
450 break;
451 case XML_FROM_C14N:
452 channel(data, "C14N ");
453 break;
454 case XML_FROM_XSLT:
455 channel(data, "XSLT ");
456 break;
457 default:
458 break;
459 }
460 if (code == XML_ERR_OK)
461 return;
462 switch (level) {
463 case XML_ERR_NONE:
464 channel(data, ": ");
465 break;
466 case XML_ERR_WARNING:
467 channel(data, "warning : ");
468 break;
469 case XML_ERR_ERROR:
470 channel(data, "error : ");
471 break;
472 case XML_ERR_FATAL:
473 channel(data, "error : ");
474 break;
475 }
476 if (code == XML_ERR_OK)
477 return;
478 if (str != NULL) {
479 int len;
480 len = xmlStrlen((const xmlChar *)str);
481 if ((len > 0) && (str[len - 1] != '\n'))
482 channel(data, "%s\n", str);
483 else
484 channel(data, "%s", str);
485 } else {
486 channel(data, "%s\n", "out of memory error");
487 }
488 if (code == XML_ERR_OK)
489 return;
490
491 if (ctxt != NULL) {
492 xmlParserPrintFileContextInternal(input, channel, data);
493 if (cur != NULL) {
494 if (cur->filename)
495 channel(data, "%s:%d: \n", cur->filename, cur->line);
496 else if ((line != 0) && (domain == XML_FROM_PARSER))
497 channel(data, "Entity: line %d: \n", cur->line);
498 xmlParserPrintFileContextInternal(cur, channel, data);
499 }
500 }
501 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
502 (err->int1 < 100) &&
503 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
504 xmlChar buf[150];
505 int i;
506
507 channel(data, "%s\n", err->str1);
508 for (i=0;i < err->int1;i++)
509 buf[i] = ' ';
510 buf[i++] = '^';
511 buf[i] = 0;
512 channel(data, "%s\n", buf);
513 }
514}
515
516static void
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000517initializeLibxml2(void) {
518 xmlGetWarningsDefaultValue = 0;
519 xmlPedanticParserDefault(0);
520
521 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
522 xmlInitParser();
523 xmlSetExternalEntityLoader(testExternalEntityLoader);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000524 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
525#ifdef LIBXML_SCHEMAS_ENABLED
526 xmlSchemaInitTypes();
527 xmlRelaxNGInitTypes();
528#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000529 libxmlMemoryAllocatedBase = xmlMemUsed();
530}
531
532
533/************************************************************************
534 * *
535 * File name and path utilities *
536 * *
537 ************************************************************************/
538
539static const char *baseFilename(const char *filename) {
540 const char *cur;
541 if (filename == NULL)
542 return(NULL);
543 cur = &filename[strlen(filename)];
544 while ((cur > filename) && (*cur != '/'))
545 cur--;
546 if (*cur == '/')
547 return(cur + 1);
548 return(cur);
549}
550
551static char *resultFilename(const char *filename, const char *out,
552 const char *suffix) {
553 const char *base;
554 char res[500];
555
556/*************
557 if ((filename[0] == 't') && (filename[1] == 'e') &&
558 (filename[2] == 's') && (filename[3] == 't') &&
559 (filename[4] == '/'))
560 filename = &filename[5];
561 *************/
562
563 base = baseFilename(filename);
564 if (suffix == NULL)
565 suffix = ".tmp";
566 if (out == NULL)
567 out = "";
568 snprintf(res, 499, "%s%s%s", out, base, suffix);
569 res[499] = 0;
570 return(strdup(res));
571}
572
573static int checkTestFile(const char *filename) {
574 struct stat buf;
575
576 if (stat(filename, &buf) == -1)
577 return(0);
578
Daniel Veillard25450d02005-07-04 16:02:38 +0000579#if defined(_WIN32) && !defined(__CYGWIN__)
580 if (!(buf.st_mode & _S_IFREG))
581 return(0);
582#else
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000583 if (!S_ISREG(buf.st_mode))
584 return(0);
Daniel Veillard25450d02005-07-04 16:02:38 +0000585#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000586
587 return(1);
588}
589
590static int compareFiles(const char *r1, const char *r2) {
591 int res1, res2;
592 int fd1, fd2;
593 char bytes1[4096];
594 char bytes2[4096];
595
596 fd1 = open(r1, O_RDONLY);
597 if (fd1 < 0)
598 return(-1);
599 fd2 = open(r2, O_RDONLY);
600 if (fd2 < 0) {
601 close(fd1);
602 return(-1);
603 }
604 while (1) {
605 res1 = read(fd1, bytes1, 4096);
606 res2 = read(fd2, bytes2, 4096);
607 if (res1 != res2) {
608 close(fd1);
609 close(fd2);
610 return(1);
611 }
612 if (res1 == 0)
613 break;
614 if (memcmp(bytes1, bytes2, res1) != 0) {
615 close(fd1);
616 close(fd2);
617 return(1);
618 }
619 }
620 close(fd1);
621 close(fd2);
622 return(0);
623}
624
Daniel Veillardfd110d22005-06-27 00:02:02 +0000625static int compareFileMem(const char *filename, const char *mem, int size) {
626 int res;
627 int fd;
628 char bytes[4096];
629 int idx = 0;
630 struct stat info;
631
632 if (stat(filename, &info) < 0)
633 return(-1);
634 if (info.st_size != size)
635 return(-1);
636 fd = open(filename, O_RDONLY);
637 if (fd < 0)
638 return(-1);
639 while (idx < size) {
640 res = read(fd, bytes, 4096);
641 if (res <= 0)
642 break;
643 if (res + idx > size)
644 break;
645 if (memcmp(bytes, &mem[idx], res) != 0) {
646 close(fd);
647 return(1);
648 }
649 idx += res;
650 }
651 close(fd);
652 return(idx != size);
653}
654
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000655static int loadMem(const char *filename, const char **mem, int *size) {
656 int fd, res;
657 struct stat info;
658 char *base;
659 int siz = 0;
660 if (stat(filename, &info) < 0)
661 return(-1);
662 base = malloc(info.st_size + 1);
663 if (base == NULL)
664 return(-1);
665 if ((fd = open(filename, O_RDONLY)) < 0) {
666 free(base);
667 return(-1);
668 }
669 while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
670 siz += res;
671 }
Kasimier T. Buchcik87db1cf2005-07-05 10:40:52 +0000672 close(fd);
673#if !defined(_WIN32)
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000674 if (siz != info.st_size) {
675 free(base);
676 return(-1);
Kasimier T. Buchcik87db1cf2005-07-05 10:40:52 +0000677 }
678#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000679 base[siz] = 0;
680 *mem = base;
681 *size = siz;
682 return(0);
683}
684
685static int unloadMem(const char *mem) {
686 free((char *)mem);
687 return(0);
688}
689
690/************************************************************************
691 * *
692 * Tests implementations *
693 * *
694 ************************************************************************/
695
Daniel Veillard4a5a9642005-06-27 10:40:55 +0000696/************************************************************************
697 * *
698 * Parse to SAX based tests *
699 * *
700 ************************************************************************/
701
702FILE *SAXdebug = NULL;
703
704/*
705 * empty SAX block
706 */
707xmlSAXHandler emptySAXHandlerStruct = {
708 NULL, /* internalSubset */
709 NULL, /* isStandalone */
710 NULL, /* hasInternalSubset */
711 NULL, /* hasExternalSubset */
712 NULL, /* resolveEntity */
713 NULL, /* getEntity */
714 NULL, /* entityDecl */
715 NULL, /* notationDecl */
716 NULL, /* attributeDecl */
717 NULL, /* elementDecl */
718 NULL, /* unparsedEntityDecl */
719 NULL, /* setDocumentLocator */
720 NULL, /* startDocument */
721 NULL, /* endDocument */
722 NULL, /* startElement */
723 NULL, /* endElement */
724 NULL, /* reference */
725 NULL, /* characters */
726 NULL, /* ignorableWhitespace */
727 NULL, /* processingInstruction */
728 NULL, /* comment */
729 NULL, /* xmlParserWarning */
730 NULL, /* xmlParserError */
731 NULL, /* xmlParserError */
732 NULL, /* getParameterEntity */
733 NULL, /* cdataBlock; */
734 NULL, /* externalSubset; */
735 1,
736 NULL,
737 NULL, /* startElementNs */
738 NULL, /* endElementNs */
739 NULL /* xmlStructuredErrorFunc */
740};
741
742static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
743int callbacks = 0;
744int quiet = 0;
745
746/**
747 * isStandaloneDebug:
748 * @ctxt: An XML parser context
749 *
750 * Is this document tagged standalone ?
751 *
752 * Returns 1 if true
753 */
754static int
755isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
756{
757 callbacks++;
758 if (quiet)
759 return(0);
760 fprintf(SAXdebug, "SAX.isStandalone()\n");
761 return(0);
762}
763
764/**
765 * hasInternalSubsetDebug:
766 * @ctxt: An XML parser context
767 *
768 * Does this document has an internal subset
769 *
770 * Returns 1 if true
771 */
772static int
773hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
774{
775 callbacks++;
776 if (quiet)
777 return(0);
778 fprintf(SAXdebug, "SAX.hasInternalSubset()\n");
779 return(0);
780}
781
782/**
783 * hasExternalSubsetDebug:
784 * @ctxt: An XML parser context
785 *
786 * Does this document has an external subset
787 *
788 * Returns 1 if true
789 */
790static int
791hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
792{
793 callbacks++;
794 if (quiet)
795 return(0);
796 fprintf(SAXdebug, "SAX.hasExternalSubset()\n");
797 return(0);
798}
799
800/**
801 * internalSubsetDebug:
802 * @ctxt: An XML parser context
803 *
804 * Does this document has an internal subset
805 */
806static void
807internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
808 const xmlChar *ExternalID, const xmlChar *SystemID)
809{
810 callbacks++;
811 if (quiet)
812 return;
813 fprintf(SAXdebug, "SAX.internalSubset(%s,", name);
814 if (ExternalID == NULL)
815 fprintf(SAXdebug, " ,");
816 else
817 fprintf(SAXdebug, " %s,", ExternalID);
818 if (SystemID == NULL)
819 fprintf(SAXdebug, " )\n");
820 else
821 fprintf(SAXdebug, " %s)\n", SystemID);
822}
823
824/**
825 * externalSubsetDebug:
826 * @ctxt: An XML parser context
827 *
828 * Does this document has an external subset
829 */
830static void
831externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
832 const xmlChar *ExternalID, const xmlChar *SystemID)
833{
834 callbacks++;
835 if (quiet)
836 return;
837 fprintf(SAXdebug, "SAX.externalSubset(%s,", name);
838 if (ExternalID == NULL)
839 fprintf(SAXdebug, " ,");
840 else
841 fprintf(SAXdebug, " %s,", ExternalID);
842 if (SystemID == NULL)
843 fprintf(SAXdebug, " )\n");
844 else
845 fprintf(SAXdebug, " %s)\n", SystemID);
846}
847
848/**
849 * resolveEntityDebug:
850 * @ctxt: An XML parser context
851 * @publicId: The public ID of the entity
852 * @systemId: The system ID of the entity
853 *
854 * Special entity resolver, better left to the parser, it has
855 * more context than the application layer.
856 * The default behaviour is to NOT resolve the entities, in that case
857 * the ENTITY_REF nodes are built in the structure (and the parameter
858 * values).
859 *
860 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
861 */
862static xmlParserInputPtr
863resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
864{
865 callbacks++;
866 if (quiet)
867 return(NULL);
868 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
869
870
871 fprintf(SAXdebug, "SAX.resolveEntity(");
872 if (publicId != NULL)
873 fprintf(SAXdebug, "%s", (char *)publicId);
874 else
875 fprintf(SAXdebug, " ");
876 if (systemId != NULL)
877 fprintf(SAXdebug, ", %s)\n", (char *)systemId);
878 else
879 fprintf(SAXdebug, ", )\n");
880/*********
881 if (systemId != NULL) {
882 return(xmlNewInputFromFile(ctxt, (char *) systemId));
883 }
884 *********/
885 return(NULL);
886}
887
888/**
889 * getEntityDebug:
890 * @ctxt: An XML parser context
891 * @name: The entity name
892 *
893 * Get an entity by name
894 *
895 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
896 */
897static xmlEntityPtr
898getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
899{
900 callbacks++;
901 if (quiet)
902 return(NULL);
903 fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
904 return(NULL);
905}
906
907/**
908 * getParameterEntityDebug:
909 * @ctxt: An XML parser context
910 * @name: The entity name
911 *
912 * Get a parameter entity by name
913 *
914 * Returns the xmlParserInputPtr
915 */
916static xmlEntityPtr
917getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
918{
919 callbacks++;
920 if (quiet)
921 return(NULL);
922 fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
923 return(NULL);
924}
925
926
927/**
928 * entityDeclDebug:
929 * @ctxt: An XML parser context
930 * @name: the entity name
931 * @type: the entity type
932 * @publicId: The public ID of the entity
933 * @systemId: The system ID of the entity
934 * @content: the entity value (without processing).
935 *
936 * An entity definition has been parsed
937 */
938static void
939entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
940 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
941{
942const xmlChar *nullstr = BAD_CAST "(null)";
943 /* not all libraries handle printing null pointers nicely */
944 if (publicId == NULL)
945 publicId = nullstr;
946 if (systemId == NULL)
947 systemId = nullstr;
948 if (content == NULL)
949 content = (xmlChar *)nullstr;
950 callbacks++;
951 if (quiet)
952 return;
953 fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
954 name, type, publicId, systemId, content);
955}
956
957/**
958 * attributeDeclDebug:
959 * @ctxt: An XML parser context
960 * @name: the attribute name
961 * @type: the attribute type
962 *
963 * An attribute definition has been parsed
964 */
965static void
966attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
967 const xmlChar * name, int type, int def,
968 const xmlChar * defaultValue, xmlEnumerationPtr tree)
969{
970 callbacks++;
971 if (quiet)
972 return;
973 if (defaultValue == NULL)
974 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
975 elem, name, type, def);
976 else
977 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
978 elem, name, type, def, defaultValue);
979 xmlFreeEnumeration(tree);
980}
981
982/**
983 * elementDeclDebug:
984 * @ctxt: An XML parser context
985 * @name: the element name
986 * @type: the element type
987 * @content: the element value (without processing).
988 *
989 * An element definition has been parsed
990 */
991static void
992elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
993 xmlElementContentPtr content ATTRIBUTE_UNUSED)
994{
995 callbacks++;
996 if (quiet)
997 return;
998 fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n",
999 name, type);
1000}
1001
1002/**
1003 * notationDeclDebug:
1004 * @ctxt: An XML parser context
1005 * @name: The name of the notation
1006 * @publicId: The public ID of the entity
1007 * @systemId: The system ID of the entity
1008 *
1009 * What to do when a notation declaration has been parsed.
1010 */
1011static void
1012notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1013 const xmlChar *publicId, const xmlChar *systemId)
1014{
1015 callbacks++;
1016 if (quiet)
1017 return;
1018 fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n",
1019 (char *) name, (char *) publicId, (char *) systemId);
1020}
1021
1022/**
1023 * unparsedEntityDeclDebug:
1024 * @ctxt: An XML parser context
1025 * @name: The name of the entity
1026 * @publicId: The public ID of the entity
1027 * @systemId: The system ID of the entity
1028 * @notationName: the name of the notation
1029 *
1030 * What to do when an unparsed entity declaration is parsed
1031 */
1032static void
1033unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1034 const xmlChar *publicId, const xmlChar *systemId,
1035 const xmlChar *notationName)
1036{
1037const xmlChar *nullstr = BAD_CAST "(null)";
1038
1039 if (publicId == NULL)
1040 publicId = nullstr;
1041 if (systemId == NULL)
1042 systemId = nullstr;
1043 if (notationName == NULL)
1044 notationName = nullstr;
1045 callbacks++;
1046 if (quiet)
1047 return;
1048 fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
1049 (char *) name, (char *) publicId, (char *) systemId,
1050 (char *) notationName);
1051}
1052
1053/**
1054 * setDocumentLocatorDebug:
1055 * @ctxt: An XML parser context
1056 * @loc: A SAX Locator
1057 *
1058 * Receive the document locator at startup, actually xmlDefaultSAXLocator
1059 * Everything is available on the context, so this is useless in our case.
1060 */
1061static void
1062setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
1063{
1064 callbacks++;
1065 if (quiet)
1066 return;
1067 fprintf(SAXdebug, "SAX.setDocumentLocator()\n");
1068}
1069
1070/**
1071 * startDocumentDebug:
1072 * @ctxt: An XML parser context
1073 *
1074 * called when the document start being processed.
1075 */
1076static void
1077startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1078{
1079 callbacks++;
1080 if (quiet)
1081 return;
1082 fprintf(SAXdebug, "SAX.startDocument()\n");
1083}
1084
1085/**
1086 * endDocumentDebug:
1087 * @ctxt: An XML parser context
1088 *
1089 * called when the document end has been detected.
1090 */
1091static void
1092endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1093{
1094 callbacks++;
1095 if (quiet)
1096 return;
1097 fprintf(SAXdebug, "SAX.endDocument()\n");
1098}
1099
1100/**
1101 * startElementDebug:
1102 * @ctxt: An XML parser context
1103 * @name: The element name
1104 *
1105 * called when an opening tag has been processed.
1106 */
1107static void
1108startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1109{
1110 int i;
1111
1112 callbacks++;
1113 if (quiet)
1114 return;
1115 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1116 if (atts != NULL) {
1117 for (i = 0;(atts[i] != NULL);i++) {
1118 fprintf(SAXdebug, ", %s='", atts[i++]);
1119 if (atts[i] != NULL)
1120 fprintf(SAXdebug, "%s'", atts[i]);
1121 }
1122 }
1123 fprintf(SAXdebug, ")\n");
1124}
1125
1126/**
1127 * endElementDebug:
1128 * @ctxt: An XML parser context
1129 * @name: The element name
1130 *
1131 * called when the end of an element has been detected.
1132 */
1133static void
1134endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1135{
1136 callbacks++;
1137 if (quiet)
1138 return;
1139 fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name);
1140}
1141
1142/**
1143 * charactersDebug:
1144 * @ctxt: An XML parser context
1145 * @ch: a xmlChar string
1146 * @len: the number of xmlChar
1147 *
1148 * receiving some chars from the parser.
1149 * Question: how much at a time ???
1150 */
1151static void
1152charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1153{
1154 char output[40];
1155 int i;
1156
1157 callbacks++;
1158 if (quiet)
1159 return;
1160 for (i = 0;(i<len) && (i < 30);i++)
1161 output[i] = ch[i];
1162 output[i] = 0;
1163
1164 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1165}
1166
1167/**
1168 * referenceDebug:
1169 * @ctxt: An XML parser context
1170 * @name: The entity name
1171 *
1172 * called when an entity reference is detected.
1173 */
1174static void
1175referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1176{
1177 callbacks++;
1178 if (quiet)
1179 return;
1180 fprintf(SAXdebug, "SAX.reference(%s)\n", name);
1181}
1182
1183/**
1184 * ignorableWhitespaceDebug:
1185 * @ctxt: An XML parser context
1186 * @ch: a xmlChar string
1187 * @start: the first char in the string
1188 * @len: the number of xmlChar
1189 *
1190 * receiving some ignorable whitespaces from the parser.
1191 * Question: how much at a time ???
1192 */
1193static void
1194ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1195{
1196 char output[40];
1197 int i;
1198
1199 callbacks++;
1200 if (quiet)
1201 return;
1202 for (i = 0;(i<len) && (i < 30);i++)
1203 output[i] = ch[i];
1204 output[i] = 0;
1205 fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
1206}
1207
1208/**
1209 * processingInstructionDebug:
1210 * @ctxt: An XML parser context
1211 * @target: the target name
1212 * @data: the PI data's
1213 * @len: the number of xmlChar
1214 *
1215 * A processing instruction has been parsed.
1216 */
1217static void
1218processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
1219 const xmlChar *data)
1220{
1221 callbacks++;
1222 if (quiet)
1223 return;
1224 if (data != NULL)
1225 fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n",
1226 (char *) target, (char *) data);
1227 else
1228 fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n",
1229 (char *) target);
1230}
1231
1232/**
1233 * cdataBlockDebug:
1234 * @ctx: the user data (XML parser context)
1235 * @value: The pcdata content
1236 * @len: the block length
1237 *
1238 * called when a pcdata block has been parsed
1239 */
1240static void
1241cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
1242{
1243 callbacks++;
1244 if (quiet)
1245 return;
1246 fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n",
1247 (char *) value, len);
1248}
1249
1250/**
1251 * commentDebug:
1252 * @ctxt: An XML parser context
1253 * @value: the comment content
1254 *
1255 * A comment has been parsed.
1256 */
1257static void
1258commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
1259{
1260 callbacks++;
1261 if (quiet)
1262 return;
1263 fprintf(SAXdebug, "SAX.comment(%s)\n", value);
1264}
1265
1266/**
1267 * warningDebug:
1268 * @ctxt: An XML parser context
1269 * @msg: the message to display/transmit
1270 * @...: extra parameters for the message display
1271 *
1272 * Display and format a warning messages, gives file, line, position and
1273 * extra parameters.
1274 */
1275static void
1276warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1277{
1278 va_list args;
1279
1280 callbacks++;
1281 if (quiet)
1282 return;
1283 va_start(args, msg);
1284 fprintf(SAXdebug, "SAX.warning: ");
1285 vfprintf(SAXdebug, msg, args);
1286 va_end(args);
1287}
1288
1289/**
1290 * errorDebug:
1291 * @ctxt: An XML parser context
1292 * @msg: the message to display/transmit
1293 * @...: extra parameters for the message display
1294 *
1295 * Display and format a error messages, gives file, line, position and
1296 * extra parameters.
1297 */
1298static void
1299errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1300{
1301 va_list args;
1302
1303 callbacks++;
1304 if (quiet)
1305 return;
1306 va_start(args, msg);
1307 fprintf(SAXdebug, "SAX.error: ");
1308 vfprintf(SAXdebug, msg, args);
1309 va_end(args);
1310}
1311
1312/**
1313 * fatalErrorDebug:
1314 * @ctxt: An XML parser context
1315 * @msg: the message to display/transmit
1316 * @...: extra parameters for the message display
1317 *
1318 * Display and format a fatalError messages, gives file, line, position and
1319 * extra parameters.
1320 */
1321static void
1322fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1323{
1324 va_list args;
1325
1326 callbacks++;
1327 if (quiet)
1328 return;
1329 va_start(args, msg);
1330 fprintf(SAXdebug, "SAX.fatalError: ");
1331 vfprintf(SAXdebug, msg, args);
1332 va_end(args);
1333}
1334
1335xmlSAXHandler debugSAXHandlerStruct = {
1336 internalSubsetDebug,
1337 isStandaloneDebug,
1338 hasInternalSubsetDebug,
1339 hasExternalSubsetDebug,
1340 resolveEntityDebug,
1341 getEntityDebug,
1342 entityDeclDebug,
1343 notationDeclDebug,
1344 attributeDeclDebug,
1345 elementDeclDebug,
1346 unparsedEntityDeclDebug,
1347 setDocumentLocatorDebug,
1348 startDocumentDebug,
1349 endDocumentDebug,
1350 startElementDebug,
1351 endElementDebug,
1352 referenceDebug,
1353 charactersDebug,
1354 ignorableWhitespaceDebug,
1355 processingInstructionDebug,
1356 commentDebug,
1357 warningDebug,
1358 errorDebug,
1359 fatalErrorDebug,
1360 getParameterEntityDebug,
1361 cdataBlockDebug,
1362 externalSubsetDebug,
1363 1,
1364 NULL,
1365 NULL,
1366 NULL,
1367 NULL
1368};
1369
1370xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
1371
1372/*
1373 * SAX2 specific callbacks
1374 */
1375/**
1376 * startElementNsDebug:
1377 * @ctxt: An XML parser context
1378 * @name: The element name
1379 *
1380 * called when an opening tag has been processed.
1381 */
1382static void
1383startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1384 const xmlChar *localname,
1385 const xmlChar *prefix,
1386 const xmlChar *URI,
1387 int nb_namespaces,
1388 const xmlChar **namespaces,
1389 int nb_attributes,
1390 int nb_defaulted,
1391 const xmlChar **attributes)
1392{
1393 int i;
1394
1395 callbacks++;
1396 if (quiet)
1397 return;
1398 fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname);
1399 if (prefix == NULL)
1400 fprintf(SAXdebug, ", NULL");
1401 else
1402 fprintf(SAXdebug, ", %s", (char *) prefix);
1403 if (URI == NULL)
1404 fprintf(SAXdebug, ", NULL");
1405 else
1406 fprintf(SAXdebug, ", '%s'", (char *) URI);
1407 fprintf(SAXdebug, ", %d", nb_namespaces);
1408
1409 if (namespaces != NULL) {
1410 for (i = 0;i < nb_namespaces * 2;i++) {
1411 fprintf(SAXdebug, ", xmlns");
1412 if (namespaces[i] != NULL)
1413 fprintf(SAXdebug, ":%s", namespaces[i]);
1414 i++;
1415 fprintf(SAXdebug, "='%s'", namespaces[i]);
1416 }
1417 }
1418 fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted);
1419 if (attributes != NULL) {
1420 for (i = 0;i < nb_attributes * 5;i += 5) {
1421 if (attributes[i + 1] != NULL)
1422 fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]);
1423 else
1424 fprintf(SAXdebug, ", %s='", attributes[i]);
1425 fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3],
1426 (int)(attributes[i + 4] - attributes[i + 3]));
1427 }
1428 }
1429 fprintf(SAXdebug, ")\n");
1430}
1431
1432/**
1433 * endElementDebug:
1434 * @ctxt: An XML parser context
1435 * @name: The element name
1436 *
1437 * called when the end of an element has been detected.
1438 */
1439static void
1440endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1441 const xmlChar *localname,
1442 const xmlChar *prefix,
1443 const xmlChar *URI)
1444{
1445 callbacks++;
1446 if (quiet)
1447 return;
1448 fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname);
1449 if (prefix == NULL)
1450 fprintf(SAXdebug, ", NULL");
1451 else
1452 fprintf(SAXdebug, ", %s", (char *) prefix);
1453 if (URI == NULL)
1454 fprintf(SAXdebug, ", NULL)\n");
1455 else
1456 fprintf(SAXdebug, ", '%s')\n", (char *) URI);
1457}
1458
1459xmlSAXHandler debugSAX2HandlerStruct = {
1460 internalSubsetDebug,
1461 isStandaloneDebug,
1462 hasInternalSubsetDebug,
1463 hasExternalSubsetDebug,
1464 resolveEntityDebug,
1465 getEntityDebug,
1466 entityDeclDebug,
1467 notationDeclDebug,
1468 attributeDeclDebug,
1469 elementDeclDebug,
1470 unparsedEntityDeclDebug,
1471 setDocumentLocatorDebug,
1472 startDocumentDebug,
1473 endDocumentDebug,
1474 NULL,
1475 NULL,
1476 referenceDebug,
1477 charactersDebug,
1478 ignorableWhitespaceDebug,
1479 processingInstructionDebug,
1480 commentDebug,
1481 warningDebug,
1482 errorDebug,
1483 fatalErrorDebug,
1484 getParameterEntityDebug,
1485 cdataBlockDebug,
1486 externalSubsetDebug,
1487 XML_SAX2_MAGIC,
1488 NULL,
1489 startElementNsDebug,
1490 endElementNsDebug,
1491 NULL
1492};
1493
1494xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
1495
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001496#ifdef LIBXML_HTML_ENABLED
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001497/**
Daniel Veillardfc319af2005-06-27 12:44:55 +00001498 * htmlstartElementDebug:
1499 * @ctxt: An XML parser context
1500 * @name: The element name
1501 *
1502 * called when an opening tag has been processed.
1503 */
1504static void
1505htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1506{
1507 int i;
1508
1509 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1510 if (atts != NULL) {
1511 for (i = 0;(atts[i] != NULL);i++) {
1512 fprintf(SAXdebug, ", %s", atts[i++]);
1513 if (atts[i] != NULL) {
1514 unsigned char output[40];
1515 const unsigned char *att = atts[i];
1516 int outlen, attlen;
1517 fprintf(SAXdebug, "='");
1518 while ((attlen = strlen((char*)att)) > 0) {
1519 outlen = sizeof output - 1;
1520 htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
1521 output[outlen] = 0;
1522 fprintf(SAXdebug, "%s", (char *) output);
1523 att += attlen;
1524 }
1525 fprintf(SAXdebug, "'");
1526 }
1527 }
1528 }
1529 fprintf(SAXdebug, ")\n");
1530}
1531
1532/**
1533 * htmlcharactersDebug:
1534 * @ctxt: An XML parser context
1535 * @ch: a xmlChar string
1536 * @len: the number of xmlChar
1537 *
1538 * receiving some chars from the parser.
1539 * Question: how much at a time ???
1540 */
1541static void
1542htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1543{
1544 unsigned char output[40];
1545 int inlen = len, outlen = 30;
1546
1547 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1548 output[outlen] = 0;
1549
1550 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1551}
1552
1553/**
1554 * htmlcdataDebug:
1555 * @ctxt: An XML parser context
1556 * @ch: a xmlChar string
1557 * @len: the number of xmlChar
1558 *
1559 * receiving some cdata chars from the parser.
1560 * Question: how much at a time ???
1561 */
1562static void
1563htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1564{
1565 unsigned char output[40];
1566 int inlen = len, outlen = 30;
1567
1568 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1569 output[outlen] = 0;
1570
1571 fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len);
1572}
1573
1574xmlSAXHandler debugHTMLSAXHandlerStruct = {
1575 internalSubsetDebug,
1576 isStandaloneDebug,
1577 hasInternalSubsetDebug,
1578 hasExternalSubsetDebug,
1579 resolveEntityDebug,
1580 getEntityDebug,
1581 entityDeclDebug,
1582 notationDeclDebug,
1583 attributeDeclDebug,
1584 elementDeclDebug,
1585 unparsedEntityDeclDebug,
1586 setDocumentLocatorDebug,
1587 startDocumentDebug,
1588 endDocumentDebug,
1589 htmlstartElementDebug,
1590 endElementDebug,
1591 referenceDebug,
1592 htmlcharactersDebug,
1593 ignorableWhitespaceDebug,
1594 processingInstructionDebug,
1595 commentDebug,
1596 warningDebug,
1597 errorDebug,
1598 fatalErrorDebug,
1599 getParameterEntityDebug,
1600 htmlcdataDebug,
1601 externalSubsetDebug,
1602 1,
1603 NULL,
1604 NULL,
1605 NULL,
1606 NULL
1607};
1608
1609xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001610#endif /* LIBXML_HTML_ENABLED */
1611
1612#ifdef LIBXML_SAX1_ENABLED
Daniel Veillardfc319af2005-06-27 12:44:55 +00001613/**
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001614 * saxParseTest:
1615 * @filename: the file to parse
1616 * @result: the file with expected result
1617 * @err: the file with error messages
1618 *
1619 * Parse a file using the SAX API and check for errors.
1620 *
1621 * Returns 0 in case of success, an error code otherwise
1622 */
1623static int
Daniel Veillardfc319af2005-06-27 12:44:55 +00001624saxParseTest(const char *filename, const char *result,
1625 const char *err ATTRIBUTE_UNUSED,
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001626 int options) {
1627 int ret;
1628 char *temp;
1629
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001630 nb_tests++;
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001631 temp = resultFilename(filename, "", ".res");
1632 if (temp == NULL) {
1633 fprintf(stderr, "out of memory\n");
1634 fatalError();
1635 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00001636 SAXdebug = fopen(temp, "wb");
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001637 if (SAXdebug == NULL) {
1638 fprintf(stderr, "Failed to write to %s\n", temp);
1639 free(temp);
1640 return(-1);
1641 }
1642
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001643 /* for SAX we really want the callbacks though the context handlers */
1644 xmlSetStructuredErrorFunc(NULL, NULL);
1645 xmlSetGenericErrorFunc(NULL, testErrorHandler);
1646
Daniel Veillardfc319af2005-06-27 12:44:55 +00001647#ifdef LIBXML_HTML_ENABLED
1648 if (options & XML_PARSE_HTML) {
1649 htmlSAXParseFile(filename, NULL, emptySAXHandler, NULL);
1650 ret = 0;
1651 } else
1652#endif
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001653 ret = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
1654 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1655 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1656 ret = 0;
1657 }
1658 if (ret != 0) {
1659 fprintf(stderr, "Failed to parse %s\n", filename);
1660 return(1);
1661 }
Daniel Veillardfc319af2005-06-27 12:44:55 +00001662#ifdef LIBXML_HTML_ENABLED
1663 if (options & XML_PARSE_HTML) {
1664 htmlSAXParseFile(filename, NULL, debugHTMLSAXHandler, NULL);
1665 ret = 0;
1666 } else
1667#endif
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001668 if (options & XML_PARSE_SAX1) {
1669 ret = xmlSAXUserParseFile(debugSAXHandler, NULL, filename);
1670 } else {
1671 ret = xmlSAXUserParseFile(debugSAX2Handler, NULL, filename);
1672 }
1673 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1674 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1675 ret = 0;
1676 }
1677 fclose(SAXdebug);
1678 if (compareFiles(temp, result)) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001679 fprintf(stderr, "Got a difference for %s\n", filename);
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001680 ret = 1;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001681 } else
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001682 unlink(temp);
1683 free(temp);
1684
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001685 /* switch back to structured error handling */
1686 xmlSetGenericErrorFunc(NULL, NULL);
1687 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
1688
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001689 return(ret);
1690}
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001691#endif
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001692
1693/************************************************************************
1694 * *
1695 * Parse to tree based tests *
1696 * *
1697 ************************************************************************/
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001698/**
1699 * oldParseTest:
1700 * @filename: the file to parse
1701 * @result: the file with expected result
Daniel Veillardfd110d22005-06-27 00:02:02 +00001702 * @err: the file with error messages: unused
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001703 *
1704 * Parse a file using the old xmlParseFile API, then serialize back
1705 * reparse the result and serialize again, then check for deviation
1706 * in serialization.
1707 *
1708 * Returns 0 in case of success, an error code otherwise
1709 */
1710static int
Daniel Veillardc111c152005-06-27 08:22:10 +00001711oldParseTest(const char *filename, const char *result,
1712 const char *err ATTRIBUTE_UNUSED,
1713 int options ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001714 xmlDocPtr doc;
1715 char *temp;
1716 int res = 0;
1717
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001718 nb_tests++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001719 /*
1720 * base of the test, parse with the old API
1721 */
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001722#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001723 doc = xmlParseFile(filename);
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001724#else
1725 doc = xmlReadFile(filename, NULL, 0);
1726#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001727 if (doc == NULL)
1728 return(1);
1729 temp = resultFilename(filename, "", ".res");
1730 if (temp == NULL) {
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001731 fprintf(stderr, "out of memory\n");
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001732 fatalError();
1733 }
1734 xmlSaveFile(temp, doc);
1735 if (compareFiles(temp, result)) {
1736 res = 1;
1737 }
1738 xmlFreeDoc(doc);
1739
1740 /*
1741 * Parse the saved result to make sure the round trip is okay
1742 */
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001743#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001744 doc = xmlParseFile(temp);
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001745#else
1746 doc = xmlReadFile(temp, NULL, 0);
1747#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001748 if (doc == NULL)
1749 return(1);
1750 xmlSaveFile(temp, doc);
1751 if (compareFiles(temp, result)) {
1752 res = 1;
1753 }
1754 xmlFreeDoc(doc);
1755
1756 unlink(temp);
1757 free(temp);
1758 return(res);
1759}
1760
Daniel Veillardfc319af2005-06-27 12:44:55 +00001761#ifdef LIBXML_PUSH_ENABLED
1762/**
1763 * pushParseTest:
1764 * @filename: the file to parse
1765 * @result: the file with expected result
1766 * @err: the file with error messages: unused
1767 *
1768 * Parse a file using the Push API, then serialize back
1769 * to check for content.
1770 *
1771 * Returns 0 in case of success, an error code otherwise
1772 */
1773static int
1774pushParseTest(const char *filename, const char *result,
1775 const char *err ATTRIBUTE_UNUSED,
1776 int options) {
1777 xmlParserCtxtPtr ctxt;
1778 xmlDocPtr doc;
1779 const char *base;
1780 int size, res;
1781 int cur = 0;
1782
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001783 nb_tests++;
Daniel Veillardfc319af2005-06-27 12:44:55 +00001784 /*
1785 * load the document in memory and work from there.
1786 */
1787 if (loadMem(filename, &base, &size) != 0) {
1788 fprintf(stderr, "Failed to load %s\n", filename);
1789 return(-1);
1790 }
1791
1792#ifdef LIBXML_HTML_ENABLED
1793 if (options & XML_PARSE_HTML)
1794 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename,
1795 XML_CHAR_ENCODING_NONE);
1796 else
1797#endif
1798 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename);
1799 xmlCtxtUseOptions(ctxt, options);
1800 cur += 4;
1801 while (cur < size) {
1802 if (cur + 1024 >= size) {
1803#ifdef LIBXML_HTML_ENABLED
1804 if (options & XML_PARSE_HTML)
1805 htmlParseChunk(ctxt, base + cur, size - cur, 1);
1806 else
1807#endif
1808 xmlParseChunk(ctxt, base + cur, size - cur, 1);
1809 break;
1810 } else {
1811#ifdef LIBXML_HTML_ENABLED
1812 if (options & XML_PARSE_HTML)
1813 htmlParseChunk(ctxt, base + cur, 1024, 0);
1814 else
1815#endif
1816 xmlParseChunk(ctxt, base + cur, 1024, 0);
1817 cur += 1024;
1818 }
1819 }
1820 doc = ctxt->myDoc;
1821#ifdef LIBXML_HTML_ENABLED
1822 if (options & XML_PARSE_HTML)
1823 res = 1;
1824 else
1825#endif
1826 res = ctxt->wellFormed;
1827 xmlFreeParserCtxt(ctxt);
1828 free((char *)base);
1829 if (!res) {
1830 xmlFreeDoc(doc);
1831 fprintf(stderr, "Failed to parse %s\n", filename);
1832 return(-1);
1833 }
1834#ifdef LIBXML_HTML_ENABLED
1835 if (options & XML_PARSE_HTML)
1836 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1837 else
1838#endif
1839 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1840 xmlFreeDoc(doc);
1841 res = compareFileMem(result, base, size);
1842 if ((base == NULL) || (res != 0)) {
1843 if (base != NULL)
1844 xmlFree((char *)base);
1845 fprintf(stderr, "Result for %s failed\n", filename);
1846 return(-1);
1847 }
1848 xmlFree((char *)base);
1849 if (err != NULL) {
1850 res = compareFileMem(err, testErrors, testErrorsSize);
1851 if (res != 0) {
1852 fprintf(stderr, "Error for %s failed\n", filename);
1853 return(-1);
1854 }
1855 }
1856 return(0);
1857}
1858#endif
1859
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001860/**
1861 * memParseTest:
1862 * @filename: the file to parse
1863 * @result: the file with expected result
Daniel Veillardfd110d22005-06-27 00:02:02 +00001864 * @err: the file with error messages: unused
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001865 *
1866 * Parse a file using the old xmlReadMemory API, then serialize back
1867 * reparse the result and serialize again, then check for deviation
1868 * in serialization.
1869 *
1870 * Returns 0 in case of success, an error code otherwise
1871 */
1872static int
Daniel Veillardc111c152005-06-27 08:22:10 +00001873memParseTest(const char *filename, const char *result,
1874 const char *err ATTRIBUTE_UNUSED,
1875 int options ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001876 xmlDocPtr doc;
1877 const char *base;
Daniel Veillardfd110d22005-06-27 00:02:02 +00001878 int size, res;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001879
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001880 nb_tests++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001881 /*
1882 * load and parse the memory
1883 */
1884 if (loadMem(filename, &base, &size) != 0) {
1885 fprintf(stderr, "Failed to load %s\n", filename);
1886 return(-1);
1887 }
1888
1889 doc = xmlReadMemory(base, size, filename, NULL, 0);
1890 unloadMem(base);
1891 if (doc == NULL) {
1892 return(1);
1893 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00001894 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001895 xmlFreeDoc(doc);
Daniel Veillardfd110d22005-06-27 00:02:02 +00001896 res = compareFileMem(result, base, size);
1897 if ((base == NULL) || (res != 0)) {
1898 if (base != NULL)
1899 xmlFree((char *)base);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001900 fprintf(stderr, "Result for %s failed\n", filename);
1901 return(-1);
1902 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00001903 xmlFree((char *)base);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001904 return(0);
1905}
1906
1907/**
1908 * noentParseTest:
1909 * @filename: the file to parse
1910 * @result: the file with expected result
Daniel Veillardfd110d22005-06-27 00:02:02 +00001911 * @err: the file with error messages: unused
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001912 *
1913 * Parse a file with entity resolution, then serialize back
1914 * reparse the result and serialize again, then check for deviation
1915 * in serialization.
1916 *
1917 * Returns 0 in case of success, an error code otherwise
1918 */
1919static int
Daniel Veillardc111c152005-06-27 08:22:10 +00001920noentParseTest(const char *filename, const char *result,
1921 const char *err ATTRIBUTE_UNUSED,
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001922 int options) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001923 xmlDocPtr doc;
1924 char *temp;
1925 int res = 0;
1926
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001927 nb_tests++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001928 /*
1929 * base of the test, parse with the old API
1930 */
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001931 doc = xmlReadFile(filename, NULL, options);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001932 if (doc == NULL)
1933 return(1);
1934 temp = resultFilename(filename, "", ".res");
1935 if (temp == NULL) {
1936 fprintf(stderr, "Out of memory\n");
1937 fatalError();
1938 }
1939 xmlSaveFile(temp, doc);
1940 if (compareFiles(temp, result)) {
1941 res = 1;
1942 }
1943 xmlFreeDoc(doc);
1944
1945 /*
1946 * Parse the saved result to make sure the round trip is okay
1947 */
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001948 doc = xmlReadFile(filename, NULL, options);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001949 if (doc == NULL)
1950 return(1);
1951 xmlSaveFile(temp, doc);
1952 if (compareFiles(temp, result)) {
1953 res = 1;
1954 }
1955 xmlFreeDoc(doc);
1956
1957 unlink(temp);
1958 free(temp);
1959 return(res);
1960}
1961
Daniel Veillardfd110d22005-06-27 00:02:02 +00001962/**
Daniel Veillardc111c152005-06-27 08:22:10 +00001963 * errParseTest:
Daniel Veillardfd110d22005-06-27 00:02:02 +00001964 * @filename: the file to parse
1965 * @result: the file with expected result
1966 * @err: the file with error messages
1967 *
1968 * Parse a file using the xmlReadFile API and check for errors.
1969 *
1970 * Returns 0 in case of success, an error code otherwise
1971 */
1972static int
Daniel Veillardc111c152005-06-27 08:22:10 +00001973errParseTest(const char *filename, const char *result, const char *err,
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001974 int options) {
Daniel Veillardfd110d22005-06-27 00:02:02 +00001975 xmlDocPtr doc;
Daniel Veillard970adf52005-06-27 16:40:10 +00001976 const char *base = NULL;
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001977 int size, res = 0;
Daniel Veillardfd110d22005-06-27 00:02:02 +00001978
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001979 nb_tests++;
Daniel Veillardfc319af2005-06-27 12:44:55 +00001980#ifdef LIBXML_HTML_ENABLED
1981 if (options & XML_PARSE_HTML) {
1982 doc = htmlReadFile(filename, NULL, options);
1983 } else
1984#endif
Daniel Veillard970adf52005-06-27 16:40:10 +00001985#ifdef LIBXML_XINCLUDE_ENABLED
1986 if (options & XML_PARSE_XINCLUDE) {
1987 doc = xmlReadFile(filename, NULL, options);
1988 xmlXIncludeProcessFlags(doc, options);
1989 } else
1990#endif
Daniel Veillardfc319af2005-06-27 12:44:55 +00001991 {
1992 xmlGetWarningsDefaultValue = 1;
1993 doc = xmlReadFile(filename, NULL, options);
1994 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00001995 xmlGetWarningsDefaultValue = 0;
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001996 if (result) {
1997 if (doc == NULL) {
1998 base = "";
1999 size = 0;
2000 } else {
2001#ifdef LIBXML_HTML_ENABLED
2002 if (options & XML_PARSE_HTML) {
2003 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2004 } else
2005#endif
2006 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2007 }
2008 res = compareFileMem(result, base, size);
2009 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00002010 if (doc != NULL) {
2011 if (base != NULL)
2012 xmlFree((char *)base);
2013 xmlFreeDoc(doc);
2014 }
2015 if (res != 0) {
2016 fprintf(stderr, "Result for %s failed\n", filename);
2017 return(-1);
2018 }
Daniel Veillard4a5a9642005-06-27 10:40:55 +00002019 if (err != NULL) {
2020 res = compareFileMem(err, testErrors, testErrorsSize);
2021 if (res != 0) {
2022 fprintf(stderr, "Error for %s failed\n", filename);
2023 return(-1);
2024 }
Daniel Veillarddbee0f12005-06-27 13:42:57 +00002025 } else if (options & XML_PARSE_DTDVALID) {
2026 if (testErrorsSize != 0)
2027 fprintf(stderr, "Validation for %s failed\n", filename);
Daniel Veillardfd110d22005-06-27 00:02:02 +00002028 }
2029
2030 return(0);
2031}
2032
Daniel Veillardc111c152005-06-27 08:22:10 +00002033#ifdef LIBXML_READER_ENABLED
Daniel Veillard4a5a9642005-06-27 10:40:55 +00002034/************************************************************************
2035 * *
2036 * Reader based tests *
2037 * *
2038 ************************************************************************/
2039
Daniel Veillardc111c152005-06-27 08:22:10 +00002040static void processNode(FILE *out, xmlTextReaderPtr reader) {
2041 const xmlChar *name, *value;
2042 int type, empty;
2043
2044 type = xmlTextReaderNodeType(reader);
2045 empty = xmlTextReaderIsEmptyElement(reader);
2046
2047 name = xmlTextReaderConstName(reader);
2048 if (name == NULL)
2049 name = BAD_CAST "--";
2050
2051 value = xmlTextReaderConstValue(reader);
2052
2053
2054 fprintf(out, "%d %d %s %d %d",
2055 xmlTextReaderDepth(reader),
2056 type,
2057 name,
2058 empty,
2059 xmlTextReaderHasValue(reader));
2060 if (value == NULL)
2061 fprintf(out, "\n");
2062 else {
2063 fprintf(out, " %s\n", value);
2064 }
Daniel Veillardc111c152005-06-27 08:22:10 +00002065}
Daniel Veillardc111c152005-06-27 08:22:10 +00002066static int
Daniel Veillardc950d702005-06-27 09:15:06 +00002067streamProcessTest(const char *filename, const char *result, const char *err,
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002068 xmlTextReaderPtr reader, const char *rng) {
Daniel Veillardc111c152005-06-27 08:22:10 +00002069 int ret;
2070 char *temp = NULL;
2071 FILE *t = NULL;
2072
Daniel Veillardc950d702005-06-27 09:15:06 +00002073 if (reader == NULL)
2074 return(-1);
2075
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002076 nb_tests++;
Daniel Veillardc111c152005-06-27 08:22:10 +00002077 if (result != NULL) {
2078 temp = resultFilename(filename, "", ".res");
2079 if (temp == NULL) {
2080 fprintf(stderr, "Out of memory\n");
2081 fatalError();
2082 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00002083 t = fopen(temp, "wb");
Daniel Veillardc111c152005-06-27 08:22:10 +00002084 if (t == NULL) {
2085 fprintf(stderr, "Can't open temp file %s\n", temp);
2086 free(temp);
2087 return(-1);
2088 }
2089 }
Daniel Veillard95175012005-07-03 16:09:51 +00002090#ifdef LIBXML_SCHEMAS_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002091 if (rng != NULL) {
2092 ret = xmlTextReaderRelaxNGValidate(reader, rng);
2093 if (ret < 0) {
2094 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2095 rng);
2096 fclose(t);
2097 unlink(temp);
2098 free(temp);
2099 return(0);
2100 }
2101 }
Daniel Veillard95175012005-07-03 16:09:51 +00002102#endif
Daniel Veillardc111c152005-06-27 08:22:10 +00002103 xmlGetWarningsDefaultValue = 1;
Daniel Veillardc111c152005-06-27 08:22:10 +00002104 ret = xmlTextReaderRead(reader);
2105 while (ret == 1) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002106 if ((t != NULL) && (rng == NULL))
Daniel Veillardc111c152005-06-27 08:22:10 +00002107 processNode(t, reader);
2108 ret = xmlTextReaderRead(reader);
2109 }
2110 if (ret != 0) {
2111 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2112 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002113 if (rng != NULL) {
2114 if (xmlTextReaderIsValid(reader) != 1) {
2115 testErrorHandler(NULL, "%s fails to validate\n", filename);
2116 } else {
2117 testErrorHandler(NULL, "%s validates\n", filename);
2118 }
2119 }
Daniel Veillardc111c152005-06-27 08:22:10 +00002120 xmlGetWarningsDefaultValue = 0;
2121 if (t != NULL) {
2122 fclose(t);
2123 ret = compareFiles(temp, result);
2124 unlink(temp);
2125 free(temp);
2126 if (ret) {
2127 fprintf(stderr, "Result for %s failed\n", filename);
2128 return(-1);
2129 }
2130 }
2131 if (err != NULL) {
2132 ret = compareFileMem(err, testErrors, testErrorsSize);
2133 if (ret != 0) {
2134 fprintf(stderr, "Error for %s failed\n", filename);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002135 printf("%s", testErrors);
Daniel Veillardc111c152005-06-27 08:22:10 +00002136 return(-1);
2137 }
2138 }
2139
2140 return(0);
2141}
Daniel Veillardc950d702005-06-27 09:15:06 +00002142
2143/**
2144 * streamParseTest:
2145 * @filename: the file to parse
2146 * @result: the file with expected result
2147 * @err: the file with error messages
2148 *
2149 * Parse a file using the reader API and check for errors.
2150 *
2151 * Returns 0 in case of success, an error code otherwise
2152 */
2153static int
2154streamParseTest(const char *filename, const char *result, const char *err,
2155 int options) {
2156 xmlTextReaderPtr reader;
2157 int ret;
2158
2159 reader = xmlReaderForFile(filename, NULL, options);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002160 ret = streamProcessTest(filename, result, err, reader, NULL);
Daniel Veillardc950d702005-06-27 09:15:06 +00002161 xmlFreeTextReader(reader);
2162 return(ret);
2163}
2164
2165/**
2166 * walkerParseTest:
2167 * @filename: the file to parse
2168 * @result: the file with expected result
2169 * @err: the file with error messages
2170 *
2171 * Parse a file using the walker, i.e. a reader built from a atree.
2172 *
2173 * Returns 0 in case of success, an error code otherwise
2174 */
2175static int
2176walkerParseTest(const char *filename, const char *result, const char *err,
2177 int options) {
2178 xmlDocPtr doc;
2179 xmlTextReaderPtr reader;
2180 int ret;
2181
2182 doc = xmlReadFile(filename, NULL, options);
2183 if (doc == NULL) {
2184 fprintf(stderr, "Failed to parse %s\n", filename);
2185 return(-1);
2186 }
2187 reader = xmlReaderWalker(doc);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002188 ret = streamProcessTest(filename, result, err, reader, NULL);
Daniel Veillardc950d702005-06-27 09:15:06 +00002189 xmlFreeTextReader(reader);
2190 xmlFreeDoc(doc);
2191 return(ret);
2192}
2193
2194/**
2195 * streamMemParseTest:
2196 * @filename: the file to parse
2197 * @result: the file with expected result
2198 * @err: the file with error messages
2199 *
2200 * Parse a file using the reader API from memory and check for errors.
2201 *
2202 * Returns 0 in case of success, an error code otherwise
2203 */
2204static int
2205streamMemParseTest(const char *filename, const char *result, const char *err,
2206 int options) {
2207 xmlTextReaderPtr reader;
2208 int ret;
2209 const char *base;
2210 int size;
2211
2212 /*
2213 * load and parse the memory
2214 */
2215 if (loadMem(filename, &base, &size) != 0) {
2216 fprintf(stderr, "Failed to load %s\n", filename);
2217 return(-1);
2218 }
2219 reader = xmlReaderForMemory(base, size, filename, NULL, options);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002220 ret = streamProcessTest(filename, result, err, reader, NULL);
Daniel Veillardc950d702005-06-27 09:15:06 +00002221 free((char *)base);
2222 xmlFreeTextReader(reader);
2223 return(ret);
2224}
Daniel Veillardc111c152005-06-27 08:22:10 +00002225#endif
2226
Daniel Veillard970adf52005-06-27 16:40:10 +00002227#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard39e5c892005-07-03 22:48:50 +00002228#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard970adf52005-06-27 16:40:10 +00002229/************************************************************************
2230 * *
Daniel Veillard30564042005-06-28 07:30:41 +00002231 * XPath and XPointer based tests *
Daniel Veillard970adf52005-06-27 16:40:10 +00002232 * *
2233 ************************************************************************/
2234
2235FILE *xpathOutput;
2236xmlDocPtr xpathDocument;
2237
2238static void
2239testXPath(const char *str, int xptr, int expr) {
2240 xmlXPathObjectPtr res;
2241 xmlXPathContextPtr ctxt;
2242
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002243 nb_tests++;
Daniel Veillard970adf52005-06-27 16:40:10 +00002244#if defined(LIBXML_XPTR_ENABLED)
2245 if (xptr) {
2246 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2247 res = xmlXPtrEval(BAD_CAST str, ctxt);
2248 } else {
2249#endif
2250 ctxt = xmlXPathNewContext(xpathDocument);
2251 ctxt->node = xmlDocGetRootElement(xpathDocument);
2252 if (expr)
2253 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2254 else {
2255 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2256 xmlXPathCompExprPtr comp;
2257
2258 comp = xmlXPathCompile(BAD_CAST str);
2259 if (comp != NULL) {
2260 res = xmlXPathCompiledEval(comp, ctxt);
2261 xmlXPathFreeCompExpr(comp);
2262 } else
2263 res = NULL;
2264 }
2265#if defined(LIBXML_XPTR_ENABLED)
2266 }
2267#endif
2268 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2269 xmlXPathFreeObject(res);
2270 xmlXPathFreeContext(ctxt);
2271}
Daniel Veillard54a203c2005-06-27 22:29:56 +00002272
Daniel Veillard970adf52005-06-27 16:40:10 +00002273/**
2274 * xpathExprTest:
2275 * @filename: the file to parse
2276 * @result: the file with expected result
2277 * @err: the file with error messages
2278 *
2279 * Parse a file containing XPath standalone expressions and evaluate them
2280 *
2281 * Returns 0 in case of success, an error code otherwise
2282 */
2283static int
Daniel Veillard54a203c2005-06-27 22:29:56 +00002284xpathCommonTest(const char *filename, const char *result,
2285 int xptr, int expr) {
Daniel Veillard970adf52005-06-27 16:40:10 +00002286 FILE *input;
2287 char expression[5000];
2288 int len, ret = 0;
2289 char *temp;
2290
2291 temp = resultFilename(filename, "", ".res");
2292 if (temp == NULL) {
2293 fprintf(stderr, "Out of memory\n");
2294 fatalError();
2295 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00002296 xpathOutput = fopen(temp, "wb");
Daniel Veillard970adf52005-06-27 16:40:10 +00002297 if (xpathOutput == NULL) {
2298 fprintf(stderr, "failed to open output file %s\n", temp);
2299 free(temp);
2300 return(-1);
2301 }
2302
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00002303 input = fopen(filename, "rb");
Daniel Veillard970adf52005-06-27 16:40:10 +00002304 if (input == NULL) {
2305 xmlGenericError(xmlGenericErrorContext,
2306 "Cannot open %s for reading\n", filename);
2307 free(temp);
2308 return(-1);
2309 }
2310 while (fgets(expression, 4500, input) != NULL) {
2311 len = strlen(expression);
2312 len--;
2313 while ((len >= 0) &&
2314 ((expression[len] == '\n') || (expression[len] == '\t') ||
2315 (expression[len] == '\r') || (expression[len] == ' '))) len--;
2316 expression[len + 1] = 0;
2317 if (len >= 0) {
2318 fprintf(xpathOutput,
2319 "\n========================\nExpression: %s\n",
2320 expression) ;
Daniel Veillard54a203c2005-06-27 22:29:56 +00002321 testXPath(expression, xptr, expr);
Daniel Veillard970adf52005-06-27 16:40:10 +00002322 }
2323 }
2324
2325 fclose(input);
2326 fclose(xpathOutput);
2327 if (result != NULL) {
2328 ret = compareFiles(temp, result);
2329 if (ret) {
2330 fprintf(stderr, "Result for %s failed\n", filename);
2331 }
2332 }
2333
2334 unlink(temp);
2335 free(temp);
2336 return(ret);
2337}
Daniel Veillard54a203c2005-06-27 22:29:56 +00002338
2339/**
2340 * xpathExprTest:
2341 * @filename: the file to parse
2342 * @result: the file with expected result
2343 * @err: the file with error messages
2344 *
2345 * Parse a file containing XPath standalone expressions and evaluate them
2346 *
2347 * Returns 0 in case of success, an error code otherwise
2348 */
2349static int
2350xpathExprTest(const char *filename, const char *result,
2351 const char *err ATTRIBUTE_UNUSED,
2352 int options ATTRIBUTE_UNUSED) {
2353 return(xpathCommonTest(filename, result, 0, 1));
2354}
2355
2356/**
2357 * xpathDocTest:
2358 * @filename: the file to parse
2359 * @result: the file with expected result
2360 * @err: the file with error messages
2361 *
2362 * Parse a file containing XPath expressions and evaluate them against
2363 * a set of corresponding documents.
2364 *
2365 * Returns 0 in case of success, an error code otherwise
2366 */
2367static int
2368xpathDocTest(const char *filename,
2369 const char *resul ATTRIBUTE_UNUSED,
2370 const char *err ATTRIBUTE_UNUSED,
2371 int options) {
2372
2373 char pattern[500];
2374 char result[500];
2375 glob_t globbuf;
2376 size_t i;
2377 int ret = 0, res;
2378
2379 xpathDocument = xmlReadFile(filename, NULL,
2380 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2381 if (xpathDocument == NULL) {
2382 fprintf(stderr, "Failed to load %s\n", filename);
2383 return(-1);
2384 }
2385
2386 snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename));
2387 pattern[499] = 0;
2388 globbuf.gl_offs = 0;
2389 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2390 for (i = 0;i < globbuf.gl_pathc;i++) {
2391 snprintf(result, 499, "result/XPath/tests/%s",
2392 baseFilename(globbuf.gl_pathv[i]));
2393 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2394 if (res != 0)
2395 ret = res;
2396 }
2397 globfree(&globbuf);
2398
2399 xmlFreeDoc(xpathDocument);
2400 return(ret);
2401}
2402
2403#ifdef LIBXML_XPTR_ENABLED
2404/**
2405 * xptrDocTest:
2406 * @filename: the file to parse
2407 * @result: the file with expected result
2408 * @err: the file with error messages
2409 *
2410 * Parse a file containing XPath expressions and evaluate them against
2411 * a set of corresponding documents.
2412 *
2413 * Returns 0 in case of success, an error code otherwise
2414 */
2415static int
2416xptrDocTest(const char *filename,
2417 const char *resul ATTRIBUTE_UNUSED,
2418 const char *err ATTRIBUTE_UNUSED,
2419 int options) {
2420
2421 char pattern[500];
2422 char result[500];
2423 glob_t globbuf;
2424 size_t i;
2425 int ret = 0, res;
2426
2427 xpathDocument = xmlReadFile(filename, NULL,
2428 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2429 if (xpathDocument == NULL) {
2430 fprintf(stderr, "Failed to load %s\n", filename);
2431 return(-1);
2432 }
2433
2434 snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename));
2435 pattern[499] = 0;
2436 globbuf.gl_offs = 0;
2437 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2438 for (i = 0;i < globbuf.gl_pathc;i++) {
2439 snprintf(result, 499, "result/XPath/xptr/%s",
2440 baseFilename(globbuf.gl_pathv[i]));
2441 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2442 if (res != 0)
2443 ret = res;
2444 }
2445 globfree(&globbuf);
2446
2447 xmlFreeDoc(xpathDocument);
2448 return(ret);
2449}
2450#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard48dec9d2005-06-27 22:56:11 +00002451
2452/**
2453 * xmlidDocTest:
2454 * @filename: the file to parse
2455 * @result: the file with expected result
2456 * @err: the file with error messages
2457 *
2458 * Parse a file containing xml:id and check for errors and verify
2459 * that XPath queries will work on them as expected.
2460 *
2461 * Returns 0 in case of success, an error code otherwise
2462 */
2463static int
2464xmlidDocTest(const char *filename,
2465 const char *result,
2466 const char *err,
2467 int options) {
2468
2469 int res = 0;
2470 int ret = 0;
2471 char *temp;
2472
2473 xpathDocument = xmlReadFile(filename, NULL,
2474 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2475 if (xpathDocument == NULL) {
2476 fprintf(stderr, "Failed to load %s\n", filename);
2477 return(-1);
2478 }
2479
2480 temp = resultFilename(filename, "", ".res");
2481 if (temp == NULL) {
2482 fprintf(stderr, "Out of memory\n");
2483 fatalError();
2484 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00002485 xpathOutput = fopen(temp, "wb");
Daniel Veillard48dec9d2005-06-27 22:56:11 +00002486 if (xpathOutput == NULL) {
2487 fprintf(stderr, "failed to open output file %s\n", temp);
2488 xmlFreeDoc(xpathDocument);
2489 free(temp);
2490 return(-1);
2491 }
2492
2493 testXPath("id('bar')", 0, 0);
2494
2495 fclose(xpathOutput);
2496 if (result != NULL) {
2497 ret = compareFiles(temp, result);
2498 if (ret) {
2499 fprintf(stderr, "Result for %s failed\n", filename);
2500 res = 1;
2501 }
2502 }
2503
2504 unlink(temp);
2505 free(temp);
2506 xmlFreeDoc(xpathDocument);
2507
2508 if (err != NULL) {
2509 ret = compareFileMem(err, testErrors, testErrorsSize);
2510 if (ret != 0) {
2511 fprintf(stderr, "Error for %s failed\n", filename);
2512 res = 1;
2513 }
2514 }
2515 return(res);
2516}
2517
Daniel Veillard39e5c892005-07-03 22:48:50 +00002518#endif /* LIBXML_DEBUG_ENABLED */
Daniel Veillard970adf52005-06-27 16:40:10 +00002519#endif /* XPATH */
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00002520/************************************************************************
2521 * *
Daniel Veillard30564042005-06-28 07:30:41 +00002522 * URI based tests *
2523 * *
2524 ************************************************************************/
2525
2526static void
2527handleURI(const char *str, const char *base, FILE *o) {
2528 int ret;
2529 xmlURIPtr uri;
2530 xmlChar *res = NULL, *parsed = NULL;
2531
2532 uri = xmlCreateURI();
2533
2534 if (base == NULL) {
2535 ret = xmlParseURIReference(uri, str);
2536 if (ret != 0)
2537 fprintf(o, "%s : error %d\n", str, ret);
2538 else {
2539 xmlNormalizeURIPath(uri->path);
2540 xmlPrintURI(o, uri);
2541 fprintf(o, "\n");
2542 }
2543 } else {
2544 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2545 if (res != NULL) {
2546 fprintf(o, "%s\n", (char *) res);
2547 }
2548 else
2549 fprintf(o, "::ERROR::\n");
2550 }
2551 if (res != NULL)
2552 xmlFree(res);
2553 if (parsed != NULL)
2554 xmlFree(parsed);
2555 xmlFreeURI(uri);
2556}
2557
2558/**
2559 * uriCommonTest:
2560 * @filename: the file to parse
2561 * @result: the file with expected result
2562 * @err: the file with error messages
2563 *
2564 * Parse a file containing URI and check for errors
2565 *
2566 * Returns 0 in case of success, an error code otherwise
2567 */
2568static int
2569uriCommonTest(const char *filename,
2570 const char *result,
2571 const char *err,
2572 const char *base) {
2573 char *temp;
2574 FILE *o, *f;
2575 char str[1024];
2576 int res = 0, i, ret;
2577
2578 temp = resultFilename(filename, "", ".res");
2579 if (temp == NULL) {
2580 fprintf(stderr, "Out of memory\n");
2581 fatalError();
2582 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00002583 o = fopen(temp, "wb");
Daniel Veillard30564042005-06-28 07:30:41 +00002584 if (o == NULL) {
2585 fprintf(stderr, "failed to open output file %s\n", temp);
2586 free(temp);
2587 return(-1);
2588 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00002589 f = fopen(filename, "rb");
Daniel Veillard30564042005-06-28 07:30:41 +00002590 if (f == NULL) {
2591 fprintf(stderr, "failed to open input file %s\n", filename);
2592 fclose(o);
2593 unlink(temp);
2594 free(temp);
2595 return(-1);
2596 }
2597
2598 while (1) {
2599 /*
2600 * read one line in string buffer.
2601 */
2602 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2603 break;
2604
2605 /*
2606 * remove the ending spaces
2607 */
2608 i = strlen(str);
2609 while ((i > 0) &&
2610 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2611 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2612 i--;
2613 str[i] = 0;
2614 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002615 nb_tests++;
Daniel Veillard30564042005-06-28 07:30:41 +00002616 handleURI(str, base, o);
2617 }
2618
2619 fclose(f);
2620 fclose(o);
2621
2622 if (result != NULL) {
2623 ret = compareFiles(temp, result);
2624 if (ret) {
2625 fprintf(stderr, "Result for %s failed\n", filename);
2626 res = 1;
2627 }
2628 }
2629 if (err != NULL) {
2630 ret = compareFileMem(err, testErrors, testErrorsSize);
2631 if (ret != 0) {
2632 fprintf(stderr, "Error for %s failed\n", filename);
2633 res = 1;
2634 }
2635 }
2636
2637 unlink(temp);
2638 free(temp);
2639 return(res);
2640}
2641
2642/**
2643 * uriParseTest:
2644 * @filename: the file to parse
2645 * @result: the file with expected result
2646 * @err: the file with error messages
2647 *
2648 * Parse a file containing URI and check for errors
2649 *
2650 * Returns 0 in case of success, an error code otherwise
2651 */
2652static int
2653uriParseTest(const char *filename,
2654 const char *result,
2655 const char *err,
2656 int options ATTRIBUTE_UNUSED) {
2657 return(uriCommonTest(filename, result, err, NULL));
2658}
2659
2660/**
2661 * uriBaseTest:
2662 * @filename: the file to parse
2663 * @result: the file with expected result
2664 * @err: the file with error messages
2665 *
2666 * Parse a file containing URI, compose them against a fixed base and
2667 * check for errors
2668 *
2669 * Returns 0 in case of success, an error code otherwise
2670 */
2671static int
2672uriBaseTest(const char *filename,
2673 const char *result,
2674 const char *err,
2675 int options ATTRIBUTE_UNUSED) {
2676 return(uriCommonTest(filename, result, err,
2677 "http://foo.com/path/to/index.html?orig#help"));
2678}
2679
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002680#ifdef LIBXML_SCHEMAS_ENABLED
2681/************************************************************************
2682 * *
2683 * Schemas tests *
2684 * *
2685 ************************************************************************/
2686static int
2687schemasOneTest(const char *sch,
2688 const char *filename,
2689 const char *result,
2690 const char *err,
2691 int options,
2692 xmlSchemaPtr schemas) {
2693 xmlDocPtr doc;
2694 xmlSchemaValidCtxtPtr ctxt;
2695 int ret = 0;
2696 char *temp;
2697 FILE *schemasOutput;
2698
2699 doc = xmlReadFile(filename, NULL, options);
2700 if (doc == NULL) {
2701 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2702 return(-1);
2703 }
2704
2705 temp = resultFilename(result, "", ".res");
2706 if (temp == NULL) {
2707 fprintf(stderr, "Out of memory\n");
2708 fatalError();
2709 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00002710 schemasOutput = fopen(temp, "wb");
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002711 if (schemasOutput == NULL) {
2712 fprintf(stderr, "failed to open output file %s\n", temp);
2713 xmlFreeDoc(doc);
2714 free(temp);
2715 return(-1);
2716 }
2717
2718 ctxt = xmlSchemaNewValidCtxt(schemas);
2719 xmlSchemaSetValidErrors(ctxt,
2720 (xmlSchemaValidityErrorFunc) testErrorHandler,
2721 (xmlSchemaValidityWarningFunc) testErrorHandler,
2722 ctxt);
2723 ret = xmlSchemaValidateDoc(ctxt, doc);
2724 if (ret == 0) {
2725 fprintf(schemasOutput, "%s validates\n", filename);
2726 } else if (ret > 0) {
2727 fprintf(schemasOutput, "%s fails to validate\n", filename);
2728 } else {
2729 fprintf(schemasOutput, "%s validation generated an internal error\n",
2730 filename);
2731 }
2732 fclose(schemasOutput);
2733 if (result) {
2734 if (compareFiles(temp, result)) {
2735 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
2736 ret = 1;
2737 }
2738 }
2739 unlink(temp);
2740 free(temp);
2741
2742 if (err != NULL) {
2743 if (compareFileMem(err, testErrors, testErrorsSize)) {
2744 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
2745 ret = 1;
2746 }
2747 }
2748
2749
2750 xmlSchemaFreeValidCtxt(ctxt);
2751 xmlFreeDoc(doc);
2752 return(ret);
2753}
2754/**
2755 * schemasTest:
2756 * @filename: the schemas file
2757 * @result: the file with expected result
2758 * @err: the file with error messages
2759 *
2760 * Parse a file containing URI, compose them against a fixed base and
2761 * check for errors
2762 *
2763 * Returns 0 in case of success, an error code otherwise
2764 */
2765static int
2766schemasTest(const char *filename,
2767 const char *resul ATTRIBUTE_UNUSED,
2768 const char *errr ATTRIBUTE_UNUSED,
2769 int options) {
2770 const char *base = baseFilename(filename);
2771 const char *base2;
2772 const char *instance;
2773 xmlSchemaParserCtxtPtr ctxt;
2774 xmlSchemaPtr schemas;
2775 int res = 0, len, ret;
2776 char pattern[500];
2777 char prefix[500];
2778 char result[500];
2779 char err[500];
2780 glob_t globbuf;
2781 size_t i;
2782 char count = 0;
2783
2784 /* first compile the schemas if possible */
2785 ctxt = xmlSchemaNewParserCtxt(filename);
2786 xmlSchemaSetParserErrors(ctxt,
2787 (xmlSchemaValidityErrorFunc) testErrorHandler,
2788 (xmlSchemaValidityWarningFunc) testErrorHandler,
2789 ctxt);
2790 schemas = xmlSchemaParse(ctxt);
2791 xmlSchemaFreeParserCtxt(ctxt);
2792
2793 /*
2794 * most of the mess is about the output filenames generated by the Makefile
2795 */
2796 len = strlen(base);
2797 if ((len > 499) || (len < 5)) {
2798 xmlSchemaFree(schemas);
2799 return(-1);
2800 }
2801 len -= 4; /* remove trailing .xsd */
2802 if (base[len - 2] == '_') {
2803 len -= 2; /* remove subtest number */
2804 }
2805 if (base[len - 2] == '_') {
2806 len -= 2; /* remove subtest number */
2807 }
2808 memcpy(prefix, base, len);
2809 prefix[len] = 0;
2810
2811 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
2812 pattern[499] = 0;
2813
2814 if (base[len] == '_') {
2815 len += 2;
2816 memcpy(prefix, base, len);
2817 prefix[len] = 0;
2818 }
2819
2820 globbuf.gl_offs = 0;
2821 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2822 for (i = 0;i < globbuf.gl_pathc;i++) {
2823 testErrorsSize = 0;
2824 testErrors[0] = 0;
2825 instance = globbuf.gl_pathv[i];
2826 base2 = baseFilename(instance);
2827 len = strlen(base2);
2828 if ((len > 6) && (base2[len - 6] == '_')) {
2829 count = base2[len - 5];
2830 snprintf(result, 499, "result/schemas/%s_%c",
2831 prefix, count);
2832 result[499] = 0;
2833 snprintf(err, 499, "result/schemas/%s_%c.err",
2834 prefix, count);
2835 err[499] = 0;
2836 } else {
2837 fprintf(stderr, "don't know how to process %s\n", instance);
2838 continue;
2839 }
2840 if (schemas == NULL) {
2841 } else {
2842 nb_tests++;
2843 ret = schemasOneTest(filename, instance, result, err,
2844 options, schemas);
2845 if (res != 0)
2846 ret = res;
2847 }
2848 }
2849 globfree(&globbuf);
2850 xmlSchemaFree(schemas);
2851
2852 return(res);
2853}
2854
2855/************************************************************************
2856 * *
2857 * Schemas tests *
2858 * *
2859 ************************************************************************/
2860static int
2861rngOneTest(const char *sch,
2862 const char *filename,
2863 const char *result,
2864 const char *err,
2865 int options,
2866 xmlRelaxNGPtr schemas) {
2867 xmlDocPtr doc;
2868 xmlRelaxNGValidCtxtPtr ctxt;
2869 int ret = 0;
2870 char *temp;
2871 FILE *schemasOutput;
2872
2873 doc = xmlReadFile(filename, NULL, options);
2874 if (doc == NULL) {
2875 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2876 return(-1);
2877 }
2878
2879 temp = resultFilename(result, "", ".res");
2880 if (temp == NULL) {
2881 fprintf(stderr, "Out of memory\n");
2882 fatalError();
2883 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00002884 schemasOutput = fopen(temp, "wb");
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002885 if (schemasOutput == NULL) {
2886 fprintf(stderr, "failed to open output file %s\n", temp);
2887 xmlFreeDoc(doc);
2888 free(temp);
2889 return(-1);
2890 }
2891
2892 ctxt = xmlRelaxNGNewValidCtxt(schemas);
2893 xmlRelaxNGSetValidErrors(ctxt,
2894 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
2895 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
2896 ctxt);
2897 ret = xmlRelaxNGValidateDoc(ctxt, doc);
2898 if (ret == 0) {
2899 testErrorHandler(NULL, "%s validates\n", filename);
2900 } else if (ret > 0) {
2901 testErrorHandler(NULL, "%s fails to validate\n", filename);
2902 } else {
2903 testErrorHandler(NULL, "%s validation generated an internal error\n",
2904 filename);
2905 }
2906 fclose(schemasOutput);
2907 if (result) {
2908 if (compareFiles(temp, result)) {
2909 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
2910 ret = 1;
2911 }
2912 }
2913 unlink(temp);
2914 free(temp);
2915
2916 if (err != NULL) {
2917 if (compareFileMem(err, testErrors, testErrorsSize)) {
2918 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
2919 ret = 1;
2920 printf("%s", testErrors);
2921 }
2922 }
2923
2924
2925 xmlRelaxNGFreeValidCtxt(ctxt);
2926 xmlFreeDoc(doc);
2927 return(ret);
2928}
2929/**
2930 * rngTest:
2931 * @filename: the schemas file
2932 * @result: the file with expected result
2933 * @err: the file with error messages
2934 *
2935 * Parse an RNG schemas and then apply it to the related .xml
2936 *
2937 * Returns 0 in case of success, an error code otherwise
2938 */
2939static int
2940rngTest(const char *filename,
2941 const char *resul ATTRIBUTE_UNUSED,
2942 const char *errr ATTRIBUTE_UNUSED,
2943 int options) {
2944 const char *base = baseFilename(filename);
2945 const char *base2;
2946 const char *instance;
2947 xmlRelaxNGParserCtxtPtr ctxt;
2948 xmlRelaxNGPtr schemas;
2949 int res = 0, len, ret;
2950 char pattern[500];
2951 char prefix[500];
2952 char result[500];
2953 char err[500];
2954 glob_t globbuf;
2955 size_t i;
2956 char count = 0;
2957
2958 /* first compile the schemas if possible */
2959 ctxt = xmlRelaxNGNewParserCtxt(filename);
2960 xmlRelaxNGSetParserErrors(ctxt,
2961 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
2962 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
2963 ctxt);
2964 schemas = xmlRelaxNGParse(ctxt);
2965 xmlRelaxNGFreeParserCtxt(ctxt);
2966
2967 /*
2968 * most of the mess is about the output filenames generated by the Makefile
2969 */
2970 len = strlen(base);
2971 if ((len > 499) || (len < 5)) {
2972 xmlRelaxNGFree(schemas);
2973 return(-1);
2974 }
2975 len -= 4; /* remove trailing .rng */
2976 memcpy(prefix, base, len);
2977 prefix[len] = 0;
2978
2979 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
2980 pattern[499] = 0;
2981
2982 globbuf.gl_offs = 0;
2983 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2984 for (i = 0;i < globbuf.gl_pathc;i++) {
2985 testErrorsSize = 0;
2986 testErrors[0] = 0;
2987 instance = globbuf.gl_pathv[i];
2988 base2 = baseFilename(instance);
2989 len = strlen(base2);
2990 if ((len > 6) && (base2[len - 6] == '_')) {
2991 count = base2[len - 5];
2992 snprintf(result, 499, "result/relaxng/%s_%c",
2993 prefix, count);
2994 result[499] = 0;
2995 snprintf(err, 499, "result/relaxng/%s_%c.err",
2996 prefix, count);
2997 err[499] = 0;
2998 } else {
2999 fprintf(stderr, "don't know how to process %s\n", instance);
3000 continue;
3001 }
3002 if (schemas == NULL) {
3003 } else {
3004 nb_tests++;
3005 ret = rngOneTest(filename, instance, result, err,
3006 options, schemas);
3007 if (res != 0)
3008 ret = res;
3009 }
3010 }
3011 globfree(&globbuf);
3012 xmlRelaxNGFree(schemas);
3013
3014 return(res);
3015}
3016
Daniel Veillard39e5c892005-07-03 22:48:50 +00003017#ifdef LIBXML_READER_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003018/**
3019 * rngStreamTest:
3020 * @filename: the schemas file
3021 * @result: the file with expected result
3022 * @err: the file with error messages
3023 *
3024 * Parse a set of files with streaming, applying an RNG schemas
3025 *
3026 * Returns 0 in case of success, an error code otherwise
3027 */
3028static int
3029rngStreamTest(const char *filename,
3030 const char *resul ATTRIBUTE_UNUSED,
3031 const char *errr ATTRIBUTE_UNUSED,
3032 int options) {
3033 const char *base = baseFilename(filename);
3034 const char *base2;
3035 const char *instance;
3036 int res = 0, len, ret;
3037 char pattern[500];
3038 char prefix[500];
3039 char result[500];
3040 char err[500];
3041 glob_t globbuf;
3042 size_t i;
3043 char count = 0;
3044 xmlTextReaderPtr reader;
3045 int disable_err = 0;
3046
3047 /*
3048 * most of the mess is about the output filenames generated by the Makefile
3049 */
3050 len = strlen(base);
3051 if ((len > 499) || (len < 5)) {
3052 fprintf(stderr, "len(base) == %d !\n", len);
3053 return(-1);
3054 }
3055 len -= 4; /* remove trailing .rng */
3056 memcpy(prefix, base, len);
3057 prefix[len] = 0;
3058
3059 /*
3060 * strictly unifying the error messages is nearly impossible this
3061 * hack is also done in the Makefile
3062 */
3063 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
3064 (!strcmp(prefix, "tutor3_2")))
3065 disable_err = 1;
3066
3067 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3068 pattern[499] = 0;
3069
3070 globbuf.gl_offs = 0;
3071 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3072 for (i = 0;i < globbuf.gl_pathc;i++) {
3073 testErrorsSize = 0;
3074 testErrors[0] = 0;
3075 instance = globbuf.gl_pathv[i];
3076 base2 = baseFilename(instance);
3077 len = strlen(base2);
3078 if ((len > 6) && (base2[len - 6] == '_')) {
3079 count = base2[len - 5];
3080 snprintf(result, 499, "result/relaxng/%s_%c",
3081 prefix, count);
3082 result[499] = 0;
3083 snprintf(err, 499, "result/relaxng/%s_%c.err",
3084 prefix, count);
3085 err[499] = 0;
3086 } else {
3087 fprintf(stderr, "don't know how to process %s\n", instance);
3088 continue;
3089 }
3090 reader = xmlReaderForFile(instance, NULL, options);
3091 if (reader == NULL) {
3092 fprintf(stderr, "Failed to build reder for %s\n", instance);
3093 }
3094 if (disable_err == 1)
3095 ret = streamProcessTest(instance, result, NULL, reader, filename);
3096 else
3097 ret = streamProcessTest(instance, result, err, reader, filename);
3098 xmlFreeTextReader(reader);
3099 if (ret != 0) {
3100 fprintf(stderr, "instance %s failed\n", instance);
3101 res = ret;
3102 }
3103 }
3104 globfree(&globbuf);
3105
3106 return(res);
3107}
Daniel Veillard39e5c892005-07-03 22:48:50 +00003108#endif /* READER */
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003109
3110#endif
3111
3112#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillard39e5c892005-07-03 22:48:50 +00003113#ifdef LIBXML_READER_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003114/************************************************************************
3115 * *
3116 * Patterns tests *
3117 * *
3118 ************************************************************************/
3119static void patternNode(FILE *out, xmlTextReaderPtr reader,
3120 const char *pattern, xmlPatternPtr patternc,
3121 xmlStreamCtxtPtr patstream) {
3122 xmlChar *path = NULL;
3123 int match = -1;
3124 int type, empty;
3125
3126 type = xmlTextReaderNodeType(reader);
3127 empty = xmlTextReaderIsEmptyElement(reader);
3128
3129 if (type == XML_READER_TYPE_ELEMENT) {
3130 /* do the check only on element start */
3131 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3132
3133 if (match) {
3134 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3135 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3136 }
3137 }
3138 if (patstream != NULL) {
3139 int ret;
3140
3141 if (type == XML_READER_TYPE_ELEMENT) {
3142 ret = xmlStreamPush(patstream,
3143 xmlTextReaderConstLocalName(reader),
3144 xmlTextReaderConstNamespaceUri(reader));
3145 if (ret < 0) {
3146 fprintf(out, "xmlStreamPush() failure\n");
3147 xmlFreeStreamCtxt(patstream);
3148 patstream = NULL;
3149 } else if (ret != match) {
3150 if (path == NULL) {
3151 path = xmlGetNodePath(
3152 xmlTextReaderCurrentNode(reader));
3153 }
3154 fprintf(out,
3155 "xmlPatternMatch and xmlStreamPush disagree\n");
3156 fprintf(out,
3157 " pattern %s node %s\n",
3158 pattern, path);
3159 }
3160
3161
3162 }
3163 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3164 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3165 ret = xmlStreamPop(patstream);
3166 if (ret < 0) {
3167 fprintf(out, "xmlStreamPop() failure\n");
3168 xmlFreeStreamCtxt(patstream);
3169 patstream = NULL;
3170 }
3171 }
3172 }
3173 if (path != NULL)
3174 xmlFree(path);
3175}
3176
3177/**
3178 * patternTest:
3179 * @filename: the schemas file
3180 * @result: the file with expected result
3181 * @err: the file with error messages
3182 *
3183 * Parse a set of files with streaming, applying an RNG schemas
3184 *
3185 * Returns 0 in case of success, an error code otherwise
3186 */
3187static int
3188patternTest(const char *filename,
3189 const char *resul ATTRIBUTE_UNUSED,
3190 const char *err ATTRIBUTE_UNUSED,
3191 int options) {
3192 xmlPatternPtr patternc = NULL;
3193 xmlStreamCtxtPtr patstream = NULL;
3194 FILE *o, *f;
3195 char str[1024];
3196 char xml[500];
3197 char result[500];
3198 int len, i;
3199 int ret = 0, res;
3200 char *temp;
3201 xmlTextReaderPtr reader;
3202 xmlDocPtr doc;
3203
3204 len = strlen(filename);
3205 len -= 4;
3206 memcpy(xml, filename, len);
3207 xml[len] = 0;
3208 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3209 result[499] = 0;
3210 memcpy(xml + len, ".xml", 5);
3211
3212 if (!checkTestFile(xml)) {
3213 fprintf(stderr, "Missing xml file %s\n", xml);
3214 return(-1);
3215 }
3216 if (!checkTestFile(result)) {
3217 fprintf(stderr, "Missing result file %s\n", result);
3218 return(-1);
3219 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00003220 f = fopen(filename, "rb");
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003221 if (f == NULL) {
3222 fprintf(stderr, "Failed to open %s\n", filename);
3223 return(-1);
3224 }
3225 temp = resultFilename(filename, "", ".res");
3226 if (temp == NULL) {
3227 fprintf(stderr, "Out of memory\n");
3228 fatalError();
3229 }
Daniel Veillardcfbb0dd2005-07-04 17:12:01 +00003230 o = fopen(temp, "wb");
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003231 if (o == NULL) {
3232 fprintf(stderr, "failed to open output file %s\n", temp);
3233 fclose(f);
3234 free(temp);
3235 return(-1);
3236 }
3237 while (1) {
3238 /*
3239 * read one line in string buffer.
3240 */
3241 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3242 break;
3243
3244 /*
3245 * remove the ending spaces
3246 */
3247 i = strlen(str);
3248 while ((i > 0) &&
3249 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3250 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3251 i--;
3252 str[i] = 0;
3253 }
3254 doc = xmlReadFile(xml, NULL, options);
3255 if (doc == NULL) {
3256 fprintf(stderr, "Failed to parse %s\n", xml);
3257 ret = 1;
3258 } else {
3259 xmlNodePtr root;
3260 const xmlChar *namespaces[22];
3261 int j;
3262 xmlNsPtr ns;
3263
3264 root = xmlDocGetRootElement(doc);
3265 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3266 namespaces[j++] = ns->href;
3267 namespaces[j++] = ns->prefix;
3268 }
3269 namespaces[j++] = NULL;
3270 namespaces[j++] = NULL;
3271
3272 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3273 0, &namespaces[0]);
3274 if (patternc == NULL) {
3275 testErrorHandler(NULL,
3276 "Pattern %s failed to compile\n", str);
3277 xmlFreeDoc(doc);
3278 ret = 1;
3279 continue;
3280 }
3281 patstream = xmlPatternGetStreamCtxt(patternc);
3282 if (patstream != NULL) {
3283 ret = xmlStreamPush(patstream, NULL, NULL);
3284 if (ret < 0) {
3285 fprintf(stderr, "xmlStreamPush() failure\n");
3286 xmlFreeStreamCtxt(patstream);
3287 patstream = NULL;
3288 }
3289 }
3290 nb_tests++;
3291
3292 reader = xmlReaderWalker(doc);
3293 res = xmlTextReaderRead(reader);
3294 while (res == 1) {
3295 patternNode(o, reader, str, patternc, patstream);
3296 res = xmlTextReaderRead(reader);
3297 }
3298 if (res != 0) {
3299 fprintf(o, "%s : failed to parse\n", filename);
3300 }
3301 xmlFreeTextReader(reader);
3302 xmlFreeDoc(doc);
3303 xmlFreeStreamCtxt(patstream);
3304 patstream = NULL;
3305 xmlFreePattern(patternc);
3306
3307 }
3308 }
3309
3310 fclose(f);
3311 fclose(o);
3312
3313 ret = compareFiles(temp, result);
3314 if (ret) {
3315 fprintf(stderr, "Result for %s failed\n", filename);
3316 ret = 1;
3317 }
3318 unlink(temp);
3319 free(temp);
3320 return(ret);
3321}
Daniel Veillard39e5c892005-07-03 22:48:50 +00003322#endif /* READER */
3323#endif /* PATTERN */
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003324#ifdef LIBXML_C14N_ENABLED
3325/************************************************************************
3326 * *
3327 * Canonicalization tests *
3328 * *
3329 ************************************************************************/
3330static xmlXPathObjectPtr
3331load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
3332 xmlXPathObjectPtr xpath;
3333 xmlDocPtr doc;
3334 xmlChar *expr;
3335 xmlXPathContextPtr ctx;
3336 xmlNodePtr node;
3337 xmlNsPtr ns;
3338
3339 /*
3340 * load XPath expr as a file
3341 */
3342 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3343 xmlSubstituteEntitiesDefault(1);
3344
3345 doc = xmlParseFile(filename);
3346 if (doc == NULL) {
3347 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3348 return(NULL);
3349 }
3350
3351 /*
3352 * Check the document is of the right kind
3353 */
3354 if(xmlDocGetRootElement(doc) == NULL) {
3355 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3356 xmlFreeDoc(doc);
3357 return(NULL);
3358 }
3359
3360 node = doc->children;
3361 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3362 node = node->next;
3363 }
3364
3365 if(node == NULL) {
3366 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3367 xmlFreeDoc(doc);
3368 return(NULL);
3369 }
3370
3371 expr = xmlNodeGetContent(node);
3372 if(expr == NULL) {
3373 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3374 xmlFreeDoc(doc);
3375 return(NULL);
3376 }
3377
3378 ctx = xmlXPathNewContext(parent_doc);
3379 if(ctx == NULL) {
3380 fprintf(stderr,"Error: unable to create new context\n");
3381 xmlFree(expr);
3382 xmlFreeDoc(doc);
3383 return(NULL);
3384 }
3385
3386 /*
3387 * Register namespaces
3388 */
3389 ns = node->nsDef;
3390 while(ns != NULL) {
3391 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3392 fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
3393 xmlFree(expr);
3394 xmlXPathFreeContext(ctx);
3395 xmlFreeDoc(doc);
3396 return(NULL);
3397 }
3398 ns = ns->next;
3399 }
3400
3401 /*
3402 * Evaluate xpath
3403 */
3404 xpath = xmlXPathEvalExpression(expr, ctx);
3405 if(xpath == NULL) {
3406 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3407 xmlFree(expr);
3408 xmlXPathFreeContext(ctx);
3409 xmlFreeDoc(doc);
3410 return(NULL);
3411 }
3412
3413 /* print_xpath_nodes(xpath->nodesetval); */
3414
3415 xmlFree(expr);
3416 xmlXPathFreeContext(ctx);
3417 xmlFreeDoc(doc);
3418 return(xpath);
3419}
3420
3421/*
3422 * Macro used to grow the current buffer.
3423 */
3424#define xxx_growBufferReentrant() { \
3425 buffer_size *= 2; \
3426 buffer = (xmlChar **) \
3427 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
3428 if (buffer == NULL) { \
3429 perror("realloc failed"); \
3430 return(NULL); \
3431 } \
3432}
3433
3434static xmlChar **
3435parse_list(xmlChar *str) {
3436 xmlChar **buffer;
3437 xmlChar **out = NULL;
3438 int buffer_size = 0;
3439 int len;
3440
3441 if(str == NULL) {
3442 return(NULL);
3443 }
3444
3445 len = xmlStrlen(str);
3446 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3447 str[len - 1] = '\0';
3448 str++;
3449 len -= 2;
3450 }
3451 /*
3452 * allocate an translation buffer.
3453 */
3454 buffer_size = 1000;
3455 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3456 if (buffer == NULL) {
3457 perror("malloc failed");
3458 return(NULL);
3459 }
3460 out = buffer;
3461
3462 while(*str != '\0') {
3463 if (out - buffer > buffer_size - 10) {
3464 int indx = out - buffer;
3465
3466 xxx_growBufferReentrant();
3467 out = &buffer[indx];
3468 }
3469 (*out++) = str;
3470 while(*str != ',' && *str != '\0') ++str;
3471 if(*str == ',') *(str++) = '\0';
3472 }
3473 (*out) = NULL;
3474 return buffer;
3475}
3476
3477static int
3478c14nRunTest(const char* xml_filename, int with_comments, int exclusive,
3479 const char* xpath_filename, const char *ns_filename,
3480 const char* result_file) {
3481 xmlDocPtr doc;
3482 xmlXPathObjectPtr xpath = NULL;
3483 xmlChar *result = NULL;
3484 int ret;
3485 xmlChar **inclusive_namespaces = NULL;
3486 const char *nslist = NULL;
3487 int nssize;
3488
3489
3490 /*
3491 * build an XML tree from a the file; we need to add default
3492 * attributes and resolve all character and entities references
3493 */
3494 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3495 xmlSubstituteEntitiesDefault(1);
3496
3497 doc = xmlParseFile(xml_filename);
3498 if (doc == NULL) {
3499 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3500 return(-1);
3501 }
3502
3503 /*
3504 * Check the document is of the right kind
3505 */
3506 if(xmlDocGetRootElement(doc) == NULL) {
3507 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3508 xmlFreeDoc(doc);
3509 return(-1);
3510 }
3511
3512 /*
3513 * load xpath file if specified
3514 */
3515 if(xpath_filename) {
3516 xpath = load_xpath_expr(doc, xpath_filename);
3517 if(xpath == NULL) {
3518 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3519 xmlFreeDoc(doc);
3520 return(-1);
3521 }
3522 }
3523
3524 if (ns_filename != NULL) {
3525 if (loadMem(ns_filename, &nslist, &nssize)) {
3526 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3527 if(xpath != NULL) xmlXPathFreeObject(xpath);
3528 xmlFreeDoc(doc);
3529 return(-1);
3530 }
3531 inclusive_namespaces = parse_list((xmlChar *) nslist);
3532 }
3533
3534 /*
3535 * Canonical form
3536 */
3537 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
3538 ret = xmlC14NDocDumpMemory(doc,
3539 (xpath) ? xpath->nodesetval : NULL,
3540 exclusive, inclusive_namespaces,
3541 with_comments, &result);
3542 if (ret >= 0) {
3543 if(result != NULL) {
3544 if (compareFileMem(result_file, (const char *) result, ret)) {
3545 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
3546 ret = -1;
3547 }
3548 }
3549 } else {
3550 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3551 ret = -1;
3552 }
3553
3554 /*
3555 * Cleanup
3556 */
3557 if (result != NULL) xmlFree(result);
3558 if(xpath != NULL) xmlXPathFreeObject(xpath);
3559 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3560 if (nslist != NULL) free((char *) nslist);
3561 xmlFreeDoc(doc);
3562
3563 return(ret);
3564}
3565
3566static int
3567c14nCommonTest(const char *filename, int with_comments, int exclusive,
3568 const char *subdir) {
3569 char buf[500];
3570 char prefix[500];
3571 const char *base;
3572 int len;
3573 char *result = NULL;
3574 char *xpath = NULL;
3575 char *ns = NULL;
3576 int ret = 0;
3577
3578 base = baseFilename(filename);
3579 len = strlen(base);
3580 len -= 4;
3581 memcpy(prefix, base, len);
3582 prefix[len] = 0;
3583
3584 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
3585 if (!checkTestFile(buf)) {
3586 fprintf(stderr, "Missing result file %s", buf);
3587 return(-1);
3588 }
3589 result = strdup(buf);
3590 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3591 if (checkTestFile(buf)) {
3592 xpath = strdup(buf);
3593 }
3594 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3595 if (checkTestFile(buf)) {
3596 ns = strdup(buf);
3597 }
3598
3599 nb_tests++;
3600 if (c14nRunTest(filename, with_comments, exclusive,
3601 xpath, ns, result) < 0)
3602 ret = 1;
3603
3604 if (result != NULL) free(result);
3605 if (xpath != NULL) free(xpath);
3606 if (ns != NULL) free(ns);
3607 return(ret);
3608}
3609
3610static int
3611c14nWithCommentTest(const char *filename,
3612 const char *resul ATTRIBUTE_UNUSED,
3613 const char *err ATTRIBUTE_UNUSED,
3614 int options ATTRIBUTE_UNUSED) {
3615 return(c14nCommonTest(filename, 1, 0, "with-comments"));
3616}
3617static int
3618c14nWithoutCommentTest(const char *filename,
3619 const char *resul ATTRIBUTE_UNUSED,
3620 const char *err ATTRIBUTE_UNUSED,
3621 int options ATTRIBUTE_UNUSED) {
3622 return(c14nCommonTest(filename, 0, 0, "without-comments"));
3623}
3624static int
3625c14nExcWithoutCommentTest(const char *filename,
3626 const char *resul ATTRIBUTE_UNUSED,
3627 const char *err ATTRIBUTE_UNUSED,
3628 int options ATTRIBUTE_UNUSED) {
3629 return(c14nCommonTest(filename, 0, 1, "exc-without-comments"));
3630}
3631#endif
3632#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
3633/************************************************************************
3634 * *
3635 * Catalog and threads test *
3636 * *
3637 ************************************************************************/
3638
3639/*
3640 * mostly a cut and paste from testThreads.c
3641 */
3642#define MAX_ARGC 20
3643
3644static const char *catalog = "test/threads/complex.xml";
3645static const char *testfiles[] = {
3646 "test/threads/abc.xml",
3647 "test/threads/acb.xml",
3648 "test/threads/bac.xml",
3649 "test/threads/bca.xml",
3650 "test/threads/cab.xml",
3651 "test/threads/cba.xml",
3652 "test/threads/invalid.xml",
3653};
3654
3655const char *Okay = "OK";
3656const char *Failed = "Failed";
3657
3658#ifndef xmlDoValidityCheckingDefaultValue
3659#error xmlDoValidityCheckingDefaultValue is not a macro
3660#endif
3661#ifndef xmlGenericErrorContext
3662#error xmlGenericErrorContext is not a macro
3663#endif
3664
3665static void *
3666thread_specific_data(void *private_data)
3667{
3668 xmlDocPtr myDoc;
3669 const char *filename = (const char *) private_data;
3670 int okay = 1;
3671
3672 if (!strcmp(filename, "test/threads/invalid.xml")) {
3673 xmlDoValidityCheckingDefaultValue = 0;
3674 xmlGenericErrorContext = stdout;
3675 } else {
3676 xmlDoValidityCheckingDefaultValue = 1;
3677 xmlGenericErrorContext = stderr;
3678 }
3679 myDoc = xmlParseFile(filename);
3680 if (myDoc) {
3681 xmlFreeDoc(myDoc);
3682 } else {
3683 printf("parse failed\n");
3684 okay = 0;
3685 }
3686 if (!strcmp(filename, "test/threads/invalid.xml")) {
3687 if (xmlDoValidityCheckingDefaultValue != 0) {
3688 printf("ValidityCheckingDefaultValue override failed\n");
3689 okay = 0;
3690 }
3691 if (xmlGenericErrorContext != stdout) {
3692 printf("xmlGenericErrorContext override failed\n");
3693 okay = 0;
3694 }
3695 } else {
3696 if (xmlDoValidityCheckingDefaultValue != 1) {
3697 printf("ValidityCheckingDefaultValue override failed\n");
3698 okay = 0;
3699 }
3700 if (xmlGenericErrorContext != stderr) {
3701 printf("xmlGenericErrorContext override failed\n");
3702 okay = 0;
3703 }
3704 }
3705 if (okay == 0)
3706 return ((void *) Failed);
3707 return ((void *) Okay);
3708}
3709
3710#if defined(linux) || defined(solaris)
3711
3712#include <pthread.h>
3713
3714static pthread_t tid[MAX_ARGC];
3715
3716static int
3717testThread(void)
3718{
3719 unsigned int i, repeat;
3720 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3721 void *results[MAX_ARGC];
3722 int ret;
3723 int res = 0;
3724
3725 xmlInitParser();
3726
3727 for (repeat = 0; repeat < 500; repeat++) {
3728 xmlLoadCatalog(catalog);
3729 nb_tests++;
3730
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003731 for (i = 0; i < num_threads; i++) {
3732 results[i] = NULL;
3733 tid[i] = (pthread_t) - 1;
3734 }
3735
3736 for (i = 0; i < num_threads; i++) {
3737 ret = pthread_create(&tid[i], 0, thread_specific_data,
3738 (void *) testfiles[i]);
3739 if (ret != 0) {
3740 fprintf(stderr, "pthread_create failed\n");
3741 return (1);
3742 }
3743 }
3744 for (i = 0; i < num_threads; i++) {
3745 ret = pthread_join(tid[i], &results[i]);
3746 if (ret != 0) {
3747 fprintf(stderr, "pthread_join failed\n");
3748 return (1);
3749 }
3750 }
3751
3752 xmlCatalogCleanup();
3753 for (i = 0; i < num_threads; i++)
3754 if (results[i] != (void *) Okay) {
3755 fprintf(stderr, "Thread %d handling %s failed\n",
3756 i, testfiles[i]);
3757 res = 1;
3758 }
3759 }
3760 return (res);
3761}
3762
3763#elif defined WIN32
3764#include <windows.h>
3765#include <string.h>
3766
Daniel Veillard90837782005-07-04 15:45:10 +00003767#define TEST_REPEAT_COUNT 500
3768
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003769static HANDLE tid[MAX_ARGC];
3770
3771static DWORD WINAPI
3772win32_thread_specific_data(void *private_data)
3773{
Daniel Veillard90837782005-07-04 15:45:10 +00003774 return((DWORD) thread_specific_data(private_data));
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003775}
3776
3777static int
3778testThread(void)
3779{
3780 unsigned int i, repeat;
3781 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3782 DWORD results[MAX_ARGC];
3783 BOOL ret;
3784 int res = 0;
3785
3786 xmlInitParser();
3787 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
3788 xmlLoadCatalog(catalog);
Daniel Veillardf7d16602005-07-04 16:47:58 +00003789 nb_tests++;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003790
3791 for (i = 0; i < num_threads; i++) {
3792 results[i] = 0;
3793 tid[i] = (HANDLE) - 1;
3794 }
3795
3796 for (i = 0; i < num_threads; i++) {
3797 DWORD useless;
3798
3799 tid[i] = CreateThread(NULL, 0,
Daniel Veillard25450d02005-07-04 16:02:38 +00003800 win32_thread_specific_data,
Daniel Veillard89074392005-07-04 16:24:31 +00003801 (void *) testfiles[i], 0,
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003802 &useless);
3803 if (tid[i] == NULL) {
3804 fprintf(stderr, "CreateThread failed\n");
3805 return(1);
3806 }
3807 }
3808
3809 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
3810 WAIT_FAILED) {
3811 fprintf(stderr, "WaitForMultipleObjects failed\n");
3812 return(1);
3813 }
3814
3815 for (i = 0; i < num_threads; i++) {
3816 ret = GetExitCodeThread(tid[i], &results[i]);
3817 if (ret == 0) {
3818 fprintf(stderr, "GetExitCodeThread failed\n");
3819 return(1);
3820 }
3821 CloseHandle(tid[i]);
3822 }
3823
3824 xmlCatalogCleanup();
3825 for (i = 0; i < num_threads; i++) {
3826 if (results[i] != (DWORD) Okay) {
3827 fprintf(stderr, "Thread %d handling %s failed\n",
3828 i, testfiles[i]);
3829 res = 1;
3830 }
3831 }
3832 }
3833
3834 return (res);
3835}
3836
3837#elif defined __BEOS__
3838#include <OS.h>
3839
3840static thread_id tid[MAX_ARGC];
3841
3842static int
3843testThread(void)
3844{
3845 unsigned int i, repeat;
3846 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3847 void *results[MAX_ARGC];
3848 status_t ret;
3849 int res = 0;
3850
3851 xmlInitParser();
3852 for (repeat = 0; repeat < 500; repeat++) {
3853 xmlLoadCatalog(catalog);
3854 for (i = 0; i < num_threads; i++) {
3855 results[i] = NULL;
3856 tid[i] = (thread_id) - 1;
3857 }
3858 for (i = 0; i < num_threads; i++) {
3859 tid[i] =
3860 spawn_thread(thread_specific_data, "xmlTestThread",
3861 B_NORMAL_PRIORITY, (void *) testfiles[i]);
3862 if (tid[i] < B_OK) {
3863 fprintf(stderr, "beos_thread_create failed\n");
3864 return (1);
3865 }
3866 printf("beos_thread_create %d -> %d\n", i, tid[i]);
3867 }
3868 for (i = 0; i < num_threads; i++) {
3869 ret = wait_for_thread(tid[i], &results[i]);
3870 printf("beos_thread_wait %d -> %d\n", i, ret);
3871 if (ret != B_OK) {
3872 fprintf(stderr, "beos_thread_wait failed\n");
3873 return (1);
3874 }
3875 }
3876
3877 xmlCatalogCleanup();
3878 ret = B_OK;
3879 for (i = 0; i < num_threads; i++)
3880 if (results[i] != (void *) Okay) {
3881 printf("Thread %d handling %s failed\n", i, testfiles[i]);
3882 ret = B_ERROR;
3883 }
3884 }
3885 if (ret != B_OK)
3886 return(1);
3887 return (0);
3888}
3889#else
3890static int
3891testThread(void)
3892{
3893 fprintf(stderr,
3894 "Specific platform thread support not detected\n");
3895 return (-1);
3896}
3897#endif
3898static int
3899threadsTest(const char *filename ATTRIBUTE_UNUSED,
3900 const char *resul ATTRIBUTE_UNUSED,
3901 const char *err ATTRIBUTE_UNUSED,
3902 int options ATTRIBUTE_UNUSED) {
3903 return(testThread());
3904}
3905#endif
Daniel Veillard30564042005-06-28 07:30:41 +00003906/************************************************************************
3907 * *
3908 * Tests Descriptions *
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00003909 * *
3910 ************************************************************************/
3911
3912static
3913testDesc testDescriptions[] = {
Daniel Veillardfd110d22005-06-27 00:02:02 +00003914 { "XML regression tests" ,
Daniel Veillardc111c152005-06-27 08:22:10 +00003915 oldParseTest, "./test/*", "result/", "", NULL,
3916 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +00003917 { "XML regression tests on memory" ,
Daniel Veillardc111c152005-06-27 08:22:10 +00003918 memParseTest, "./test/*", "result/", "", NULL,
3919 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +00003920 { "XML entity subst regression tests" ,
Daniel Veillardc111c152005-06-27 08:22:10 +00003921 noentParseTest, "./test/*", "result/noent/", "", NULL,
Daniel Veillard4a5a9642005-06-27 10:40:55 +00003922 XML_PARSE_NOENT },
Daniel Veillardfd110d22005-06-27 00:02:02 +00003923 { "XML Namespaces regression tests",
Daniel Veillardc111c152005-06-27 08:22:10 +00003924 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
3925 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +00003926 { "Error cases regression tests",
Daniel Veillardc111c152005-06-27 08:22:10 +00003927 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
3928 0 },
3929#ifdef LIBXML_READER_ENABLED
3930 { "Error cases stream regression tests",
3931 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
3932 0 },
3933 { "Reader regression tests",
3934 streamParseTest, "./test/*", "result/", ".rdr", NULL,
3935 0 },
3936 { "Reader entities substitution regression tests",
3937 streamParseTest, "./test/*", "result/", ".rde", NULL,
3938 XML_PARSE_NOENT },
Daniel Veillardc950d702005-06-27 09:15:06 +00003939 { "Reader on memory regression tests",
3940 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
3941 0 },
3942 { "Walker regression tests",
3943 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
3944 0 },
Daniel Veillardc111c152005-06-27 08:22:10 +00003945#endif
Daniel Veillard6b6d6802005-07-03 21:00:34 +00003946#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard4a5a9642005-06-27 10:40:55 +00003947 { "SAX1 callbacks regression tests" ,
3948 saxParseTest, "./test/*", "result/", ".sax", NULL,
3949 XML_PARSE_SAX1 },
3950 { "SAX2 callbacks regression tests" ,
3951 saxParseTest, "./test/*", "result/", ".sax2", NULL,
3952 0 },
Daniel Veillard6b6d6802005-07-03 21:00:34 +00003953#endif
Daniel Veillardfc319af2005-06-27 12:44:55 +00003954#ifdef LIBXML_PUSH_ENABLED
3955 { "XML push regression tests" ,
3956 pushParseTest, "./test/*", "result/", "", NULL,
3957 0 },
3958#endif
3959#ifdef LIBXML_HTML_ENABLED
3960 { "HTML regression tests" ,
3961 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
3962 XML_PARSE_HTML },
3963#ifdef LIBXML_PUSH_ENABLED
3964 { "Push HTML regression tests" ,
3965 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
3966 XML_PARSE_HTML },
3967#endif
Daniel Veillard6b6d6802005-07-03 21:00:34 +00003968#ifdef LIBXML_SAX1_ENABLED
Daniel Veillardfc319af2005-06-27 12:44:55 +00003969 { "HTML SAX regression tests" ,
3970 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
3971 XML_PARSE_HTML },
3972#endif
Daniel Veillard6b6d6802005-07-03 21:00:34 +00003973#endif
Daniel Veillarddbee0f12005-06-27 13:42:57 +00003974#ifdef LIBXML_VALID_ENABLED
3975 { "Valid documents regression tests" ,
3976 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
3977 XML_PARSE_DTDVALID },
3978 { "Validity checking regression tests" ,
3979 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
3980 XML_PARSE_DTDVALID },
3981 { "General documents valid regression tests" ,
3982 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
3983 XML_PARSE_DTDVALID },
3984#endif
Daniel Veillard970adf52005-06-27 16:40:10 +00003985#ifdef LIBXML_XINCLUDE_ENABLED
3986 { "XInclude regression tests" ,
3987 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
3988 /* Ignore errors at this point ".err", */
3989 XML_PARSE_XINCLUDE },
3990 { "XInclude xmlReader regression tests",
3991 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
3992 /* Ignore errors at this point ".err", */
3993 NULL, XML_PARSE_XINCLUDE },
3994 { "XInclude regression tests stripping include nodes" ,
3995 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
3996 /* Ignore errors at this point ".err", */
3997 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
3998 { "XInclude xmlReader regression tests stripping include nodes",
3999 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4000 /* Ignore errors at this point ".err", */
4001 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4002#endif
4003#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard39e5c892005-07-03 22:48:50 +00004004#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard970adf52005-06-27 16:40:10 +00004005 { "XPath expressions regression tests" ,
4006 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4007 0 },
Daniel Veillard54a203c2005-06-27 22:29:56 +00004008 { "XPath document queries regression tests" ,
4009 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4010 0 },
4011#ifdef LIBXML_XPTR_ENABLED
4012 { "XPointer document queries regression tests" ,
4013 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4014 0 },
4015#endif
Daniel Veillard48dec9d2005-06-27 22:56:11 +00004016 { "xml:id regression tests" ,
4017 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4018 0 },
Daniel Veillard970adf52005-06-27 16:40:10 +00004019#endif
Daniel Veillard39e5c892005-07-03 22:48:50 +00004020#endif
Daniel Veillard30564042005-06-28 07:30:41 +00004021 { "URI parsing tests" ,
4022 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4023 0 },
4024 { "URI base composition tests" ,
4025 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4026 0 },
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004027#ifdef LIBXML_SCHEMAS_ENABLED
4028 { "Schemas regression tests" ,
4029 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4030 0 },
4031 { "Relax-NG regression tests" ,
4032 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4033 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
Daniel Veillard39e5c892005-07-03 22:48:50 +00004034#ifdef LIBXML_READER_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004035 { "Relax-NG streaming regression tests" ,
4036 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4037 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4038#endif
Daniel Veillard39e5c892005-07-03 22:48:50 +00004039#endif
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004040#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillard39e5c892005-07-03 22:48:50 +00004041#ifdef LIBXML_READER_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004042 { "Pattern regression tests" ,
4043 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4044 0 },
4045#endif
Daniel Veillard39e5c892005-07-03 22:48:50 +00004046#endif
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004047#ifdef LIBXML_C14N_ENABLED
4048 { "C14N with comments regression tests" ,
4049 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4050 0 },
4051 { "C14N without comments regression tests" ,
4052 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4053 0 },
4054 { "C14N exclusive without comments regression tests" ,
4055 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4056 0 },
4057#endif
4058#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
4059 { "Catalog and Threads regression tests" ,
4060 threadsTest, NULL, NULL, NULL, NULL,
4061 0 },
4062#endif
Daniel Veillardc111c152005-06-27 08:22:10 +00004063 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004064};
4065
4066/************************************************************************
4067 * *
Daniel Veillard4a5a9642005-06-27 10:40:55 +00004068 * The main code driving the tests *
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004069 * *
4070 ************************************************************************/
4071
4072static int
4073launchTests(testDescPtr tst) {
4074 int res = 0, err = 0;
4075 size_t i;
4076 char *result;
Daniel Veillardfd110d22005-06-27 00:02:02 +00004077 char *error;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004078 int mem;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004079
4080 if (tst == NULL) return(-1);
4081 if (tst->in != NULL) {
4082 glob_t globbuf;
4083
4084 globbuf.gl_offs = 0;
4085 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4086 for (i = 0;i < globbuf.gl_pathc;i++) {
4087 if (!checkTestFile(globbuf.gl_pathv[i]))
4088 continue;
Daniel Veillardfd110d22005-06-27 00:02:02 +00004089 if (tst->suffix != NULL) {
4090 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4091 tst->suffix);
4092 if (result == NULL) {
4093 fprintf(stderr, "Out of memory !\n");
4094 fatalError();
4095 }
4096 } else {
4097 result = NULL;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004098 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00004099 if (tst->err != NULL) {
4100 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4101 tst->err);
4102 if (error == NULL) {
4103 fprintf(stderr, "Out of memory !\n");
4104 fatalError();
4105 }
4106 } else {
4107 error = NULL;
4108 }
4109 if ((result) &&(!checkTestFile(result))) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004110 fprintf(stderr, "Missing result file %s\n", result);
Daniel Veillardfd110d22005-06-27 00:02:02 +00004111 } else if ((error) &&(!checkTestFile(error))) {
4112 fprintf(stderr, "Missing error file %s\n", error);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004113 } else {
4114 mem = xmlMemUsed();
4115 extraMemoryFromResolver = 0;
Daniel Veillardfd110d22005-06-27 00:02:02 +00004116 testErrorsSize = 0;
4117 testErrors[0] = 0;
Daniel Veillardc111c152005-06-27 08:22:10 +00004118 res = tst->func(globbuf.gl_pathv[i], result, error,
4119 tst->options);
Daniel Veillardfc319af2005-06-27 12:44:55 +00004120 xmlResetLastError();
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004121 if (res != 0) {
4122 fprintf(stderr, "File %s generated an error\n",
4123 globbuf.gl_pathv[i]);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004124 nb_errors++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004125 err++;
4126 }
4127 else if (xmlMemUsed() != mem) {
Daniel Veillardfd110d22005-06-27 00:02:02 +00004128 if ((xmlMemUsed() != mem) &&
4129 (extraMemoryFromResolver == 0)) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004130 fprintf(stderr, "File %s leaked %d bytes\n",
4131 globbuf.gl_pathv[i], xmlMemUsed() - mem);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004132 nb_leaks++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004133 err++;
4134 }
4135 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00004136 testErrorsSize = 0;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004137 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00004138 if (result)
4139 free(result);
4140 if (error)
4141 free(error);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004142 }
Daniel Veillard54a203c2005-06-27 22:29:56 +00004143 globfree(&globbuf);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004144 } else {
Daniel Veillardfd110d22005-06-27 00:02:02 +00004145 testErrorsSize = 0;
4146 testErrors[0] = 0;
4147 extraMemoryFromResolver = 0;
Daniel Veillardc111c152005-06-27 08:22:10 +00004148 res = tst->func(NULL, NULL, NULL, tst->options);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004149 if (res != 0) {
4150 nb_errors++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004151 err++;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004152 }
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004153 }
4154 return(err);
4155}
4156
4157int
Daniel Veillardc111c152005-06-27 08:22:10 +00004158main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004159 int i = 0, res, ret = 0;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004160 int verbose = 0;
4161 int old_errors, old_tests, old_leaks;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004162
4163 initializeLibxml2();
4164
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004165 if ((argc >= 2) && (!strcmp(argv[1], "-v")))
4166 verbose = 1;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004167 for (i = 0; testDescriptions[i].func != NULL; i++) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004168 old_errors = nb_errors;
4169 old_tests = nb_tests;
4170 old_leaks = nb_leaks;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004171 if (testDescriptions[i].desc != NULL)
4172 printf("## %s\n", testDescriptions[i].desc);
4173 res = launchTests(&testDescriptions[i]);
4174 if (res != 0)
4175 ret++;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004176 if (verbose) {
4177 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4178 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4179 else
4180 printf("Ran %d tests, %d errors, %d leaks\n",
4181 nb_tests - old_tests,
4182 nb_errors - old_errors,
4183 nb_leaks - old_leaks);
4184 }
4185 }
4186 if ((nb_errors == 0) && (nb_leaks == 0)) {
4187 ret = 0;
4188 printf("Total %d tests, no errors\n",
4189 nb_tests);
4190 } else {
4191 ret = 1;
4192 printf("Total %d tests, %d errors, %d leaks\n",
4193 nb_tests, nb_errors, nb_leaks);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004194 }
4195 xmlCleanupParser();
4196 xmlMemoryDump();
4197
4198 return(ret);
4199}
Daniel Veillard6b6d6802005-07-03 21:00:34 +00004200
4201#else /* ! LIBXML_OUTPUT_ENABLED */
4202int
4203main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4204 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4205 return(1);
4206}
4207#endif