1 /* 2 Test program for TinyXML. 3 */ 4 5 6 #include "tinyxml.h" 7 8 #ifdef TIXML_USE_STL 9 #include <iostream> 10 #include <sstream> 11 using namespace std; 12 #else 13 #include <stdio.h> 14 #endif 15 16 #if defined( WIN32 ) && defined( TUNE ) 17 #include <windows.h> 18 // Apologies to non-windows users! But I need some good timers for 19 // profiling, and these are very platform specific. 20 __int64 start; 21 __int64 end; 22 __int64 freq; 23 #endif 24 25 static int gPass = 0; 26 static int gFail = 0; 27 28 29 bool XmlTest (const char* testString, const char* expected, const char* found, bool noEcho = false) 30 { 31 bool pass = !strcmp( expected, found ); 32 if ( pass ) 33 printf ("[pass]"); 34 else 35 printf ("[fail]"); 36 37 if ( noEcho ) 38 printf (" %s\n", testString); 39 else 40 printf (" %s [%s][%s]\n", testString, expected, found); 41 42 if ( pass ) 43 ++gPass; 44 else 45 ++gFail; 46 return pass; 47 } 48 49 50 bool XmlTest( const char* testString, int expected, int found, bool noEcho = false ) 51 { 52 bool pass = ( expected == found ); 53 if ( pass ) 54 printf ("[pass]"); 55 else 56 printf ("[fail]"); 57 58 if ( noEcho ) 59 printf (" %s\n", testString); 60 else 61 printf (" %s [%d][%d]\n", testString, expected, found); 62 63 if ( pass ) 64 ++gPass; 65 else 66 ++gFail; 67 return pass; 68 } 69 70 71 // 72 // This file demonstrates some basic functionality of TinyXml. 73 // Note that the example is very contrived. It presumes you know 74 // what is in the XML file. But it does test the basic operations, 75 // and show how to add and remove nodes. 76 // 77 78 int main() 79 { 80 // 81 // We start with the 'demoStart' todo list. Process it. And 82 // should hopefully end up with the todo list as illustrated. 83 // 84 const char* demoStart = 85 "<?xml version=\"1.0\" standalone='no' >\n" 86 "<!-- Our to do list data -->" 87 "<ToDo>\n" 88 "<!-- Do I need a secure PDA? -->\n" 89 "<Item priority=\"1\" distance='close'> Go to the <bold>Toy store!</bold></Item>" 90 "<Item priority=\"2\" distance='none'> Do bills </Item>" 91 "<Item priority=\"2\" distance='far & back'> Look for Evil Dinosaurs! </Item>" 92 "</ToDo>"; 93 94 #ifdef TIXML_USE_STL 95 /* What the todo list should look like after processing. 96 In stream (no formatting) representation. */ 97 const char* demoEnd = 98 "<?xml version=\"1.0\" standalone=\"no\" ?>" 99 "<!-- Our to do list data -->" 100 "<ToDo>" 101 "<!-- Do I need a secure PDA? -->" 102 "<Item priority=\"2\" distance=\"close\">Go to the" 103 "<bold>Toy store!" 104 "</bold>" 105 "</Item>" 106 "<Item priority=\"1\" distance=\"far\">Talk to:" 107 "<Meeting where=\"School\">" 108 "<Attendee name=\"Marple\" position=\"teacher\" />" 109 "<Attendee name=\"Voel\" position=\"counselor\" />" 110 "</Meeting>" 111 "<Meeting where=\"Lunch\" />" 112 "</Item>" 113 "<Item priority=\"2\" distance=\"here\">Do bills" 114 "</Item>" 115 "</ToDo>"; 116 #endif 117 118 // The example parses from the character string (above): 119 #if defined( WIN32 ) && defined( TUNE ) 120 QueryPerformanceCounter( (LARGE_INTEGER*) (&start) ); 121 #endif 122 123 { 124 // Write to a file and read it back, to check file I/O. 125 126 TiXmlDocument doc( "demotest.xml" ); 127 doc.Parse( demoStart ); 128 129 if ( doc.Error() ) 130 { 131 printf( "Error in %s: %s\n", doc.Value(), doc.ErrorDesc() ); 132 exit( 1 ); 133 } 134 doc.SaveFile(); 135 } 136 137 TiXmlDocument doc( "demotest.xml" ); 138 bool loadOkay = doc.LoadFile(); 139 140 if ( !loadOkay ) 141 { 142 printf( "Could not load test file 'demotest.xml'. Error='%s'. Exiting.\n", doc.ErrorDesc() ); 143 exit( 1 ); 144 } 145 146 printf( "** Demo doc read from disk: ** \n\n" ); 147 doc.Print( stdout ); 148 149 TiXmlNode* node = 0; 150 TiXmlElement* todoElement = 0; 151 TiXmlElement* itemElement = 0; 152 153 154 // -------------------------------------------------------- 155 // An example of changing existing attributes, and removing 156 // an element from the document. 157 // -------------------------------------------------------- 158 159 // Get the "ToDo" element. 160 // It is a child of the document, and can be selected by name. 161 node = doc.FirstChild( "ToDo" ); 162 assert( node ); 163 todoElement = node->ToElement(); 164 assert( todoElement ); 165 166 // Going to the toy store is now our second priority... 167 // So set the "priority" attribute of the first item in the list. 168 node = todoElement->FirstChildElement(); // This skips the "PDA" comment. 169 assert( node ); 170 itemElement = node->ToElement(); 171 assert( itemElement ); 172 itemElement->SetAttribute( "priority", 2 ); 173 174 // Change the distance to "doing bills" from 175 // "none" to "here". It's the next sibling element. 176 itemElement = itemElement->NextSiblingElement(); 177 assert( itemElement ); 178 itemElement->SetAttribute( "distance", "here" ); 179 180 // Remove the "Look for Evil Dinosaurs!" item. 181 // It is 1 more sibling away. We ask the parent to remove 182 // a particular child. 183 itemElement = itemElement->NextSiblingElement(); 184 todoElement->RemoveChild( itemElement ); 185 186 itemElement = 0; 187 188 // -------------------------------------------------------- 189 // What follows is an example of created elements and text 190 // nodes and adding them to the document. 191 // -------------------------------------------------------- 192 193 // Add some meetings. 194 TiXmlElement item( "Item" ); 195 item.SetAttribute( "priority", "1" ); 196 item.SetAttribute( "distance", "far" ); 197 198 TiXmlText text( "Talk to:" ); 199 200 TiXmlElement meeting1( "Meeting" ); 201 meeting1.SetAttribute( "where", "School" ); 202 203 TiXmlElement meeting2( "Meeting" ); 204 meeting2.SetAttribute( "where", "Lunch" ); 205 206 TiXmlElement attendee1( "Attendee" ); 207 attendee1.SetAttribute( "name", "Marple" ); 208 attendee1.SetAttribute( "position", "teacher" ); 209 210 TiXmlElement attendee2( "Attendee" ); 211 attendee2.SetAttribute( "name", "Voel" ); 212 attendee2.SetAttribute( "position", "counselor" ); 213 214 // Assemble the nodes we've created: 215 meeting1.InsertEndChild( attendee1 ); 216 meeting1.InsertEndChild( attendee2 ); 217 218 item.InsertEndChild( text ); 219 item.InsertEndChild( meeting1 ); 220 item.InsertEndChild( meeting2 ); 221 222 // And add the node to the existing list after the first child. 223 node = todoElement->FirstChild( "Item" ); 224 assert( node ); 225 itemElement = node->ToElement(); 226 assert( itemElement ); 227 228 todoElement->InsertAfterChild( itemElement, item ); 229 230 printf( "\n** Demo doc processed: ** \n\n" ); 231 doc.Print( stdout ); 232 233 234 #ifdef TIXML_USE_STL 235 printf( "** Demo doc processed to stream: ** \n\n" ); 236 cout << doc << endl << endl; 237 #endif 238 239 // -------------------------------------------------------- 240 // Different tests...do we have what we expect? 241 // -------------------------------------------------------- 242 243 int count = 0; 244 TiXmlElement* element; 245 246 ////////////////////////////////////////////////////// 247 248 #ifdef TIXML_USE_STL 249 cout << "** Basic structure. **\n"; 250 ostringstream outputStream( ostringstream::out ); 251 outputStream << doc; 252 XmlTest( "Output stream correct.", string( demoEnd ).c_str(), 253 outputStream.str().c_str(), true ); 254 #endif 255 256 node = doc.RootElement(); 257 XmlTest( "Root element exists.", true, ( node != 0 && node->ToElement() ) ); 258 XmlTest ( "Root element value is 'ToDo'.", "ToDo", node->Value()); 259 260 node = node->FirstChild(); 261 XmlTest( "First child exists & is a comment.", true, ( node != 0 && node->ToComment() ) ); 262 node = node->NextSibling(); 263 XmlTest( "Sibling element exists & is an element.", true, ( node != 0 && node->ToElement() ) ); 264 XmlTest ( "Value is 'Item'.", "Item", node->Value() ); 265 266 node = node->FirstChild(); 267 XmlTest ( "First child exists.", true, ( node != 0 && node->ToText() ) ); 268 XmlTest ( "Value is 'Go to the'.", "Go to the", node->Value() ); 269 270 271 ////////////////////////////////////////////////////// 272 printf ("\n** Iterators. **\n"); 273 274 // Walk all the top level nodes of the document. 275 count = 0; 276 for( node = doc.FirstChild(); 277 node; 278 node = node->NextSibling() ) 279 { 280 count++; 281 } 282 XmlTest( "Top level nodes, using First / Next.", 3, count ); 283 284 count = 0; 285 for( node = doc.LastChild(); 286 node; 287 node = node->PreviousSibling() ) 288 { 289 count++; 290 } 291 XmlTest( "Top level nodes, using Last / Previous.", 3, count ); 292 293 // Walk all the top level nodes of the document, 294 // using a different syntax. 295 count = 0; 296 for( node = doc.IterateChildren( 0 ); 297 node; 298 node = doc.IterateChildren( node ) ) 299 { 300 count++; 301 } 302 XmlTest( "Top level nodes, using IterateChildren.", 3, count ); 303 304 // Walk all the elements in a node. 305 count = 0; 306 for( element = todoElement->FirstChildElement(); 307 element; 308 element = element->NextSiblingElement() ) 309 { 310 count++; 311 } 312 XmlTest( "Children of the 'ToDo' element, using First / Next.", 313 3, count ); 314 315 // Walk all the elements in a node by value. 316 count = 0; 317 for( node = todoElement->FirstChild( "Item" ); 318 node; 319 node = node->NextSibling( "Item" ) ) 320 { 321 count++; 322 } 323 XmlTest( "'Item' children of the 'ToDo' element, using First/Next.", 3, count ); 324 325 count = 0; 326 for( node = todoElement->LastChild( "Item" ); 327 node; 328 node = node->PreviousSibling( "Item" ) ) 329 { 330 count++; 331 } 332 XmlTest( "'Item' children of the 'ToDo' element, using Last/Previous.", 3, count ); 333 334 #ifdef TIXML_USE_STL 335 { 336 cout << "\n** Parsing. **\n"; 337 istringstream parse0( "<Element0 attribute0='foo0' attribute1= noquotes attribute2 = '>' />" ); 338 TiXmlElement element0( "default" ); 339 parse0 >> element0; 340 341 XmlTest ( "Element parsed, value is 'Element0'.", "Element0", element0.Value() ); 342 XmlTest ( "Reads attribute 'attribute0=\"foo0\"'.", "foo0", element0.Attribute( "attribute0" )); 343 XmlTest ( "Reads incorrectly formatted 'attribute1=noquotes'.", "noquotes", element0.Attribute( "attribute1" ) ); 344 XmlTest ( "Read attribute with entity value '>'.", ">", element0.Attribute( "attribute2" ) ); 345 } 346 #endif 347 348 { 349 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n" 350 "<passages count=\"006\" formatversion=\"20020620\">\n" 351 " <wrong error>\n" 352 "</passages>"; 353 354 TiXmlDocument doc; 355 doc.Parse( error ); 356 XmlTest( "Error row", doc.ErrorRow(), 3 ); 357 XmlTest( "Error column", doc.ErrorCol(), 17 ); 358 //printf( "error=%d id='%s' row %d col%d\n", (int) doc.Error(), doc.ErrorDesc(), doc.ErrorRow()+1, doc.ErrorCol() + 1 ); 359 360 } 361 { 362 const char* str = "\t<?xml version=\"1.0\" standalone=\"no\" ?>\t<room doors='2'>\n" 363 " <!-- Silly example -->\n" 364 " <door wall='north'>A great door!</door>\n" 365 "\t<door wall='east'/>" 366 "</room>"; 367 368 TiXmlDocument doc; 369 doc.Parse( str ); 370 371 TiXmlHandle docHandle( &doc ); 372 TiXmlHandle roomHandle = docHandle.FirstChildElement( "room" ); 373 TiXmlHandle commentHandle = docHandle.FirstChildElement( "room" ).FirstChild(); 374 TiXmlHandle textHandle = docHandle.FirstChildElement( "room" ).ChildElement( "door", 0 ).FirstChild(); 375 TiXmlHandle door0Handle = docHandle.FirstChildElement( "room" ).ChildElement( 0 ); 376 TiXmlHandle door1Handle = docHandle.FirstChildElement( "room" ).ChildElement( 1 ); 377 378 assert( docHandle.Node() ); 379 assert( roomHandle.Element() ); 380 assert( commentHandle.Node() ); 381 assert( textHandle.Text() ); 382 assert( door0Handle.Element() ); 383 assert( door1Handle.Element() ); 384 385 TiXmlDeclaration* declaration = doc.FirstChild()->ToDeclaration(); 386 assert( declaration ); 387 TiXmlElement* room = roomHandle.Element(); 388 assert( room ); 389 TiXmlAttribute* doors = room->FirstAttribute(); 390 assert( doors ); 391 TiXmlText* text = textHandle.Text(); 392 TiXmlComment* comment = commentHandle.Node()->ToComment(); 393 assert( comment ); 394 TiXmlElement* door0 = door0Handle.Element(); 395 TiXmlElement* door1 = door1Handle.Element(); 396 397 XmlTest( "Location tracking: Declaration row", declaration->Row(), 1 ); 398 XmlTest( "Location tracking: Declaration col", declaration->Column(), 5 ); 399 XmlTest( "Location tracking: room row", room->Row(), 1 ); 400 XmlTest( "Location tracking: room col", room->Column(), 45 ); 401 XmlTest( "Location tracking: doors row", doors->Row(), 1 ); 402 XmlTest( "Location tracking: doors col", doors->Column(), 51 ); 403 XmlTest( "Location tracking: Comment row", comment->Row(), 2 ); 404 XmlTest( "Location tracking: Comment col", comment->Column(), 3 ); 405 XmlTest( "Location tracking: text row", text->Row(), 3 ); 406 XmlTest( "Location tracking: text col", text->Column(), 24 ); 407 XmlTest( "Location tracking: door0 row", door0->Row(), 3 ); 408 XmlTest( "Location tracking: door0 col", door0->Column(), 5 ); 409 XmlTest( "Location tracking: door1 row", door1->Row(), 4 ); 410 XmlTest( "Location tracking: door1 col", door1->Column(), 5 ); 411 } 412 { 413 const char* str = "\t<?xml version=\"1.0\" standalone=\"no\" ?>\t<room doors='2'>\n" 414 "</room>"; 415 416 TiXmlDocument doc; 417 doc.SetTabSize( 8 ); 418 doc.Parse( str ); 419 420 TiXmlHandle docHandle( &doc ); 421 TiXmlHandle roomHandle = docHandle.FirstChildElement( "room" ); 422 423 assert( docHandle.Node() ); 424 assert( roomHandle.Element() ); 425 426 TiXmlElement* room = roomHandle.Element(); 427 assert( room ); 428 TiXmlAttribute* doors = room->FirstAttribute(); 429 assert( doors ); 430 431 XmlTest( "Location tracking: Tab 8: room row", room->Row(), 1 ); 432 XmlTest( "Location tracking: Tab 8: room col", room->Column(), 49 ); 433 XmlTest( "Location tracking: Tab 8: doors row", doors->Row(), 1 ); 434 XmlTest( "Location tracking: Tab 8: doors col", doors->Column(), 55 ); 435 } 436 437 { 438 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />"; 439 440 TiXmlDocument doc; 441 doc.Parse( str ); 442 443 TiXmlElement* ele = doc.FirstChildElement(); 444 445 int iVal, result; 446 double dVal; 447 448 result = ele->QueryDoubleAttribute( "attr0", &dVal ); 449 XmlTest( "Query attribute: int as double", result, TIXML_SUCCESS ); 450 XmlTest( "Query attribute: int as double", (int)dVal, 1 ); 451 result = ele->QueryDoubleAttribute( "attr1", &dVal ); 452 XmlTest( "Query attribute: double as double", (int)dVal, 2 ); 453 result = ele->QueryIntAttribute( "attr1", &iVal ); 454 XmlTest( "Query attribute: double as int", result, TIXML_SUCCESS ); 455 XmlTest( "Query attribute: double as int", iVal, 2 ); 456 result = ele->QueryIntAttribute( "attr2", &iVal ); 457 XmlTest( "Query attribute: not a number", result, TIXML_WRONG_TYPE ); 458 result = ele->QueryIntAttribute( "bar", &iVal ); 459 XmlTest( "Query attribute: does not exist", result, TIXML_NO_ATTRIBUTE ); 460 } 461 462 #ifdef TIXML_USE_STL 463 { 464 ////////////////////////////////////////////////////// 465 cout << "\n** Streaming. **\n"; 466 467 // Round trip check: stream in, then stream back out to verify. The stream 468 // out has already been checked, above. We use the output 469 470 istringstream inputStringStream( outputStream.str() ); 471 TiXmlDocument document0; 472 473 inputStringStream >> document0; 474 475 ostringstream outputStream0( ostringstream::out ); 476 outputStream0 << document0; 477 478 XmlTest( "Stream round trip correct.", string( demoEnd ).c_str(), 479 outputStream0.str().c_str(), true ); 480 481 std::string str; 482 str << document0; 483 484 XmlTest( "String printing correct.", string( demoEnd ).c_str(), 485 str.c_str(), true ); 486 } 487 #endif 488 489 // -------------------------------------------------------- 490 // UTF-8 testing. It is important to test: 491 // 1. Making sure name, value, and text read correctly 492 // 2. Row, Col functionality 493 // 3. Correct output 494 // -------------------------------------------------------- 495 printf ("\n** UTF-8 **\n"); 496 { 497 TiXmlDocument doc( "utf8test.xml" ); 498 doc.LoadFile(); 499 if ( doc.Error() && doc.ErrorId() == TiXmlBase::TIXML_ERROR_OPENING_FILE ) { 500 printf( "WARNING: File 'utf8test.xml' not found.\n" 501 "(Are you running the test from the wrong directory?)\n" 502 "Could not test UTF-8 functionality.\n" ); 503 } 504 else 505 { 506 TiXmlHandle docH( &doc ); 507 // Get the attribute "value" from the "Russian" element and check it. 508 TiXmlElement* element = docH.FirstChildElement( "document" ).FirstChildElement( "Russian" ).Element(); 509 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU, 510 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 }; 511 512 XmlTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ), true ); 513 XmlTest( "UTF-8: Russian value row.", 4, element->Row() ); 514 XmlTest( "UTF-8: Russian value column.", 5, element->Column() ); 515 516 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U, 517 0xd1U, 0x81U, 0xd1U, 0x81U, 518 0xd0U, 0xbaU, 0xd0U, 0xb8U, 519 0xd0U, 0xb9U, 0 }; 520 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>"; 521 522 TiXmlText* text = docH.FirstChildElement( "document" ).FirstChildElement( (const char*) russianElementName ).Child( 0 ).Text(); 523 XmlTest( "UTF-8: Browsing russian element name.", 524 russianText, 525 text->Value(), 526 true ); 527 XmlTest( "UTF-8: Russian element name row.", 7, text->Row() ); 528 XmlTest( "UTF-8: Russian element name column.", 47, text->Column() ); 529 530 TiXmlDeclaration* dec = docH.Child( 0 ).Node()->ToDeclaration(); 531 XmlTest( "UTF-8: Declaration column.", 1, dec->Column() ); 532 XmlTest( "UTF-8: Document column.", 1, doc.Column() ); 533 534 // Now try for a round trip. 535 doc.SaveFile( "utf8testout.xml" ); 536 537 // Check the round trip. 538 char savedBuf[256]; 539 char verifyBuf[256]; 540 int okay = 1; 541 542 FILE* saved = fopen( "utf8testout.xml", "r" ); 543 FILE* verify = fopen( "utf8testverify.xml", "r" ); 544 if ( saved && verify ) 545 { 546 while ( fgets( verifyBuf, 256, verify ) ) 547 { 548 fgets( savedBuf, 256, saved ); 549 if ( strcmp( verifyBuf, savedBuf ) ) 550 { 551 okay = 0; 552 break; 553 } 554 } 555 fclose( saved ); 556 fclose( verify ); 557 } 558 XmlTest( "UTF-8: Verified multi-language round trip.", 1, okay ); 559 560 // On most Western machines, this is an element that contains 561 // the word "resume" with the correct accents, in a latin encoding. 562 // It will be something else completely on non-wester machines, 563 // which is why TinyXml is switching to UTF-8. 564 const char latin[] = "<element>r\x82sum\x82</element>"; 565 566 TiXmlDocument latinDoc; 567 latinDoc.Parse( latin, 0, TIXML_ENCODING_LEGACY ); 568 569 text = latinDoc.FirstChildElement()->FirstChild()->ToText(); 570 XmlTest( "Legacy encoding: Verify text element.", "r\x82sum\x82", text->Value() ); 571 } 572 } 573 574 ////////////////////// 575 // Copy and assignment 576 ////////////////////// 577 printf ("\n** Copy and Assignment **\n"); 578 { 579 TiXmlElement element( "foo" ); 580 element.Parse( "<element name='value' />", 0, TIXML_ENCODING_UNKNOWN ); 581 582 TiXmlElement elementCopy( element ); 583 TiXmlElement elementAssign( "foo" ); 584 elementAssign.Parse( "<incorrect foo='bar'/>", 0, TIXML_ENCODING_UNKNOWN ); 585 elementAssign = element; 586 587 XmlTest( "Copy/Assign: element copy #1.", "element", elementCopy.Value() ); 588 XmlTest( "Copy/Assign: element copy #2.", "value", elementCopy.Attribute( "name" ) ); 589 XmlTest( "Copy/Assign: element assign #1.", "element", elementAssign.Value() ); 590 XmlTest( "Copy/Assign: element assign #2.", "value", elementAssign.Attribute( "name" ) ); 591 XmlTest( "Copy/Assign: element assign #3.", 0, (int) elementAssign.Attribute( "foo" ) ); 592 593 TiXmlComment comment; 594 comment.Parse( "<!--comment-->", 0, TIXML_ENCODING_UNKNOWN ); 595 TiXmlComment commentCopy( comment ); 596 TiXmlComment commentAssign; 597 commentAssign = commentCopy; 598 XmlTest( "Copy/Assign: comment copy.", "comment", commentCopy.Value() ); 599 XmlTest( "Copy/Assign: comment assign.", "comment", commentAssign.Value() ); 600 601 TiXmlUnknown unknown; 602 unknown.Parse( "<[unknown]>", 0, TIXML_ENCODING_UNKNOWN ); 603 TiXmlUnknown unknownCopy( unknown ); 604 TiXmlUnknown unknownAssign; 605 unknownAssign.Parse( "incorrect", 0, TIXML_ENCODING_UNKNOWN ); 606 unknownAssign = unknownCopy; 607 XmlTest( "Copy/Assign: unknown copy.", "[unknown]", unknownCopy.Value() ); 608 XmlTest( "Copy/Assign: unknown assign.", "[unknown]", unknownAssign.Value() ); 609 610 TiXmlText text( "TextNode" ); 611 TiXmlText textCopy( text ); 612 TiXmlText textAssign( "incorrect" ); 613 textAssign = text; 614 XmlTest( "Copy/Assign: text copy.", "TextNode", textCopy.Value() ); 615 XmlTest( "Copy/Assign: text assign.", "TextNode", textAssign.Value() ); 616 617 TiXmlDeclaration dec; 618 dec.Parse( "<?xml version='1.0' encoding='UTF-8'?>", 0, TIXML_ENCODING_UNKNOWN ); 619 TiXmlDeclaration decCopy( dec ); 620 TiXmlDeclaration decAssign; 621 decAssign = dec; 622 623 XmlTest( "Copy/Assign: declaration copy.", "UTF-8", decCopy.Encoding() ); 624 XmlTest( "Copy/Assign: text assign.", "UTF-8", decAssign.Encoding() ); 625 626 TiXmlDocument doc; 627 elementCopy.InsertEndChild( textCopy ); 628 doc.InsertEndChild( decAssign ); 629 doc.InsertEndChild( elementCopy ); 630 doc.InsertEndChild( unknownAssign ); 631 632 TiXmlDocument docCopy( doc ); 633 TiXmlDocument docAssign; 634 docAssign = docCopy; 635 636 #ifdef TIXML_USE_STL 637 std::string original, copy, assign; 638 original << doc; 639 copy << docCopy; 640 assign << docAssign; 641 XmlTest( "Copy/Assign: document copy.", original.c_str(), copy.c_str(), true ); 642 XmlTest( "Copy/Assign: document assign.", original.c_str(), assign.c_str(), true ); 643 644 #endif 645 } 646 647 ////////////////////////////////////////////////////// 648 #ifdef TIXML_USE_STL 649 printf ("\n** Parsing, no Condense Whitespace **\n"); 650 TiXmlBase::SetCondenseWhiteSpace( false ); 651 652 istringstream parse1( "<start>This is \ntext</start>" ); 653 TiXmlElement text1( "text" ); 654 parse1 >> text1; 655 656 XmlTest ( "Condense white space OFF.", "This is \ntext", 657 text1.FirstChild()->Value(), 658 true ); 659 660 TiXmlBase::SetCondenseWhiteSpace( true ); 661 #endif 662 663 ////////////////////////////////////////////////////// 664 // GetText(); 665 { 666 const char* str = "<foo>This is text</foo>"; 667 TiXmlDocument doc; 668 doc.Parse( str ); 669 const TiXmlElement* element = doc.RootElement(); 670 671 XmlTest( "GetText() normal use.", "This is text", element->GetText() ); 672 673 str = "<foo><b>This is text</b></foo>"; 674 doc.Clear(); 675 doc.Parse( str ); 676 element = doc.RootElement(); 677 678 XmlTest( "GetText() contained element.", element->GetText() == 0, true ); 679 680 str = "<foo>This is <b>text</b></foo>"; 681 doc.Clear(); 682 TiXmlBase::SetCondenseWhiteSpace( false ); 683 doc.Parse( str ); 684 TiXmlBase::SetCondenseWhiteSpace( true ); 685 element = doc.RootElement(); 686 687 XmlTest( "GetText() partial.", "This is ", element->GetText() ); 688 } 689 690 691 ////////////////////////////////////////////////////// 692 // CDATA 693 { 694 const char* str = "<xmlElement>" 695 "<![CDATA[" 696 "I am > the rules!\n" 697 "...since I make symbolic puns" 698 "]]>" 699 "</xmlElement>"; 700 TiXmlDocument doc; 701 doc.Parse( str ); 702 //doc.Print(); 703 704 XmlTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(), 705 "I am > the rules!\n...since I make symbolic puns", 706 true ); 707 708 #ifdef TIXML_USE_STL 709 //cout << doc << '\n'; 710 711 doc.Clear(); 712 713 istringstream parse0( str ); 714 parse0 >> doc; 715 //cout << doc << '\n'; 716 717 XmlTest( "CDATA stream.", doc.FirstChildElement()->FirstChild()->Value(), 718 "I am > the rules!\n...since I make symbolic puns", 719 true ); 720 #endif 721 722 TiXmlDocument doc1 = doc; 723 //doc.Print(); 724 725 XmlTest( "CDATA copy.", doc1.FirstChildElement()->FirstChild()->Value(), 726 "I am > the rules!\n...since I make symbolic puns", 727 true ); 728 } 729 730 731 ////////////////////////////////////////////////////// 732 printf ("\n** Bug regression tests **\n"); 733 734 // InsertBeforeChild and InsertAfterChild causes crash. 735 { 736 TiXmlElement parent( "Parent" ); 737 TiXmlElement childText0( "childText0" ); 738 TiXmlElement childText1( "childText1" ); 739 TiXmlNode* childNode0 = parent.InsertEndChild( childText0 ); 740 TiXmlNode* childNode1 = parent.InsertBeforeChild( childNode0, childText1 ); 741 742 XmlTest( "Test InsertBeforeChild on empty node.", ( childNode1 == parent.FirstChild() ), true ); 743 } 744 745 { 746 // InsertBeforeChild and InsertAfterChild causes crash. 747 TiXmlElement parent( "Parent" ); 748 TiXmlElement childText0( "childText0" ); 749 TiXmlElement childText1( "childText1" ); 750 TiXmlNode* childNode0 = parent.InsertEndChild( childText0 ); 751 TiXmlNode* childNode1 = parent.InsertAfterChild( childNode0, childText1 ); 752 753 XmlTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent.LastChild() ), true ); 754 } 755 756 // Reports of missing constructors, irregular string problems. 757 { 758 // Missing constructor implementation. No test -- just compiles. 759 TiXmlText text( "Missing" ); 760 761 #ifdef TIXML_USE_STL 762 // Missing implementation: 763 TiXmlDocument doc; 764 string name = "missing"; 765 doc.LoadFile( name ); 766 767 TiXmlText textSTL( name ); 768 #else 769 // verifying some basic string functions: 770 TiXmlString a; 771 TiXmlString b( "Hello" ); 772 TiXmlString c( "ooga" ); 773 774 c = " World!"; 775 a = b; 776 a += c; 777 a = a; 778 779 XmlTest( "Basic TiXmlString test. ", "Hello World!", a.c_str() ); 780 #endif 781 } 782 783 // Long filenames crashing STL version 784 { 785 TiXmlDocument doc( "midsummerNightsDreamWithAVeryLongFilenameToConfuseTheStringHandlingRoutines.xml" ); 786 bool loadOkay = doc.LoadFile(); 787 loadOkay = true; // get rid of compiler warning. 788 // Won't pass on non-dev systems. Just a "no crash" check. 789 //XmlTest( "Long filename. ", true, loadOkay ); 790 } 791 792 { 793 // Entities not being written correctly. 794 // From Lynn Allen 795 796 const char* passages = 797 "<?xml version=\"1.0\" standalone=\"no\" ?>" 798 "<passages count=\"006\" formatversion=\"20020620\">" 799 "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'." 800 " It also has <, >, and &, as well as a fake copyright ©.\"> </psg>" 801 "</passages>"; 802 803 TiXmlDocument doc( "passages.xml" ); 804 doc.Parse( passages ); 805 TiXmlElement* psg = doc.RootElement()->FirstChildElement(); 806 const char* context = psg->Attribute( "context" ); 807 const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9."; 808 809 XmlTest( "Entity transformation: read. ", expected, context, true ); 810 811 FILE* textfile = fopen( "textfile.txt", "w" ); 812 if ( textfile ) 813 { 814 psg->Print( textfile, 0 ); 815 fclose( textfile ); 816 } 817 textfile = fopen( "textfile.txt", "r" ); 818 assert( textfile ); 819 if ( textfile ) 820 { 821 char buf[ 1024 ]; 822 fgets( buf, 1024, textfile ); 823 XmlTest( "Entity transformation: write. ", 824 "<psg context=\'Line 5 has "quotation marks" and 'apostrophe marks'." 825 " It also has <, >, and &, as well as a fake copyright \xC2\xA9.' />", 826 buf, 827 true ); 828 } 829 fclose( textfile ); 830 } 831 832 { 833 FILE* textfile = fopen( "test5.xml", "w" ); 834 if ( textfile ) 835 { 836 fputs("<?xml version='1.0'?><a.elem xmi.version='2.0'/>", textfile); 837 fclose(textfile); 838 839 TiXmlDocument doc; 840 doc.LoadFile( "test5.xml" ); 841 XmlTest( "dot in element attributes and names", doc.Error(), 0); 842 } 843 } 844 845 { 846 FILE* textfile = fopen( "test6.xml", "w" ); 847 if ( textfile ) 848 { 849 fputs("<element><Name>1.1 Start easy ignore fin thickness
</Name></element>", textfile ); 850 fclose(textfile); 851 852 TiXmlDocument doc; 853 bool result = doc.LoadFile( "test6.xml" ); 854 XmlTest( "Entity with one digit.", result, true ); 855 856 TiXmlText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText(); 857 XmlTest( "Entity with one digit.", 858 text->Value(), "1.1 Start easy ignore fin thickness\n" ); 859 } 860 } 861 862 { 863 // DOCTYPE not preserved (950171) 864 // 865 const char* doctype = 866 "<?xml version=\"1.0\" ?>" 867 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>" 868 "<!ELEMENT title (#PCDATA)>" 869 "<!ELEMENT books (title,authors)>" 870 "<element />"; 871 872 TiXmlDocument doc; 873 doc.Parse( doctype ); 874 doc.SaveFile( "test7.xml" ); 875 doc.Clear(); 876 doc.LoadFile( "test7.xml" ); 877 878 TiXmlHandle docH( &doc ); 879 TiXmlUnknown* unknown = docH.Child( 1 ).Unknown(); 880 XmlTest( "Correct value of unknown.", "!DOCTYPE PLAY SYSTEM 'play.dtd'", unknown->Value() ); 881 #ifdef TIXML_USE_STL 882 TiXmlNode* node = docH.Child( 2 ).Node(); 883 std::string str; 884 str << (*node); 885 XmlTest( "Correct streaming of unknown.", "<!ELEMENT title (#PCDATA)>", str.c_str() ); 886 #endif 887 } 888 889 { 890 // [ 791411 ] Formatting bug 891 // Comments do not stream out correctly. 892 const char* doctype = 893 "<!-- Somewhat<evil> -->"; 894 TiXmlDocument doc; 895 doc.Parse( doctype ); 896 897 TiXmlHandle docH( &doc ); 898 TiXmlComment* comment = docH.Child( 0 ).Node()->ToComment(); 899 900 XmlTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() ); 901 #ifdef TIXML_USE_STL 902 std::string str; 903 str << (*comment); 904 XmlTest( "Comment streaming.", "<!-- Somewhat<evil> -->", str.c_str() ); 905 #endif 906 } 907 908 { 909 // [ 870502 ] White space issues 910 TiXmlDocument doc; 911 TiXmlText* text; 912 TiXmlHandle docH( &doc ); 913 914 const char* doctype0 = "<element> This has leading and trailing space </element>"; 915 const char* doctype1 = "<element>This has internal space</element>"; 916 const char* doctype2 = "<element> This has leading, trailing, and internal space </element>"; 917 918 TiXmlBase::SetCondenseWhiteSpace( false ); 919 doc.Clear(); 920 doc.Parse( doctype0 ); 921 text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); 922 XmlTest( "White space kept.", " This has leading and trailing space ", text->Value() ); 923 924 doc.Clear(); 925 doc.Parse( doctype1 ); 926 text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); 927 XmlTest( "White space kept.", "This has internal space", text->Value() ); 928 929 doc.Clear(); 930 doc.Parse( doctype2 ); 931 text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); 932 XmlTest( "White space kept.", " This has leading, trailing, and internal space ", text->Value() ); 933 934 TiXmlBase::SetCondenseWhiteSpace( true ); 935 doc.Clear(); 936 doc.Parse( doctype0 ); 937 text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); 938 XmlTest( "White space condensed.", "This has leading and trailing space", text->Value() ); 939 940 doc.Clear(); 941 doc.Parse( doctype1 ); 942 text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); 943 XmlTest( "White space condensed.", "This has internal space", text->Value() ); 944 945 doc.Clear(); 946 doc.Parse( doctype2 ); 947 text = docH.FirstChildElement( "element" ).Child( 0 ).Text(); 948 XmlTest( "White space condensed.", "This has leading, trailing, and internal space", text->Value() ); 949 } 950 951 { 952 // Double attributes 953 const char* doctype = "<element attr='red' attr='blue' />"; 954 955 TiXmlDocument doc; 956 doc.Parse( doctype ); 957 958 XmlTest( "Parsing repeated attributes.", 0, (int)doc.Error() ); // not an error to tinyxml 959 XmlTest( "Parsing repeated attributes.", "blue", doc.FirstChildElement( "element" )->Attribute( "attr" ) ); 960 } 961 962 { 963 // Embedded null in stream. 964 const char* doctype = "<element att\0r='red' attr='blue' />"; 965 966 TiXmlDocument doc; 967 doc.Parse( doctype ); 968 XmlTest( "Embedded null throws error.", true, doc.Error() ); 969 970 #ifdef TIXML_USE_STL 971 istringstream strm( doctype ); 972 doc.Clear(); 973 doc.ClearError(); 974 strm >> doc; 975 XmlTest( "Embedded null throws error.", true, doc.Error() ); 976 #endif 977 } 978 979 { 980 // Legacy mode test. (This test may only pass on a western system) 981 const char* str = 982 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" 983 "<>" 984 "Cntnt" 985 "</>"; 986 987 TiXmlDocument doc; 988 doc.Parse( str ); 989 990 //doc.Print( stdout, 0 ); 991 992 TiXmlHandle docHandle( &doc ); 993 TiXmlHandle aHandle = docHandle.FirstChildElement( "" ); 994 TiXmlHandle tHandle = aHandle.Child( 0 ); 995 assert( aHandle.Element() ); 996 assert( tHandle.Text() ); 997 XmlTest( "ISO-8859-1 Parsing.", "Cntnt", tHandle.Text()->Value() ); 998 } 999 1000 { 1001 // Empty documents should return TIXML_ERROR_PARSING_EMPTY, bug 1070717 1002 const char* str = " "; 1003 TiXmlDocument doc; 1004 doc.Parse( str ); 1005 XmlTest( "Empty document error TIXML_ERROR_DOCUMENT_EMPTY", TiXmlBase::TIXML_ERROR_DOCUMENT_EMPTY, doc.ErrorId() ); 1006 } 1007 #ifndef TIXML_USE_STL 1008 { 1009 // String equality. [ 1006409 ] string operator==/!= no worky in all cases 1010 TiXmlString temp; 1011 XmlTest( "Empty tinyxml string compare equal", ( temp == "" ), true ); 1012 1013 TiXmlString foo; 1014 TiXmlString bar( "" ); 1015 XmlTest( "Empty tinyxml string compare equal", ( foo == bar ), true ); 1016 } 1017 1018 #endif 1019 { 1020 // Bug [ 1195696 ] from marlonism 1021 TiXmlBase::SetCondenseWhiteSpace(false); 1022 TiXmlDocument xml; 1023 xml.Parse("<text><break/>This hangs</text>"); 1024 XmlTest( "Test safe error return.", xml.Error(), false ); 1025 } 1026 1027 { 1028 // Bug [ 1243992 ] - another infinite loop 1029 TiXmlDocument doc; 1030 doc.SetCondenseWhiteSpace(false); 1031 doc.Parse("<p><pb></pb>test</p>"); 1032 } 1033 { 1034 // Low entities 1035 TiXmlDocument xml; 1036 xml.Parse( "<test></test>" ); 1037 const char result[] = { 0x0e, 0 }; 1038 XmlTest( "Low entities.", xml.FirstChildElement()->GetText(), result ); 1039 xml.Print(); 1040 } 1041 1042 #if defined( WIN32 ) && defined( TUNE ) 1043 QueryPerformanceCounter( (LARGE_INTEGER*) (&end) ); 1044 QueryPerformanceFrequency( (LARGE_INTEGER*) (&freq) ); 1045 printf( "Time for run: %f\n", ( double )( end-start ) / (double) freq ); 1046 #endif 1047 1048 printf ("\nPass %d, Fail %d\n", gPass, gFail); 1049 return gFail; 1050 } 1051 1052 1053