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