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