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