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