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