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>�</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>éèàçêÈ</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>éèàçêÈ</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 ä ö ü ä ö ü >'\n" 394 " >\xE4 \xF6 \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 '&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