1 #if defined( _MSC_VER )
2 #if !defined( _CRT_SECURE_NO_WARNINGS )
3 #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
4 #endif
5 #endif
6
7 #include "tinyxml2.h"
8 #include <cerrno>
9 #include <cstdlib>
10 #include <cstring>
11 #include <ctime>
12
13 #if defined( _MSC_VER ) || defined (WIN32)
14 #include <crtdbg.h>
15 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
17 _CrtMemState startMemState;
18 _CrtMemState endMemState;
19 #else
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #endif
23
24 using namespace tinyxml2;
25 using namespace std;
26 int gPass = 0;
27 int gFail = 0;
28
29
XMLTest(const char * testString,const char * expected,const char * found,bool echo=true,bool extraNL=false)30 bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
31 {
32 bool pass;
33 if ( !expected && !found )
34 pass = true;
35 else if ( !expected || !found )
36 pass = false;
37 else
38 pass = !strcmp( expected, found );
39 if ( pass )
40 printf ("[pass]");
41 else
42 printf ("[fail]");
43
44 if ( !echo ) {
45 printf (" %s\n", testString);
46 }
47 else {
48 if ( extraNL ) {
49 printf( " %s\n", testString );
50 printf( "%s\n", expected );
51 printf( "%s\n", found );
52 }
53 else {
54 printf (" %s [%s][%s]\n", testString, expected, found);
55 }
56 }
57
58 if ( pass )
59 ++gPass;
60 else
61 ++gFail;
62 return pass;
63 }
64
XMLTest(const char * testString,XMLError expected,XMLError found,bool echo=true,bool extraNL=false)65 bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
66 {
67 return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
68 }
69
XMLTest(const char * testString,bool expected,bool found,bool echo=true,bool extraNL=false)70 bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
71 {
72 return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
73 }
74
XMLTest(const char * testString,T expected,T found,bool echo=true)75 template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
76 {
77 bool pass = ( expected == found );
78 if ( pass )
79 printf ("[pass]");
80 else
81 printf ("[fail]");
82
83 if ( !echo )
84 printf (" %s\n", testString);
85 else {
86 char expectedAsString[64];
87 XMLUtil::ToStr(expected, expectedAsString, sizeof(expectedAsString));
88
89 char foundAsString[64];
90 XMLUtil::ToStr(found, foundAsString, sizeof(foundAsString));
91
92 printf (" %s [%s][%s]\n", testString, expectedAsString, foundAsString );
93 }
94
95 if ( pass )
96 ++gPass;
97 else
98 ++gFail;
99 return pass;
100 }
101
102
NullLineEndings(char * p)103 void NullLineEndings( char* p )
104 {
105 while( p && *p ) {
106 if ( *p == '\n' || *p == '\r' ) {
107 *p = 0;
108 return;
109 }
110 ++p;
111 }
112 }
113
114
example_1()115 int example_1()
116 {
117 XMLDocument doc;
118 doc.LoadFile( "resources/dream.xml" );
119
120 return doc.ErrorID();
121 }
122 /** @page Example_1 Load an XML File
123 * @dontinclude ./xmltest.cpp
124 * Basic XML file loading.
125 * The basic syntax to load an XML file from
126 * disk and check for an error. (ErrorID()
127 * will return 0 for no error.)
128 * @skip example_1()
129 * @until }
130 */
131
132
example_2()133 int example_2()
134 {
135 static const char* xml = "<element/>";
136 XMLDocument doc;
137 doc.Parse( xml );
138
139 return doc.ErrorID();
140 }
141 /** @page Example_2 Parse an XML from char buffer
142 * @dontinclude ./xmltest.cpp
143 * Basic XML string parsing.
144 * The basic syntax to parse an XML for
145 * a char* and check for an error. (ErrorID()
146 * will return 0 for no error.)
147 * @skip example_2()
148 * @until }
149 */
150
151
example_3()152 int example_3()
153 {
154 static const char* xml =
155 "<?xml version=\"1.0\"?>"
156 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
157 "<PLAY>"
158 "<TITLE>A Midsummer Night's Dream</TITLE>"
159 "</PLAY>";
160
161 XMLDocument doc;
162 doc.Parse( xml );
163
164 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
165 const char* title = titleElement->GetText();
166 printf( "Name of play (1): %s\n", title );
167
168 XMLText* textNode = titleElement->FirstChild()->ToText();
169 title = textNode->Value();
170 printf( "Name of play (2): %s\n", title );
171
172 return doc.ErrorID();
173 }
174 /** @page Example_3 Get information out of XML
175 @dontinclude ./xmltest.cpp
176 In this example, we navigate a simple XML
177 file, and read some interesting text. Note
178 that this example doesn't use error
179 checking; working code should check for null
180 pointers when walking an XML tree, or use
181 XMLHandle.
182
183 (The XML is an excerpt from "dream.xml").
184
185 @skip example_3()
186 @until </PLAY>";
187
188 The structure of the XML file is:
189
190 <ul>
191 <li>(declaration)</li>
192 <li>(dtd stuff)</li>
193 <li>Element "PLAY"</li>
194 <ul>
195 <li>Element "TITLE"</li>
196 <ul>
197 <li>Text "A Midsummer Night's Dream"</li>
198 </ul>
199 </ul>
200 </ul>
201
202 For this example, we want to print out the
203 title of the play. The text of the title (what
204 we want) is child of the "TITLE" element which
205 is a child of the "PLAY" element.
206
207 We want to skip the declaration and dtd, so the
208 method FirstChildElement() is a good choice. The
209 FirstChildElement() of the Document is the "PLAY"
210 Element, the FirstChildElement() of the "PLAY" Element
211 is the "TITLE" Element.
212
213 @until ( "TITLE" );
214
215 We can then use the convenience function GetText()
216 to get the title of the play.
217
218 @until title );
219
220 Text is just another Node in the XML DOM. And in
221 fact you should be a little cautious with it, as
222 text nodes can contain elements.
223
224 @verbatim
225 Consider: A Midsummer Night's <b>Dream</b>
226 @endverbatim
227
228 It is more correct to actually query the Text Node
229 if in doubt:
230
231 @until title );
232
233 Noting that here we use FirstChild() since we are
234 looking for XMLText, not an element, and ToText()
235 is a cast from a Node to a XMLText.
236 */
237
238
example_4()239 bool example_4()
240 {
241 static const char* xml =
242 "<information>"
243 " <attributeApproach v='2' />"
244 " <textApproach>"
245 " <v>2</v>"
246 " </textApproach>"
247 "</information>";
248
249 XMLDocument doc;
250 doc.Parse( xml );
251
252 int v0 = 0;
253 int v1 = 0;
254
255 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
256 attributeApproachElement->QueryIntAttribute( "v", &v0 );
257
258 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
259 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
260
261 printf( "Both values are the same: %d and %d\n", v0, v1 );
262
263 return !doc.Error() && ( v0 == v1 );
264 }
265 /** @page Example_4 Read attributes and text information.
266 @dontinclude ./xmltest.cpp
267
268 There are fundamentally 2 ways of writing a key-value
269 pair into an XML file. (Something that's always annoyed
270 me about XML.) Either by using attributes, or by writing
271 the key name into an element and the value into
272 the text node wrapped by the element. Both approaches
273 are illustrated in this example, which shows two ways
274 to encode the value "2" into the key "v":
275
276 @skip example_4()
277 @until "</information>";
278
279 TinyXML-2 has accessors for both approaches.
280
281 When using an attribute, you navigate to the XMLElement
282 with that attribute and use the QueryIntAttribute()
283 group of methods. (Also QueryFloatAttribute(), etc.)
284
285 @skip XMLElement* attributeApproachElement
286 @until &v0 );
287
288 When using the text approach, you need to navigate
289 down one more step to the XMLElement that contains
290 the text. Note the extra FirstChildElement( "v" )
291 in the code below. The value of the text can then
292 be safely queried with the QueryIntText() group
293 of methods. (Also QueryFloatText(), etc.)
294
295 @skip XMLElement* textApproachElement
296 @until &v1 );
297 */
298
299
main(int argc,const char ** argv)300 int main( int argc, const char ** argv )
301 {
302 #if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
303 _CrtMemCheckpoint( &startMemState );
304 // Enable MS Visual C++ debug heap memory leaks dump on exit
305 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
306 {
307 int leaksOnStart = _CrtDumpMemoryLeaks();
308 XMLTest( "No leaks on start?", FALSE, leaksOnStart );
309 }
310 #endif
311
312 {
313 TIXMLASSERT( true );
314 }
315
316 if ( argc > 1 ) {
317 XMLDocument* doc = new XMLDocument();
318 clock_t startTime = clock();
319 doc->LoadFile( argv[1] );
320 clock_t loadTime = clock();
321 int errorID = doc->ErrorID();
322 delete doc; doc = 0;
323 clock_t deleteTime = clock();
324
325 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
326 if ( !errorID ) {
327 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
328 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
329 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
330 }
331 exit(0);
332 }
333
334 FILE* fp = fopen( "resources/dream.xml", "r" );
335 if ( !fp ) {
336 printf( "Error opening test file 'dream.xml'.\n"
337 "Is your working directory the same as where \n"
338 "the xmltest.cpp and dream.xml file are?\n\n"
339 #if defined( _MSC_VER )
340 "In windows Visual Studio you may need to set\n"
341 "Properties->Debugging->Working Directory to '..'\n"
342 #endif
343 );
344 exit( 1 );
345 }
346 fclose( fp );
347
348 XMLTest( "Example_1", 0, example_1() );
349 XMLTest( "Example_2", 0, example_2() );
350 XMLTest( "Example_3", 0, example_3() );
351 XMLTest( "Example_4", true, example_4() );
352
353 /* ------ Example 2: Lookup information. ---- */
354
355 {
356 static const char* test[] = { "<element />",
357 "<element></element>",
358 "<element><subelement/></element>",
359 "<element><subelement></subelement></element>",
360 "<element><subelement><subsub/></subelement></element>",
361 "<!--comment beside elements--><element><subelement></subelement></element>",
362 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
363 "<element attrib1='foo' attrib2=\"bar\" ></element>",
364 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
365 "<element>Text inside element.</element>",
366 "<element><b></b></element>",
367 "<element>Text inside and <b>bolded</b> in the element.</element>",
368 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
369 "<element>This & That.</element>",
370 "<element attrib='This<That' />",
371 0
372 };
373 for( int i=0; test[i]; ++i ) {
374 XMLDocument doc;
375 doc.Parse( test[i] );
376 XMLTest( "Element test", false, doc.Error() );
377 doc.Print();
378 printf( "----------------------------------------------\n" );
379 }
380 }
381 #if 1
382 {
383 static const char* test = "<!--hello world\n"
384 " line 2\r"
385 " line 3\r\n"
386 " line 4\n\r"
387 " line 5\r-->";
388
389 XMLDocument doc;
390 doc.Parse( test );
391 XMLTest( "Hello world declaration", false, doc.Error() );
392 doc.Print();
393 }
394
395 {
396 // This test is pre-test for the next one
397 // (where Element1 is inserted "after itself".
398 // This code didn't use to crash.
399 XMLDocument doc;
400 XMLElement* element1 = doc.NewElement("Element1");
401 XMLElement* element2 = doc.NewElement("Element2");
402 doc.InsertEndChild(element1);
403 doc.InsertEndChild(element2);
404 doc.InsertAfterChild(element2, element2);
405 doc.InsertAfterChild(element2, element2);
406 }
407
408 {
409 XMLDocument doc;
410 XMLElement* element1 = doc.NewElement("Element1");
411 XMLElement* element2 = doc.NewElement("Element2");
412 doc.InsertEndChild(element1);
413 doc.InsertEndChild(element2);
414
415 // This insertion "after itself"
416 // used to cause invalid memory access and crash
417 doc.InsertAfterChild(element1, element1);
418 doc.InsertAfterChild(element1, element1);
419 doc.InsertAfterChild(element2, element2);
420 doc.InsertAfterChild(element2, element2);
421 }
422
423 {
424 static const char* test = "<element>Text before.</element>";
425 XMLDocument doc;
426 doc.Parse( test );
427 XMLTest( "Element text before", false, doc.Error() );
428 XMLElement* root = doc.FirstChildElement();
429 XMLElement* newElement = doc.NewElement( "Subelement" );
430 root->InsertEndChild( newElement );
431 doc.Print();
432 }
433 {
434 XMLDocument* doc = new XMLDocument();
435 static const char* test = "<element><sub/></element>";
436 doc->Parse( test );
437 XMLTest( "Element with sub element", false, doc->Error() );
438 delete doc;
439 }
440 {
441 // Test: Programmatic DOM nodes insertion return values
442 XMLDocument doc;
443
444 XMLNode* first = doc.NewElement( "firstElement" );
445 XMLTest( "New element", true, first != 0 );
446 XMLNode* firstAfterInsertion = doc.InsertFirstChild( first );
447 XMLTest( "New element inserted first", true, firstAfterInsertion == first );
448
449 XMLNode* last = doc.NewElement( "lastElement" );
450 XMLTest( "New element", true, last != 0 );
451 XMLNode* lastAfterInsertion = doc.InsertEndChild( last );
452 XMLTest( "New element inserted last", true, lastAfterInsertion == last );
453
454 XMLNode* middle = doc.NewElement( "middleElement" );
455 XMLTest( "New element", true, middle != 0 );
456 XMLNode* middleAfterInsertion = doc.InsertAfterChild( first, middle );
457 XMLTest( "New element inserted middle", true, middleAfterInsertion == middle );
458 }
459 {
460 // Test: Programmatic DOM
461 // Build:
462 // <element>
463 // <!--comment-->
464 // <sub attrib="0" />
465 // <sub attrib="1" />
466 // <sub attrib="2" >& Text!</sub>
467 // <element>
468
469 XMLDocument* doc = new XMLDocument();
470 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
471
472 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
473 for( int i=0; i<3; ++i ) {
474 sub[i]->SetAttribute( "attrib", i );
475 }
476 element->InsertEndChild( sub[2] );
477
478 const int dummyInitialValue = 1000;
479 int dummyValue = dummyInitialValue;
480
481 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
482 comment->SetUserData(&dummyValue);
483 element->InsertAfterChild( comment, sub[0] );
484 element->InsertAfterChild( sub[0], sub[1] );
485 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
486 doc->Print();
487 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
488 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
489 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
490 XMLTest( "Programmatic DOM", "& Text!",
491 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
492 XMLTest("User data - pointer", true, &dummyValue == comment->GetUserData(), false);
493 XMLTest("User data - value behind pointer", dummyInitialValue, dummyValue, false);
494
495 // And now deletion:
496 element->DeleteChild( sub[2] );
497 doc->DeleteNode( comment );
498
499 element->FirstChildElement()->SetAttribute( "attrib", true );
500 element->LastChildElement()->DeleteAttribute( "attrib" );
501
502 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
503 const int defaultIntValue = 10;
504 const int replacementIntValue = 20;
505 int value1 = defaultIntValue;
506 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
507 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
508 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
509 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
510 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
511
512 doc->Print();
513
514 {
515 XMLPrinter streamer;
516 doc->Print( &streamer );
517 printf( "%s", streamer.CStr() );
518 }
519 {
520 XMLPrinter streamer( 0, true );
521 doc->Print( &streamer );
522 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
523 }
524 doc->SaveFile( "./resources/out/pretty.xml" );
525 XMLTest( "Save pretty.xml", false, doc->Error() );
526 doc->SaveFile( "./resources/out/compact.xml", true );
527 XMLTest( "Save compact.xml", false, doc->Error() );
528 delete doc;
529 }
530 {
531 // Test: Dream
532 // XML1 : 1,187,569 bytes in 31,209 allocations
533 // XML2 : 469,073 bytes in 323 allocations
534 //int newStart = gNew;
535 XMLDocument doc;
536 doc.LoadFile( "resources/dream.xml" );
537 XMLTest( "Load dream.xml", false, doc.Error() );
538
539 doc.SaveFile( "resources/out/dreamout.xml" );
540 XMLTest( "Save dreamout.xml", false, doc.Error() );
541 doc.PrintError();
542
543 XMLTest( "Dream", "xml version=\"1.0\"",
544 doc.FirstChild()->ToDeclaration()->Value() );
545 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() != 0 );
546 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
547 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
548 XMLTest( "Dream", "And Robin shall restore amends.",
549 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
550 XMLTest( "Dream", "And Robin shall restore amends.",
551 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
552
553 XMLDocument doc2;
554 doc2.LoadFile( "resources/out/dreamout.xml" );
555 XMLTest( "Load dreamout.xml", false, doc2.Error() );
556 XMLTest( "Dream-out", "xml version=\"1.0\"",
557 doc2.FirstChild()->ToDeclaration()->Value() );
558 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() != 0 );
559 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
560 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
561 XMLTest( "Dream-out", "And Robin shall restore amends.",
562 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
563
564 //gNewTotal = gNew - newStart;
565 }
566
567
568 {
569 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
570 "<passages count=\"006\" formatversion=\"20020620\">\n"
571 " <wrong error>\n"
572 "</passages>";
573
574 XMLDocument doc;
575 doc.Parse( error );
576 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
577 const char* errorStr = doc.ErrorStr();
578 XMLTest("Formatted error string",
579 "Error=XML_ERROR_PARSING_ATTRIBUTE ErrorID=7 (0x7) Line number=3: XMLElement name=wrong",
580 errorStr);
581 }
582
583 {
584 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
585
586 XMLDocument doc;
587 doc.Parse( str );
588 XMLTest( "Top level attributes", false, doc.Error() );
589
590 XMLElement* ele = doc.FirstChildElement();
591
592 int iVal;
593 XMLError result;
594 double dVal;
595
596 result = ele->QueryDoubleAttribute( "attr0", &dVal );
597 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
598 XMLTest( "Query attribute: int as double", 1, (int)dVal );
599 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
600
601 result = ele->QueryDoubleAttribute( "attr1", &dVal );
602 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
603 XMLTest( "Query attribute: double as double", 2.0, dVal );
604 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
605
606 result = ele->QueryIntAttribute( "attr1", &iVal );
607 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
608 XMLTest( "Query attribute: double as int", 2, iVal );
609
610 result = ele->QueryIntAttribute( "attr2", &iVal );
611 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
612 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
613
614 result = ele->QueryIntAttribute( "bar", &iVal );
615 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
616 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
617 }
618
619 {
620 const char* str = "<doc/>";
621
622 XMLDocument doc;
623 doc.Parse( str );
624 XMLTest( "Empty top element", false, doc.Error() );
625
626 XMLElement* ele = doc.FirstChildElement();
627
628 int iVal, iVal2;
629 double dVal, dVal2;
630
631 ele->SetAttribute( "str", "strValue" );
632 ele->SetAttribute( "int", 1 );
633 ele->SetAttribute( "double", -1.0 );
634
635 const char* answer = 0;
636 ele->QueryAttribute("str", &answer);
637 XMLTest("Query char attribute", "strValue", answer);
638
639 const char* cStr = ele->Attribute( "str" );
640 {
641 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
642 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
643 }
644 {
645 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
646 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
647 }
648
649 {
650 XMLError queryResult = ele->QueryAttribute( "int", &iVal2 );
651 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
652 }
653 {
654 XMLError queryResult = ele->QueryAttribute( "double", &dVal2 );
655 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
656 }
657
658 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
659 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
660 XMLTest( "Attribute round trip. int.", 1, iVal );
661 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
662 XMLTest( "Alternate query", true, iVal == iVal2 );
663 XMLTest( "Alternate query", true, dVal == dVal2 );
664 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
665 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
666 }
667
668 {
669 XMLDocument doc;
670 doc.LoadFile( "resources/utf8test.xml" );
671 XMLTest( "Load utf8test.xml", false, doc.Error() );
672
673 // Get the attribute "value" from the "Russian" element and check it.
674 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
675 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
676 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
677
678 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
679
680 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
681 0xd1U, 0x81U, 0xd1U, 0x81U,
682 0xd0U, 0xbaU, 0xd0U, 0xb8U,
683 0xd0U, 0xb9U, 0 };
684 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
685
686 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
687 XMLTest( "UTF-8: Browsing russian element name.",
688 russianText,
689 text->Value() );
690
691 // Now try for a round trip.
692 doc.SaveFile( "resources/out/utf8testout.xml" );
693 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
694
695 // Check the round trip.
696 bool roundTripOkay = false;
697
698 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
699 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
700
701 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
702 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
703
704 if ( saved && verify )
705 {
706 roundTripOkay = true;
707 char verifyBuf[256];
708 while ( fgets( verifyBuf, 256, verify ) )
709 {
710 char savedBuf[256];
711 fgets( savedBuf, 256, saved );
712 NullLineEndings( verifyBuf );
713 NullLineEndings( savedBuf );
714
715 if ( strcmp( verifyBuf, savedBuf ) )
716 {
717 printf( "verify:%s<\n", verifyBuf );
718 printf( "saved :%s<\n", savedBuf );
719 roundTripOkay = false;
720 break;
721 }
722 }
723 }
724 if ( saved )
725 fclose( saved );
726 if ( verify )
727 fclose( verify );
728 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
729 }
730
731 // --------GetText()-----------
732 {
733 const char* str = "<foo>This is text</foo>";
734 XMLDocument doc;
735 doc.Parse( str );
736 XMLTest( "Double whitespace", false, doc.Error() );
737 const XMLElement* element = doc.RootElement();
738
739 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
740
741 str = "<foo><b>This is text</b></foo>";
742 doc.Parse( str );
743 XMLTest( "Bold text simulation", false, doc.Error() );
744 element = doc.RootElement();
745
746 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
747 }
748
749
750 // --------SetText()-----------
751 {
752 const char* str = "<foo></foo>";
753 XMLDocument doc;
754 doc.Parse( str );
755 XMLTest( "Empty closed element", false, doc.Error() );
756 XMLElement* element = doc.RootElement();
757
758 element->SetText("darkness.");
759 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
760
761 element->SetText("blue flame.");
762 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
763
764 str = "<foo/>";
765 doc.Parse( str );
766 XMLTest( "Empty self-closed element", false, doc.Error() );
767 element = doc.RootElement();
768
769 element->SetText("The driver");
770 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
771
772 element->SetText("<b>horses</b>");
773 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
774 //doc.Print();
775
776 str = "<foo><bar>Text in nested element</bar></foo>";
777 doc.Parse( str );
778 XMLTest( "Text in nested element", false, doc.Error() );
779 element = doc.RootElement();
780
781 element->SetText("wolves");
782 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
783
784 str = "<foo/>";
785 doc.Parse( str );
786 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
787 element = doc.RootElement();
788
789 element->SetText( "str" );
790 XMLTest( "SetText types", "str", element->GetText() );
791
792 element->SetText( 1 );
793 XMLTest( "SetText types", "1", element->GetText() );
794
795 element->SetText( 1U );
796 XMLTest( "SetText types", "1", element->GetText() );
797
798 element->SetText( true );
799 XMLTest( "SetText types", "true", element->GetText() );
800
801 element->SetText( 1.5f );
802 XMLTest( "SetText types", "1.5", element->GetText() );
803
804 element->SetText( 1.5 );
805 XMLTest( "SetText types", "1.5", element->GetText() );
806 }
807
808 // ---------- Attributes ---------
809 {
810 static const int64_t BIG = -123456789012345678;
811 static const uint64_t BIG_POS = 123456789012345678;
812 XMLDocument doc;
813 XMLElement* element = doc.NewElement("element");
814 doc.InsertFirstChild(element);
815
816 {
817 element->SetAttribute("attrib", int(-100));
818 {
819 int v = 0;
820 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
821 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
822 XMLTest("Attribute: int", -100, v, true);
823 }
824 {
825 int v = 0;
826 XMLError queryResult = element->QueryAttribute("attrib", &v);
827 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
828 XMLTest("Attribute: int", -100, v, true);
829 }
830 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
831 }
832 {
833 element->SetAttribute("attrib", unsigned(100));
834 {
835 unsigned v = 0;
836 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
837 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
838 XMLTest("Attribute: unsigned", unsigned(100), v, true);
839 }
840 {
841 unsigned v = 0;
842 XMLError queryResult = element->QueryAttribute("attrib", &v);
843 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
844 XMLTest("Attribute: unsigned", unsigned(100), v, true);
845 }
846 {
847 const char* v = "failed";
848 XMLError queryResult = element->QueryStringAttribute("not-attrib", &v);
849 XMLTest("Attribute: string default", false, queryResult == XML_SUCCESS);
850 queryResult = element->QueryStringAttribute("attrib", &v);
851 XMLTest("Attribute: string", XML_SUCCESS, queryResult, true);
852 XMLTest("Attribute: string", "100", v);
853 }
854 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
855 }
856 {
857 element->SetAttribute("attrib", BIG);
858 {
859 int64_t v = 0;
860 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
861 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
862 XMLTest("Attribute: int64_t", BIG, v, true);
863 }
864 {
865 int64_t v = 0;
866 XMLError queryResult = element->QueryAttribute("attrib", &v);
867 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
868 XMLTest("Attribute: int64_t", BIG, v, true);
869 }
870 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
871 }
872 {
873 element->SetAttribute("attrib", BIG_POS);
874 {
875 uint64_t v = 0;
876 XMLError queryResult = element->QueryUnsigned64Attribute("attrib", &v);
877 XMLTest("Attribute: uint64_t", XML_SUCCESS, queryResult, true);
878 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
879 }
880 {
881 uint64_t v = 0;
882 XMLError queryResult = element->QueryAttribute("attrib", &v);
883 XMLTest("Attribute: uint64_t", (int)XML_SUCCESS, queryResult, true);
884 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
885 }
886 XMLTest("Attribute: uint64_t", BIG_POS, element->Unsigned64Attribute("attrib"), true);
887 }
888 {
889 element->SetAttribute("attrib", true);
890 {
891 bool v = false;
892 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
893 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
894 XMLTest("Attribute: bool", true, v, true);
895 }
896 {
897 bool v = false;
898 XMLError queryResult = element->QueryAttribute("attrib", &v);
899 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
900 XMLTest("Attribute: bool", true, v, true);
901 }
902 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
903 }
904 {
905 element->SetAttribute("attrib", true);
906 const char* result = element->Attribute("attrib");
907 XMLTest("Bool true is 'true'", "true", result);
908
909 XMLUtil::SetBoolSerialization("1", "0");
910 element->SetAttribute("attrib", true);
911 result = element->Attribute("attrib");
912 XMLTest("Bool true is '1'", "1", result);
913
914 XMLUtil::SetBoolSerialization(0, 0);
915 }
916 {
917 element->SetAttribute("attrib", 100.0);
918 {
919 double v = 0;
920 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
921 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
922 XMLTest("Attribute: double", 100.0, v, true);
923 }
924 {
925 double v = 0;
926 XMLError queryResult = element->QueryAttribute("attrib", &v);
927 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
928 XMLTest("Attribute: double", 100.0, v, true);
929 }
930 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
931 }
932 {
933 element->SetAttribute("attrib", 100.0f);
934 {
935 float v = 0;
936 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
937 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
938 XMLTest("Attribute: float", 100.0f, v, true);
939 }
940 {
941 float v = 0;
942 XMLError queryResult = element->QueryAttribute("attrib", &v);
943 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
944 XMLTest("Attribute: float", 100.0f, v, true);
945 }
946 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
947 }
948 {
949 element->SetText(BIG);
950 int64_t v = 0;
951 XMLError queryResult = element->QueryInt64Text(&v);
952 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
953 XMLTest("Element: int64_t", BIG, v, true);
954 }
955 {
956 element->SetText(BIG_POS);
957 uint64_t v = 0;
958 XMLError queryResult = element->QueryUnsigned64Text(&v);
959 XMLTest("Element: uint64_t", XML_SUCCESS, queryResult, true);
960 XMLTest("Element: uint64_t", BIG_POS, v, true);
961 }
962 }
963
964 // ---------- XMLPrinter stream mode ------
965 {
966 {
967 FILE* printerfp = fopen("resources/out/printer.xml", "w");
968 XMLTest("Open printer.xml", true, printerfp != 0);
969 XMLPrinter printer(printerfp);
970 printer.OpenElement("foo");
971 printer.PushAttribute("attrib-text", "text");
972 printer.PushAttribute("attrib-int", int(1));
973 printer.PushAttribute("attrib-unsigned", unsigned(2));
974 printer.PushAttribute("attrib-int64", int64_t(3));
975 printer.PushAttribute("attrib-uint64", uint64_t(37));
976 printer.PushAttribute("attrib-bool", true);
977 printer.PushAttribute("attrib-double", 4.0);
978 printer.CloseElement();
979 fclose(printerfp);
980 }
981 {
982 XMLDocument doc;
983 doc.LoadFile("resources/out/printer.xml");
984 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
985
986 const XMLDocument& cdoc = doc;
987
988 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
989 XMLTest("attrib-text", "text", attrib->Value(), true);
990 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
991 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
992 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
993 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
994 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
995 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
996 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-uint64");
997 XMLTest("attrib-uint64", uint64_t(37), attrib->Unsigned64Value(), true);
998 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
999 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
1000 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
1001 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
1002 }
1003 // Add API_testcatse :PushDeclaration();PushText();PushComment()
1004 {
1005 FILE* fp1 = fopen("resources/out/printer_1.xml", "w");
1006 XMLPrinter printer(fp1);
1007
1008 printer.PushDeclaration("version = '1.0' enconding = 'utf-8'");
1009
1010 printer.OpenElement("foo");
1011 printer.PushAttribute("attrib-text", "text");
1012
1013 printer.OpenElement("text");
1014 printer.PushText("Tinyxml2");
1015 printer.CloseElement();
1016
1017 printer.OpenElement("int");
1018 printer.PushText(int(11));
1019 printer.CloseElement();
1020
1021 printer.OpenElement("unsigned");
1022 printer.PushText(unsigned(12));
1023 printer.CloseElement();
1024
1025 printer.OpenElement("int64_t");
1026 printer.PushText(int64_t(13));
1027 printer.CloseElement();
1028
1029 printer.OpenElement("uint64_t");
1030 printer.PushText(uint64_t(14));
1031 printer.CloseElement();
1032
1033 printer.OpenElement("bool");
1034 printer.PushText(true);
1035 printer.CloseElement();
1036
1037 printer.OpenElement("float");
1038 printer.PushText("1.56");
1039 printer.CloseElement();
1040
1041 printer.OpenElement("double");
1042 printer.PushText("12.12");
1043 printer.CloseElement();
1044
1045 printer.OpenElement("comment");
1046 printer.PushComment("this is Tinyxml2");
1047 printer.CloseElement();
1048
1049 printer.CloseElement();
1050 fclose(fp1);
1051 }
1052 {
1053 XMLDocument doc;
1054 doc.LoadFile("resources/out/printer_1.xml");
1055 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
1056
1057 const XMLDocument& cdoc = doc;
1058
1059 const XMLElement* root = cdoc.FirstChildElement("foo");
1060
1061 const char* text_value;
1062 text_value = root->FirstChildElement("text")->GetText();
1063 XMLTest("PushText( const char* text, bool cdata=false ) test", "Tinyxml2", text_value);
1064
1065 int int_value;
1066 int_value = root->FirstChildElement("int")->IntText();
1067 XMLTest("PushText( int value ) test", 11, int_value);
1068
1069 unsigned unsigned_value;
1070 unsigned_value = root->FirstChildElement("unsigned")->UnsignedText();
1071 XMLTest("PushText( unsigned value ) test", (unsigned)12, unsigned_value);
1072
1073 int64_t int64_t_value;
1074 int64_t_value = root->FirstChildElement("int64_t")->Int64Text();
1075 XMLTest("PushText( int64_t value ) test", (int64_t) 13, int64_t_value);
1076
1077 uint64_t uint64_t_value;
1078 uint64_t_value = root->FirstChildElement("uint64_t")->Unsigned64Text();
1079 XMLTest("PushText( uint64_t value ) test", (uint64_t) 14, uint64_t_value);
1080
1081 float float_value;
1082 float_value = root->FirstChildElement("float")->FloatText();
1083 XMLTest("PushText( float value ) test", 1.56f, float_value);
1084
1085 double double_value;
1086 double_value = root->FirstChildElement("double")->DoubleText();
1087 XMLTest("PushText( double value ) test", 12.12, double_value);
1088
1089 bool bool_value;
1090 bool_value = root->FirstChildElement("bool")->BoolText();
1091 XMLTest("PushText( bool value ) test", true, bool_value);
1092
1093 const XMLComment* comment = root->FirstChildElement("comment")->FirstChild()->ToComment();
1094 const char* comment_value = comment->Value();
1095 XMLTest("PushComment() test", "this is Tinyxml2", comment_value);
1096
1097 const XMLDeclaration* declaration = cdoc.FirstChild()->ToDeclaration();
1098 const char* declaration_value = declaration->Value();
1099 XMLTest("PushDeclaration() test", "version = '1.0' enconding = 'utf-8'", declaration_value);
1100 }
1101 }
1102
1103
1104 // ---------- CDATA ---------------
1105 {
1106 const char* str = "<xmlElement>"
1107 "<![CDATA["
1108 "I am > the rules!\n"
1109 "...since I make symbolic puns"
1110 "]]>"
1111 "</xmlElement>";
1112 XMLDocument doc;
1113 doc.Parse( str );
1114 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
1115 doc.Print();
1116
1117 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
1118 doc.FirstChildElement()->FirstChild()->Value(),
1119 false );
1120 }
1121
1122 // ----------- CDATA -------------
1123 {
1124 const char* str = "<xmlElement>"
1125 "<![CDATA["
1126 "<b>I am > the rules!</b>\n"
1127 "...since I make symbolic puns"
1128 "]]>"
1129 "</xmlElement>";
1130 XMLDocument doc;
1131 doc.Parse( str );
1132 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
1133 doc.Print();
1134
1135 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
1136 "<b>I am > the rules!</b>\n...since I make symbolic puns",
1137 doc.FirstChildElement()->FirstChild()->Value(),
1138 false );
1139 }
1140
1141 // InsertAfterChild causes crash.
1142 {
1143 // InsertBeforeChild and InsertAfterChild causes crash.
1144 XMLDocument doc;
1145 XMLElement* parent = doc.NewElement( "Parent" );
1146 doc.InsertFirstChild( parent );
1147
1148 XMLElement* childText0 = doc.NewElement( "childText0" );
1149 XMLElement* childText1 = doc.NewElement( "childText1" );
1150
1151 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
1152 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
1153 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
1154 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
1155
1156 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
1157 }
1158
1159 {
1160 // Entities not being written correctly.
1161 // From Lynn Allen
1162
1163 const char* passages =
1164 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1165 "<passages count=\"006\" formatversion=\"20020620\">"
1166 "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'."
1167 " It also has <, >, and &, as well as a fake copyright ©.\"> </psg>"
1168 "</passages>";
1169
1170 XMLDocument doc;
1171 doc.Parse( passages );
1172 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
1173 XMLElement* psg = doc.RootElement()->FirstChildElement();
1174 const char* context = psg->Attribute( "context" );
1175 const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9.";
1176
1177 XMLTest( "Entity transformation: read. ", expected, context, true );
1178
1179 const char* textFilePath = "resources/out/textfile.txt";
1180 FILE* textfile = fopen( textFilePath, "w" );
1181 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
1182 if ( textfile )
1183 {
1184 XMLPrinter streamer( textfile );
1185 bool acceptResult = psg->Accept( &streamer );
1186 fclose( textfile );
1187 XMLTest( "Entity transformation: Accept", true, acceptResult );
1188 }
1189
1190 textfile = fopen( textFilePath, "r" );
1191 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
1192 if ( textfile )
1193 {
1194 char buf[ 1024 ];
1195 fgets( buf, 1024, textfile );
1196 XMLTest( "Entity transformation: write. ",
1197 "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'."
1198 " It also has <, >, and &, as well as a fake copyright \xC2\xA9.\"/>\n",
1199 buf, false );
1200 fclose( textfile );
1201 }
1202 }
1203
1204 {
1205 // Suppress entities.
1206 const char* passages =
1207 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1208 "<passages count=\"006\" formatversion=\"20020620\">"
1209 "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'.\">Crazy &ttk;</psg>"
1210 "</passages>";
1211
1212 XMLDocument doc( false );
1213 doc.Parse( passages );
1214 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
1215
1216 XMLTest( "No entity parsing.",
1217 "Line 5 has "quotation marks" and 'apostrophe marks'.",
1218 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1219 XMLTest( "No entity parsing.", "Crazy &ttk;",
1220 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
1221 doc.Print();
1222 }
1223
1224 {
1225 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
1226
1227 XMLDocument doc;
1228 doc.Parse( test );
1229 XMLTest( "dot in names", false, doc.Error() );
1230 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1231 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
1232 }
1233
1234 {
1235 const char* test = "<element><Name>1.1 Start easy ignore fin thickness
</Name></element>";
1236
1237 XMLDocument doc;
1238 doc.Parse( test );
1239 XMLTest( "fin thickness", false, doc.Error() );
1240
1241 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1242 XMLTest( "Entity with one digit.",
1243 "1.1 Start easy ignore fin thickness\n", text->Value(),
1244 false );
1245 }
1246
1247 {
1248 // DOCTYPE not preserved (950171)
1249 //
1250 const char* doctype =
1251 "<?xml version=\"1.0\" ?>"
1252 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1253 "<!ELEMENT title (#PCDATA)>"
1254 "<!ELEMENT books (title,authors)>"
1255 "<element />";
1256
1257 XMLDocument doc;
1258 doc.Parse( doctype );
1259 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
1260 doc.SaveFile( "resources/out/test7.xml" );
1261 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
1262 doc.DeleteChild( doc.RootElement() );
1263 doc.LoadFile( "resources/out/test7.xml" );
1264 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
1265 doc.Print();
1266
1267 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1268 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1269
1270 }
1271
1272 {
1273 // Comments do not stream out correctly.
1274 const char* doctype =
1275 "<!-- Somewhat<evil> -->";
1276 XMLDocument doc;
1277 doc.Parse( doctype );
1278 XMLTest( "Comment somewhat evil", false, doc.Error() );
1279
1280 XMLComment* comment = doc.FirstChild()->ToComment();
1281
1282 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1283 }
1284 {
1285 // Double attributes
1286 const char* doctype = "<element attr='red' attr='blue' />";
1287
1288 XMLDocument doc;
1289 doc.Parse( doctype );
1290
1291 XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues)
1292 doc.PrintError();
1293 }
1294
1295 {
1296 // Embedded null in stream.
1297 const char* doctype = "<element att\0r='red' attr='blue' />";
1298
1299 XMLDocument doc;
1300 doc.Parse( doctype );
1301 XMLTest( "Embedded null throws error.", true, doc.Error() );
1302 }
1303
1304 {
1305 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1306 const char* str = "";
1307 XMLDocument doc;
1308 doc.Parse( str );
1309 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1310
1311 // But be sure there is an error string!
1312 const char* errorStr = doc.ErrorStr();
1313 XMLTest("Error string should be set",
1314 "Error=XML_ERROR_EMPTY_DOCUMENT ErrorID=13 (0xd) Line number=0",
1315 errorStr);
1316 }
1317
1318 {
1319 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1320 const char* str = " ";
1321 XMLDocument doc;
1322 doc.Parse( str );
1323 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1324 }
1325
1326 {
1327 // Low entities
1328 XMLDocument doc;
1329 doc.Parse( "<test></test>" );
1330 XMLTest( "Hex values", false, doc.Error() );
1331 const char result[] = { 0x0e, 0 };
1332 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
1333 doc.Print();
1334 }
1335
1336 {
1337 // Attribute values with trailing quotes not handled correctly
1338 XMLDocument doc;
1339 doc.Parse( "<foo attribute=bar\" />" );
1340 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
1341 }
1342
1343 {
1344 // [ 1663758 ] Failure to report error on bad XML
1345 XMLDocument xml;
1346 xml.Parse("<x>");
1347 XMLTest("Missing end tag at end of input", true, xml.Error());
1348 xml.Parse("<x> ");
1349 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
1350 xml.Parse("<x></y>");
1351 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
1352 }
1353
1354
1355 {
1356 // [ 1475201 ] TinyXML parses entities in comments
1357 XMLDocument xml;
1358 xml.Parse("<!-- declarations for <head> & <body> -->"
1359 "<!-- far & away -->" );
1360 XMLTest( "Declarations for head and body", false, xml.Error() );
1361
1362 XMLNode* e0 = xml.FirstChild();
1363 XMLNode* e1 = e0->NextSibling();
1364 XMLComment* c0 = e0->ToComment();
1365 XMLComment* c1 = e1->ToComment();
1366
1367 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1368 XMLTest( "Comments ignore entities.", " far & away ", c1->Value(), true );
1369 }
1370
1371 {
1372 XMLDocument xml;
1373 xml.Parse( "<Parent>"
1374 "<child1 att=''/>"
1375 "<!-- With this comment, child2 will not be parsed! -->"
1376 "<child2 att=''/>"
1377 "</Parent>" );
1378 XMLTest( "Comments iteration", false, xml.Error() );
1379 xml.Print();
1380
1381 int count = 0;
1382
1383 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1384 ele;
1385 ele = ele->NextSibling() )
1386 {
1387 ++count;
1388 }
1389
1390 XMLTest( "Comments iterate correctly.", 3, count );
1391 }
1392
1393 {
1394 // trying to repro [1874301]. If it doesn't go into an infinite loop, all is well.
1395 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1396 buf[60] = 239;
1397 buf[61] = 0;
1398
1399 XMLDocument doc;
1400 doc.Parse( (const char*)buf);
1401 XMLTest( "Broken CDATA", true, doc.Error() );
1402 }
1403
1404
1405 {
1406 // bug 1827248 Error while parsing a little bit malformed file
1407 // Actually not malformed - should work.
1408 XMLDocument xml;
1409 xml.Parse( "<attributelist> </attributelist >" );
1410 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1411 }
1412
1413 {
1414 // This one must not result in an infinite loop
1415 XMLDocument xml;
1416 xml.Parse( "<infinite>loop" );
1417 XMLTest( "No closing element", true, xml.Error() );
1418 XMLTest( "Infinite loop test.", true, true );
1419 }
1420 #endif
1421 {
1422 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1423 XMLDocument doc;
1424 doc.Parse( pub );
1425 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
1426
1427 XMLDocument clone;
1428 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1429 XMLNode* copy = node->ShallowClone( &clone );
1430 clone.InsertEndChild( copy );
1431 }
1432
1433 clone.Print();
1434
1435 int count=0;
1436 const XMLNode* a=clone.FirstChild();
1437 const XMLNode* b=doc.FirstChild();
1438 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1439 ++count;
1440 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1441 }
1442 XMLTest( "Clone and Equal", 4, count );
1443 }
1444
1445 {
1446 // Deep Cloning of root element.
1447 XMLDocument doc2;
1448 XMLPrinter printer1;
1449 {
1450 // Make sure doc1 is deleted before we test doc2
1451 const char* xml =
1452 "<root>"
1453 " <child1 foo='bar'/>"
1454 " <!-- comment thing -->"
1455 " <child2 val='1'>Text</child2>"
1456 "</root>";
1457 XMLDocument doc;
1458 doc.Parse(xml);
1459 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
1460
1461 doc.Print(&printer1);
1462 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1463 doc2.InsertFirstChild(root);
1464 }
1465 XMLPrinter printer2;
1466 doc2.Print(&printer2);
1467
1468 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1469 }
1470
1471 {
1472 // Deep Cloning of sub element.
1473 XMLDocument doc2;
1474 XMLPrinter printer1;
1475 {
1476 // Make sure doc1 is deleted before we test doc2
1477 const char* xml =
1478 "<?xml version ='1.0'?>"
1479 "<root>"
1480 " <child1 foo='bar'/>"
1481 " <!-- comment thing -->"
1482 " <child2 val='1'>Text</child2>"
1483 "</root>";
1484 XMLDocument doc;
1485 doc.Parse(xml);
1486 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
1487
1488 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1489 bool acceptResult = subElement->Accept(&printer1);
1490 XMLTest( "Accept before deep cloning", true, acceptResult );
1491
1492 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1493 doc2.InsertFirstChild(clonedSubElement);
1494 }
1495 XMLPrinter printer2;
1496 doc2.Print(&printer2);
1497
1498 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1499 }
1500
1501 {
1502 // Deep cloning of document.
1503 XMLDocument doc2;
1504 XMLPrinter printer1;
1505 {
1506 // Make sure doc1 is deleted before we test doc2
1507 const char* xml =
1508 "<?xml version ='1.0'?>"
1509 "<!-- Top level comment. -->"
1510 "<root>"
1511 " <child1 foo='bar'/>"
1512 " <!-- comment thing -->"
1513 " <child2 val='1'>Text</child2>"
1514 "</root>";
1515 XMLDocument doc;
1516 doc.Parse(xml);
1517 XMLTest( "Parse before deep cloning document", false, doc.Error() );
1518 doc.Print(&printer1);
1519
1520 doc.DeepCopy(&doc2);
1521 }
1522 XMLPrinter printer2;
1523 doc2.Print(&printer2);
1524
1525 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1526 }
1527
1528
1529 {
1530 // This shouldn't crash.
1531 XMLDocument doc;
1532 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
1533 {
1534 doc.PrintError();
1535 }
1536 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1537 }
1538
1539 {
1540 // Attribute ordering.
1541 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1542 XMLDocument doc;
1543 doc.Parse( xml );
1544 XMLTest( "Parse for attribute ordering", false, doc.Error() );
1545 XMLElement* ele = doc.FirstChildElement();
1546
1547 const XMLAttribute* a = ele->FirstAttribute();
1548 XMLTest( "Attribute order", "1", a->Value() );
1549 a = a->Next();
1550 XMLTest( "Attribute order", "2", a->Value() );
1551 a = a->Next();
1552 XMLTest( "Attribute order", "3", a->Value() );
1553 XMLTest( "Attribute order", "attrib3", a->Name() );
1554
1555 ele->DeleteAttribute( "attrib2" );
1556 a = ele->FirstAttribute();
1557 XMLTest( "Attribute order", "1", a->Value() );
1558 a = a->Next();
1559 XMLTest( "Attribute order", "3", a->Value() );
1560
1561 ele->DeleteAttribute( "attrib1" );
1562 ele->DeleteAttribute( "attrib3" );
1563 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
1564 }
1565
1566 {
1567 // Make sure an attribute with a space in it succeeds.
1568 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1569 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1570 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1571 XMLDocument doc0;
1572 doc0.Parse( xml0 );
1573 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
1574 XMLDocument doc1;
1575 doc1.Parse( xml1 );
1576 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
1577 XMLDocument doc2;
1578 doc2.Parse( xml2 );
1579 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
1580
1581 XMLElement* ele = 0;
1582 ele = doc0.FirstChildElement();
1583 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1584 ele = doc1.FirstChildElement();
1585 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1586 ele = doc2.FirstChildElement();
1587 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
1588 }
1589
1590 {
1591 // Make sure we don't go into an infinite loop.
1592 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1593 XMLDocument doc;
1594 doc.Parse( xml );
1595 XMLTest( "Parse two elements with attribute", false, doc.Error() );
1596 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1597 XMLElement* ele1 = ele0->NextSiblingElement();
1598 bool equal = ele0->ShallowEqual( ele1 );
1599
1600 XMLTest( "Infinite loop in shallow equal.", true, equal );
1601 }
1602
1603 // -------- Handles ------------
1604 {
1605 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1606 XMLDocument doc;
1607 doc.Parse( xml );
1608 XMLTest( "Handle, parse element with attribute and nested element", false, doc.Error() );
1609
1610 {
1611 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1612 XMLTest( "Handle, non-const, element is found", true, ele != 0 );
1613 XMLTest( "Handle, non-const, element name matches", "sub", ele->Value() );
1614 }
1615
1616 {
1617 XMLHandle docH( doc );
1618 XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1619 XMLTest( "Handle, non-const, element not found", true, ele == 0 );
1620 }
1621
1622 {
1623 const XMLElement* ele = XMLConstHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1624 XMLTest( "Handle, const, element is found", true, ele != 0 );
1625 XMLTest( "Handle, const, element name matches", "sub", ele->Value() );
1626 }
1627
1628 {
1629 XMLConstHandle docH( doc );
1630 const XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1631 XMLTest( "Handle, const, element not found", true, ele == 0 );
1632 }
1633 }
1634 {
1635 // Default Declaration & BOM
1636 XMLDocument doc;
1637 doc.InsertEndChild( doc.NewDeclaration() );
1638 doc.SetBOM( true );
1639
1640 XMLPrinter printer;
1641 doc.Print( &printer );
1642
1643 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1644 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1645 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
1646 }
1647 {
1648 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1649 XMLDocument doc;
1650 doc.Parse( xml );
1651 XMLTest( "Ill formed XML", true, doc.Error() );
1652 }
1653
1654 {
1655 //API:IntText(),UnsignedText(),Int64Text(),DoubleText(),BoolText() and FloatText() test
1656 const char* xml = "<point> <IntText>-24</IntText> <UnsignedText>42</UnsignedText> \
1657 <Int64Text>38</Int64Text> <BoolText>true</BoolText> <DoubleText>2.35</DoubleText> </point>";
1658 XMLDocument doc;
1659 doc.Parse(xml);
1660
1661 const XMLElement* pointElement = doc.RootElement();
1662 int test1 = pointElement->FirstChildElement("IntText")->IntText();
1663 XMLTest("IntText() test", -24, test1);
1664
1665 unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
1666 XMLTest("UnsignedText() test", static_cast<unsigned>(42), test2);
1667
1668 int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
1669 XMLTest("Int64Text() test", static_cast<int64_t>(38), test3);
1670
1671 double test4 = pointElement->FirstChildElement("DoubleText")->DoubleText();
1672 XMLTest("DoubleText() test", 2.35, test4);
1673
1674 float test5 = pointElement->FirstChildElement("DoubleText")->FloatText();
1675 XMLTest("FloatText()) test", 2.35f, test5);
1676
1677 bool test6 = pointElement->FirstChildElement("BoolText")->BoolText();
1678 XMLTest("FloatText()) test", true, test6);
1679 }
1680
1681 {
1682 // hex value test
1683 const char* xml = "<point> <IntText> 0x2020</IntText> <UnsignedText>0X2020</UnsignedText> \
1684 <Int64Text> 0x1234</Int64Text></point>";
1685 XMLDocument doc;
1686 doc.Parse(xml);
1687
1688 const XMLElement* pointElement = doc.RootElement();
1689 int test1 = pointElement->FirstChildElement("IntText")->IntText();
1690 XMLTest("IntText() hex value test", 0x2020, test1);
1691
1692 unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
1693 XMLTest("UnsignedText() hex value test", static_cast<unsigned>(0x2020), test2);
1694
1695 int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
1696 XMLTest("Int64Text() hex value test", static_cast<int64_t>(0x1234), test3);
1697 }
1698
1699 {
1700 //API:ShallowEqual() test
1701 const char* xml = "<playlist id = 'playlist'>"
1702 "<property name = 'track_name'>voice</property>"
1703 "</playlist>";
1704 XMLDocument doc;
1705 doc.Parse( xml );
1706 const XMLNode* PlaylistNode = doc.RootElement();
1707 const XMLNode* PropertyNode = PlaylistNode->FirstChildElement();
1708 bool result;
1709 result = PlaylistNode->ShallowEqual(PropertyNode);
1710 XMLTest("ShallowEqual() test",false,result);
1711 result = PlaylistNode->ShallowEqual(PlaylistNode);
1712 XMLTest("ShallowEqual() test",true,result);
1713 }
1714
1715 {
1716 //API: previousSiblingElement() and NextSiblingElement() test
1717 const char* xml = "<playlist id = 'playlist'>"
1718 "<property name = 'track_name'>voice</property>"
1719 "<entry out = '946' producer = '2_playlist1' in = '0'/>"
1720 "<blank length = '1'/>"
1721 "</playlist>";
1722 XMLDocument doc;
1723 doc.Parse( xml );
1724 XMLElement* ElementPlaylist = doc.FirstChildElement("playlist");
1725 XMLTest("previousSiblingElement() test",true,ElementPlaylist != 0);
1726 const XMLElement* pre = ElementPlaylist->PreviousSiblingElement();
1727 XMLTest("previousSiblingElement() test",true,pre == 0);
1728 const XMLElement* ElementBlank = ElementPlaylist->FirstChildElement("entry")->NextSiblingElement("blank");
1729 XMLTest("NextSiblingElement() test",true,ElementBlank != 0);
1730 const XMLElement* next = ElementBlank->NextSiblingElement();
1731 XMLTest("NextSiblingElement() test",true,next == 0);
1732 const XMLElement* ElementEntry = ElementBlank->PreviousSiblingElement("entry");
1733 XMLTest("PreviousSiblingElement test",true,ElementEntry != 0);
1734 }
1735
1736 // QueryXYZText
1737 {
1738 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1739 XMLDocument doc;
1740 doc.Parse( xml );
1741 XMLTest( "Parse points", false, doc.Error() );
1742
1743 const XMLElement* pointElement = doc.RootElement();
1744
1745 {
1746 int intValue = 0;
1747 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1748 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1749 XMLTest( "QueryIntText", 1, intValue, false );
1750 }
1751
1752 {
1753 unsigned unsignedValue = 0;
1754 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1755 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1756 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1757 }
1758
1759 {
1760 float floatValue = 0;
1761 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1762 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1763 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1764 }
1765
1766 {
1767 double doubleValue = 0;
1768 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1769 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1770 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1771 }
1772
1773 {
1774 bool boolValue = false;
1775 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1776 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1777 XMLTest( "QueryBoolText", true, boolValue, false );
1778 }
1779 }
1780
1781 {
1782 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1783 XMLDocument doc;
1784 doc.Parse( xml );
1785 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
1786 }
1787
1788 {
1789 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1790 XMLDocument doc;
1791 doc.Parse( xml );
1792 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
1793 }
1794
1795 {
1796 const char* xml = "<3lement></3lement>";
1797 XMLDocument doc;
1798 doc.Parse( xml );
1799 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
1800 }
1801
1802 {
1803 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1804 XMLDocument doc;
1805 doc.Parse( xml, 10 );
1806 XMLTest( "Set length of incoming data", false, doc.Error() );
1807 }
1808
1809 {
1810 XMLDocument doc;
1811 XMLTest( "Document is initially empty", true, doc.NoChildren() );
1812 doc.Clear();
1813 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
1814 doc.LoadFile( "resources/dream.xml" );
1815 XMLTest( "Load dream.xml", false, doc.Error() );
1816 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
1817 doc.Clear();
1818 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
1819 }
1820
1821 {
1822 XMLDocument doc;
1823 XMLTest( "No error initially", false, doc.Error() );
1824 XMLError error = doc.Parse( "This is not XML" );
1825 XMLTest( "Error after invalid XML", true, doc.Error() );
1826 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1827 doc.Clear();
1828 XMLTest( "No error after Clear()", false, doc.Error() );
1829 }
1830
1831 // ----------- Whitespace ------------
1832 {
1833 const char* xml = "<element>"
1834 "<a> This \nis ' text ' </a>"
1835 "<b> This is ' text ' \n</b>"
1836 "<c>This is ' \n\n text '</c>"
1837 "</element>";
1838 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1839 doc.Parse( xml );
1840 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
1841
1842 const XMLElement* element = doc.FirstChildElement();
1843 for( const XMLElement* parent = element->FirstChildElement();
1844 parent;
1845 parent = parent->NextSiblingElement() )
1846 {
1847 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1848 }
1849 }
1850
1851 #if 0
1852 {
1853 // Passes if assert doesn't fire.
1854 XMLDocument xmlDoc;
1855
1856 xmlDoc.NewDeclaration();
1857 xmlDoc.NewComment("Configuration file");
1858
1859 XMLElement *root = xmlDoc.NewElement("settings");
1860 root->SetAttribute("version", 2);
1861 }
1862 #endif
1863
1864 {
1865 const char* xml = "<element> </element>";
1866 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1867 doc.Parse( xml );
1868 XMLTest( "Parse with all whitespaces", false, doc.Error() );
1869 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1870 }
1871
1872 // ----------- Preserve Whitespace ------------
1873 {
1874 const char* xml = "<element>This is ' \n\n text '</element>";
1875 XMLDocument doc(true, PRESERVE_WHITESPACE);
1876 doc.Parse(xml);
1877 XMLTest("Parse with whitespace preserved", false, doc.Error());
1878 XMLTest("Whitespace preserved", "This is ' \n\n text '", doc.FirstChildElement()->GetText());
1879 }
1880
1881 {
1882 const char* xml = "<element> This \nis ' text ' </element>";
1883 XMLDocument doc(true, PRESERVE_WHITESPACE);
1884 doc.Parse(xml);
1885 XMLTest("Parse with whitespace preserved", false, doc.Error());
1886 XMLTest("Whitespace preserved", " This \nis ' text ' ", doc.FirstChildElement()->GetText());
1887 }
1888
1889 {
1890 const char* xml = "<element> \n This is ' text ' \n</element>";
1891 XMLDocument doc(true, PRESERVE_WHITESPACE);
1892 doc.Parse(xml);
1893 XMLTest("Parse with whitespace preserved", false, doc.Error());
1894 XMLTest("Whitespace preserved", " \n This is ' text ' \n", doc.FirstChildElement()->GetText());
1895 }
1896
1897 // Following cases are for text that is all whitespace which are not preserved intentionally
1898 {
1899 const char* xml = "<element> </element>";
1900 XMLDocument doc(true, PRESERVE_WHITESPACE);
1901 doc.Parse(xml);
1902 XMLTest("Parse with whitespace preserved", false, doc.Error());
1903 XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
1904 }
1905
1906 {
1907 const char* xml = "<element> </element>";
1908 XMLDocument doc(true, PRESERVE_WHITESPACE);
1909 doc.Parse(xml);
1910 XMLTest("Parse with whitespace preserved", false, doc.Error());
1911 XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
1912 }
1913
1914 {
1915 const char* xml = "<element>\n\n</element>";
1916 XMLDocument doc(true, PRESERVE_WHITESPACE);
1917 doc.Parse(xml);
1918 XMLTest("Parse with whitespace preserved", false, doc.Error());
1919 XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
1920 }
1921
1922 {
1923 const char* xml = "<element> \n</element>";
1924 XMLDocument doc(true, PRESERVE_WHITESPACE);
1925 doc.Parse(xml);
1926 XMLTest("Parse with whitespace preserved", false, doc.Error());
1927 XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
1928 }
1929
1930 {
1931 const char* xml = "<element> \n \n </element>";
1932 XMLDocument doc(true, PRESERVE_WHITESPACE);
1933 doc.Parse(xml);
1934 XMLTest("Parse with whitespace preserved", false, doc.Error());
1935 XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
1936 }
1937
1938 // ----------- Pedantic Whitespace ------------
1939 {
1940 const char* xml = "<element>This is ' \n\n text '</element>";
1941 XMLDocument doc(true, PEDANTIC_WHITESPACE);
1942 doc.Parse(xml);
1943 XMLTest("Parse with pedantic whitespace", false, doc.Error());
1944 XMLTest("Pedantic whitespace", "This is ' \n\n text '", doc.FirstChildElement()->GetText());
1945 }
1946
1947 {
1948 const char* xml = "<element> This \nis ' text ' </element>";
1949 XMLDocument doc(true, PEDANTIC_WHITESPACE);
1950 doc.Parse(xml);
1951 XMLTest("Parse with pedantic whitespace", false, doc.Error());
1952 XMLTest("Pedantic whitespace", " This \nis ' text ' ", doc.FirstChildElement()->GetText());
1953 }
1954
1955 {
1956 const char* xml = "<element> \n This is ' text ' \n</element>";
1957 XMLDocument doc(true, PEDANTIC_WHITESPACE);
1958 doc.Parse(xml);
1959 XMLTest("Parse with pedantic whitespace", false, doc.Error());
1960 XMLTest("Pedantic whitespace", " \n This is ' text ' \n", doc.FirstChildElement()->GetText());
1961 }
1962
1963 // Following cases are for text that is all whitespace which is preserved with pedantic mode
1964 {
1965 const char* xml = "<element> </element>";
1966 XMLDocument doc(true, PEDANTIC_WHITESPACE);
1967 doc.Parse(xml);
1968 XMLTest("Parse with pedantic whitespace", false, doc.Error());
1969 XMLTest("Pedantic whitespace", " ", doc.FirstChildElement()->GetText());
1970 }
1971
1972 {
1973 const char* xml = "<element> </element>";
1974 XMLDocument doc(true, PEDANTIC_WHITESPACE);
1975 doc.Parse(xml);
1976 XMLTest("Parse with pedantic whitespace", false, doc.Error());
1977 XMLTest("Pedantic whitespace", " ", doc.FirstChildElement()->GetText());
1978 }
1979
1980 {
1981 const char* xml = "<element>\n\n</element>\n";
1982 XMLDocument doc(true, PEDANTIC_WHITESPACE);
1983 doc.Parse(xml);
1984 XMLTest("Parse with pedantic whitespace", false, doc.Error());
1985 XMLTest("Pedantic whitespace", "\n\n", doc.FirstChildElement()->GetText());
1986 }
1987
1988 {
1989 const char* xml = "<element> \n</element> \n ";
1990 XMLDocument doc(true, PEDANTIC_WHITESPACE);
1991 doc.Parse(xml);
1992 XMLTest("Parse with pedantic whitespace", false, doc.Error());
1993 XMLTest("Pedantic whitespace", " \n", doc.FirstChildElement()->GetText());
1994 }
1995
1996 {
1997 const char* xml = "<element> \n \n </element> ";
1998 XMLDocument doc(true, PEDANTIC_WHITESPACE);
1999 doc.Parse(xml);
2000 XMLTest("Parse with pedantic whitespace", false, doc.Error());
2001 XMLTest("Pedantic whitespace", " \n \n ", doc.FirstChildElement()->GetText());
2002 }
2003
2004 // Following cases are for checking nested elements are still parsed with pedantic whitespace
2005 {
2006 const char* xml = "<element>\n\t<a> This is nested text </a>\n</element> ";
2007 XMLDocument doc(true, PEDANTIC_WHITESPACE);
2008 doc.Parse(xml);
2009 XMLTest("Parse nested elements with pedantic whitespace", false, doc.Error());
2010 XMLTest("Pedantic whitespace", " This is nested text ", doc.RootElement()->FirstChildElement()->GetText());
2011 }
2012
2013 {
2014 const char* xml = "<element> <b> </b> </element>\n";
2015 XMLDocument doc(true, PEDANTIC_WHITESPACE);
2016 doc.Parse(xml);
2017 XMLTest("Parse nested elements with pedantic whitespace", false, doc.Error());
2018 XMLTest("Pedantic whitespace", " ", doc.RootElement()->FirstChildElement()->GetText());
2019 }
2020
2021 {
2022 const char* xml = "<element> <c attribute=\"test\"/> </element>\n ";
2023 XMLDocument doc(true, PEDANTIC_WHITESPACE);
2024 doc.Parse(xml);
2025 XMLTest("Parse nested elements with pedantic whitespace", false, doc.Error());
2026 XMLTest("Pedantic whitespace", true, 0 == doc.RootElement()->FirstChildElement()->GetText());
2027 }
2028
2029 // Check sample xml can be parsed with pedantic mode
2030 {
2031 XMLDocument doc(true, PEDANTIC_WHITESPACE);
2032 doc.LoadFile("resources/dream.xml");
2033 XMLTest("Load dream.xml with pedantic whitespace mode", false, doc.Error());
2034
2035 XMLTest("Dream", "xml version=\"1.0\"",
2036 doc.FirstChild()->ToDeclaration()->Value());
2037 XMLTest("Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() != 0);
2038 XMLTest("Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
2039 doc.FirstChild()->NextSibling()->ToUnknown()->Value());
2040 XMLTest("Dream", "And Robin shall restore amends.",
2041 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText());
2042 }
2043
2044 {
2045 // An assert should not fire.
2046 const char* xml = "<element/>";
2047 XMLDocument doc;
2048 doc.Parse( xml );
2049 XMLTest( "Parse with self-closed element", false, doc.Error() );
2050 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
2051 XMLTest( "Tracking unused elements", true, ele != 0, false );
2052 }
2053
2054
2055 {
2056 const char* xml = "<parent><child>abc</child></parent>";
2057 XMLDocument doc;
2058 doc.Parse( xml );
2059 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
2060 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
2061
2062 XMLPrinter printer;
2063 bool acceptResult = ele->Accept( &printer );
2064 XMLTest( "Accept of sub-element", true, acceptResult );
2065 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
2066 }
2067
2068
2069 {
2070 XMLDocument doc;
2071 XMLError error = doc.LoadFile( "resources/empty.xml" );
2072 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
2073 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
2074 doc.PrintError();
2075 }
2076
2077 {
2078 // BOM preservation
2079 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
2080 {
2081 XMLDocument doc;
2082 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
2083 XMLPrinter printer;
2084 doc.Print( &printer );
2085
2086 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
2087 doc.SaveFile( "resources/out/bomtest.xml" );
2088 XMLTest( "Save bomtest.xml", false, doc.Error() );
2089 }
2090 {
2091 XMLDocument doc;
2092 doc.LoadFile( "resources/out/bomtest.xml" );
2093 XMLTest( "Load bomtest.xml", false, doc.Error() );
2094 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
2095
2096 XMLPrinter printer;
2097 doc.Print( &printer );
2098 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
2099 }
2100 }
2101
2102 {
2103 // Insertion with Removal
2104 const char* xml = "<?xml version=\"1.0\" ?>"
2105 "<root>"
2106 "<one>"
2107 "<subtree>"
2108 "<elem>element 1</elem>text<!-- comment -->"
2109 "</subtree>"
2110 "</one>"
2111 "<two/>"
2112 "</root>";
2113 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
2114 "<root>"
2115 "<one/>"
2116 "<two>"
2117 "<subtree>"
2118 "<elem>element 1</elem>text<!-- comment -->"
2119 "</subtree>"
2120 "</two>"
2121 "</root>";
2122 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
2123 "<root>"
2124 "<one/>"
2125 "<subtree>"
2126 "<elem>element 1</elem>text<!-- comment -->"
2127 "</subtree>"
2128 "<two/>"
2129 "</root>";
2130 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
2131 "<root>"
2132 "<one/>"
2133 "<two/>"
2134 "<subtree>"
2135 "<elem>element 1</elem>text<!-- comment -->"
2136 "</subtree>"
2137 "</root>";
2138
2139 XMLDocument doc;
2140 doc.Parse(xml);
2141 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
2142 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
2143 XMLElement* two = doc.RootElement()->FirstChildElement("two");
2144 two->InsertFirstChild(subtree);
2145 XMLPrinter printer1(0, true);
2146 bool acceptResult = doc.Accept(&printer1);
2147 XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
2148 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
2149
2150 doc.Parse(xml);
2151 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
2152 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
2153 two = doc.RootElement()->FirstChildElement("two");
2154 doc.RootElement()->InsertAfterChild(two, subtree);
2155 XMLPrinter printer2(0, true);
2156 acceptResult = doc.Accept(&printer2);
2157 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
2158 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
2159
2160 doc.Parse(xml);
2161 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
2162 XMLNode* one = doc.RootElement()->FirstChildElement("one");
2163 subtree = one->FirstChildElement("subtree");
2164 doc.RootElement()->InsertAfterChild(one, subtree);
2165 XMLPrinter printer3(0, true);
2166 acceptResult = doc.Accept(&printer3);
2167 XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
2168 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
2169
2170 doc.Parse(xml);
2171 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
2172 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
2173 two = doc.RootElement()->FirstChildElement("two");
2174 XMLTest("<two> is the last child at root level", true, two == doc.RootElement()->LastChildElement());
2175 doc.RootElement()->InsertEndChild(subtree);
2176 XMLPrinter printer4(0, true);
2177 acceptResult = doc.Accept(&printer4);
2178 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
2179 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
2180 }
2181
2182 {
2183 const char* xml = "<svg width = \"128\" height = \"128\">"
2184 " <text> </text>"
2185 "</svg>";
2186 XMLDocument doc;
2187 doc.Parse(xml);
2188 XMLTest( "Parse svg with text", false, doc.Error() );
2189 doc.Print();
2190 }
2191
2192 {
2193 // Test that it doesn't crash.
2194 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
2195 XMLDocument doc;
2196 doc.Parse(xml);
2197 XMLTest( "Parse root-sample-field0", true, doc.Error() );
2198 doc.PrintError();
2199 }
2200
2201 #if 1
2202 // the question being explored is what kind of print to use:
2203 // https://github.com/leethomason/tinyxml2/issues/63
2204 {
2205 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
2206 const char* xml = "<element/>";
2207 XMLDocument doc;
2208 doc.Parse( xml );
2209 XMLTest( "Parse self-closed empty element", false, doc.Error() );
2210 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
2211 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
2212 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
2213 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
2214 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
2215 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
2216
2217 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
2218 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
2219 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
2220 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
2221 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
2222 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
2223
2224 doc.Print();
2225
2226 /* The result of this test is platform, compiler, and library version dependent. :("
2227 XMLPrinter printer;
2228 doc.Print( &printer );
2229 XMLTest( "Float and double formatting.",
2230 "<element attrA-f64=\"123456789.12345679\" attrB-f64=\"1001000000\" attrC-f64=\"1e+20\" attrD-f64=\"0.123456789\" attrA-f32=\"1.2345679e+08\" attrB-f32=\"1.001e+09\" attrC-f32=\"1e+20\" attrD-f32=\"0.12345679\"/>\n",
2231 printer.CStr(),
2232 true );
2233 */
2234 }
2235 #endif
2236
2237 {
2238 // Issue #184
2239 // If it doesn't assert, it passes. Caused by objects
2240 // getting created during parsing which are then
2241 // inaccessible in the memory pools.
2242 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
2243 {
2244 XMLDocument doc;
2245 doc.Parse(xmlText);
2246 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
2247 }
2248 {
2249 XMLDocument doc;
2250 doc.Parse(xmlText);
2251 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
2252 doc.Clear();
2253 }
2254 }
2255
2256 {
2257 // If this doesn't assert in TINYXML2_DEBUG, all is well.
2258 tinyxml2::XMLDocument doc;
2259 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
2260 doc.DeleteNode(pRoot);
2261 }
2262
2263 {
2264 XMLDocument doc;
2265 XMLElement* root = doc.NewElement( "Root" );
2266 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
2267 doc.InsertEndChild( root );
2268 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
2269 }
2270
2271 {
2272 // If this doesn't assert in TINYXML2_DEBUG, all is well.
2273 XMLDocument doc;
2274 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
2275 XMLElement* linkedRoot = doc.NewElement( "Root" );
2276 doc.InsertFirstChild( linkedRoot );
2277 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
2278 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
2279 }
2280
2281 {
2282 // Should not assert in TINYXML2_DEBUG
2283 XMLPrinter printer;
2284 }
2285
2286 {
2287 // Issue 291. Should not crash
2288 const char* xml = "�</a>";
2289 XMLDocument doc;
2290 doc.Parse( xml );
2291 XMLTest( "Parse hex with closing tag", false, doc.Error() );
2292
2293 XMLPrinter printer;
2294 doc.Print( &printer );
2295 }
2296 {
2297 // Issue 299. Can print elements that are not linked in.
2298 // Will crash if issue not fixed.
2299 XMLDocument doc;
2300 XMLElement* newElement = doc.NewElement( "printme" );
2301 XMLPrinter printer;
2302 bool acceptResult = newElement->Accept( &printer );
2303 XMLTest( "printme - Accept()", true, acceptResult );
2304 // Delete the node to avoid possible memory leak report in debug output
2305 doc.DeleteNode( newElement );
2306 }
2307 {
2308 // Issue 302. Clear errors from LoadFile/SaveFile
2309 XMLDocument doc;
2310 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
2311 doc.SaveFile( "./no/such/path/pretty.xml" );
2312 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
2313 doc.SaveFile( "./resources/out/compact.xml", true );
2314 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
2315 }
2316
2317 {
2318 // If a document fails to load then subsequent
2319 // successful loads should clear the error
2320 XMLDocument doc;
2321 XMLTest( "Should be no error initially", false, doc.Error() );
2322 doc.LoadFile( "resources/no-such-file.xml" );
2323 XMLTest( "No such file - should fail", true, doc.Error() );
2324
2325 doc.LoadFile("resources/dream.xml");
2326 XMLTest("Error should be cleared", false, doc.Error());
2327
2328 doc.LoadFile( "resources/xmltest-5330.xml" );
2329 XMLTest( "parse errors occur - should fail", true, doc.Error() );
2330
2331 doc.LoadFile( "resources/dream.xml" );
2332 XMLTest( "Error should be cleared", false, doc.Error() );
2333 }
2334
2335 {
2336 // Check that declarations are allowed only at beginning of document
2337 const char* xml0 = "<?xml version=\"1.0\" ?>"
2338 " <!-- xml version=\"1.1\" -->"
2339 "<first />";
2340 const char* xml1 = "<?xml version=\"1.0\" ?>"
2341 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
2342 "<first />";
2343 const char* xml2 = "<first />"
2344 "<?xml version=\"1.0\" ?>";
2345 const char* xml3 = "<first></first>"
2346 "<?xml version=\"1.0\" ?>";
2347
2348 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
2349
2350 XMLDocument doc;
2351 doc.Parse(xml0);
2352 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
2353 doc.Parse(xml1);
2354 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
2355 doc.Parse(xml2);
2356 XMLTest("Test that declaration after self-closed child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
2357 doc.Parse(xml3);
2358 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
2359 doc.Parse(xml4);
2360 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
2361 }
2362
2363 {
2364 // No matter - before or after successfully parsing a text -
2365 // calling XMLDocument::Value() used to cause an assert in debug.
2366 // Null must be returned.
2367 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
2368 "<first />"
2369 "<second />";
2370 XMLDocument* doc = new XMLDocument();
2371 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2372 doc->Parse( validXml );
2373 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
2374 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2375 delete doc;
2376 }
2377
2378 {
2379 XMLDocument doc;
2380 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
2381 const XMLError error = static_cast<XMLError>(i);
2382 const char* name = XMLDocument::ErrorIDToName(error);
2383 XMLTest( "ErrorName() not null after ClearError()", true, name != 0 );
2384 if( name == 0 ) {
2385 // passing null pointer into strlen() is undefined behavior, so
2386 // compiler is allowed to optimise away the null test above if it's
2387 // as reachable as the strlen() call
2388 continue;
2389 }
2390 XMLTest( "ErrorName() not empty after ClearError()", true, strlen(name) > 0 );
2391 }
2392 }
2393
2394 {
2395 const char* html("<!DOCTYPE html><html><body><p>test</p><p><br/></p></body></html>");
2396 XMLDocument doc(false);
2397 doc.Parse(html);
2398
2399 XMLPrinter printer(0, true);
2400 doc.Print(&printer);
2401
2402 XMLTest(html, html, printer.CStr());
2403 }
2404
2405 {
2406 // Evil memory leaks.
2407 // If an XMLElement (etc) is allocated via NewElement() (etc.)
2408 // and NOT added to the XMLDocument, what happens?
2409 //
2410 // Previously (buggy):
2411 // The memory would be free'd when the XMLDocument is
2412 // destructed. But the XMLElement destructor wasn't called, so
2413 // memory allocated for the XMLElement text would not be free'd.
2414 // In practice this meant strings allocated for the XMLElement
2415 // text would be leaked. An edge case, but annoying.
2416 // Now:
2417 // The XMLElement destructor is called. But the unlinked nodes
2418 // have to be tracked using a list. This has a minor performance
2419 // impact that can become significant if you have a lot of
2420 // unlinked nodes. (But why would you do that?)
2421 // The only way to see this bug was in a Visual C++ runtime debug heap
2422 // leak tracker. This is compiled in by default on Windows Debug and
2423 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
2424 {
2425 XMLDocument doc;
2426 doc.NewElement("LEAK 1");
2427 }
2428 {
2429 XMLDocument doc;
2430 XMLElement* ele = doc.NewElement("LEAK 2");
2431 doc.DeleteNode(ele);
2432 }
2433 }
2434
2435 {
2436 // Bad bad crash. Parsing error results in stack overflow, if uncaught.
2437 const char* TESTS[] = {
2438 "./resources/xmltest-5330.xml",
2439 "./resources/xmltest-4636783552757760.xml",
2440 "./resources/xmltest-5720541257269248.xml",
2441 0
2442 };
2443 for (int i=0; TESTS[i]; ++i) {
2444 XMLDocument doc;
2445 doc.LoadFile(TESTS[i]);
2446 XMLTest("Stack overflow prevented.", XML_ELEMENT_DEPTH_EXCEEDED, doc.ErrorID());
2447 }
2448 }
2449 {
2450 const char* TESTS[] = {
2451 "./resources/xmltest-5662204197076992.xml", // Security-level performance issue.
2452 0
2453 };
2454 for (int i = 0; TESTS[i]; ++i) {
2455 XMLDocument doc;
2456 doc.LoadFile(TESTS[i]);
2457 // Need only not crash / lock up.
2458 XMLTest("Fuzz attack prevented.", true, true);
2459 }
2460 }
2461 {
2462 // Crashing reported via email.
2463 const char* xml =
2464 "<playlist id='playlist1'>"
2465 "<property name='track_name'>voice</property>"
2466 "<property name='audio_track'>1</property>"
2467 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2468 "<blank length = '1' />"
2469 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2470 "<blank length = '2' />"
2471 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2472 "<blank length = '1' />"
2473 "<entry out = '128' producer = '1_playlist1' in = '0' />"
2474 "</playlist>";
2475
2476 // It's not a good idea to delete elements as you walk the
2477 // list. I'm not sure this technically should work; but it's
2478 // an interesting test case.
2479 XMLDocument doc;
2480 XMLError err = doc.Parse(xml);
2481 XMLTest("Crash bug parsing", XML_SUCCESS, err );
2482
2483 XMLElement* playlist = doc.FirstChildElement("playlist");
2484 XMLTest("Crash bug parsing", true, playlist != 0);
2485
2486 {
2487 const char* elementName = "entry";
2488 XMLElement* entry = playlist->FirstChildElement(elementName);
2489 XMLTest("Crash bug parsing", true, entry != 0);
2490 while (entry) {
2491 XMLElement* todelete = entry;
2492 entry = entry->NextSiblingElement(elementName);
2493 playlist->DeleteChild(todelete);
2494 }
2495 entry = playlist->FirstChildElement(elementName);
2496 XMLTest("Crash bug parsing", true, entry == 0);
2497 }
2498 {
2499 const char* elementName = "blank";
2500 XMLElement* blank = playlist->FirstChildElement(elementName);
2501 XMLTest("Crash bug parsing", true, blank != 0);
2502 while (blank) {
2503 XMLElement* todelete = blank;
2504 blank = blank->NextSiblingElement(elementName);
2505 playlist->DeleteChild(todelete);
2506 }
2507 XMLTest("Crash bug parsing", true, blank == 0);
2508 }
2509
2510 tinyxml2::XMLPrinter printer;
2511 const bool acceptResult = playlist->Accept(&printer);
2512 XMLTest("Crash bug parsing - Accept()", true, acceptResult);
2513 printf("%s\n", printer.CStr());
2514
2515 // No test; it only need to not crash.
2516 // Still, wrap it up with a sanity check
2517 int nProperty = 0;
2518 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2519 nProperty++;
2520 }
2521 XMLTest("Crash bug parsing", 2, nProperty);
2522 }
2523
2524 // ----------- Line Number Tracking --------------
2525 {
2526 struct TestUtil: XMLVisitor
2527 {
2528 TestUtil() : str() {}
2529
2530 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2531 {
2532 XMLDocument doc;
2533 const XMLError parseError = doc.Parse(docStr);
2534
2535 XMLTest(testString, parseError, doc.ErrorID());
2536 XMLTest(testString, true, doc.Error());
2537 XMLTest(testString, expected_error, parseError);
2538 XMLTest(testString, expectedLine, doc.ErrorLineNum());
2539 };
2540
2541 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2542 {
2543 XMLDocument doc;
2544 doc.Parse(docStr);
2545 XMLTest(testString, false, doc.Error());
2546 TestDocLines(testString, doc, expectedLines);
2547 }
2548
2549 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2550 {
2551 XMLDocument doc;
2552 doc.LoadFile(file_name);
2553 XMLTest(testString, false, doc.Error());
2554 TestDocLines(testString, doc, expectedLines);
2555 }
2556
2557 private:
2558 DynArray<char, 10> str;
2559
2560 void Push(char type, int lineNum)
2561 {
2562 str.Push(type);
2563 str.Push(char('0' + (lineNum / 10)));
2564 str.Push(char('0' + (lineNum % 10)));
2565 }
2566
2567 bool VisitEnter(const XMLDocument& doc)
2568 {
2569 Push('D', doc.GetLineNum());
2570 return true;
2571 }
2572 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2573 {
2574 Push('E', element.GetLineNum());
2575 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
2576 Push('A', attr->GetLineNum());
2577 return true;
2578 }
2579 bool Visit(const XMLDeclaration& declaration)
2580 {
2581 Push('L', declaration.GetLineNum());
2582 return true;
2583 }
2584 bool Visit(const XMLText& text)
2585 {
2586 Push('T', text.GetLineNum());
2587 return true;
2588 }
2589 bool Visit(const XMLComment& comment)
2590 {
2591 Push('C', comment.GetLineNum());
2592 return true;
2593 }
2594 bool Visit(const XMLUnknown& unknown)
2595 {
2596 Push('U', unknown.GetLineNum());
2597 return true;
2598 }
2599
2600 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2601 {
2602 str.Clear();
2603 const bool acceptResult = doc.Accept(this);
2604 XMLTest(testString, true, acceptResult);
2605 str.Push(0);
2606 XMLTest(testString, expectedLines, str.Mem());
2607 }
2608 } tester;
2609
2610 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2611 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2612 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2613 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2614 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2615 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2616 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2617 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2618 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2619 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2620 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
2621
2622 tester.TestStringLines(
2623 "LineNumbers-String",
2624
2625 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2626 "<root a='b' \n" // 2 Element Attribute
2627 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2628 "newline in text \n" // 4 Text
2629 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2630 " cdata test ]]><!-- comment -->\n" // 6 Comment
2631 "<! unknown></root>", // 7 Unknown
2632
2633 "D01L01E02A02A03T03E03T04E05T05C06U07");
2634
2635 tester.TestStringLines(
2636 "LineNumbers-CRLF",
2637
2638 "\r\n" // 1 Doc (arguably should be line 2)
2639 "<?xml version=\"1.0\"?>\n" // 2 DecL
2640 "<root>\r\n" // 3 Element
2641 "\n" // 4
2642 "text contining new line \n" // 5 Text
2643 " and also containing crlf \r\n" // 6
2644 "<sub><![CDATA[\n" // 7 Element Text
2645 "cdata containing new line \n" // 8
2646 " and also containing cflr\r\n" // 9
2647 "]]></sub><sub2/></root>", // 10 Element
2648
2649 "D01L02E03T05E07T07E10");
2650
2651 tester.TestFileLines(
2652 "LineNumbers-File",
2653 "resources/utf8test.xml",
2654 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2655 }
2656
2657 {
2658 const char* xml = "<Hello>Text</Error>";
2659 XMLDocument doc;
2660 doc.Parse(xml);
2661 XMLTest("Test mismatched elements.", true, doc.Error());
2662 XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2663 // For now just make sure calls work & doesn't crash.
2664 // May solidify the error output in the future.
2665 printf("%s\n", doc.ErrorStr());
2666 doc.PrintError();
2667 }
2668
2669 // ----------- Performance tracking --------------
2670 {
2671 #if defined( _MSC_VER )
2672 __int64 start, end, freq;
2673 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
2674 #endif
2675
2676 FILE* perfFP = fopen("resources/dream.xml", "r");
2677 XMLTest("Open dream.xml", true, perfFP != 0);
2678 fseek(perfFP, 0, SEEK_END);
2679 long size = ftell(perfFP);
2680 fseek(perfFP, 0, SEEK_SET);
2681
2682 char* mem = new char[size + 1];
2683 memset(mem, 0xfe, size);
2684 size_t bytesRead = fread(mem, 1, size, perfFP);
2685 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
2686 fclose(perfFP);
2687 mem[size] = 0;
2688
2689 #if defined( _MSC_VER )
2690 QueryPerformanceCounter((LARGE_INTEGER*)&start);
2691 #else
2692 clock_t cstart = clock();
2693 #endif
2694 bool parseDreamXmlFailed = false;
2695 static const int COUNT = 10;
2696 for (int i = 0; i < COUNT; ++i) {
2697 XMLDocument doc;
2698 doc.Parse(mem);
2699 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
2700 }
2701 #if defined( _MSC_VER )
2702 QueryPerformanceCounter((LARGE_INTEGER*)&end);
2703 #else
2704 clock_t cend = clock();
2705 #endif
2706 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
2707
2708 delete[] mem;
2709
2710 static const char* note =
2711 #ifdef TINYXML2_DEBUG
2712 "DEBUG";
2713 #else
2714 "Release";
2715 #endif
2716
2717 #if defined( _MSC_VER )
2718 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
2719 #else
2720 const double duration = (double)(cend - cstart) / (double)COUNT;
2721 #endif
2722 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
2723 }
2724
2725 #if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
2726 {
2727 _CrtMemCheckpoint( &endMemState );
2728
2729 _CrtMemState diffMemState;
2730 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2731 _CrtMemDumpStatistics( &diffMemState );
2732
2733 {
2734 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2735 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2736 }
2737 }
2738 #endif
2739
2740 printf ("\nPass %d, Fail %d\n", gPass, gFail);
2741
2742 return gFail;
2743 }
2744