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