]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/expat/tests/runtests.c
MFC r363988:
[FreeBSD/stable/9.git] / contrib / expat / tests / runtests.c
1 /* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
2    See the file COPYING for copying permission.
3
4    runtest.c : run the Expat test suite
5 */
6
7 #ifdef HAVE_EXPAT_CONFIG_H
8 #include <expat_config.h>
9 #endif
10
11 #include <assert.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdint.h>
16 #include <stddef.h>  /* ptrdiff_t */
17 #ifndef __cplusplus
18 # include <stdbool.h>
19 #endif
20
21 #include "expat.h"
22 #include "chardata.h"
23 #include "internal.h"  /* for UNUSED_P only */
24 #include "minicheck.h"
25
26 #if defined(__amigaos__) && defined(__USE_INLINE__)
27 #include <proto/expat.h>
28 #endif
29
30 #ifdef XML_LARGE_SIZE
31 #define XML_FMT_INT_MOD "ll"
32 #else
33 #define XML_FMT_INT_MOD "l"
34 #endif
35
36 static XML_Parser parser;
37
38
39 static void
40 basic_setup(void)
41 {
42     parser = XML_ParserCreate(NULL);
43     if (parser == NULL)
44         fail("Parser not created.");
45 }
46
47 static void
48 basic_teardown(void)
49 {
50     if (parser != NULL)
51         XML_ParserFree(parser);
52 }
53
54 /* Generate a failure using the parser state to create an error message;
55    this should be used when the parser reports an error we weren't
56    expecting.
57 */
58 static void
59 _xml_failure(XML_Parser parser, const char *file, int line)
60 {
61     char buffer[1024];
62     enum XML_Error err = XML_GetErrorCode(parser);
63     sprintf(buffer,
64             "    %d: %s (line %" XML_FMT_INT_MOD "u, offset %"\
65                 XML_FMT_INT_MOD "u)\n    reported from %s, line %d\n",
66             err,
67             XML_ErrorString(err),
68             XML_GetCurrentLineNumber(parser),
69             XML_GetCurrentColumnNumber(parser),
70             file, line);
71     _fail_unless(0, file, line, buffer);
72 }
73
74 static enum XML_Status
75 _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len, int isFinal)
76 {
77     enum XML_Status res = XML_STATUS_ERROR;
78     int offset = 0;
79
80     if (len == 0) {
81         return XML_Parse(parser, s, len, isFinal);
82     }
83
84     for (; offset < len; offset++) {
85         const int innerIsFinal = (offset == len - 1) && isFinal;
86         const char c = s[offset]; /* to help out-of-bounds detection */
87         res = XML_Parse(parser, &c, sizeof(char), innerIsFinal);
88         if (res != XML_STATUS_OK) {
89             return res;
90         }
91     }
92     return res;
93 }
94
95 #define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
96
97 static void
98 _expect_failure(const char *text, enum XML_Error errorCode, const char *errorMessage,
99                 const char *file, int lineno)
100 {
101     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK)
102         /* Hackish use of _fail_unless() macro, but let's us report
103            the right filename and line number. */
104         _fail_unless(0, file, lineno, errorMessage);
105     if (XML_GetErrorCode(parser) != errorCode)
106         _xml_failure(parser, file, lineno);
107 }
108
109 #define expect_failure(text, errorCode, errorMessage) \
110         _expect_failure((text), (errorCode), (errorMessage), \
111                         __FILE__, __LINE__)
112
113 /* Dummy handlers for when we need to set a handler to tickle a bug,
114    but it doesn't need to do anything.
115 */
116
117 static void XMLCALL
118 dummy_start_doctype_handler(void           *UNUSED_P(userData),
119                             const XML_Char *UNUSED_P(doctypeName),
120                             const XML_Char *UNUSED_P(sysid),
121                             const XML_Char *UNUSED_P(pubid),
122                             int            UNUSED_P(has_internal_subset))
123 {}
124
125 static void XMLCALL
126 dummy_end_doctype_handler(void *UNUSED_P(userData))
127 {}
128
129 static void XMLCALL
130 dummy_entity_decl_handler(void           *UNUSED_P(userData),
131                           const XML_Char *UNUSED_P(entityName),
132                           int            UNUSED_P(is_parameter_entity),
133                           const XML_Char *UNUSED_P(value),
134                           int            UNUSED_P(value_length),
135                           const XML_Char *UNUSED_P(base),
136                           const XML_Char *UNUSED_P(systemId),
137                           const XML_Char *UNUSED_P(publicId),
138                           const XML_Char *UNUSED_P(notationName))
139 {}
140
141 static void XMLCALL
142 dummy_notation_decl_handler(void *UNUSED_P(userData),
143                             const XML_Char *UNUSED_P(notationName),
144                             const XML_Char *UNUSED_P(base),
145                             const XML_Char *UNUSED_P(systemId),
146                             const XML_Char *UNUSED_P(publicId))
147 {}
148
149 static void XMLCALL
150 dummy_element_decl_handler(void *UNUSED_P(userData),
151                            const XML_Char *UNUSED_P(name),
152                            XML_Content *UNUSED_P(model))
153 {}
154
155 static void XMLCALL
156 dummy_attlist_decl_handler(void           *UNUSED_P(userData),
157                            const XML_Char *UNUSED_P(elname),
158                            const XML_Char *UNUSED_P(attname),
159                            const XML_Char *UNUSED_P(att_type),
160                            const XML_Char *UNUSED_P(dflt),
161                            int            UNUSED_P(isrequired))
162 {}
163
164 static void XMLCALL
165 dummy_comment_handler(void *UNUSED_P(userData), const XML_Char *UNUSED_P(data))
166 {}
167
168 static void XMLCALL
169 dummy_pi_handler(void *UNUSED_P(userData), const XML_Char *UNUSED_P(target), const XML_Char *UNUSED_P(data))
170 {}
171
172 static void XMLCALL
173 dummy_start_element(void *UNUSED_P(userData),
174                     const XML_Char *UNUSED_P(name), const XML_Char **UNUSED_P(atts))
175 {}
176
177
178 /*
179  * Character & encoding tests.
180  */
181
182 START_TEST(test_nul_byte)
183 {
184     char text[] = "<doc>\0</doc>";
185
186     /* test that a NUL byte (in US-ASCII data) is an error */
187     if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_OK)
188         fail("Parser did not report error on NUL-byte.");
189     if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
190         xml_failure(parser);
191 }
192 END_TEST
193
194
195 START_TEST(test_u0000_char)
196 {
197     /* test that a NUL byte (in US-ASCII data) is an error */
198     expect_failure("<doc>&#0;</doc>",
199                    XML_ERROR_BAD_CHAR_REF,
200                    "Parser did not report error on NUL-byte.");
201 }
202 END_TEST
203
204 START_TEST(test_bom_utf8)
205 {
206     /* This test is really just making sure we don't core on a UTF-8 BOM. */
207     const char *text = "\357\273\277<e/>";
208
209     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
210         xml_failure(parser);
211 }
212 END_TEST
213
214 START_TEST(test_bom_utf16_be)
215 {
216     char text[] = "\376\377\0<\0e\0/\0>";
217
218     if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
219         xml_failure(parser);
220 }
221 END_TEST
222
223 START_TEST(test_bom_utf16_le)
224 {
225     char text[] = "\377\376<\0e\0/\0>\0";
226
227     if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
228         xml_failure(parser);
229 }
230 END_TEST
231
232 static void XMLCALL
233 accumulate_characters(void *userData, const XML_Char *s, int len)
234 {
235     CharData_AppendXMLChars((CharData *)userData, s, len);
236 }
237
238 static void XMLCALL
239 accumulate_attribute(void *userData, const XML_Char *UNUSED_P(name),
240                      const XML_Char **atts)
241 {
242     CharData *storage = (CharData *)userData;
243     if (storage->count < 0 && atts != NULL && atts[0] != NULL) {
244         /* "accumulate" the value of the first attribute we see */
245         CharData_AppendXMLChars(storage, atts[1], -1);
246     }
247 }
248
249
250 static void
251 _run_character_check(const XML_Char *text, const XML_Char *expected,
252                      const char *file, int line)
253 {
254     CharData storage;
255
256     CharData_Init(&storage);
257     XML_SetUserData(parser, &storage);
258     XML_SetCharacterDataHandler(parser, accumulate_characters);
259     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
260         _xml_failure(parser, file, line);
261     CharData_CheckXMLChars(&storage, expected);
262 }
263
264 #define run_character_check(text, expected) \
265         _run_character_check(text, expected, __FILE__, __LINE__)
266
267 static void
268 _run_attribute_check(const XML_Char *text, const XML_Char *expected,
269                      const char *file, int line)
270 {
271     CharData storage;
272
273     CharData_Init(&storage);
274     XML_SetUserData(parser, &storage);
275     XML_SetStartElementHandler(parser, accumulate_attribute);
276     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
277         _xml_failure(parser, file, line);
278     CharData_CheckXMLChars(&storage, expected);
279 }
280
281 #define run_attribute_check(text, expected) \
282         _run_attribute_check(text, expected, __FILE__, __LINE__)
283
284 /* Regression test for SF bug #491986. */
285 START_TEST(test_danish_latin1)
286 {
287     const char *text =
288         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
289         "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>";
290     run_character_check(text,
291              "J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
292 }
293 END_TEST
294
295
296 /* Regression test for SF bug #514281. */
297 START_TEST(test_french_charref_hexidecimal)
298 {
299     const char *text =
300         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
301         "<doc>&#xE9;&#xE8;&#xE0;&#xE7;&#xEA;&#xC8;</doc>";
302     run_character_check(text,
303                         "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
304 }
305 END_TEST
306
307 START_TEST(test_french_charref_decimal)
308 {
309     const char *text =
310         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
311         "<doc>&#233;&#232;&#224;&#231;&#234;&#200;</doc>";
312     run_character_check(text,
313                         "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
314 }
315 END_TEST
316
317 START_TEST(test_french_latin1)
318 {
319     const char *text =
320         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
321         "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
322     run_character_check(text,
323                         "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
324 }
325 END_TEST
326
327 START_TEST(test_french_utf8)
328 {
329     const char *text =
330         "<?xml version='1.0' encoding='utf-8'?>\n"
331         "<doc>\xC3\xA9</doc>";
332     run_character_check(text, "\xC3\xA9");
333 }
334 END_TEST
335
336 /* Regression test for SF bug #600479.
337    XXX There should be a test that exercises all legal XML Unicode
338    characters as PCDATA and attribute value content, and XML Name
339    characters as part of element and attribute names.
340 */
341 START_TEST(test_utf8_false_rejection)
342 {
343     const char *text = "<doc>\xEF\xBA\xBF</doc>";
344     run_character_check(text, "\xEF\xBA\xBF");
345 }
346 END_TEST
347
348 /* Regression test for SF bug #477667.
349    This test assures that any 8-bit character followed by a 7-bit
350    character will not be mistakenly interpreted as a valid UTF-8
351    sequence.
352 */
353 START_TEST(test_illegal_utf8)
354 {
355     char text[100];
356     int i;
357
358     for (i = 128; i <= 255; ++i) {
359         sprintf(text, "<e>%ccd</e>", i);
360         if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK) {
361             sprintf(text,
362                     "expected token error for '%c' (ordinal %d) in UTF-8 text",
363                     i, i);
364             fail(text);
365         }
366         else if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
367             xml_failure(parser);
368         /* Reset the parser since we use the same parser repeatedly. */
369         XML_ParserReset(parser, NULL);
370     }
371 }
372 END_TEST
373
374
375 /* Examples, not masks: */
376 #define UTF8_LEAD_1  "\x7f"  /* 0b01111111 */
377 #define UTF8_LEAD_2  "\xdf"  /* 0b11011111 */
378 #define UTF8_LEAD_3  "\xef"  /* 0b11101111 */
379 #define UTF8_LEAD_4  "\xf7"  /* 0b11110111 */
380 #define UTF8_FOLLOW  "\xbf"  /* 0b10111111 */
381
382 START_TEST(test_utf8_auto_align)
383 {
384     struct TestCase {
385         ptrdiff_t expectedMovementInChars;
386         const char * input;
387     };
388
389     struct TestCase cases[] = {
390         {00, ""},
391
392         {00, UTF8_LEAD_1},
393
394         {-1, UTF8_LEAD_2},
395         {00, UTF8_LEAD_2 UTF8_FOLLOW},
396
397         {-1, UTF8_LEAD_3},
398         {-2, UTF8_LEAD_3 UTF8_FOLLOW},
399         {00, UTF8_LEAD_3 UTF8_FOLLOW UTF8_FOLLOW},
400
401         {-1, UTF8_LEAD_4},
402         {-2, UTF8_LEAD_4 UTF8_FOLLOW},
403         {-3, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW},
404         {00, UTF8_LEAD_4 UTF8_FOLLOW UTF8_FOLLOW UTF8_FOLLOW},
405     };
406
407     size_t i = 0;
408     bool success = true;
409     for (; i < sizeof(cases) / sizeof(*cases); i++) {
410         const char * fromLim = cases[i].input + strlen(cases[i].input);
411         const char * const fromLimInitially = fromLim;
412         ptrdiff_t actualMovementInChars;
413
414         align_limit_to_full_utf8_characters(cases[i].input, &fromLim);
415
416         actualMovementInChars = (fromLim - fromLimInitially);
417         if (actualMovementInChars != cases[i].expectedMovementInChars) {
418             size_t j = 0;
419             success = false;
420             printf("[-] UTF-8 case %2lu: Expected movement by %2ld chars"
421                     ", actually moved by %2ld chars: \"",
422                     i + 1, cases[i].expectedMovementInChars, actualMovementInChars);
423             for (; j < strlen(cases[i].input); j++) {
424                 printf("\\x%02x", (unsigned char)cases[i].input[j]);
425             }
426             printf("\"\n");
427         }
428     }
429
430     if (! success) {
431         fail("UTF-8 auto-alignment is not bullet-proof\n");
432     }
433 }
434 END_TEST
435
436 START_TEST(test_utf16)
437 {
438     /* <?xml version="1.0" encoding="UTF-16"?>
439        <doc a='123'>some text</doc>
440     */
441     char text[] =
442         "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
443         "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
444         "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
445         "\000'\000?\000>\000\n"
446         "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'"
447         "\000>\000s\000o\000m\000e\000 \000t\000e\000x\000t\000<\000/"
448         "\000d\000o\000c\000>";
449     if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
450         xml_failure(parser);
451 }
452 END_TEST
453
454 START_TEST(test_utf16_le_epilog_newline)
455 {
456     unsigned int first_chunk_bytes = 17;
457     char text[] = 
458         "\xFF\xFE"                      /* BOM */
459         "<\000e\000/\000>\000"          /* document element */
460         "\r\000\n\000\r\000\n\000";     /* epilog */
461
462     if (first_chunk_bytes >= sizeof(text) - 1)
463         fail("bad value of first_chunk_bytes");
464     if (  _XML_Parse_SINGLE_BYTES(parser, text, first_chunk_bytes, XML_FALSE)
465           == XML_STATUS_ERROR)
466         xml_failure(parser);
467     else {
468         enum XML_Status rc;
469         rc = _XML_Parse_SINGLE_BYTES(parser, text + first_chunk_bytes,
470                        sizeof(text) - first_chunk_bytes - 1, XML_TRUE);
471         if (rc == XML_STATUS_ERROR)
472             xml_failure(parser);
473     }
474 }
475 END_TEST
476
477 /* Regression test for SF bug #481609, #774028. */
478 START_TEST(test_latin1_umlauts)
479 {
480     const char *text =
481         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
482         "<e a='\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; >'\n"
483         "  >\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; ></e>";
484     const char *utf8 =
485         "\xC3\xA4 \xC3\xB6 \xC3\xBC "
486         "\xC3\xA4 \xC3\xB6 \xC3\xBC "
487         "\xC3\xA4 \xC3\xB6 \xC3\xBC >";
488     run_character_check(text, utf8);
489     XML_ParserReset(parser, NULL);
490     run_attribute_check(text, utf8);
491 }
492 END_TEST
493
494 /* Regression test #1 for SF bug #653180. */
495 START_TEST(test_line_number_after_parse)
496 {  
497     const char *text =
498         "<tag>\n"
499         "\n"
500         "\n</tag>";
501     XML_Size lineno;
502
503     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
504         xml_failure(parser);
505     lineno = XML_GetCurrentLineNumber(parser);
506     if (lineno != 4) {
507         char buffer[100];
508         sprintf(buffer, 
509             "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
510         fail(buffer);
511     }
512 }
513 END_TEST
514
515 /* Regression test #2 for SF bug #653180. */
516 START_TEST(test_column_number_after_parse)
517 {
518     const char *text = "<tag></tag>";
519     XML_Size colno;
520
521     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
522         xml_failure(parser);
523     colno = XML_GetCurrentColumnNumber(parser);
524     if (colno != 11) {
525         char buffer[100];
526         sprintf(buffer, 
527             "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
528         fail(buffer);
529     }
530 }
531 END_TEST
532
533 static void XMLCALL
534 start_element_event_handler2(void *userData, const XML_Char *name,
535                              const XML_Char **UNUSED_P(attr))
536 {
537     CharData *storage = (CharData *) userData;
538     char buffer[100];
539
540     sprintf(buffer,
541         "<%s> at col:%" XML_FMT_INT_MOD "u line:%"\
542             XML_FMT_INT_MOD "u\n", name,
543             XML_GetCurrentColumnNumber(parser),
544             XML_GetCurrentLineNumber(parser));
545     CharData_AppendString(storage, buffer);
546 }
547
548 static void XMLCALL
549 end_element_event_handler2(void *userData, const XML_Char *name)
550 {
551     CharData *storage = (CharData *) userData;
552     char buffer[100];
553
554     sprintf(buffer,
555         "</%s> at col:%" XML_FMT_INT_MOD "u line:%"\
556             XML_FMT_INT_MOD "u\n", name,
557             XML_GetCurrentColumnNumber(parser),
558             XML_GetCurrentLineNumber(parser));
559     CharData_AppendString(storage, buffer);
560 }
561
562 /* Regression test #3 for SF bug #653180. */
563 START_TEST(test_line_and_column_numbers_inside_handlers)
564 {
565     const char *text =
566         "<a>\n"        /* Unix end-of-line */
567         "  <b>\r\n"    /* Windows end-of-line */
568         "    <c/>\r"   /* Mac OS end-of-line */
569         "  </b>\n"
570         "  <d>\n"
571         "    <f/>\n"
572         "  </d>\n"
573         "</a>";
574     const char *expected =
575         "<a> at col:0 line:1\n"
576         "<b> at col:2 line:2\n"
577         "<c> at col:4 line:3\n"
578         "</c> at col:8 line:3\n"
579         "</b> at col:2 line:4\n"
580         "<d> at col:2 line:5\n"
581         "<f> at col:4 line:6\n"
582         "</f> at col:8 line:6\n"
583         "</d> at col:2 line:7\n"
584         "</a> at col:0 line:8\n";
585     CharData storage;
586
587     CharData_Init(&storage);
588     XML_SetUserData(parser, &storage);
589     XML_SetStartElementHandler(parser, start_element_event_handler2);
590     XML_SetEndElementHandler(parser, end_element_event_handler2);
591     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
592         xml_failure(parser);
593
594     CharData_CheckString(&storage, expected); 
595 }
596 END_TEST
597
598 /* Regression test #4 for SF bug #653180. */
599 START_TEST(test_line_number_after_error)
600 {
601     const char *text =
602         "<a>\n"
603         "  <b>\n"
604         "  </a>";  /* missing </b> */
605     XML_Size lineno;
606     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
607         fail("Expected a parse error");
608
609     lineno = XML_GetCurrentLineNumber(parser);
610     if (lineno != 3) {
611         char buffer[100];
612         sprintf(buffer, "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
613         fail(buffer);
614     }
615 }
616 END_TEST
617     
618 /* Regression test #5 for SF bug #653180. */
619 START_TEST(test_column_number_after_error)
620 {
621     const char *text =
622         "<a>\n"
623         "  <b>\n"
624         "  </a>";  /* missing </b> */
625     XML_Size colno;
626     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
627         fail("Expected a parse error");
628
629     colno = XML_GetCurrentColumnNumber(parser);
630     if (colno != 4) { 
631         char buffer[100];
632         sprintf(buffer, 
633             "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
634         fail(buffer);
635     }
636 }
637 END_TEST
638
639 /* Regression test for SF bug #478332. */
640 START_TEST(test_really_long_lines)
641 {
642     /* This parses an input line longer than INIT_DATA_BUF_SIZE
643        characters long (defined to be 1024 in xmlparse.c).  We take a
644        really cheesy approach to building the input buffer, because
645        this avoids writing bugs in buffer-filling code.
646     */
647     const char *text =
648         "<e>"
649         /* 64 chars */
650         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
651         /* until we have at least 1024 characters on the line: */
652         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
653         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
654         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
655         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
656         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
657         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
658         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
659         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
660         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
661         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
662         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
663         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
664         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
665         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
666         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
667         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
668         "</e>";
669     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
670         xml_failure(parser);
671 }
672 END_TEST
673
674
675 /*
676  * Element event tests.
677  */
678
679 static void XMLCALL
680 end_element_event_handler(void *userData, const XML_Char *name)
681 {
682     CharData *storage = (CharData *) userData;
683     CharData_AppendString(storage, "/");
684     CharData_AppendXMLChars(storage, name, -1);
685 }
686
687 START_TEST(test_end_element_events)
688 {
689     const char *text = "<a><b><c/></b><d><f/></d></a>";
690     const char *expected = "/c/b/f/d/a";
691     CharData storage;
692
693     CharData_Init(&storage);
694     XML_SetUserData(parser, &storage);
695     XML_SetEndElementHandler(parser, end_element_event_handler);
696     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
697         xml_failure(parser);
698     CharData_CheckString(&storage, expected);
699 }
700 END_TEST
701
702
703 /*
704  * Attribute tests.
705  */
706
707 /* Helpers used by the following test; this checks any "attr" and "refs"
708    attributes to make sure whitespace has been normalized.
709
710    Return true if whitespace has been normalized in a string, using
711    the rules for attribute value normalization.  The 'is_cdata' flag
712    is needed since CDATA attributes don't need to have multiple
713    whitespace characters collapsed to a single space, while other
714    attribute data types do.  (Section 3.3.3 of the recommendation.)
715 */
716 static int
717 is_whitespace_normalized(const XML_Char *s, int is_cdata)
718 {
719     int blanks = 0;
720     int at_start = 1;
721     while (*s) {
722         if (*s == ' ')
723             ++blanks;
724         else if (*s == '\t' || *s == '\n' || *s == '\r')
725             return 0;
726         else {
727             if (at_start) {
728                 at_start = 0;
729                 if (blanks && !is_cdata)
730                     /* illegal leading blanks */
731                     return 0;
732             }
733             else if (blanks > 1 && !is_cdata)
734                 return 0;
735             blanks = 0;
736         }
737         ++s;
738     }
739     if (blanks && !is_cdata)
740         return 0;
741     return 1;
742 }
743
744 /* Check the attribute whitespace checker: */
745 static void
746 testhelper_is_whitespace_normalized(void)
747 {
748     assert(is_whitespace_normalized("abc", 0));
749     assert(is_whitespace_normalized("abc", 1));
750     assert(is_whitespace_normalized("abc def ghi", 0));
751     assert(is_whitespace_normalized("abc def ghi", 1));
752     assert(!is_whitespace_normalized(" abc def ghi", 0));
753     assert(is_whitespace_normalized(" abc def ghi", 1));
754     assert(!is_whitespace_normalized("abc  def ghi", 0));
755     assert(is_whitespace_normalized("abc  def ghi", 1));
756     assert(!is_whitespace_normalized("abc def ghi ", 0));
757     assert(is_whitespace_normalized("abc def ghi ", 1));
758     assert(!is_whitespace_normalized(" ", 0));
759     assert(is_whitespace_normalized(" ", 1));
760     assert(!is_whitespace_normalized("\t", 0));
761     assert(!is_whitespace_normalized("\t", 1));
762     assert(!is_whitespace_normalized("\n", 0));
763     assert(!is_whitespace_normalized("\n", 1));
764     assert(!is_whitespace_normalized("\r", 0));
765     assert(!is_whitespace_normalized("\r", 1));
766     assert(!is_whitespace_normalized("abc\t def", 1));
767 }
768
769 static void XMLCALL
770 check_attr_contains_normalized_whitespace(void *UNUSED_P(userData),
771                                           const XML_Char *UNUSED_P(name),
772                                           const XML_Char **atts)
773 {
774     int i;
775     for (i = 0; atts[i] != NULL; i += 2) {
776         const XML_Char *attrname = atts[i];
777         const XML_Char *value = atts[i + 1];
778         if (strcmp("attr", attrname) == 0
779             || strcmp("ents", attrname) == 0
780             || strcmp("refs", attrname) == 0) {
781             if (!is_whitespace_normalized(value, 0)) {
782                 char buffer[256];
783                 sprintf(buffer, "attribute value not normalized: %s='%s'",
784                         attrname, value);
785                 fail(buffer);
786             }
787         }
788     }
789 }
790
791 START_TEST(test_attr_whitespace_normalization)
792 {
793     const char *text =
794         "<!DOCTYPE doc [\n"
795         "  <!ATTLIST doc\n"
796         "            attr NMTOKENS #REQUIRED\n"
797         "            ents ENTITIES #REQUIRED\n"
798         "            refs IDREFS   #REQUIRED>\n"
799         "]>\n"
800         "<doc attr='    a  b c\t\td\te\t' refs=' id-1   \t  id-2\t\t'  \n"
801         "     ents=' ent-1   \t\r\n"
802         "            ent-2  ' >\n"
803         "  <e id='id-1'/>\n"
804         "  <e id='id-2'/>\n"
805         "</doc>";
806
807     XML_SetStartElementHandler(parser,
808                                check_attr_contains_normalized_whitespace);
809     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
810         xml_failure(parser);
811 }
812 END_TEST
813
814
815 /*
816  * XML declaration tests.
817  */
818
819 START_TEST(test_xmldecl_misplaced)
820 {
821     expect_failure("\n"
822                    "<?xml version='1.0'?>\n"
823                    "<a/>",
824                    XML_ERROR_MISPLACED_XML_PI,
825                    "failed to report misplaced XML declaration");
826 }
827 END_TEST
828
829 /* Regression test for SF bug #584832. */
830 static int XMLCALL
831 UnknownEncodingHandler(void *UNUSED_P(data),const XML_Char *encoding,XML_Encoding *info)
832 {
833     if (strcmp(encoding,"unsupported-encoding") == 0) {
834         int i;
835         for (i = 0; i < 256; ++i)
836             info->map[i] = i;
837         info->data = NULL;
838         info->convert = NULL;
839         info->release = NULL;
840         return XML_STATUS_OK;
841     }
842     return XML_STATUS_ERROR;
843 }
844
845 START_TEST(test_unknown_encoding_internal_entity)
846 {
847     const char *text =
848         "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
849         "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
850         "<test a='&foo;'/>";
851
852     XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, NULL);
853     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
854         xml_failure(parser);
855 }
856 END_TEST
857
858 /* Regression test for SF bug #620106. */
859 static int XMLCALL
860 external_entity_loader_set_encoding(XML_Parser parser,
861                                     const XML_Char *context,
862                                     const XML_Char *UNUSED_P(base),
863                                     const XML_Char *UNUSED_P(systemId),
864                                     const XML_Char *UNUSED_P(publicId))
865 {
866     /* This text says it's an unsupported encoding, but it's really
867        UTF-8, which we tell Expat using XML_SetEncoding().
868     */
869     const char *text =
870         "<?xml encoding='iso-8859-3'?>"
871         "\xC3\xA9";
872     XML_Parser extparser;
873
874     extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
875     if (extparser == NULL)
876         fail("Could not create external entity parser.");
877     if (!XML_SetEncoding(extparser, "utf-8"))
878         fail("XML_SetEncoding() ignored for external entity");
879     if (  _XML_Parse_SINGLE_BYTES(extparser, text, strlen(text), XML_TRUE)
880           == XML_STATUS_ERROR) {
881         xml_failure(parser);
882         return 0;
883     }
884     return 1;
885 }
886
887 START_TEST(test_ext_entity_set_encoding)
888 {
889     const char *text =
890         "<!DOCTYPE doc [\n"
891         "  <!ENTITY en SYSTEM 'http://xml.libexpat.org/dummy.ent'>\n"
892         "]>\n"
893         "<doc>&en;</doc>";
894
895     XML_SetExternalEntityRefHandler(parser,
896                                     external_entity_loader_set_encoding);
897     run_character_check(text, "\xC3\xA9");
898 }
899 END_TEST
900
901 /* Test that no error is reported for unknown entities if we don't
902    read an external subset.  This was fixed in Expat 1.95.5.
903 */
904 START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
905     const char *text =
906         "<!DOCTYPE doc SYSTEM 'foo'>\n"
907         "<doc>&entity;</doc>";
908
909     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
910         xml_failure(parser);
911 }
912 END_TEST
913
914 /* Test that an error is reported for unknown entities if we don't
915    have an external subset.
916 */
917 START_TEST(test_wfc_undeclared_entity_no_external_subset) {
918     expect_failure("<doc>&entity;</doc>",
919                    XML_ERROR_UNDEFINED_ENTITY,
920                    "Parser did not report undefined entity w/out a DTD.");
921 }
922 END_TEST
923
924 /* Test that an error is reported for unknown entities if we don't
925    read an external subset, but have been declared standalone.
926 */
927 START_TEST(test_wfc_undeclared_entity_standalone) {
928     const char *text =
929         "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
930         "<!DOCTYPE doc SYSTEM 'foo'>\n"
931         "<doc>&entity;</doc>";
932
933     expect_failure(text,
934                    XML_ERROR_UNDEFINED_ENTITY,
935                    "Parser did not report undefined entity (standalone).");
936 }
937 END_TEST
938
939 static int XMLCALL
940 external_entity_loader(XML_Parser parser,
941                        const XML_Char *context,
942                        const XML_Char *UNUSED_P(base),
943                        const XML_Char *UNUSED_P(systemId),
944                        const XML_Char *UNUSED_P(publicId))
945 {
946     char *text = (char *)XML_GetUserData(parser);
947     XML_Parser extparser;
948
949     extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
950     if (extparser == NULL)
951         fail("Could not create external entity parser.");
952     if (  _XML_Parse_SINGLE_BYTES(extparser, text, strlen(text), XML_TRUE)
953           == XML_STATUS_ERROR) {
954         xml_failure(parser);
955         return XML_STATUS_ERROR;
956     }
957     return XML_STATUS_OK;
958 }
959
960 /* Test that an error is reported for unknown entities if we have read
961    an external subset, and standalone is true.
962 */
963 START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) {
964     const char *text =
965         "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
966         "<!DOCTYPE doc SYSTEM 'foo'>\n"
967         "<doc>&entity;</doc>";
968     char foo_text[] =
969         "<!ELEMENT doc (#PCDATA)*>";
970
971     XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
972     XML_SetUserData(parser, foo_text);
973     XML_SetExternalEntityRefHandler(parser, external_entity_loader);
974     expect_failure(text,
975                    XML_ERROR_UNDEFINED_ENTITY,
976                    "Parser did not report undefined entity (external DTD).");
977 }
978 END_TEST
979
980 /* Test that no error is reported for unknown entities if we have read
981    an external subset, and standalone is false.
982 */
983 START_TEST(test_wfc_undeclared_entity_with_external_subset) {
984     const char *text =
985         "<?xml version='1.0' encoding='us-ascii'?>\n"
986         "<!DOCTYPE doc SYSTEM 'foo'>\n"
987         "<doc>&entity;</doc>";
988     char foo_text[] =
989         "<!ELEMENT doc (#PCDATA)*>";
990
991     XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
992     XML_SetUserData(parser, foo_text);
993     XML_SetExternalEntityRefHandler(parser, external_entity_loader);
994     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
995         xml_failure(parser);
996 }
997 END_TEST
998
999 START_TEST(test_wfc_no_recursive_entity_refs)
1000 {
1001     const char *text =
1002         "<!DOCTYPE doc [\n"
1003         "  <!ENTITY entity '&#38;entity;'>\n"
1004         "]>\n"
1005         "<doc>&entity;</doc>";
1006
1007     expect_failure(text,
1008                    XML_ERROR_RECURSIVE_ENTITY_REF,
1009                    "Parser did not report recursive entity reference.");
1010 }
1011 END_TEST
1012
1013 /* Regression test for SF bug #483514. */
1014 START_TEST(test_dtd_default_handling)
1015 {
1016     const char *text =
1017         "<!DOCTYPE doc [\n"
1018         "<!ENTITY e SYSTEM 'http://xml.libexpat.org/e'>\n"
1019         "<!NOTATION n SYSTEM 'http://xml.libexpat.org/n'>\n"
1020         "<!ELEMENT doc EMPTY>\n"
1021         "<!ATTLIST doc a CDATA #IMPLIED>\n"
1022         "<?pi in dtd?>\n"
1023         "<!--comment in dtd-->\n"
1024         "]><doc/>";
1025
1026     XML_SetDefaultHandler(parser, accumulate_characters);
1027     XML_SetDoctypeDeclHandler(parser,
1028                               dummy_start_doctype_handler,
1029                               dummy_end_doctype_handler);
1030     XML_SetEntityDeclHandler(parser, dummy_entity_decl_handler);
1031     XML_SetNotationDeclHandler(parser, dummy_notation_decl_handler);
1032     XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
1033     XML_SetAttlistDeclHandler(parser, dummy_attlist_decl_handler);
1034     XML_SetProcessingInstructionHandler(parser, dummy_pi_handler);
1035     XML_SetCommentHandler(parser, dummy_comment_handler);
1036     run_character_check(text, "\n\n\n\n\n\n\n<doc/>");
1037 }
1038 END_TEST
1039
1040 /* See related SF bug #673791.
1041    When namespace processing is enabled, setting the namespace URI for
1042    a prefix is not allowed; this test ensures that it *is* allowed
1043    when namespace processing is not enabled.
1044    (See Namespaces in XML, section 2.)
1045 */
1046 START_TEST(test_empty_ns_without_namespaces)
1047 {
1048     const char *text =
1049         "<doc xmlns:prefix='http://www.example.com/'>\n"
1050         "  <e xmlns:prefix=''/>\n"
1051         "</doc>";
1052
1053     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1054         xml_failure(parser);
1055 }
1056 END_TEST
1057
1058 /* Regression test for SF bug #824420.
1059    Checks that an xmlns:prefix attribute set in an attribute's default
1060    value isn't misinterpreted.
1061 */
1062 START_TEST(test_ns_in_attribute_default_without_namespaces)
1063 {
1064     const char *text =
1065         "<!DOCTYPE e:element [\n"
1066         "  <!ATTLIST e:element\n"
1067         "    xmlns:e CDATA 'http://example.com/'>\n"
1068         "      ]>\n"
1069         "<e:element/>";
1070
1071     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1072         xml_failure(parser);
1073 }
1074 END_TEST
1075
1076 static const char *long_character_data_text =
1077     "<?xml version='1.0' encoding='iso-8859-1'?><s>"
1078     "012345678901234567890123456789012345678901234567890123456789"
1079     "012345678901234567890123456789012345678901234567890123456789"
1080     "012345678901234567890123456789012345678901234567890123456789"
1081     "012345678901234567890123456789012345678901234567890123456789"
1082     "012345678901234567890123456789012345678901234567890123456789"
1083     "012345678901234567890123456789012345678901234567890123456789"
1084     "012345678901234567890123456789012345678901234567890123456789"
1085     "012345678901234567890123456789012345678901234567890123456789"
1086     "012345678901234567890123456789012345678901234567890123456789"
1087     "012345678901234567890123456789012345678901234567890123456789"
1088     "012345678901234567890123456789012345678901234567890123456789"
1089     "012345678901234567890123456789012345678901234567890123456789"
1090     "012345678901234567890123456789012345678901234567890123456789"
1091     "012345678901234567890123456789012345678901234567890123456789"
1092     "012345678901234567890123456789012345678901234567890123456789"
1093     "012345678901234567890123456789012345678901234567890123456789"
1094     "012345678901234567890123456789012345678901234567890123456789"
1095     "012345678901234567890123456789012345678901234567890123456789"
1096     "012345678901234567890123456789012345678901234567890123456789"
1097     "012345678901234567890123456789012345678901234567890123456789"
1098     "</s>";
1099
1100 static XML_Bool resumable = XML_FALSE;
1101
1102 static void
1103 clearing_aborting_character_handler(void *UNUSED_P(userData),
1104                                     const XML_Char *UNUSED_P(s), int UNUSED_P(len))
1105 {
1106     XML_StopParser(parser, resumable);
1107     XML_SetCharacterDataHandler(parser, NULL);
1108 }
1109
1110 /* Regression test for SF bug #1515266: missing check of stopped
1111    parser in doContext() 'for' loop. */
1112 START_TEST(test_stop_parser_between_char_data_calls)
1113 {
1114     /* The sample data must be big enough that there are two calls to
1115        the character data handler from within the inner "for" loop of
1116        the XML_TOK_DATA_CHARS case in doContent(), and the character
1117        handler must stop the parser and clear the character data
1118        handler.
1119     */
1120     const char *text = long_character_data_text;
1121
1122     XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
1123     resumable = XML_FALSE;
1124     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
1125         xml_failure(parser);
1126     if (XML_GetErrorCode(parser) != XML_ERROR_ABORTED)
1127         xml_failure(parser);
1128 }
1129 END_TEST
1130
1131 /* Regression test for SF bug #1515266: missing check of stopped
1132    parser in doContext() 'for' loop. */
1133 START_TEST(test_suspend_parser_between_char_data_calls)
1134 {
1135     /* The sample data must be big enough that there are two calls to
1136        the character data handler from within the inner "for" loop of
1137        the XML_TOK_DATA_CHARS case in doContent(), and the character
1138        handler must stop the parser and clear the character data
1139        handler.
1140     */
1141     const char *text = long_character_data_text;
1142
1143     XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
1144     resumable = XML_TRUE;
1145     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) != XML_STATUS_SUSPENDED)
1146         xml_failure(parser);
1147     if (XML_GetErrorCode(parser) != XML_ERROR_NONE)
1148         xml_failure(parser);
1149 }
1150 END_TEST
1151
1152 START_TEST(test_good_cdata_ascii)
1153 {
1154     const char *text = "<a><![CDATA[<greeting>Hello, world!</greeting>]]></a>";
1155     const char *expected = "<greeting>Hello, world!</greeting>";
1156
1157     CharData storage;
1158     CharData_Init(&storage);
1159     XML_SetUserData(parser, &storage);
1160     XML_SetCharacterDataHandler(parser, accumulate_characters);
1161
1162     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1163         xml_failure(parser);
1164     CharData_CheckXMLChars(&storage, expected);
1165 }
1166 END_TEST
1167
1168 START_TEST(test_good_cdata_utf16)
1169 {
1170     /* Test data is:
1171      *   <?xml version='1.0' encoding='utf-16'?>
1172      *   <a><![CDATA[hello]]></a>
1173      */
1174     const char text[] =
1175             "\0<\0?\0x\0m\0l\0"
1176                 " \0v\0e\0r\0s\0i\0o\0n\0=\0'\0\x31\0.\0\x30\0'\0"
1177                 " \0e\0n\0c\0o\0d\0i\0n\0g\0=\0'\0u\0t\0f\0-\0""1\0""6\0'"
1178                 "\0?\0>\0\n"
1179             "\0<\0a\0>\0<\0!\0[\0C\0D\0A\0T\0A\0[\0h\0e\0l\0l\0o\0]\0]\0>\0<\0/\0a\0>";
1180     const char *expected = "hello";
1181
1182     CharData storage;
1183     CharData_Init(&storage);
1184     XML_SetUserData(parser, &storage);
1185     XML_SetCharacterDataHandler(parser, accumulate_characters);
1186
1187     if (_XML_Parse_SINGLE_BYTES(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_ERROR)
1188         xml_failure(parser);
1189     CharData_CheckXMLChars(&storage, expected);
1190 }
1191 END_TEST
1192
1193 START_TEST(test_bad_cdata)
1194 {
1195     struct CaseData {
1196         const char *text;
1197         enum XML_Error expectedError;
1198     };
1199
1200     struct CaseData cases[] = {
1201         {"<a><", XML_ERROR_UNCLOSED_TOKEN},
1202         {"<a><!", XML_ERROR_UNCLOSED_TOKEN},
1203         {"<a><![", XML_ERROR_UNCLOSED_TOKEN},
1204         {"<a><![C", XML_ERROR_UNCLOSED_TOKEN},
1205         {"<a><![CD", XML_ERROR_UNCLOSED_TOKEN},
1206         {"<a><![CDA", XML_ERROR_UNCLOSED_TOKEN},
1207         {"<a><![CDAT", XML_ERROR_UNCLOSED_TOKEN},
1208         {"<a><![CDATA", XML_ERROR_UNCLOSED_TOKEN},
1209
1210         {"<a><![CDATA[", XML_ERROR_UNCLOSED_CDATA_SECTION},
1211         {"<a><![CDATA[]", XML_ERROR_UNCLOSED_CDATA_SECTION},
1212         {"<a><![CDATA[]]", XML_ERROR_UNCLOSED_CDATA_SECTION},
1213
1214         {"<a><!<a/>", XML_ERROR_INVALID_TOKEN},
1215         {"<a><![<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
1216         {"<a><![C<a/>", XML_ERROR_UNCLOSED_TOKEN}, /* ?! */
1217         {"<a><![CD<a/>", XML_ERROR_INVALID_TOKEN},
1218         {"<a><![CDA<a/>", XML_ERROR_INVALID_TOKEN},
1219         {"<a><![CDAT<a/>", XML_ERROR_INVALID_TOKEN},
1220         {"<a><![CDATA<a/>", XML_ERROR_INVALID_TOKEN},
1221
1222         {"<a><![CDATA[<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
1223         {"<a><![CDATA[]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION},
1224         {"<a><![CDATA[]]<a/>", XML_ERROR_UNCLOSED_CDATA_SECTION}
1225     };
1226
1227     size_t i = 0;
1228     for (; i < sizeof(cases) / sizeof(struct CaseData); i++) {
1229         const enum XML_Status actualStatus = _XML_Parse_SINGLE_BYTES(
1230                 parser, cases[i].text, strlen(cases[i].text), XML_TRUE);
1231         const enum XML_Error actualError = XML_GetErrorCode(parser);
1232
1233         assert(actualStatus == XML_STATUS_ERROR);
1234
1235         if (actualError != cases[i].expectedError) {
1236             char message[100];
1237             sprintf(message, "Expected error %d but got error %d for case %u: \"%s\"\n",
1238                     cases[i].expectedError, actualError, (unsigned int)i + 1, cases[i].text);
1239             fail(message);
1240         }
1241
1242         XML_ParserReset(parser, NULL);
1243     }
1244 }
1245 END_TEST
1246
1247
1248 /*
1249  * Namespaces tests.
1250  */
1251
1252 static void
1253 namespace_setup(void)
1254 {
1255     parser = XML_ParserCreateNS(NULL, ' ');
1256     if (parser == NULL)
1257         fail("Parser not created.");
1258 }
1259
1260 static void
1261 namespace_teardown(void)
1262 {
1263     basic_teardown();
1264 }
1265
1266 /* Check that an element name and attribute name match the expected values.
1267    The expected values are passed as an array reference of string pointers
1268    provided as the userData argument; the first is the expected
1269    element name, and the second is the expected attribute name.
1270 */
1271 static void XMLCALL
1272 triplet_start_checker(void *userData, const XML_Char *name,
1273                       const XML_Char **atts)
1274 {
1275     char **elemstr = (char **)userData;
1276     char buffer[1024];
1277     if (strcmp(elemstr[0], name) != 0) {
1278         sprintf(buffer, "unexpected start string: '%s'", name);
1279         fail(buffer);
1280     }
1281     if (strcmp(elemstr[1], atts[0]) != 0) {
1282         sprintf(buffer, "unexpected attribute string: '%s'", atts[0]);
1283         fail(buffer);
1284     }
1285 }
1286
1287 /* Check that the element name passed to the end-element handler matches
1288    the expected value.  The expected value is passed as the first element
1289    in an array of strings passed as the userData argument.
1290 */
1291 static void XMLCALL
1292 triplet_end_checker(void *userData, const XML_Char *name)
1293 {
1294     char **elemstr = (char **)userData;
1295     if (strcmp(elemstr[0], name) != 0) {
1296         char buffer[1024];
1297         sprintf(buffer, "unexpected end string: '%s'", name);
1298         fail(buffer);
1299     }
1300 }
1301
1302 START_TEST(test_return_ns_triplet)
1303 {
1304     const char *text =
1305         "<foo:e xmlns:foo='http://expat.sf.net/' bar:a='12'\n"
1306         "       xmlns:bar='http://expat.sf.net/'></foo:e>";
1307     const char *elemstr[] = {
1308         "http://expat.sf.net/ e foo",
1309         "http://expat.sf.net/ a bar"
1310     };
1311     XML_SetReturnNSTriplet(parser, XML_TRUE);
1312     XML_SetUserData(parser, elemstr);
1313     XML_SetElementHandler(parser, triplet_start_checker, triplet_end_checker);
1314     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1315         xml_failure(parser);
1316 }
1317 END_TEST
1318
1319 static void XMLCALL
1320 overwrite_start_checker(void *userData, const XML_Char *name,
1321                         const XML_Char **atts)
1322 {
1323     CharData *storage = (CharData *) userData;
1324     CharData_AppendString(storage, "start ");
1325     CharData_AppendXMLChars(storage, name, -1);
1326     while (*atts != NULL) {
1327         CharData_AppendString(storage, "\nattribute ");
1328         CharData_AppendXMLChars(storage, *atts, -1);
1329         atts += 2;
1330     }
1331     CharData_AppendString(storage, "\n");
1332 }
1333
1334 static void XMLCALL
1335 overwrite_end_checker(void *userData, const XML_Char *name)
1336 {
1337     CharData *storage = (CharData *) userData;
1338     CharData_AppendString(storage, "end ");
1339     CharData_AppendXMLChars(storage, name, -1);
1340     CharData_AppendString(storage, "\n");
1341 }
1342
1343 static void
1344 run_ns_tagname_overwrite_test(const char *text, const char *result)
1345 {
1346     CharData storage;
1347     CharData_Init(&storage);
1348     XML_SetUserData(parser, &storage);
1349     XML_SetElementHandler(parser,
1350                           overwrite_start_checker, overwrite_end_checker);
1351     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1352         xml_failure(parser);
1353     CharData_CheckString(&storage, result);
1354 }
1355
1356 /* Regression test for SF bug #566334. */
1357 START_TEST(test_ns_tagname_overwrite)
1358 {
1359     const char *text =
1360         "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
1361         "  <n:f n:attr='foo'/>\n"
1362         "  <n:g n:attr2='bar'/>\n"
1363         "</n:e>";
1364     const char *result =
1365         "start http://xml.libexpat.org/ e\n"
1366         "start http://xml.libexpat.org/ f\n"
1367         "attribute http://xml.libexpat.org/ attr\n"
1368         "end http://xml.libexpat.org/ f\n"
1369         "start http://xml.libexpat.org/ g\n"
1370         "attribute http://xml.libexpat.org/ attr2\n"
1371         "end http://xml.libexpat.org/ g\n"
1372         "end http://xml.libexpat.org/ e\n";
1373     run_ns_tagname_overwrite_test(text, result);
1374 }
1375 END_TEST
1376
1377 /* Regression test for SF bug #566334. */
1378 START_TEST(test_ns_tagname_overwrite_triplet)
1379 {
1380     const char *text =
1381         "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
1382         "  <n:f n:attr='foo'/>\n"
1383         "  <n:g n:attr2='bar'/>\n"
1384         "</n:e>";
1385     const char *result =
1386         "start http://xml.libexpat.org/ e n\n"
1387         "start http://xml.libexpat.org/ f n\n"
1388         "attribute http://xml.libexpat.org/ attr n\n"
1389         "end http://xml.libexpat.org/ f n\n"
1390         "start http://xml.libexpat.org/ g n\n"
1391         "attribute http://xml.libexpat.org/ attr2 n\n"
1392         "end http://xml.libexpat.org/ g n\n"
1393         "end http://xml.libexpat.org/ e n\n";
1394     XML_SetReturnNSTriplet(parser, XML_TRUE);
1395     run_ns_tagname_overwrite_test(text, result);
1396 }
1397 END_TEST
1398
1399
1400 /* Regression test for SF bug #620343. */
1401 static void XMLCALL
1402 start_element_fail(void *UNUSED_P(userData),
1403                    const XML_Char *UNUSED_P(name), const XML_Char **UNUSED_P(atts))
1404 {
1405     /* We should never get here. */
1406     fail("should never reach start_element_fail()");
1407 }
1408
1409 static void XMLCALL
1410 start_ns_clearing_start_element(void *userData,
1411                                 const XML_Char *UNUSED_P(prefix),
1412                                 const XML_Char *UNUSED_P(uri))
1413 {
1414     XML_SetStartElementHandler((XML_Parser) userData, NULL);
1415 }
1416
1417 START_TEST(test_start_ns_clears_start_element)
1418 {
1419     /* This needs to use separate start/end tags; using the empty tag
1420        syntax doesn't cause the problematic path through Expat to be
1421        taken.
1422     */
1423     const char *text = "<e xmlns='http://xml.libexpat.org/'></e>";
1424
1425     XML_SetStartElementHandler(parser, start_element_fail);
1426     XML_SetStartNamespaceDeclHandler(parser, start_ns_clearing_start_element);
1427     XML_UseParserAsHandlerArg(parser);
1428     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1429         xml_failure(parser);
1430 }
1431 END_TEST
1432
1433 /* Regression test for SF bug #616863. */
1434 static int XMLCALL
1435 external_entity_handler(XML_Parser parser,
1436                         const XML_Char *context,
1437                         const XML_Char *UNUSED_P(base),
1438                         const XML_Char *UNUSED_P(systemId),
1439                         const XML_Char *UNUSED_P(publicId))
1440 {
1441     intptr_t callno = 1 + (intptr_t)XML_GetUserData(parser);
1442     const char *text;
1443     XML_Parser p2;
1444
1445     if (callno == 1)
1446         text = ("<!ELEMENT doc (e+)>\n"
1447                 "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
1448                 "<!ELEMENT e EMPTY>\n");
1449     else
1450         text = ("<?xml version='1.0' encoding='us-ascii'?>"
1451                 "<e/>");
1452
1453     XML_SetUserData(parser, (void *) callno);
1454     p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
1455     if (_XML_Parse_SINGLE_BYTES(p2, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) {
1456         xml_failure(p2);
1457         return 0;
1458     }
1459     XML_ParserFree(p2);
1460     return 1;
1461 }
1462
1463 START_TEST(test_default_ns_from_ext_subset_and_ext_ge)
1464 {
1465     const char *text =
1466         "<?xml version='1.0'?>\n"
1467         "<!DOCTYPE doc SYSTEM 'http://xml.libexpat.org/doc.dtd' [\n"
1468         "  <!ENTITY en SYSTEM 'http://xml.libexpat.org/entity.ent'>\n"
1469         "]>\n"
1470         "<doc xmlns='http://xml.libexpat.org/ns1'>\n"
1471         "&en;\n"
1472         "</doc>";
1473
1474     XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1475     XML_SetExternalEntityRefHandler(parser, external_entity_handler);
1476     /* We actually need to set this handler to tickle this bug. */
1477     XML_SetStartElementHandler(parser, dummy_start_element);
1478     XML_SetUserData(parser, NULL);
1479     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1480         xml_failure(parser);
1481 }
1482 END_TEST
1483
1484 /* Regression test #1 for SF bug #673791. */
1485 START_TEST(test_ns_prefix_with_empty_uri_1)
1486 {
1487     const char *text =
1488         "<doc xmlns:prefix='http://xml.libexpat.org/'>\n"
1489         "  <e xmlns:prefix=''/>\n"
1490         "</doc>";
1491
1492     expect_failure(text,
1493                    XML_ERROR_UNDECLARING_PREFIX,
1494                    "Did not report re-setting namespace"
1495                    " URI with prefix to ''.");
1496 }
1497 END_TEST
1498
1499 /* Regression test #2 for SF bug #673791. */
1500 START_TEST(test_ns_prefix_with_empty_uri_2)
1501 {
1502     const char *text =
1503         "<?xml version='1.0'?>\n"
1504         "<docelem xmlns:pre=''/>";
1505
1506     expect_failure(text,
1507                    XML_ERROR_UNDECLARING_PREFIX,
1508                    "Did not report setting namespace URI with prefix to ''.");
1509 }
1510 END_TEST
1511
1512 /* Regression test #3 for SF bug #673791. */
1513 START_TEST(test_ns_prefix_with_empty_uri_3)
1514 {
1515     const char *text =
1516         "<!DOCTYPE doc [\n"
1517         "  <!ELEMENT doc EMPTY>\n"
1518         "  <!ATTLIST doc\n"
1519         "    xmlns:prefix CDATA ''>\n"
1520         "]>\n"
1521         "<doc/>";
1522
1523     expect_failure(text,
1524                    XML_ERROR_UNDECLARING_PREFIX,
1525                    "Didn't report attr default setting NS w/ prefix to ''.");
1526 }
1527 END_TEST
1528
1529 /* Regression test #4 for SF bug #673791. */
1530 START_TEST(test_ns_prefix_with_empty_uri_4)
1531 {
1532     const char *text =
1533         "<!DOCTYPE doc [\n"
1534         "  <!ELEMENT prefix:doc EMPTY>\n"
1535         "  <!ATTLIST prefix:doc\n"
1536         "    xmlns:prefix CDATA 'http://xml.libexpat.org/'>\n"
1537         "]>\n"
1538         "<prefix:doc/>";
1539     /* Packaged info expected by the end element handler;
1540        the weird structuring lets us re-use the triplet_end_checker()
1541        function also used for another test. */
1542     const char *elemstr[] = {
1543         "http://xml.libexpat.org/ doc prefix"
1544     };
1545     XML_SetReturnNSTriplet(parser, XML_TRUE);
1546     XML_SetUserData(parser, elemstr);
1547     XML_SetEndElementHandler(parser, triplet_end_checker);
1548     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1549         xml_failure(parser);
1550 }
1551 END_TEST
1552
1553 START_TEST(test_ns_default_with_empty_uri)
1554 {
1555     const char *text =
1556         "<doc xmlns='http://xml.libexpat.org/'>\n"
1557         "  <e xmlns=''/>\n"
1558         "</doc>";
1559     if (_XML_Parse_SINGLE_BYTES(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1560         xml_failure(parser);
1561 }
1562 END_TEST
1563
1564 /* Regression test for SF bug #692964: two prefixes for one namespace. */
1565 START_TEST(test_ns_duplicate_attrs_diff_prefixes)
1566 {
1567     const char *text =
1568         "<doc xmlns:a='http://xml.libexpat.org/a'\n"
1569         "     xmlns:b='http://xml.libexpat.org/a'\n"
1570         "     a:a='v' b:a='v' />";
1571     expect_failure(text,
1572                    XML_ERROR_DUPLICATE_ATTRIBUTE,
1573                    "did not report multiple attributes with same URI+name");
1574 }
1575 END_TEST
1576
1577 /* Regression test for SF bug #695401: unbound prefix. */
1578 START_TEST(test_ns_unbound_prefix_on_attribute)
1579 {
1580     const char *text = "<doc a:attr=''/>";
1581     expect_failure(text,
1582                    XML_ERROR_UNBOUND_PREFIX,
1583                    "did not report unbound prefix on attribute");
1584 }
1585 END_TEST
1586
1587 /* Regression test for SF bug #695401: unbound prefix. */
1588 START_TEST(test_ns_unbound_prefix_on_element)
1589 {
1590     const char *text = "<a:doc/>";
1591     expect_failure(text,
1592                    XML_ERROR_UNBOUND_PREFIX,
1593                    "did not report unbound prefix on element");
1594 }
1595 END_TEST
1596
1597 static Suite *
1598 make_suite(void)
1599 {
1600     Suite *s = suite_create("basic");
1601     TCase *tc_basic = tcase_create("basic tests");
1602     TCase *tc_namespace = tcase_create("XML namespaces");
1603
1604     suite_add_tcase(s, tc_basic);
1605     tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
1606     tcase_add_test(tc_basic, test_nul_byte);
1607     tcase_add_test(tc_basic, test_u0000_char);
1608     tcase_add_test(tc_basic, test_bom_utf8);
1609     tcase_add_test(tc_basic, test_bom_utf16_be);
1610     tcase_add_test(tc_basic, test_bom_utf16_le);
1611     tcase_add_test(tc_basic, test_illegal_utf8);
1612     tcase_add_test(tc_basic, test_utf8_auto_align);
1613     tcase_add_test(tc_basic, test_utf16);
1614     tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
1615     tcase_add_test(tc_basic, test_latin1_umlauts);
1616     /* Regression test for SF bug #491986. */
1617     tcase_add_test(tc_basic, test_danish_latin1);
1618     /* Regression test for SF bug #514281. */
1619     tcase_add_test(tc_basic, test_french_charref_hexidecimal);
1620     tcase_add_test(tc_basic, test_french_charref_decimal);
1621     tcase_add_test(tc_basic, test_french_latin1);
1622     tcase_add_test(tc_basic, test_french_utf8);
1623     tcase_add_test(tc_basic, test_utf8_false_rejection);
1624     tcase_add_test(tc_basic, test_line_number_after_parse);
1625     tcase_add_test(tc_basic, test_column_number_after_parse);
1626     tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers);
1627     tcase_add_test(tc_basic, test_line_number_after_error);
1628     tcase_add_test(tc_basic, test_column_number_after_error);
1629     tcase_add_test(tc_basic, test_really_long_lines);
1630     tcase_add_test(tc_basic, test_end_element_events);
1631     tcase_add_test(tc_basic, test_attr_whitespace_normalization);
1632     tcase_add_test(tc_basic, test_xmldecl_misplaced);
1633     tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
1634     tcase_add_test(tc_basic,
1635                    test_wfc_undeclared_entity_unread_external_subset);
1636     tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
1637     tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
1638     tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
1639     tcase_add_test(tc_basic,
1640                    test_wfc_undeclared_entity_with_external_subset_standalone);
1641     tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
1642     tcase_add_test(tc_basic, test_ext_entity_set_encoding);
1643     tcase_add_test(tc_basic, test_dtd_default_handling);
1644     tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
1645     tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
1646     tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls);
1647     tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls);
1648     tcase_add_test(tc_basic, test_good_cdata_ascii);
1649     tcase_add_test(tc_basic, test_good_cdata_utf16);
1650     tcase_add_test(tc_basic, test_bad_cdata);
1651
1652     suite_add_tcase(s, tc_namespace);
1653     tcase_add_checked_fixture(tc_namespace,
1654                               namespace_setup, namespace_teardown);
1655     tcase_add_test(tc_namespace, test_return_ns_triplet);
1656     tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
1657     tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
1658     tcase_add_test(tc_namespace, test_start_ns_clears_start_element);
1659     tcase_add_test(tc_namespace, test_default_ns_from_ext_subset_and_ext_ge);
1660     tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1);
1661     tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2);
1662     tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3);
1663     tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4);
1664     tcase_add_test(tc_namespace, test_ns_default_with_empty_uri);
1665     tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
1666     tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute);
1667     tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element);
1668
1669     return s;
1670 }
1671
1672
1673 int
1674 main(int argc, char *argv[])
1675 {
1676     int i, nf;
1677     int verbosity = CK_NORMAL;
1678     Suite *s = make_suite();
1679     SRunner *sr = srunner_create(s);
1680
1681     /* run the tests for internal helper functions */
1682     testhelper_is_whitespace_normalized();
1683
1684     for (i = 1; i < argc; ++i) {
1685         char *opt = argv[i];
1686         if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0)
1687             verbosity = CK_VERBOSE;
1688         else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0)
1689             verbosity = CK_SILENT;
1690         else {
1691             fprintf(stderr, "runtests: unknown option '%s'\n", opt);
1692             return 2;
1693         }
1694     }
1695     if (verbosity != CK_SILENT)
1696         printf("Expat version: %s\n", XML_ExpatVersion());
1697     srunner_run_all(sr, verbosity);
1698     nf = srunner_ntests_failed(sr);
1699     srunner_free(sr);
1700
1701     return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
1702 }