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