xref: /freebsd/contrib/expat/tests/runtests.c (revision f0a75d274af375d15b97b830966b99a02b7db911)
1 #include <assert.h>
2 #include <check.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 
7 #include "expat.h"
8 #include "chardata.h"
9 
10 
11 static XML_Parser parser;
12 
13 
14 static void
15 basic_setup(void)
16 {
17     parser = XML_ParserCreate(NULL);
18     if (parser == NULL)
19         fail("Parser not created.");
20 }
21 
22 static void
23 basic_teardown(void)
24 {
25     if (parser != NULL)
26         XML_ParserFree(parser);
27 }
28 
29 /* Generate a failure using the parser state to create an error message;
30    this should be used when the parser reports an error we weren't
31    expecting.
32 */
33 static void
34 _xml_failure(XML_Parser parser, const char *file, int line)
35 {
36     char buffer[1024];
37     sprintf(buffer,
38             "\n    %s (line %d, offset %d)\n    reported from %s, line %d",
39             XML_ErrorString(XML_GetErrorCode(parser)),
40             XML_GetCurrentLineNumber(parser),
41             XML_GetCurrentColumnNumber(parser),
42             file, line);
43     fail(buffer);
44 }
45 
46 #define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
47 
48 static void
49 _expect_failure(char *text, enum XML_Error errorCode, char *errorMessage,
50                 char *file, int lineno)
51 {
52     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_OK)
53         fail(errorMessage);
54     if (XML_GetErrorCode(parser) != errorCode)
55         _xml_failure(parser, file, lineno);
56 }
57 
58 #define expect_failure(text, errorCode, errorMessage) \
59         _expect_failure((text), (errorCode), (errorMessage), \
60                         __FILE__, __LINE__)
61 
62 
63 /*
64  * Character & encoding tests.
65  */
66 
67 START_TEST(test_nul_byte)
68 {
69     char text[] = "<doc>\0</doc>";
70 
71     /* test that a NUL byte (in US-ASCII data) is an error */
72     if (XML_Parse(parser, text, sizeof(text) - 1, 1) == XML_STATUS_OK)
73         fail("Parser did not report error on NUL-byte.");
74     if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
75         xml_failure(parser);
76 }
77 END_TEST
78 
79 
80 START_TEST(test_u0000_char)
81 {
82     /* test that a NUL byte (in US-ASCII data) is an error */
83     expect_failure("<doc>&#0;</doc>",
84                    XML_ERROR_BAD_CHAR_REF,
85                    "Parser did not report error on NUL-byte.");
86 }
87 END_TEST
88 
89 START_TEST(test_bom_utf8)
90 {
91     /* This test is really just making sure we don't core on a UTF-8 BOM. */
92     char *text = "\357\273\277<e/>";
93 
94     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
95         xml_failure(parser);
96 }
97 END_TEST
98 
99 START_TEST(test_bom_utf16_be)
100 {
101     char text[] = "\376\377\0<\0e\0/\0>";
102 
103     if (XML_Parse(parser, text, sizeof(text) - 1, 1) == XML_STATUS_ERROR)
104         xml_failure(parser);
105 }
106 END_TEST
107 
108 START_TEST(test_bom_utf16_le)
109 {
110     char text[] = "\377\376<\0e\0/\0>\0";
111 
112     if (XML_Parse(parser, text, sizeof(text) - 1, 1) == XML_STATUS_ERROR)
113         xml_failure(parser);
114 }
115 END_TEST
116 
117 static void
118 accumulate_characters(void *userData, const XML_Char *s, int len)
119 {
120     CharData_AppendXMLChars((CharData *)userData, s, len);
121 }
122 
123 static void
124 accumulate_attribute(void *userData, const XML_Char *name,
125                      const XML_Char **atts)
126 {
127     CharData *storage = (CharData *)userData;
128     if (storage->count < 0 && atts != NULL && atts[0] != NULL) {
129         /* "accumulate" the value of the first attribute we see */
130         CharData_AppendXMLChars(storage, atts[1], -1);
131     }
132 }
133 
134 
135 static void
136 run_character_check(XML_Char *text, XML_Char *expected)
137 {
138     CharData storage;
139 
140     CharData_Init(&storage);
141     XML_SetUserData(parser, &storage);
142     XML_SetCharacterDataHandler(parser, accumulate_characters);
143     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
144         xml_failure(parser);
145     CharData_CheckXMLChars(&storage, expected);
146 }
147 
148 static void
149 run_attribute_check(XML_Char *text, XML_Char *expected)
150 {
151     CharData storage;
152 
153     CharData_Init(&storage);
154     XML_SetUserData(parser, &storage);
155     XML_SetStartElementHandler(parser, accumulate_attribute);
156     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
157         xml_failure(parser);
158     CharData_CheckXMLChars(&storage, expected);
159 }
160 
161 /* Regression test for SF bug #491986. */
162 START_TEST(test_danish_latin1)
163 {
164     char *text =
165         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
166         "<e>J�rgen ������</e>";
167     run_character_check(text,
168              "J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
169 }
170 END_TEST
171 
172 
173 /* Regression test for SF bug #514281. */
174 START_TEST(test_french_charref_hexidecimal)
175 {
176     char *text =
177         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
178         "<doc>&#xE9;&#xE8;&#xE0;&#xE7;&#xEA;&#xC8;</doc>";
179     run_character_check(text,
180                         "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
181 }
182 END_TEST
183 
184 START_TEST(test_french_charref_decimal)
185 {
186     char *text =
187         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
188         "<doc>&#233;&#232;&#224;&#231;&#234;&#200;</doc>";
189     run_character_check(text,
190                         "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
191 }
192 END_TEST
193 
194 START_TEST(test_french_latin1)
195 {
196     char *text =
197         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
198         "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
199     run_character_check(text,
200                         "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
201 }
202 END_TEST
203 
204 START_TEST(test_french_utf8)
205 {
206     char *text =
207         "<?xml version='1.0' encoding='utf-8'?>\n"
208         "<doc>\xC3\xA9</doc>";
209     run_character_check(text, "\xC3\xA9");
210 }
211 END_TEST
212 
213 /* Regression test for SF bug #600479.
214    XXX There should be a test that exercises all legal XML Unicode
215    characters as PCDATA and attribute value content, and XML Name
216    characters as part of element and attribute names.
217 */
218 START_TEST(test_utf8_false_rejection)
219 {
220     char *text = "<doc>\xEF\xBA\xBF</doc>";
221     run_character_check(text, "\xEF\xBA\xBF");
222 }
223 END_TEST
224 
225 /* Regression test for SF bug #477667.
226    This test assures that any 8-bit character followed by a 7-bit
227    character will not be mistakenly interpreted as a valid UTF-8
228    sequence.
229 */
230 START_TEST(test_illegal_utf8)
231 {
232     char text[100];
233     int i;
234 
235     for (i = 128; i <= 255; ++i) {
236         sprintf(text, "<e>%ccd</e>", i);
237         if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_OK) {
238             sprintf(text,
239                     "expected token error for '%c' (ordinal %d) in UTF-8 text",
240                     i, i);
241             fail(text);
242         }
243         else if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
244             xml_failure(parser);
245         /* Reset the parser since we use the same parser repeatedly. */
246         XML_ParserReset(parser, NULL);
247     }
248 }
249 END_TEST
250 
251 START_TEST(test_utf16)
252 {
253     /* <?xml version="1.0" encoding="UTF-16"?>
254        <doc a='123'>some text</doc>
255     */
256     char text[] =
257         "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
258         "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
259         "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
260         "\000'\000?\000>\000\n"
261         "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'"
262         "\000>\000s\000o\000m\000e\000 \000t\000e\000x\000t\000<\000/"
263         "\000d\000o\000c\000>";
264     if (XML_Parse(parser, text, sizeof(text) - 1, 1) == XML_STATUS_ERROR)
265         xml_failure(parser);
266 }
267 END_TEST
268 
269 START_TEST(test_utf16_le_epilog_newline)
270 {
271     int first_chunk_bytes = 17;
272     char text[] =
273         "\xFF\xFE"                      /* BOM */
274         "<\000e\000/\000>\000"          /* document element */
275         "\r\000\n\000\r\000\n\000";     /* epilog */
276 
277     if (first_chunk_bytes >= sizeof(text) - 1)
278         fail("bad value of first_chunk_bytes");
279     if (XML_Parse(parser, text, first_chunk_bytes, 0) == XML_STATUS_ERROR)
280         xml_failure(parser);
281     else {
282         enum XML_Status rc;
283         rc = XML_Parse(parser, text + first_chunk_bytes,
284                        sizeof(text) - first_chunk_bytes - 1, 1);
285         if (rc == XML_STATUS_ERROR)
286             xml_failure(parser);
287     }
288 }
289 END_TEST
290 
291 /* Regression test for SF bug #481609. */
292 START_TEST(test_latin1_umlauts)
293 {
294     char *text =
295         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
296         "<e a='� � � &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC;'\n"
297         "  >� � � &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC;</e>";
298     char *utf8 =
299         "\xC3\xA4 \xC3\xB6 \xC3\xBC "
300         "\xC3\xA4 \xC3\xB6 \xC3\xBC "
301         "\xC3\xA4 \xC3\xB6 \xC3\xBC";
302     run_character_check(text, utf8);
303     XML_ParserReset(parser, NULL);
304     run_attribute_check(text, utf8);
305 }
306 END_TEST
307 
308 /* Regression test for SF bug #422239 (maybe).
309    It's not clear that this reproduces enough of the context
310    of the reported bug.
311 */
312 START_TEST(test_line_count)
313 {
314     char *text =
315         "<e>\n"
316         "  <e/>\n"
317         "</e>";
318     int lineno;
319     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
320         xml_failure(parser);
321     lineno = XML_GetCurrentLineNumber(parser);
322     if (lineno != 3) {
323         char buffer[100];
324         sprintf(buffer, "expected 3 lines, saw %d", lineno);
325         fail(buffer);
326     }
327 }
328 END_TEST
329 
330 /* Regression test for SF bug #478332. */
331 START_TEST(test_really_long_lines)
332 {
333     /* This parses an input line longer than INIT_DATA_BUF_SIZE
334        characters long (defined to be 1024 in xmlparse.c).  We take a
335        really cheesy approach to building the input buffer, because
336        this avoids writing bugs in buffer-filling code.
337     */
338     char *text =
339         "<e>"
340         /* 64 chars */
341         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
342         /* until we have at least 1024 characters on the line: */
343         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
344         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
345         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
346         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
347         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
348         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
349         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
350         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
351         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
352         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
353         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
354         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
355         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
356         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
357         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
358         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
359         "</e>";
360     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
361         xml_failure(parser);
362 }
363 END_TEST
364 
365 
366 /*
367  * Element event tests.
368  */
369 
370 static void
371 end_element_event_handler(void *userData, const XML_Char *name)
372 {
373     CharData *storage = (CharData *) userData;
374     CharData_AppendString(storage, "/");
375     CharData_AppendXMLChars(storage, name, -1);
376 }
377 
378 START_TEST(test_end_element_events)
379 {
380     char *text = "<a><b><c/></b><d><f/></d></a>";
381     char *expected = "/c/b/f/d/a";
382     CharData storage;
383 
384     CharData_Init(&storage);
385     XML_SetUserData(parser, &storage);
386     XML_SetEndElementHandler(parser, end_element_event_handler);
387     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
388         xml_failure(parser);
389     CharData_CheckString(&storage, expected);
390 }
391 END_TEST
392 
393 
394 /*
395  * Attribute tests.
396  */
397 
398 /* Helpers used by the following test; this checks any "attr" and "refs"
399    attributes to make sure whitespace has been normalized.
400 
401    Return true if whitespace has been normalized in a string, using
402    the rules for attribute value normalization.  The 'is_cdata' flag
403    is needed since CDATA attributes don't need to have multiple
404    whitespace characters collapsed to a single space, while other
405    attribute data types do.  (Section 3.3.3 of the recommendation.)
406 */
407 static int
408 is_whitespace_normalized(const XML_Char *s, int is_cdata)
409 {
410     int blanks = 0;
411     int at_start = 1;
412     while (*s) {
413         if (*s == ' ')
414             ++blanks;
415         else if (*s == '\t' || *s == '\n' || *s == '\r')
416             return 0;
417         else {
418             if (at_start) {
419                 at_start = 0;
420                 if (blanks && !is_cdata)
421                     /* illegal leading blanks */
422                     return 0;
423             }
424             else if (blanks > 1 && !is_cdata)
425                 return 0;
426             blanks = 0;
427         }
428         ++s;
429     }
430     if (blanks && !is_cdata)
431         return 0;
432     return 1;
433 }
434 
435 /* Check the attribute whitespace checker: */
436 static void
437 testhelper_is_whitespace_normalized(void)
438 {
439     assert(is_whitespace_normalized("abc", 0));
440     assert(is_whitespace_normalized("abc", 1));
441     assert(is_whitespace_normalized("abc def ghi", 0));
442     assert(is_whitespace_normalized("abc def ghi", 1));
443     assert(!is_whitespace_normalized(" abc def ghi", 0));
444     assert(is_whitespace_normalized(" abc def ghi", 1));
445     assert(!is_whitespace_normalized("abc  def ghi", 0));
446     assert(is_whitespace_normalized("abc  def ghi", 1));
447     assert(!is_whitespace_normalized("abc def ghi ", 0));
448     assert(is_whitespace_normalized("abc def ghi ", 1));
449     assert(!is_whitespace_normalized(" ", 0));
450     assert(is_whitespace_normalized(" ", 1));
451     assert(!is_whitespace_normalized("\t", 0));
452     assert(!is_whitespace_normalized("\t", 1));
453     assert(!is_whitespace_normalized("\n", 0));
454     assert(!is_whitespace_normalized("\n", 1));
455     assert(!is_whitespace_normalized("\r", 0));
456     assert(!is_whitespace_normalized("\r", 1));
457     assert(!is_whitespace_normalized("abc\t def", 1));
458 }
459 
460 static void
461 check_attr_contains_normalized_whitespace(void *userData,
462                                           const XML_Char *name,
463                                           const XML_Char **atts)
464 {
465     int i;
466     for (i = 0; atts[i] != NULL; i += 2) {
467         const XML_Char *attrname = atts[i];
468         const XML_Char *value = atts[i + 1];
469         if (strcmp("attr", attrname) == 0
470             || strcmp("ents", attrname) == 0
471             || strcmp("refs", attrname) == 0) {
472             if (!is_whitespace_normalized(value, 0)) {
473                 char buffer[256];
474                 sprintf(buffer, "attribute value not normalized: %s='%s'",
475                         attrname, value);
476                 fail(buffer);
477             }
478         }
479     }
480 }
481 
482 START_TEST(test_attr_whitespace_normalization)
483 {
484     char *text =
485         "<!DOCTYPE doc [\n"
486         "  <!ATTLIST doc\n"
487         "            attr NMTOKENS #REQUIRED\n"
488         "            ents ENTITIES #REQUIRED\n"
489         "            refs IDREFS   #REQUIRED>\n"
490         "]>\n"
491         "<doc attr='    a  b c\t\td\te\t' refs=' id-1   \t  id-2\t\t'  \n"
492         "     ents=' ent-1   \t\r\n"
493         "            ent-2  ' >\n"
494         "  <e id='id-1'/>\n"
495         "  <e id='id-2'/>\n"
496         "</doc>";
497 
498     XML_SetStartElementHandler(parser,
499                                check_attr_contains_normalized_whitespace);
500     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
501         xml_failure(parser);
502 }
503 END_TEST
504 
505 
506 /*
507  * XML declaration tests.
508  */
509 
510 START_TEST(test_xmldecl_misplaced)
511 {
512     expect_failure("\n"
513                    "<?xml version='1.0'?>\n"
514                    "<a/>",
515                    XML_ERROR_MISPLACED_XML_PI,
516                    "failed to report misplaced XML declaration");
517 }
518 END_TEST
519 
520 /* Regression test for SF bug #584832. */
521 static int
522 UnknownEncodingHandler(void *data,const XML_Char *encoding,XML_Encoding *info)
523 {
524     if (strcmp(encoding,"unsupported-encoding") == 0) {
525         int i;
526         for (i = 0; i < 256; ++i)
527             info->map[i] = i;
528         info->data=NULL;
529         info->convert=NULL;
530         info->release=NULL;
531         return 1;
532     }
533     return 0;
534 }
535 
536 START_TEST(test_unknown_encoding_internal_entity)
537 {
538     char *text =
539         "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
540         "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
541         "<test a='&foo;'/>";
542 
543     XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, NULL);
544     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
545         xml_failure(parser);
546 }
547 END_TEST
548 
549 /* Test that no error is reported for unknown entities if we don't
550    read an external subset.  This was fixed in Expat 1.95.5.
551 */
552 START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
553     char *text =
554         "<!DOCTYPE doc SYSTEM 'foo'>\n"
555         "<doc>&entity;</doc>";
556 
557     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
558         xml_failure(parser);
559 }
560 END_TEST
561 
562 /* Test that an error is reported for unknown entities if we don't
563    have an external subset.
564 */
565 START_TEST(test_wfc_undeclared_entity_no_external_subset) {
566     expect_failure("<doc>&entity;</doc>",
567                    XML_ERROR_UNDEFINED_ENTITY,
568                    "Parser did not report undefined entity w/out a DTD.");
569 }
570 END_TEST
571 
572 /* Test that an error is reported for unknown entities if we don't
573    read an external subset, but have been declared standalone.
574 */
575 START_TEST(test_wfc_undeclared_entity_standalone) {
576     char *text =
577         "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
578         "<!DOCTYPE doc SYSTEM 'foo'>\n"
579         "<doc>&entity;</doc>";
580 
581     expect_failure(text,
582                    XML_ERROR_UNDEFINED_ENTITY,
583                    "Parser did not report undefined entity (standalone).");
584 }
585 END_TEST
586 
587 static int
588 external_entity_loader(XML_Parser parser,
589                        const XML_Char *context,
590                        const XML_Char *base,
591                        const XML_Char *systemId,
592                        const XML_Char *publicId)
593 {
594     char *text = (char *)XML_GetUserData(parser);
595     XML_Parser extparser;
596 
597     extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
598     if (extparser == NULL)
599         fail("Could not create external entity parser.");
600     if (XML_Parse(extparser, text, strlen(text), 1) == XML_STATUS_ERROR) {
601         xml_failure(parser);
602         return 0;
603     }
604     return 1;
605 }
606 
607 /* Test that an error is reported for unknown entities if we have read
608    an external subset.
609 */
610 START_TEST(test_wfc_undeclared_entity_with_external_subset) {
611     char *text =
612         "<?xml version='1.0' encoding='us-ascii'?>\n"
613         "<!DOCTYPE doc SYSTEM 'foo'>\n"
614         "<doc>&entity;</doc>";
615     char *foo_text =
616         "<!ELEMENT doc (#PCDATA)*>";
617 
618     XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
619     XML_SetUserData(parser, foo_text);
620     XML_SetExternalEntityRefHandler(parser, external_entity_loader);
621     expect_failure(text,
622                    XML_ERROR_UNDEFINED_ENTITY,
623                    "Parser did not report undefined entity with DTD.");
624 }
625 END_TEST
626 
627 START_TEST(test_wfc_no_recursive_entity_refs)
628 {
629     char *text =
630         "<!DOCTYPE doc [\n"
631         "  <!ENTITY entity '&#38;entity;'>\n"
632         "]>\n"
633         "<doc>&entity;</doc>";
634 
635     expect_failure(text,
636                    XML_ERROR_RECURSIVE_ENTITY_REF,
637                    "Parser did not report recursive entity reference.");
638 }
639 END_TEST
640 
641 
642 /*
643  * Namespaces tests.
644  */
645 
646 static void
647 namespace_setup(void)
648 {
649     parser = XML_ParserCreateNS(NULL, ' ');
650     if (parser == NULL)
651         fail("Parser not created.");
652 }
653 
654 static void
655 namespace_teardown(void)
656 {
657     basic_teardown();
658 }
659 
660 /* Check that an element name and attribute name match the expected values.
661    The expected values are passed as an array reference of string pointers
662    provided as the userData argument; the first is the expected
663    element name, and the second is the expected attribute name.
664 */
665 static void
666 triplet_start_checker(void *userData, const XML_Char *name,
667                       const XML_Char **atts)
668 {
669     char **elemstr = (char **)userData;
670     char buffer[1024];
671     if (strcmp(elemstr[0], name) != 0) {
672         sprintf(buffer, "unexpected start string: '%s'", name);
673         fail(buffer);
674     }
675     if (strcmp(elemstr[1], atts[0]) != 0) {
676         sprintf(buffer, "unexpected attribute string: '%s'", atts[0]);
677         fail(buffer);
678     }
679 }
680 
681 /* Check that the element name passed to the end-element handler matches
682    the expected value.  The expected value is passed as the first element
683    in an array of strings passed as the userData argument.
684 */
685 static void
686 triplet_end_checker(void *userData, const XML_Char *name)
687 {
688     char **elemstr = (char **)userData;
689     if (strcmp(elemstr[0], name) != 0) {
690         char buffer[1024];
691         sprintf(buffer, "unexpected end string: '%s'", name);
692         fail(buffer);
693     }
694 }
695 
696 START_TEST(test_return_ns_triplet)
697 {
698     char *text =
699         "<foo:e xmlns:foo='http://expat.sf.net/' bar:a='12'\n"
700         "       xmlns:bar='http://expat.sf.net/'></foo:e>";
701     char *elemstr[] = {
702         "http://expat.sf.net/ e foo",
703         "http://expat.sf.net/ a bar"
704     };
705     XML_SetReturnNSTriplet(parser, 1);
706     XML_SetUserData(parser, elemstr);
707     XML_SetElementHandler(parser, triplet_start_checker, triplet_end_checker);
708     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
709         xml_failure(parser);
710 }
711 END_TEST
712 
713 static void
714 overwrite_start_checker(void *userData, const XML_Char *name,
715                         const XML_Char **atts)
716 {
717     CharData *storage = (CharData *) userData;
718     CharData_AppendString(storage, "start ");
719     CharData_AppendXMLChars(storage, name, -1);
720     while (*atts != NULL) {
721         CharData_AppendString(storage, "\nattribute ");
722         CharData_AppendXMLChars(storage, *atts, -1);
723         atts += 2;
724     }
725     CharData_AppendString(storage, "\n");
726 }
727 
728 static void
729 overwrite_end_checker(void *userData, const XML_Char *name)
730 {
731     CharData *storage = (CharData *) userData;
732     CharData_AppendString(storage, "end ");
733     CharData_AppendXMLChars(storage, name, -1);
734     CharData_AppendString(storage, "\n");
735 }
736 
737 static void
738 run_ns_tagname_overwrite_test(char *text, char *result)
739 {
740     CharData storage;
741     CharData_Init(&storage);
742     XML_SetUserData(parser, &storage);
743     XML_SetElementHandler(parser,
744                           overwrite_start_checker, overwrite_end_checker);
745     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
746         xml_failure(parser);
747     CharData_CheckString(&storage, result);
748 }
749 
750 /* Regression test for SF bug #566334. */
751 START_TEST(test_ns_tagname_overwrite)
752 {
753     char *text =
754         "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
755         "  <n:f n:attr='foo'/>\n"
756         "  <n:g n:attr2='bar'/>\n"
757         "</n:e>";
758     char *result =
759         "start http://xml.libexpat.org/ e\n"
760         "start http://xml.libexpat.org/ f\n"
761         "attribute http://xml.libexpat.org/ attr\n"
762         "end http://xml.libexpat.org/ f\n"
763         "start http://xml.libexpat.org/ g\n"
764         "attribute http://xml.libexpat.org/ attr2\n"
765         "end http://xml.libexpat.org/ g\n"
766         "end http://xml.libexpat.org/ e\n";
767     run_ns_tagname_overwrite_test(text, result);
768 }
769 END_TEST
770 
771 /* Regression test for SF bug #566334. */
772 START_TEST(test_ns_tagname_overwrite_triplet)
773 {
774     char *text =
775         "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
776         "  <n:f n:attr='foo'/>\n"
777         "  <n:g n:attr2='bar'/>\n"
778         "</n:e>";
779     char *result =
780         "start http://xml.libexpat.org/ e n\n"
781         "start http://xml.libexpat.org/ f n\n"
782         "attribute http://xml.libexpat.org/ attr n\n"
783         "end http://xml.libexpat.org/ f n\n"
784         "start http://xml.libexpat.org/ g n\n"
785         "attribute http://xml.libexpat.org/ attr2 n\n"
786         "end http://xml.libexpat.org/ g n\n"
787         "end http://xml.libexpat.org/ e n\n";
788     XML_SetReturnNSTriplet(parser, 1);
789     run_ns_tagname_overwrite_test(text, result);
790 }
791 END_TEST
792 
793 static Suite *
794 make_basic_suite(void)
795 {
796     Suite *s = suite_create("basic");
797     TCase *tc_basic = tcase_create("basic tests");
798     TCase *tc_namespace = tcase_create("XML namespaces");
799 
800     suite_add_tcase(s, tc_basic);
801     tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
802     tcase_add_test(tc_basic, test_nul_byte);
803     tcase_add_test(tc_basic, test_u0000_char);
804     tcase_add_test(tc_basic, test_bom_utf8);
805     tcase_add_test(tc_basic, test_bom_utf16_be);
806     tcase_add_test(tc_basic, test_bom_utf16_le);
807     tcase_add_test(tc_basic, test_illegal_utf8);
808     tcase_add_test(tc_basic, test_utf16);
809     tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
810     tcase_add_test(tc_basic, test_latin1_umlauts);
811     /* Regression test for SF bug #491986. */
812     tcase_add_test(tc_basic, test_danish_latin1);
813     /* Regression test for SF bug #514281. */
814     tcase_add_test(tc_basic, test_french_charref_hexidecimal);
815     tcase_add_test(tc_basic, test_french_charref_decimal);
816     tcase_add_test(tc_basic, test_french_latin1);
817     tcase_add_test(tc_basic, test_french_utf8);
818     tcase_add_test(tc_basic, test_utf8_false_rejection);
819     tcase_add_test(tc_basic, test_line_count);
820     tcase_add_test(tc_basic, test_really_long_lines);
821     tcase_add_test(tc_basic, test_end_element_events);
822     tcase_add_test(tc_basic, test_attr_whitespace_normalization);
823     tcase_add_test(tc_basic, test_xmldecl_misplaced);
824     tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
825     tcase_add_test(tc_basic,
826                    test_wfc_undeclared_entity_unread_external_subset);
827     tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
828     tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
829     tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
830     tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
831 
832     suite_add_tcase(s, tc_namespace);
833     tcase_add_checked_fixture(tc_namespace,
834                               namespace_setup, namespace_teardown);
835     tcase_add_test(tc_namespace, test_return_ns_triplet);
836     tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
837     tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
838 
839     return s;
840 }
841 
842 
843 int
844 main(int argc, char *argv[])
845 {
846     int i, nf;
847     int forking = 0, forking_set = 0;
848     int verbosity = CK_NORMAL;
849     Suite *s = make_basic_suite();
850     SRunner *sr = srunner_create(s);
851 
852     /* run the tests for internal helper functions */
853     testhelper_is_whitespace_normalized();
854 
855     for (i = 1; i < argc; ++i) {
856         char *opt = argv[i];
857         if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0)
858             verbosity = CK_VERBOSE;
859         else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0)
860             verbosity = CK_SILENT;
861         else if (strcmp(opt, "-f") == 0 || strcmp(opt, "--fork") == 0) {
862             forking = 1;
863             forking_set = 1;
864         }
865         else if (strcmp(opt, "-n") == 0 || strcmp(opt, "--no-fork") == 0) {
866             forking = 0;
867             forking_set = 1;
868         }
869         else {
870             fprintf(stderr, "runtests: unknown option '%s'\n", opt);
871             return 2;
872         }
873     }
874     if (forking_set)
875         srunner_set_fork_status(sr, forking ? CK_FORK : CK_NOFORK);
876     srunner_run_all(sr, verbosity);
877     nf = srunner_ntests_failed(sr);
878     srunner_free(sr);
879     suite_free(s);
880 
881     return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
882 }
883