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* cStr = ele->Attribute( "str" );
636 {
637 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
638 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
639 }
640 {
641 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
642 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
643 }
644
645 {
646 int queryResult = ele->QueryAttribute( "int", &iVal2 );
647 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
648 }
649 {
650 int queryResult = ele->QueryAttribute( "double", &dVal2 );
651 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
652 }
653
654 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
655 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
656 XMLTest( "Attribute round trip. int.", 1, iVal );
657 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
658 XMLTest( "Alternate query", true, iVal == iVal2 );
659 XMLTest( "Alternate query", true, dVal == dVal2 );
660 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
661 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
662 }
663
664 {
665 XMLDocument doc;
666 doc.LoadFile( "resources/utf8test.xml" );
667 XMLTest( "Load utf8test.xml", false, doc.Error() );
668
669 // Get the attribute "value" from the "Russian" element and check it.
670 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
671 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
672 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
673
674 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
675
676 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
677 0xd1U, 0x81U, 0xd1U, 0x81U,
678 0xd0U, 0xbaU, 0xd0U, 0xb8U,
679 0xd0U, 0xb9U, 0 };
680 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
681
682 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
683 XMLTest( "UTF-8: Browsing russian element name.",
684 russianText,
685 text->Value() );
686
687 // Now try for a round trip.
688 doc.SaveFile( "resources/out/utf8testout.xml" );
689 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
690
691 // Check the round trip.
692 bool roundTripOkay = false;
693
694 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
695 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
696
697 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
698 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
699
700 if ( saved && verify )
701 {
702 roundTripOkay = true;
703 char verifyBuf[256];
704 while ( fgets( verifyBuf, 256, verify ) )
705 {
706 char savedBuf[256];
707 fgets( savedBuf, 256, saved );
708 NullLineEndings( verifyBuf );
709 NullLineEndings( savedBuf );
710
711 if ( strcmp( verifyBuf, savedBuf ) )
712 {
713 printf( "verify:%s<\n", verifyBuf );
714 printf( "saved :%s<\n", savedBuf );
715 roundTripOkay = false;
716 break;
717 }
718 }
719 }
720 if ( saved )
721 fclose( saved );
722 if ( verify )
723 fclose( verify );
724 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
725 }
726
727 // --------GetText()-----------
728 {
729 const char* str = "<foo>This is text</foo>";
730 XMLDocument doc;
731 doc.Parse( str );
732 XMLTest( "Double whitespace", false, doc.Error() );
733 const XMLElement* element = doc.RootElement();
734
735 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
736
737 str = "<foo><b>This is text</b></foo>";
738 doc.Parse( str );
739 XMLTest( "Bold text simulation", false, doc.Error() );
740 element = doc.RootElement();
741
742 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
743 }
744
745
746 // --------SetText()-----------
747 {
748 const char* str = "<foo></foo>";
749 XMLDocument doc;
750 doc.Parse( str );
751 XMLTest( "Empty closed element", false, doc.Error() );
752 XMLElement* element = doc.RootElement();
753
754 element->SetText("darkness.");
755 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
756
757 element->SetText("blue flame.");
758 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
759
760 str = "<foo/>";
761 doc.Parse( str );
762 XMLTest( "Empty self-closed element", false, doc.Error() );
763 element = doc.RootElement();
764
765 element->SetText("The driver");
766 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
767
768 element->SetText("<b>horses</b>");
769 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
770 //doc.Print();
771
772 str = "<foo><bar>Text in nested element</bar></foo>";
773 doc.Parse( str );
774 XMLTest( "Text in nested element", false, doc.Error() );
775 element = doc.RootElement();
776
777 element->SetText("wolves");
778 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
779
780 str = "<foo/>";
781 doc.Parse( str );
782 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
783 element = doc.RootElement();
784
785 element->SetText( "str" );
786 XMLTest( "SetText types", "str", element->GetText() );
787
788 element->SetText( 1 );
789 XMLTest( "SetText types", "1", element->GetText() );
790
791 element->SetText( 1U );
792 XMLTest( "SetText types", "1", element->GetText() );
793
794 element->SetText( true );
795 XMLTest( "SetText types", "true", element->GetText() );
796
797 element->SetText( 1.5f );
798 XMLTest( "SetText types", "1.5", element->GetText() );
799
800 element->SetText( 1.5 );
801 XMLTest( "SetText types", "1.5", element->GetText() );
802 }
803
804 // ---------- Attributes ---------
805 {
806 static const int64_t BIG = -123456789012345678;
807 static const uint64_t BIG_POS = 123456789012345678;
808 XMLDocument doc;
809 XMLElement* element = doc.NewElement("element");
810 doc.InsertFirstChild(element);
811
812 {
813 element->SetAttribute("attrib", int(-100));
814 {
815 int v = 0;
816 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
817 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
818 XMLTest("Attribute: int", -100, v, true);
819 }
820 {
821 int v = 0;
822 int queryResult = element->QueryAttribute("attrib", &v);
823 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
824 XMLTest("Attribute: int", -100, v, true);
825 }
826 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
827 }
828 {
829 element->SetAttribute("attrib", unsigned(100));
830 {
831 unsigned v = 0;
832 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
833 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
834 XMLTest("Attribute: unsigned", unsigned(100), v, true);
835 }
836 {
837 unsigned v = 0;
838 int queryResult = element->QueryAttribute("attrib", &v);
839 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
840 XMLTest("Attribute: unsigned", unsigned(100), v, true);
841 }
842 {
843 const char* v = "failed";
844 XMLError queryResult = element->QueryStringAttribute("not-attrib", &v);
845 XMLTest("Attribute: string default", false, queryResult == XML_SUCCESS);
846 queryResult = element->QueryStringAttribute("attrib", &v);
847 XMLTest("Attribute: string", XML_SUCCESS, queryResult, true);
848 XMLTest("Attribute: string", "100", v);
849 }
850 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
851 }
852 {
853 element->SetAttribute("attrib", BIG);
854 {
855 int64_t v = 0;
856 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
857 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
858 XMLTest("Attribute: int64_t", BIG, v, true);
859 }
860 {
861 int64_t v = 0;
862 int queryResult = element->QueryAttribute("attrib", &v);
863 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
864 XMLTest("Attribute: int64_t", BIG, v, true);
865 }
866 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
867 }
868 {
869 element->SetAttribute("attrib", BIG_POS);
870 {
871 uint64_t v = 0;
872 XMLError queryResult = element->QueryUnsigned64Attribute("attrib", &v);
873 XMLTest("Attribute: uint64_t", XML_SUCCESS, queryResult, true);
874 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
875 }
876 {
877 uint64_t v = 0;
878 int queryResult = element->QueryAttribute("attrib", &v);
879 XMLTest("Attribute: uint64_t", (int)XML_SUCCESS, queryResult, true);
880 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
881 }
882 XMLTest("Attribute: uint64_t", BIG_POS, element->Unsigned64Attribute("attrib"), true);
883 }
884 {
885 element->SetAttribute("attrib", true);
886 {
887 bool v = false;
888 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
889 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
890 XMLTest("Attribute: bool", true, v, true);
891 }
892 {
893 bool v = false;
894 int queryResult = element->QueryAttribute("attrib", &v);
895 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
896 XMLTest("Attribute: bool", true, v, true);
897 }
898 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
899 }
900 {
901 element->SetAttribute("attrib", true);
902 const char* result = element->Attribute("attrib");
903 XMLTest("Bool true is 'true'", "true", result);
904
905 XMLUtil::SetBoolSerialization("1", "0");
906 element->SetAttribute("attrib", true);
907 result = element->Attribute("attrib");
908 XMLTest("Bool true is '1'", "1", result);
909
910 XMLUtil::SetBoolSerialization(0, 0);
911 }
912 {
913 element->SetAttribute("attrib", 100.0);
914 {
915 double v = 0;
916 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
917 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
918 XMLTest("Attribute: double", 100.0, v, true);
919 }
920 {
921 double v = 0;
922 int queryResult = element->QueryAttribute("attrib", &v);
923 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
924 XMLTest("Attribute: double", 100.0, v, true);
925 }
926 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
927 }
928 {
929 element->SetAttribute("attrib", 100.0f);
930 {
931 float v = 0;
932 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
933 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
934 XMLTest("Attribute: float", 100.0f, v, true);
935 }
936 {
937 float v = 0;
938 int queryResult = element->QueryAttribute("attrib", &v);
939 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
940 XMLTest("Attribute: float", 100.0f, v, true);
941 }
942 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
943 }
944 {
945 element->SetText(BIG);
946 int64_t v = 0;
947 XMLError queryResult = element->QueryInt64Text(&v);
948 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
949 XMLTest("Element: int64_t", BIG, v, true);
950 }
951 {
952 element->SetText(BIG_POS);
953 uint64_t v = 0;
954 XMLError queryResult = element->QueryUnsigned64Text(&v);
955 XMLTest("Element: uint64_t", XML_SUCCESS, queryResult, true);
956 XMLTest("Element: uint64_t", BIG_POS, v, true);
957 }
958 }
959
960 // ---------- XMLPrinter stream mode ------
961 {
962 {
963 FILE* printerfp = fopen("resources/out/printer.xml", "w");
964 XMLTest("Open printer.xml", true, printerfp != 0);
965 XMLPrinter printer(printerfp);
966 printer.OpenElement("foo");
967 printer.PushAttribute("attrib-text", "text");
968 printer.PushAttribute("attrib-int", int(1));
969 printer.PushAttribute("attrib-unsigned", unsigned(2));
970 printer.PushAttribute("attrib-int64", int64_t(3));
971 printer.PushAttribute("attrib-uint64", uint64_t(37));
972 printer.PushAttribute("attrib-bool", true);
973 printer.PushAttribute("attrib-double", 4.0);
974 printer.CloseElement();
975 fclose(printerfp);
976 }
977 {
978 XMLDocument doc;
979 doc.LoadFile("resources/out/printer.xml");
980 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
981
982 const XMLDocument& cdoc = doc;
983
984 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
985 XMLTest("attrib-text", "text", attrib->Value(), true);
986 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
987 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
988 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
989 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
990 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
991 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
992 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-uint64");
993 XMLTest("attrib-uint64", uint64_t(37), attrib->Unsigned64Value(), true);
994 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
995 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
996 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
997 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
998 }
999 // Add API_testcatse :PushDeclaration();PushText();PushComment()
1000 {
1001 FILE* fp1 = fopen("resources/out/printer_1.xml", "w");
1002 XMLPrinter printer(fp1);
1003
1004 printer.PushDeclaration("version = '1.0' enconding = 'utf-8'");
1005
1006 printer.OpenElement("foo");
1007 printer.PushAttribute("attrib-text", "text");
1008
1009 printer.OpenElement("text");
1010 printer.PushText("Tinyxml2");
1011 printer.CloseElement();
1012
1013 printer.OpenElement("int");
1014 printer.PushText(int(11));
1015 printer.CloseElement();
1016
1017 printer.OpenElement("unsigned");
1018 printer.PushText(unsigned(12));
1019 printer.CloseElement();
1020
1021 printer.OpenElement("int64_t");
1022 printer.PushText(int64_t(13));
1023 printer.CloseElement();
1024
1025 printer.OpenElement("uint64_t");
1026 printer.PushText(uint64_t(14));
1027 printer.CloseElement();
1028
1029 printer.OpenElement("bool");
1030 printer.PushText(true);
1031 printer.CloseElement();
1032
1033 printer.OpenElement("float");
1034 printer.PushText("1.56");
1035 printer.CloseElement();
1036
1037 printer.OpenElement("double");
1038 printer.PushText("12.12");
1039 printer.CloseElement();
1040
1041 printer.OpenElement("comment");
1042 printer.PushComment("this is Tinyxml2");
1043 printer.CloseElement();
1044
1045 printer.CloseElement();
1046 fclose(fp1);
1047 }
1048 {
1049 XMLDocument doc;
1050 doc.LoadFile("resources/out/printer_1.xml");
1051 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
1052
1053 const XMLDocument& cdoc = doc;
1054
1055 const XMLElement* root = cdoc.FirstChildElement("foo");
1056
1057 const char* text_value;
1058 text_value = root->FirstChildElement("text")->GetText();
1059 XMLTest("PushText( const char* text, bool cdata=false ) test", "Tinyxml2", text_value);
1060
1061 int int_value;
1062 int_value = root->FirstChildElement("int")->IntText();
1063 XMLTest("PushText( int value ) test", 11, int_value);
1064
1065 unsigned unsigned_value;
1066 unsigned_value = root->FirstChildElement("unsigned")->UnsignedText();
1067 XMLTest("PushText( unsigned value ) test", (unsigned)12, unsigned_value);
1068
1069 int64_t int64_t_value;
1070 int64_t_value = root->FirstChildElement("int64_t")->Int64Text();
1071 XMLTest("PushText( int64_t value ) test", (int64_t) 13, int64_t_value);
1072
1073 uint64_t uint64_t_value;
1074 uint64_t_value = root->FirstChildElement("uint64_t")->Unsigned64Text();
1075 XMLTest("PushText( uint64_t value ) test", (uint64_t) 14, uint64_t_value);
1076
1077 float float_value;
1078 float_value = root->FirstChildElement("float")->FloatText();
1079 XMLTest("PushText( float value ) test", 1.56f, float_value);
1080
1081 double double_value;
1082 double_value = root->FirstChildElement("double")->DoubleText();
1083 XMLTest("PushText( double value ) test", 12.12, double_value);
1084
1085 bool bool_value;
1086 bool_value = root->FirstChildElement("bool")->BoolText();
1087 XMLTest("PushText( bool value ) test", true, bool_value);
1088
1089 const XMLComment* comment = root->FirstChildElement("comment")->FirstChild()->ToComment();
1090 const char* comment_value = comment->Value();
1091 XMLTest("PushComment() test", "this is Tinyxml2", comment_value);
1092
1093 const XMLDeclaration* declaration = cdoc.FirstChild()->ToDeclaration();
1094 const char* declaration_value = declaration->Value();
1095 XMLTest("PushDeclaration() test", "version = '1.0' enconding = 'utf-8'", declaration_value);
1096 }
1097 }
1098
1099
1100 // ---------- CDATA ---------------
1101 {
1102 const char* str = "<xmlElement>"
1103 "<![CDATA["
1104 "I am > the rules!\n"
1105 "...since I make symbolic puns"
1106 "]]>"
1107 "</xmlElement>";
1108 XMLDocument doc;
1109 doc.Parse( str );
1110 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
1111 doc.Print();
1112
1113 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
1114 doc.FirstChildElement()->FirstChild()->Value(),
1115 false );
1116 }
1117
1118 // ----------- CDATA -------------
1119 {
1120 const char* str = "<xmlElement>"
1121 "<![CDATA["
1122 "<b>I am > the rules!</b>\n"
1123 "...since I make symbolic puns"
1124 "]]>"
1125 "</xmlElement>";
1126 XMLDocument doc;
1127 doc.Parse( str );
1128 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
1129 doc.Print();
1130
1131 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
1132 "<b>I am > the rules!</b>\n...since I make symbolic puns",
1133 doc.FirstChildElement()->FirstChild()->Value(),
1134 false );
1135 }
1136
1137 // InsertAfterChild causes crash.
1138 {
1139 // InsertBeforeChild and InsertAfterChild causes crash.
1140 XMLDocument doc;
1141 XMLElement* parent = doc.NewElement( "Parent" );
1142 doc.InsertFirstChild( parent );
1143
1144 XMLElement* childText0 = doc.NewElement( "childText0" );
1145 XMLElement* childText1 = doc.NewElement( "childText1" );
1146
1147 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
1148 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
1149 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
1150 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
1151
1152 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
1153 }
1154
1155 {
1156 // Entities not being written correctly.
1157 // From Lynn Allen
1158
1159 const char* passages =
1160 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1161 "<passages count=\"006\" formatversion=\"20020620\">"
1162 "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'."
1163 " It also has <, >, and &, as well as a fake copyright ©.\"> </psg>"
1164 "</passages>";
1165
1166 XMLDocument doc;
1167 doc.Parse( passages );
1168 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
1169 XMLElement* psg = doc.RootElement()->FirstChildElement();
1170 const char* context = psg->Attribute( "context" );
1171 const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9.";
1172
1173 XMLTest( "Entity transformation: read. ", expected, context, true );
1174
1175 const char* textFilePath = "resources/out/textfile.txt";
1176 FILE* textfile = fopen( textFilePath, "w" );
1177 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
1178 if ( textfile )
1179 {
1180 XMLPrinter streamer( textfile );
1181 bool acceptResult = psg->Accept( &streamer );
1182 fclose( textfile );
1183 XMLTest( "Entity transformation: Accept", true, acceptResult );
1184 }
1185
1186 textfile = fopen( textFilePath, "r" );
1187 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
1188 if ( textfile )
1189 {
1190 char buf[ 1024 ];
1191 fgets( buf, 1024, textfile );
1192 XMLTest( "Entity transformation: write. ",
1193 "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'."
1194 " It also has <, >, and &, as well as a fake copyright \xC2\xA9.\"/>\n",
1195 buf, false );
1196 fclose( textfile );
1197 }
1198 }
1199
1200 {
1201 // Suppress entities.
1202 const char* passages =
1203 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1204 "<passages count=\"006\" formatversion=\"20020620\">"
1205 "<psg context=\"Line 5 has "quotation marks" and 'apostrophe marks'.\">Crazy &ttk;</psg>"
1206 "</passages>";
1207
1208 XMLDocument doc( false );
1209 doc.Parse( passages );
1210 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
1211
1212 XMLTest( "No entity parsing.",
1213 "Line 5 has "quotation marks" and 'apostrophe marks'.",
1214 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1215 XMLTest( "No entity parsing.", "Crazy &ttk;",
1216 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
1217 doc.Print();
1218 }
1219
1220 {
1221 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
1222
1223 XMLDocument doc;
1224 doc.Parse( test );
1225 XMLTest( "dot in names", false, doc.Error() );
1226 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1227 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
1228 }
1229
1230 {
1231 const char* test = "<element><Name>1.1 Start easy ignore fin thickness
</Name></element>";
1232
1233 XMLDocument doc;
1234 doc.Parse( test );
1235 XMLTest( "fin thickness", false, doc.Error() );
1236
1237 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1238 XMLTest( "Entity with one digit.",
1239 "1.1 Start easy ignore fin thickness\n", text->Value(),
1240 false );
1241 }
1242
1243 {
1244 // DOCTYPE not preserved (950171)
1245 //
1246 const char* doctype =
1247 "<?xml version=\"1.0\" ?>"
1248 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1249 "<!ELEMENT title (#PCDATA)>"
1250 "<!ELEMENT books (title,authors)>"
1251 "<element />";
1252
1253 XMLDocument doc;
1254 doc.Parse( doctype );
1255 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
1256 doc.SaveFile( "resources/out/test7.xml" );
1257 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
1258 doc.DeleteChild( doc.RootElement() );
1259 doc.LoadFile( "resources/out/test7.xml" );
1260 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
1261 doc.Print();
1262
1263 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1264 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1265
1266 }
1267
1268 {
1269 // Comments do not stream out correctly.
1270 const char* doctype =
1271 "<!-- Somewhat<evil> -->";
1272 XMLDocument doc;
1273 doc.Parse( doctype );
1274 XMLTest( "Comment somewhat evil", false, doc.Error() );
1275
1276 XMLComment* comment = doc.FirstChild()->ToComment();
1277
1278 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1279 }
1280 {
1281 // Double attributes
1282 const char* doctype = "<element attr='red' attr='blue' />";
1283
1284 XMLDocument doc;
1285 doc.Parse( doctype );
1286
1287 XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues)
1288 doc.PrintError();
1289 }
1290
1291 {
1292 // Embedded null in stream.
1293 const char* doctype = "<element att\0r='red' attr='blue' />";
1294
1295 XMLDocument doc;
1296 doc.Parse( doctype );
1297 XMLTest( "Embedded null throws error.", true, doc.Error() );
1298 }
1299
1300 {
1301 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1302 const char* str = "";
1303 XMLDocument doc;
1304 doc.Parse( str );
1305 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1306
1307 // But be sure there is an error string!
1308 const char* errorStr = doc.ErrorStr();
1309 XMLTest("Error string should be set",
1310 "Error=XML_ERROR_EMPTY_DOCUMENT ErrorID=13 (0xd) Line number=0",
1311 errorStr);
1312 }
1313
1314 {
1315 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1316 const char* str = " ";
1317 XMLDocument doc;
1318 doc.Parse( str );
1319 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1320 }
1321
1322 {
1323 // Low entities
1324 XMLDocument doc;
1325 doc.Parse( "<test></test>" );
1326 XMLTest( "Hex values", false, doc.Error() );
1327 const char result[] = { 0x0e, 0 };
1328 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
1329 doc.Print();
1330 }
1331
1332 {
1333 // Attribute values with trailing quotes not handled correctly
1334 XMLDocument doc;
1335 doc.Parse( "<foo attribute=bar\" />" );
1336 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
1337 }
1338
1339 {
1340 // [ 1663758 ] Failure to report error on bad XML
1341 XMLDocument xml;
1342 xml.Parse("<x>");
1343 XMLTest("Missing end tag at end of input", true, xml.Error());
1344 xml.Parse("<x> ");
1345 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
1346 xml.Parse("<x></y>");
1347 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
1348 }
1349
1350
1351 {
1352 // [ 1475201 ] TinyXML parses entities in comments
1353 XMLDocument xml;
1354 xml.Parse("<!-- declarations for <head> & <body> -->"
1355 "<!-- far & away -->" );
1356 XMLTest( "Declarations for head and body", false, xml.Error() );
1357
1358 XMLNode* e0 = xml.FirstChild();
1359 XMLNode* e1 = e0->NextSibling();
1360 XMLComment* c0 = e0->ToComment();
1361 XMLComment* c1 = e1->ToComment();
1362
1363 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1364 XMLTest( "Comments ignore entities.", " far & away ", c1->Value(), true );
1365 }
1366
1367 {
1368 XMLDocument xml;
1369 xml.Parse( "<Parent>"
1370 "<child1 att=''/>"
1371 "<!-- With this comment, child2 will not be parsed! -->"
1372 "<child2 att=''/>"
1373 "</Parent>" );
1374 XMLTest( "Comments iteration", false, xml.Error() );
1375 xml.Print();
1376
1377 int count = 0;
1378
1379 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1380 ele;
1381 ele = ele->NextSibling() )
1382 {
1383 ++count;
1384 }
1385
1386 XMLTest( "Comments iterate correctly.", 3, count );
1387 }
1388
1389 {
1390 // trying to repro [1874301]. If it doesn't go into an infinite loop, all is well.
1391 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1392 buf[60] = 239;
1393 buf[61] = 0;
1394
1395 XMLDocument doc;
1396 doc.Parse( (const char*)buf);
1397 XMLTest( "Broken CDATA", true, doc.Error() );
1398 }
1399
1400
1401 {
1402 // bug 1827248 Error while parsing a little bit malformed file
1403 // Actually not malformed - should work.
1404 XMLDocument xml;
1405 xml.Parse( "<attributelist> </attributelist >" );
1406 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1407 }
1408
1409 {
1410 // This one must not result in an infinite loop
1411 XMLDocument xml;
1412 xml.Parse( "<infinite>loop" );
1413 XMLTest( "No closing element", true, xml.Error() );
1414 XMLTest( "Infinite loop test.", true, true );
1415 }
1416 #endif
1417 {
1418 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1419 XMLDocument doc;
1420 doc.Parse( pub );
1421 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
1422
1423 XMLDocument clone;
1424 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1425 XMLNode* copy = node->ShallowClone( &clone );
1426 clone.InsertEndChild( copy );
1427 }
1428
1429 clone.Print();
1430
1431 int count=0;
1432 const XMLNode* a=clone.FirstChild();
1433 const XMLNode* b=doc.FirstChild();
1434 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1435 ++count;
1436 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1437 }
1438 XMLTest( "Clone and Equal", 4, count );
1439 }
1440
1441 {
1442 // Deep Cloning of root element.
1443 XMLDocument doc2;
1444 XMLPrinter printer1;
1445 {
1446 // Make sure doc1 is deleted before we test doc2
1447 const char* xml =
1448 "<root>"
1449 " <child1 foo='bar'/>"
1450 " <!-- comment thing -->"
1451 " <child2 val='1'>Text</child2>"
1452 "</root>";
1453 XMLDocument doc;
1454 doc.Parse(xml);
1455 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
1456
1457 doc.Print(&printer1);
1458 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1459 doc2.InsertFirstChild(root);
1460 }
1461 XMLPrinter printer2;
1462 doc2.Print(&printer2);
1463
1464 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1465 }
1466
1467 {
1468 // Deep Cloning of sub element.
1469 XMLDocument doc2;
1470 XMLPrinter printer1;
1471 {
1472 // Make sure doc1 is deleted before we test doc2
1473 const char* xml =
1474 "<?xml version ='1.0'?>"
1475 "<root>"
1476 " <child1 foo='bar'/>"
1477 " <!-- comment thing -->"
1478 " <child2 val='1'>Text</child2>"
1479 "</root>";
1480 XMLDocument doc;
1481 doc.Parse(xml);
1482 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
1483
1484 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1485 bool acceptResult = subElement->Accept(&printer1);
1486 XMLTest( "Accept before deep cloning", true, acceptResult );
1487
1488 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1489 doc2.InsertFirstChild(clonedSubElement);
1490 }
1491 XMLPrinter printer2;
1492 doc2.Print(&printer2);
1493
1494 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1495 }
1496
1497 {
1498 // Deep cloning of document.
1499 XMLDocument doc2;
1500 XMLPrinter printer1;
1501 {
1502 // Make sure doc1 is deleted before we test doc2
1503 const char* xml =
1504 "<?xml version ='1.0'?>"
1505 "<!-- Top level comment. -->"
1506 "<root>"
1507 " <child1 foo='bar'/>"
1508 " <!-- comment thing -->"
1509 " <child2 val='1'>Text</child2>"
1510 "</root>";
1511 XMLDocument doc;
1512 doc.Parse(xml);
1513 XMLTest( "Parse before deep cloning document", false, doc.Error() );
1514 doc.Print(&printer1);
1515
1516 doc.DeepCopy(&doc2);
1517 }
1518 XMLPrinter printer2;
1519 doc2.Print(&printer2);
1520
1521 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1522 }
1523
1524
1525 {
1526 // This shouldn't crash.
1527 XMLDocument doc;
1528 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
1529 {
1530 doc.PrintError();
1531 }
1532 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1533 }
1534
1535 {
1536 // Attribute ordering.
1537 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1538 XMLDocument doc;
1539 doc.Parse( xml );
1540 XMLTest( "Parse for attribute ordering", false, doc.Error() );
1541 XMLElement* ele = doc.FirstChildElement();
1542
1543 const XMLAttribute* a = ele->FirstAttribute();
1544 XMLTest( "Attribute order", "1", a->Value() );
1545 a = a->Next();
1546 XMLTest( "Attribute order", "2", a->Value() );
1547 a = a->Next();
1548 XMLTest( "Attribute order", "3", a->Value() );
1549 XMLTest( "Attribute order", "attrib3", a->Name() );
1550
1551 ele->DeleteAttribute( "attrib2" );
1552 a = ele->FirstAttribute();
1553 XMLTest( "Attribute order", "1", a->Value() );
1554 a = a->Next();
1555 XMLTest( "Attribute order", "3", a->Value() );
1556
1557 ele->DeleteAttribute( "attrib1" );
1558 ele->DeleteAttribute( "attrib3" );
1559 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
1560 }
1561
1562 {
1563 // Make sure an attribute with a space in it succeeds.
1564 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1565 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1566 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1567 XMLDocument doc0;
1568 doc0.Parse( xml0 );
1569 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
1570 XMLDocument doc1;
1571 doc1.Parse( xml1 );
1572 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
1573 XMLDocument doc2;
1574 doc2.Parse( xml2 );
1575 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
1576
1577 XMLElement* ele = 0;
1578 ele = doc0.FirstChildElement();
1579 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1580 ele = doc1.FirstChildElement();
1581 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1582 ele = doc2.FirstChildElement();
1583 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
1584 }
1585
1586 {
1587 // Make sure we don't go into an infinite loop.
1588 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1589 XMLDocument doc;
1590 doc.Parse( xml );
1591 XMLTest( "Parse two elements with attribute", false, doc.Error() );
1592 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1593 XMLElement* ele1 = ele0->NextSiblingElement();
1594 bool equal = ele0->ShallowEqual( ele1 );
1595
1596 XMLTest( "Infinite loop in shallow equal.", true, equal );
1597 }
1598
1599 // -------- Handles ------------
1600 {
1601 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1602 XMLDocument doc;
1603 doc.Parse( xml );
1604 XMLTest( "Handle, parse element with attribute and nested element", false, doc.Error() );
1605
1606 {
1607 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1608 XMLTest( "Handle, non-const, element is found", true, ele != 0 );
1609 XMLTest( "Handle, non-const, element name matches", "sub", ele->Value() );
1610 }
1611
1612 {
1613 XMLHandle docH( doc );
1614 XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1615 XMLTest( "Handle, non-const, element not found", true, ele == 0 );
1616 }
1617
1618 {
1619 const XMLElement* ele = XMLConstHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1620 XMLTest( "Handle, const, element is found", true, ele != 0 );
1621 XMLTest( "Handle, const, element name matches", "sub", ele->Value() );
1622 }
1623
1624 {
1625 XMLConstHandle docH( doc );
1626 const XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1627 XMLTest( "Handle, const, element not found", true, ele == 0 );
1628 }
1629 }
1630 {
1631 // Default Declaration & BOM
1632 XMLDocument doc;
1633 doc.InsertEndChild( doc.NewDeclaration() );
1634 doc.SetBOM( true );
1635
1636 XMLPrinter printer;
1637 doc.Print( &printer );
1638
1639 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1640 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1641 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
1642 }
1643 {
1644 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1645 XMLDocument doc;
1646 doc.Parse( xml );
1647 XMLTest( "Ill formed XML", true, doc.Error() );
1648 }
1649
1650 {
1651 //API:IntText(),UnsignedText(),Int64Text(),DoubleText(),BoolText() and FloatText() test
1652 const char* xml = "<point> <IntText>-24</IntText> <UnsignedText>42</UnsignedText> \
1653 <Int64Text>38</Int64Text> <BoolText>true</BoolText> <DoubleText>2.35</DoubleText> </point>";
1654 XMLDocument doc;
1655 doc.Parse(xml);
1656
1657 const XMLElement* pointElement = doc.RootElement();
1658 int test1 = pointElement->FirstChildElement("IntText")->IntText();
1659 XMLTest("IntText() test", -24, test1);
1660
1661 unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
1662 XMLTest("UnsignedText() test", static_cast<unsigned>(42), test2);
1663
1664 int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
1665 XMLTest("Int64Text() test", static_cast<int64_t>(38), test3);
1666
1667 double test4 = pointElement->FirstChildElement("DoubleText")->DoubleText();
1668 XMLTest("DoubleText() test", 2.35, test4);
1669
1670 float test5 = pointElement->FirstChildElement("DoubleText")->FloatText();
1671 XMLTest("FloatText()) test", 2.35f, test5);
1672
1673 bool test6 = pointElement->FirstChildElement("BoolText")->BoolText();
1674 XMLTest("FloatText()) test", true, test6);
1675 }
1676
1677 {
1678 //API:ShallowEqual() test
1679 const char* xml = "<playlist id = 'playlist'>"
1680 "<property name = 'track_name'>voice</property>"
1681 "</playlist>";
1682 XMLDocument doc;
1683 doc.Parse( xml );
1684 const XMLNode* PlaylistNode = doc.RootElement();
1685 const XMLNode* PropertyNode = PlaylistNode->FirstChildElement();
1686 bool result;
1687 result = PlaylistNode->ShallowEqual(PropertyNode);
1688 XMLTest("ShallowEqual() test",false,result);
1689 result = PlaylistNode->ShallowEqual(PlaylistNode);
1690 XMLTest("ShallowEqual() test",true,result);
1691 }
1692
1693 {
1694 //API: previousSiblingElement() and NextSiblingElement() test
1695 const char* xml = "<playlist id = 'playlist'>"
1696 "<property name = 'track_name'>voice</property>"
1697 "<entry out = '946' producer = '2_playlist1' in = '0'/>"
1698 "<blank length = '1'/>"
1699 "</playlist>";
1700 XMLDocument doc;
1701 doc.Parse( xml );
1702 XMLElement* ElementPlaylist = doc.FirstChildElement("playlist");
1703 XMLTest("previousSiblingElement() test",true,ElementPlaylist != 0);
1704 const XMLElement* pre = ElementPlaylist->PreviousSiblingElement();
1705 XMLTest("previousSiblingElement() test",true,pre == 0);
1706 const XMLElement* ElementBlank = ElementPlaylist->FirstChildElement("entry")->NextSiblingElement("blank");
1707 XMLTest("NextSiblingElement() test",true,ElementBlank != 0);
1708 const XMLElement* next = ElementBlank->NextSiblingElement();
1709 XMLTest("NextSiblingElement() test",true,next == 0);
1710 const XMLElement* ElementEntry = ElementBlank->PreviousSiblingElement("entry");
1711 XMLTest("PreviousSiblingElement test",true,ElementEntry != 0);
1712 }
1713
1714 // QueryXYZText
1715 {
1716 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1717 XMLDocument doc;
1718 doc.Parse( xml );
1719 XMLTest( "Parse points", false, doc.Error() );
1720
1721 const XMLElement* pointElement = doc.RootElement();
1722
1723 {
1724 int intValue = 0;
1725 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1726 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1727 XMLTest( "QueryIntText", 1, intValue, false );
1728 }
1729
1730 {
1731 unsigned unsignedValue = 0;
1732 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1733 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1734 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1735 }
1736
1737 {
1738 float floatValue = 0;
1739 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1740 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1741 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1742 }
1743
1744 {
1745 double doubleValue = 0;
1746 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1747 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1748 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1749 }
1750
1751 {
1752 bool boolValue = false;
1753 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1754 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1755 XMLTest( "QueryBoolText", true, boolValue, false );
1756 }
1757 }
1758
1759 {
1760 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1761 XMLDocument doc;
1762 doc.Parse( xml );
1763 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
1764 }
1765
1766 {
1767 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1768 XMLDocument doc;
1769 doc.Parse( xml );
1770 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
1771 }
1772
1773 {
1774 const char* xml = "<3lement></3lement>";
1775 XMLDocument doc;
1776 doc.Parse( xml );
1777 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
1778 }
1779
1780 {
1781 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1782 XMLDocument doc;
1783 doc.Parse( xml, 10 );
1784 XMLTest( "Set length of incoming data", false, doc.Error() );
1785 }
1786
1787 {
1788 XMLDocument doc;
1789 XMLTest( "Document is initially empty", true, doc.NoChildren() );
1790 doc.Clear();
1791 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
1792 doc.LoadFile( "resources/dream.xml" );
1793 XMLTest( "Load dream.xml", false, doc.Error() );
1794 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
1795 doc.Clear();
1796 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
1797 }
1798
1799 {
1800 XMLDocument doc;
1801 XMLTest( "No error initially", false, doc.Error() );
1802 XMLError error = doc.Parse( "This is not XML" );
1803 XMLTest( "Error after invalid XML", true, doc.Error() );
1804 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1805 doc.Clear();
1806 XMLTest( "No error after Clear()", false, doc.Error() );
1807 }
1808
1809 // ----------- Whitespace ------------
1810 {
1811 const char* xml = "<element>"
1812 "<a> This \nis ' text ' </a>"
1813 "<b> This is ' text ' \n</b>"
1814 "<c>This is ' \n\n text '</c>"
1815 "</element>";
1816 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1817 doc.Parse( xml );
1818 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
1819
1820 const XMLElement* element = doc.FirstChildElement();
1821 for( const XMLElement* parent = element->FirstChildElement();
1822 parent;
1823 parent = parent->NextSiblingElement() )
1824 {
1825 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1826 }
1827 }
1828
1829 #if 0
1830 {
1831 // Passes if assert doesn't fire.
1832 XMLDocument xmlDoc;
1833
1834 xmlDoc.NewDeclaration();
1835 xmlDoc.NewComment("Configuration file");
1836
1837 XMLElement *root = xmlDoc.NewElement("settings");
1838 root->SetAttribute("version", 2);
1839 }
1840 #endif
1841
1842 {
1843 const char* xml = "<element> </element>";
1844 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1845 doc.Parse( xml );
1846 XMLTest( "Parse with all whitespaces", false, doc.Error() );
1847 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1848 }
1849
1850 {
1851 // An assert should not fire.
1852 const char* xml = "<element/>";
1853 XMLDocument doc;
1854 doc.Parse( xml );
1855 XMLTest( "Parse with self-closed element", false, doc.Error() );
1856 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1857 XMLTest( "Tracking unused elements", true, ele != 0, false );
1858 }
1859
1860
1861 {
1862 const char* xml = "<parent><child>abc</child></parent>";
1863 XMLDocument doc;
1864 doc.Parse( xml );
1865 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
1866 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1867
1868 XMLPrinter printer;
1869 bool acceptResult = ele->Accept( &printer );
1870 XMLTest( "Accept of sub-element", true, acceptResult );
1871 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1872 }
1873
1874
1875 {
1876 XMLDocument doc;
1877 XMLError error = doc.LoadFile( "resources/empty.xml" );
1878 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
1879 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
1880 doc.PrintError();
1881 }
1882
1883 {
1884 // BOM preservation
1885 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1886 {
1887 XMLDocument doc;
1888 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
1889 XMLPrinter printer;
1890 doc.Print( &printer );
1891
1892 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1893 doc.SaveFile( "resources/out/bomtest.xml" );
1894 XMLTest( "Save bomtest.xml", false, doc.Error() );
1895 }
1896 {
1897 XMLDocument doc;
1898 doc.LoadFile( "resources/out/bomtest.xml" );
1899 XMLTest( "Load bomtest.xml", false, doc.Error() );
1900 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1901
1902 XMLPrinter printer;
1903 doc.Print( &printer );
1904 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1905 }
1906 }
1907
1908 {
1909 // Insertion with Removal
1910 const char* xml = "<?xml version=\"1.0\" ?>"
1911 "<root>"
1912 "<one>"
1913 "<subtree>"
1914 "<elem>element 1</elem>text<!-- comment -->"
1915 "</subtree>"
1916 "</one>"
1917 "<two/>"
1918 "</root>";
1919 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1920 "<root>"
1921 "<one/>"
1922 "<two>"
1923 "<subtree>"
1924 "<elem>element 1</elem>text<!-- comment -->"
1925 "</subtree>"
1926 "</two>"
1927 "</root>";
1928 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1929 "<root>"
1930 "<one/>"
1931 "<subtree>"
1932 "<elem>element 1</elem>text<!-- comment -->"
1933 "</subtree>"
1934 "<two/>"
1935 "</root>";
1936 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1937 "<root>"
1938 "<one/>"
1939 "<two/>"
1940 "<subtree>"
1941 "<elem>element 1</elem>text<!-- comment -->"
1942 "</subtree>"
1943 "</root>";
1944
1945 XMLDocument doc;
1946 doc.Parse(xml);
1947 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
1948 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1949 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1950 two->InsertFirstChild(subtree);
1951 XMLPrinter printer1(0, true);
1952 bool acceptResult = doc.Accept(&printer1);
1953 XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
1954 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
1955
1956 doc.Parse(xml);
1957 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
1958 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1959 two = doc.RootElement()->FirstChildElement("two");
1960 doc.RootElement()->InsertAfterChild(two, subtree);
1961 XMLPrinter printer2(0, true);
1962 acceptResult = doc.Accept(&printer2);
1963 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
1964 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
1965
1966 doc.Parse(xml);
1967 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
1968 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1969 subtree = one->FirstChildElement("subtree");
1970 doc.RootElement()->InsertAfterChild(one, subtree);
1971 XMLPrinter printer3(0, true);
1972 acceptResult = doc.Accept(&printer3);
1973 XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
1974 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
1975
1976 doc.Parse(xml);
1977 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
1978 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1979 two = doc.RootElement()->FirstChildElement("two");
1980 XMLTest("<two> is the last child at root level", true, two == doc.RootElement()->LastChildElement());
1981 doc.RootElement()->InsertEndChild(subtree);
1982 XMLPrinter printer4(0, true);
1983 acceptResult = doc.Accept(&printer4);
1984 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
1985 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
1986 }
1987
1988 {
1989 const char* xml = "<svg width = \"128\" height = \"128\">"
1990 " <text> </text>"
1991 "</svg>";
1992 XMLDocument doc;
1993 doc.Parse(xml);
1994 XMLTest( "Parse svg with text", false, doc.Error() );
1995 doc.Print();
1996 }
1997
1998 {
1999 // Test that it doesn't crash.
2000 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
2001 XMLDocument doc;
2002 doc.Parse(xml);
2003 XMLTest( "Parse root-sample-field0", true, doc.Error() );
2004 doc.PrintError();
2005 }
2006
2007 #if 1
2008 // the question being explored is what kind of print to use:
2009 // https://github.com/leethomason/tinyxml2/issues/63
2010 {
2011 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
2012 const char* xml = "<element/>";
2013 XMLDocument doc;
2014 doc.Parse( xml );
2015 XMLTest( "Parse self-closed empty element", false, doc.Error() );
2016 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
2017 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
2018 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
2019 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
2020 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
2021 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
2022
2023 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
2024 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
2025 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
2026 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
2027 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
2028 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
2029
2030 doc.Print();
2031
2032 /* The result of this test is platform, compiler, and library version dependent. :("
2033 XMLPrinter printer;
2034 doc.Print( &printer );
2035 XMLTest( "Float and double formatting.",
2036 "<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",
2037 printer.CStr(),
2038 true );
2039 */
2040 }
2041 #endif
2042
2043 {
2044 // Issue #184
2045 // If it doesn't assert, it passes. Caused by objects
2046 // getting created during parsing which are then
2047 // inaccessible in the memory pools.
2048 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
2049 {
2050 XMLDocument doc;
2051 doc.Parse(xmlText);
2052 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
2053 }
2054 {
2055 XMLDocument doc;
2056 doc.Parse(xmlText);
2057 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
2058 doc.Clear();
2059 }
2060 }
2061
2062 {
2063 // If this doesn't assert in TINYXML2_DEBUG, all is well.
2064 tinyxml2::XMLDocument doc;
2065 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
2066 doc.DeleteNode(pRoot);
2067 }
2068
2069 {
2070 XMLDocument doc;
2071 XMLElement* root = doc.NewElement( "Root" );
2072 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
2073 doc.InsertEndChild( root );
2074 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
2075 }
2076
2077 {
2078 // If this doesn't assert in TINYXML2_DEBUG, all is well.
2079 XMLDocument doc;
2080 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
2081 XMLElement* linkedRoot = doc.NewElement( "Root" );
2082 doc.InsertFirstChild( linkedRoot );
2083 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
2084 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
2085 }
2086
2087 {
2088 // Should not assert in TINYXML2_DEBUG
2089 XMLPrinter printer;
2090 }
2091
2092 {
2093 // Issue 291. Should not crash
2094 const char* xml = "�</a>";
2095 XMLDocument doc;
2096 doc.Parse( xml );
2097 XMLTest( "Parse hex with closing tag", false, doc.Error() );
2098
2099 XMLPrinter printer;
2100 doc.Print( &printer );
2101 }
2102 {
2103 // Issue 299. Can print elements that are not linked in.
2104 // Will crash if issue not fixed.
2105 XMLDocument doc;
2106 XMLElement* newElement = doc.NewElement( "printme" );
2107 XMLPrinter printer;
2108 bool acceptResult = newElement->Accept( &printer );
2109 XMLTest( "printme - Accept()", true, acceptResult );
2110 // Delete the node to avoid possible memory leak report in debug output
2111 doc.DeleteNode( newElement );
2112 }
2113 {
2114 // Issue 302. Clear errors from LoadFile/SaveFile
2115 XMLDocument doc;
2116 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
2117 doc.SaveFile( "./no/such/path/pretty.xml" );
2118 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
2119 doc.SaveFile( "./resources/out/compact.xml", true );
2120 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
2121 }
2122
2123 {
2124 // If a document fails to load then subsequent
2125 // successful loads should clear the error
2126 XMLDocument doc;
2127 XMLTest( "Should be no error initially", false, doc.Error() );
2128 doc.LoadFile( "resources/no-such-file.xml" );
2129 XMLTest( "No such file - should fail", true, doc.Error() );
2130
2131 doc.LoadFile( "resources/dream.xml" );
2132 XMLTest( "Error should be cleared", false, doc.Error() );
2133 }
2134
2135 {
2136 // Check that declarations are allowed only at beginning of document
2137 const char* xml0 = "<?xml version=\"1.0\" ?>"
2138 " <!-- xml version=\"1.1\" -->"
2139 "<first />";
2140 const char* xml1 = "<?xml version=\"1.0\" ?>"
2141 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
2142 "<first />";
2143 const char* xml2 = "<first />"
2144 "<?xml version=\"1.0\" ?>";
2145 const char* xml3 = "<first></first>"
2146 "<?xml version=\"1.0\" ?>";
2147
2148 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
2149
2150 XMLDocument doc;
2151 doc.Parse(xml0);
2152 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
2153 doc.Parse(xml1);
2154 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
2155 doc.Parse(xml2);
2156 XMLTest("Test that declaration after self-closed child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
2157 doc.Parse(xml3);
2158 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
2159 doc.Parse(xml4);
2160 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
2161 }
2162
2163 {
2164 // No matter - before or after successfully parsing a text -
2165 // calling XMLDocument::Value() used to cause an assert in debug.
2166 // Null must be returned.
2167 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
2168 "<first />"
2169 "<second />";
2170 XMLDocument* doc = new XMLDocument();
2171 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2172 doc->Parse( validXml );
2173 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
2174 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2175 delete doc;
2176 }
2177
2178 {
2179 XMLDocument doc;
2180 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
2181 const XMLError error = static_cast<XMLError>(i);
2182 const char* name = XMLDocument::ErrorIDToName(error);
2183 XMLTest( "ErrorName() not null after ClearError()", true, name != 0 );
2184 if( name == 0 ) {
2185 // passing null pointer into strlen() is undefined behavior, so
2186 // compiler is allowed to optimise away the null test above if it's
2187 // as reachable as the strlen() call
2188 continue;
2189 }
2190 XMLTest( "ErrorName() not empty after ClearError()", true, strlen(name) > 0 );
2191 }
2192 }
2193
2194 {
2195 const char* html("<!DOCTYPE html><html><body><p>test</p><p><br/></p></body></html>");
2196 XMLDocument doc(false);
2197 doc.Parse(html);
2198
2199 XMLPrinter printer(0, true);
2200 doc.Print(&printer);
2201
2202 XMLTest(html, html, printer.CStr());
2203 }
2204
2205 {
2206 // Evil memory leaks.
2207 // If an XMLElement (etc) is allocated via NewElement() (etc.)
2208 // and NOT added to the XMLDocument, what happens?
2209 //
2210 // Previously (buggy):
2211 // The memory would be free'd when the XMLDocument is
2212 // destructed. But the XMLElement destructor wasn't called, so
2213 // memory allocated for the XMLElement text would not be free'd.
2214 // In practice this meant strings allocated for the XMLElement
2215 // text would be leaked. An edge case, but annoying.
2216 // Now:
2217 // The XMLElement destructor is called. But the unlinked nodes
2218 // have to be tracked using a list. This has a minor performance
2219 // impact that can become significant if you have a lot of
2220 // unlinked nodes. (But why would you do that?)
2221 // The only way to see this bug was in a Visual C++ runtime debug heap
2222 // leak tracker. This is compiled in by default on Windows Debug and
2223 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
2224 {
2225 XMLDocument doc;
2226 doc.NewElement("LEAK 1");
2227 }
2228 {
2229 XMLDocument doc;
2230 XMLElement* ele = doc.NewElement("LEAK 2");
2231 doc.DeleteNode(ele);
2232 }
2233 }
2234
2235 {
2236 // Bad bad crash. Parsing error results in stack overflow, if uncaught.
2237 const char* TESTS[] = {
2238 "./resources/xmltest-5330.xml",
2239 "./resources/xmltest-4636783552757760.xml",
2240 "./resources/xmltest-5720541257269248.xml",
2241 0
2242 };
2243 for (int i=0; TESTS[i]; ++i) {
2244 XMLDocument doc;
2245 doc.LoadFile(TESTS[i]);
2246 XMLTest("Stack overflow prevented.", XML_ELEMENT_DEPTH_EXCEEDED, doc.ErrorID());
2247 }
2248 }
2249 {
2250 const char* TESTS[] = {
2251 "./resources/xmltest-5662204197076992.xml", // Security-level performance issue.
2252 0
2253 };
2254 for (int i = 0; TESTS[i]; ++i) {
2255 XMLDocument doc;
2256 doc.LoadFile(TESTS[i]);
2257 // Need only not crash / lock up.
2258 XMLTest("Fuzz attack prevented.", true, true);
2259 }
2260 }
2261 {
2262 // Crashing reported via email.
2263 const char* xml =
2264 "<playlist id='playlist1'>"
2265 "<property name='track_name'>voice</property>"
2266 "<property name='audio_track'>1</property>"
2267 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2268 "<blank length = '1' />"
2269 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2270 "<blank length = '2' />"
2271 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2272 "<blank length = '1' />"
2273 "<entry out = '128' producer = '1_playlist1' in = '0' />"
2274 "</playlist>";
2275
2276 // It's not a good idea to delete elements as you walk the
2277 // list. I'm not sure this technically should work; but it's
2278 // an interesting test case.
2279 XMLDocument doc;
2280 XMLError err = doc.Parse(xml);
2281 XMLTest("Crash bug parsing", XML_SUCCESS, err );
2282
2283 XMLElement* playlist = doc.FirstChildElement("playlist");
2284 XMLTest("Crash bug parsing", true, playlist != 0);
2285
2286 {
2287 const char* elementName = "entry";
2288 XMLElement* entry = playlist->FirstChildElement(elementName);
2289 XMLTest("Crash bug parsing", true, entry != 0);
2290 while (entry) {
2291 XMLElement* todelete = entry;
2292 entry = entry->NextSiblingElement(elementName);
2293 playlist->DeleteChild(todelete);
2294 }
2295 entry = playlist->FirstChildElement(elementName);
2296 XMLTest("Crash bug parsing", true, entry == 0);
2297 }
2298 {
2299 const char* elementName = "blank";
2300 XMLElement* blank = playlist->FirstChildElement(elementName);
2301 XMLTest("Crash bug parsing", true, blank != 0);
2302 while (blank) {
2303 XMLElement* todelete = blank;
2304 blank = blank->NextSiblingElement(elementName);
2305 playlist->DeleteChild(todelete);
2306 }
2307 XMLTest("Crash bug parsing", true, blank == 0);
2308 }
2309
2310 tinyxml2::XMLPrinter printer;
2311 const bool acceptResult = playlist->Accept(&printer);
2312 XMLTest("Crash bug parsing - Accept()", true, acceptResult);
2313 printf("%s\n", printer.CStr());
2314
2315 // No test; it only need to not crash.
2316 // Still, wrap it up with a sanity check
2317 int nProperty = 0;
2318 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2319 nProperty++;
2320 }
2321 XMLTest("Crash bug parsing", 2, nProperty);
2322 }
2323
2324 // ----------- Line Number Tracking --------------
2325 {
2326 struct TestUtil: XMLVisitor
2327 {
2328 TestUtil() : str() {}
2329
2330 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2331 {
2332 XMLDocument doc;
2333 const XMLError parseError = doc.Parse(docStr);
2334
2335 XMLTest(testString, parseError, doc.ErrorID());
2336 XMLTest(testString, true, doc.Error());
2337 XMLTest(testString, expected_error, parseError);
2338 XMLTest(testString, expectedLine, doc.ErrorLineNum());
2339 };
2340
2341 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2342 {
2343 XMLDocument doc;
2344 doc.Parse(docStr);
2345 XMLTest(testString, false, doc.Error());
2346 TestDocLines(testString, doc, expectedLines);
2347 }
2348
2349 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2350 {
2351 XMLDocument doc;
2352 doc.LoadFile(file_name);
2353 XMLTest(testString, false, doc.Error());
2354 TestDocLines(testString, doc, expectedLines);
2355 }
2356
2357 private:
2358 DynArray<char, 10> str;
2359
2360 void Push(char type, int lineNum)
2361 {
2362 str.Push(type);
2363 str.Push(char('0' + (lineNum / 10)));
2364 str.Push(char('0' + (lineNum % 10)));
2365 }
2366
2367 bool VisitEnter(const XMLDocument& doc)
2368 {
2369 Push('D', doc.GetLineNum());
2370 return true;
2371 }
2372 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2373 {
2374 Push('E', element.GetLineNum());
2375 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
2376 Push('A', attr->GetLineNum());
2377 return true;
2378 }
2379 bool Visit(const XMLDeclaration& declaration)
2380 {
2381 Push('L', declaration.GetLineNum());
2382 return true;
2383 }
2384 bool Visit(const XMLText& text)
2385 {
2386 Push('T', text.GetLineNum());
2387 return true;
2388 }
2389 bool Visit(const XMLComment& comment)
2390 {
2391 Push('C', comment.GetLineNum());
2392 return true;
2393 }
2394 bool Visit(const XMLUnknown& unknown)
2395 {
2396 Push('U', unknown.GetLineNum());
2397 return true;
2398 }
2399
2400 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2401 {
2402 str.Clear();
2403 const bool acceptResult = doc.Accept(this);
2404 XMLTest(testString, true, acceptResult);
2405 str.Push(0);
2406 XMLTest(testString, expectedLines, str.Mem());
2407 }
2408 } tester;
2409
2410 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2411 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2412 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2413 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2414 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2415 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2416 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2417 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2418 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2419 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2420 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
2421
2422 tester.TestStringLines(
2423 "LineNumbers-String",
2424
2425 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2426 "<root a='b' \n" // 2 Element Attribute
2427 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2428 "newline in text \n" // 4 Text
2429 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2430 " cdata test ]]><!-- comment -->\n" // 6 Comment
2431 "<! unknown></root>", // 7 Unknown
2432
2433 "D01L01E02A02A03T03E03T04E05T05C06U07");
2434
2435 tester.TestStringLines(
2436 "LineNumbers-CRLF",
2437
2438 "\r\n" // 1 Doc (arguably should be line 2)
2439 "<?xml version=\"1.0\"?>\n" // 2 DecL
2440 "<root>\r\n" // 3 Element
2441 "\n" // 4
2442 "text contining new line \n" // 5 Text
2443 " and also containing crlf \r\n" // 6
2444 "<sub><![CDATA[\n" // 7 Element Text
2445 "cdata containing new line \n" // 8
2446 " and also containing cflr\r\n" // 9
2447 "]]></sub><sub2/></root>", // 10 Element
2448
2449 "D01L02E03T05E07T07E10");
2450
2451 tester.TestFileLines(
2452 "LineNumbers-File",
2453 "resources/utf8test.xml",
2454 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2455 }
2456
2457 {
2458 const char* xml = "<Hello>Text</Error>";
2459 XMLDocument doc;
2460 doc.Parse(xml);
2461 XMLTest("Test mismatched elements.", true, doc.Error());
2462 XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2463 // For now just make sure calls work & doesn't crash.
2464 // May solidify the error output in the future.
2465 printf("%s\n", doc.ErrorStr());
2466 doc.PrintError();
2467 }
2468
2469 // ----------- Performance tracking --------------
2470 {
2471 #if defined( _MSC_VER )
2472 __int64 start, end, freq;
2473 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
2474 #endif
2475
2476 FILE* perfFP = fopen("resources/dream.xml", "r");
2477 XMLTest("Open dream.xml", true, perfFP != 0);
2478 fseek(perfFP, 0, SEEK_END);
2479 long size = ftell(perfFP);
2480 fseek(perfFP, 0, SEEK_SET);
2481
2482 char* mem = new char[size + 1];
2483 memset(mem, 0xfe, size);
2484 size_t bytesRead = fread(mem, 1, size, perfFP);
2485 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
2486 fclose(perfFP);
2487 mem[size] = 0;
2488
2489 #if defined( _MSC_VER )
2490 QueryPerformanceCounter((LARGE_INTEGER*)&start);
2491 #else
2492 clock_t cstart = clock();
2493 #endif
2494 bool parseDreamXmlFailed = false;
2495 static const int COUNT = 10;
2496 for (int i = 0; i < COUNT; ++i) {
2497 XMLDocument doc;
2498 doc.Parse(mem);
2499 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
2500 }
2501 #if defined( _MSC_VER )
2502 QueryPerformanceCounter((LARGE_INTEGER*)&end);
2503 #else
2504 clock_t cend = clock();
2505 #endif
2506 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
2507
2508 delete[] mem;
2509
2510 static const char* note =
2511 #ifdef TINYXML2_DEBUG
2512 "DEBUG";
2513 #else
2514 "Release";
2515 #endif
2516
2517 #if defined( _MSC_VER )
2518 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
2519 #else
2520 const double duration = (double)(cend - cstart) / (double)COUNT;
2521 #endif
2522 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
2523 }
2524
2525 #if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
2526 {
2527 _CrtMemCheckpoint( &endMemState );
2528
2529 _CrtMemState diffMemState;
2530 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2531 _CrtMemDumpStatistics( &diffMemState );
2532
2533 {
2534 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2535 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2536 }
2537 }
2538 #endif
2539
2540 printf ("\nPass %d, Fail %d\n", gPass, gFail);
2541
2542 return gFail;
2543 }
2544