blob: 91a5626958010198aff3cf8df7d791eef48eee1f [file] [log] [blame]
Lee Thomason5b0a6772012-11-19 13:54:42 -08001#if defined( _MSC_VER )
Serhat Eser Erdemca5d6842014-04-17 14:06:15 +02002 #if !defined( _CRT_SECURE_NO_WARNINGS )
3 #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
4 #endif
Lee Thomason5b0a6772012-11-19 13:54:42 -08005#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08006
Lee Thomason5b0a6772012-11-19 13:54:42 -08007#include "tinyxml2.h"
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07008#include <cstdlib>
9#include <cstring>
10#include <ctime>
U-Lama\Leee13c3e62011-12-28 14:36:55 -080011
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080012#if defined( _MSC_VER )
Lee Thomason1ff38e02012-02-14 18:18:16 -080013 #include <crtdbg.h>
Lee Thomason6f381b72012-03-02 12:59:39 -080014 #define WIN32_LEAN_AND_MEAN
15 #include <windows.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080016 _CrtMemState startMemState;
Lee Thomason53858b42017-06-01 19:09:16 -070017 _CrtMemState endMemState;
Lee Thomason1ff38e02012-02-14 18:18:16 -080018#endif
Lee Thomasone9ecdab2012-02-13 18:11:20 -080019
U-Lama\Leee13c3e62011-12-28 14:36:55 -080020using namespace tinyxml2;
Anton Indrawan8a0006c2014-11-20 18:27:07 +010021using namespace std;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080022int gPass = 0;
23int gFail = 0;
24
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080025
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070026bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080027{
Sarat Addepalli13b2d732015-05-19 12:44:57 +053028 bool pass;
29 if ( !expected && !found )
30 pass = true;
31 else if ( !expected || !found )
32 pass = false;
Sarat Addepallid608c562015-05-20 10:19:00 +053033 else
34 pass = !strcmp( expected, found );
Lee Thomason1ff38e02012-02-14 18:18:16 -080035 if ( pass )
36 printf ("[pass]");
37 else
38 printf ("[fail]");
39
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070040 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080041 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070042 }
43 else {
44 if ( extraNL ) {
45 printf( " %s\n", testString );
46 printf( "%s\n", expected );
47 printf( "%s\n", found );
48 }
49 else {
50 printf (" %s [%s][%s]\n", testString, expected, found);
51 }
52 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080053
54 if ( pass )
55 ++gPass;
56 else
57 ++gFail;
58 return pass;
59}
60
kezenator5a700712016-11-26 13:54:42 +100061bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
62{
Lee Thomasone90e9012016-12-24 07:34:39 -080063 return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
kezenator5a700712016-11-26 13:54:42 +100064}
65
66bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
67{
68 return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
69}
Lee Thomason1ff38e02012-02-14 18:18:16 -080070
Lee Thomason21be8822012-07-15 17:27:22 -070071template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080072{
73 bool pass = ( expected == found );
74 if ( pass )
75 printf ("[pass]");
76 else
77 printf ("[fail]");
78
U-Stream\Lee09a11c52012-02-17 08:31:16 -080079 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080080 printf (" %s\n", testString);
81 else
Lee Thomasonc8312792012-07-16 12:44:41 -070082 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080083
84 if ( pass )
85 ++gPass;
86 else
87 ++gFail;
88 return pass;
89}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080090
U-Lama\Leee13c3e62011-12-28 14:36:55 -080091
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080092void NullLineEndings( char* p )
93{
94 while( p && *p ) {
95 if ( *p == '\n' || *p == '\r' ) {
96 *p = 0;
97 return;
98 }
99 ++p;
100 }
101}
102
103
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700104int example_1()
105{
106 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300107 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700108
109 return doc.ErrorID();
110}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200111/** @page Example-1 Load an XML File
112 * @dontinclude ./xmltest.cpp
113 * Basic XML file loading.
114 * The basic syntax to load an XML file from
115 * disk and check for an error. (ErrorID()
116 * will return 0 for no error.)
117 * @skip example_1()
118 * @until }
119 */
120
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700121
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700122int example_2()
123{
124 static const char* xml = "<element/>";
125 XMLDocument doc;
126 doc.Parse( xml );
127
128 return doc.ErrorID();
129}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200130/** @page Example-2 Parse an XML from char buffer
131 * @dontinclude ./xmltest.cpp
132 * Basic XML string parsing.
133 * The basic syntax to parse an XML for
134 * a char* and check for an error. (ErrorID()
135 * will return 0 for no error.)
136 * @skip example_2()
137 * @until }
138 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700139
140
141int example_3()
142{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700143 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700144 "<?xml version=\"1.0\"?>"
145 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
146 "<PLAY>"
147 "<TITLE>A Midsummer Night's Dream</TITLE>"
148 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700149
150 XMLDocument doc;
151 doc.Parse( xml );
152
153 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
154 const char* title = titleElement->GetText();
155 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700156
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700157 XMLText* textNode = titleElement->FirstChild()->ToText();
158 title = textNode->Value();
159 printf( "Name of play (2): %s\n", title );
160
161 return doc.ErrorID();
162}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200163/** @page Example-3 Get information out of XML
164 @dontinclude ./xmltest.cpp
165 In this example, we navigate a simple XML
166 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700167 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200168 checking; working code should check for null
169 pointers when walking an XML tree, or use
170 XMLHandle.
171
172 (The XML is an excerpt from "dream.xml").
173
174 @skip example_3()
175 @until </PLAY>";
176
177 The structure of the XML file is:
178
179 <ul>
180 <li>(declaration)</li>
181 <li>(dtd stuff)</li>
182 <li>Element "PLAY"</li>
183 <ul>
184 <li>Element "TITLE"</li>
185 <ul>
186 <li>Text "A Midsummer Night's Dream"</li>
187 </ul>
188 </ul>
189 </ul>
190
191 For this example, we want to print out the
192 title of the play. The text of the title (what
193 we want) is child of the "TITLE" element which
194 is a child of the "PLAY" element.
195
196 We want to skip the declaration and dtd, so the
197 method FirstChildElement() is a good choice. The
198 FirstChildElement() of the Document is the "PLAY"
199 Element, the FirstChildElement() of the "PLAY" Element
200 is the "TITLE" Element.
201
202 @until ( "TITLE" );
203
204 We can then use the convenience function GetText()
205 to get the title of the play.
206
207 @until title );
208
209 Text is just another Node in the XML DOM. And in
210 fact you should be a little cautious with it, as
211 text nodes can contain elements.
212
213 @verbatim
214 Consider: A Midsummer Night's <b>Dream</b>
215 @endverbatim
216
217 It is more correct to actually query the Text Node
218 if in doubt:
219
220 @until title );
221
222 Noting that here we use FirstChild() since we are
223 looking for XMLText, not an element, and ToText()
224 is a cast from a Node to a XMLText.
225*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700226
227
Lee Thomason21be8822012-07-15 17:27:22 -0700228bool example_4()
229{
230 static const char* xml =
231 "<information>"
232 " <attributeApproach v='2' />"
233 " <textApproach>"
234 " <v>2</v>"
235 " </textApproach>"
236 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700237
Lee Thomason21be8822012-07-15 17:27:22 -0700238 XMLDocument doc;
239 doc.Parse( xml );
240
241 int v0 = 0;
242 int v1 = 0;
243
244 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
245 attributeApproachElement->QueryIntAttribute( "v", &v0 );
246
247 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
248 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
249
250 printf( "Both values are the same: %d and %d\n", v0, v1 );
251
252 return !doc.Error() && ( v0 == v1 );
253}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200254/** @page Example-4 Read attributes and text information.
255 @dontinclude ./xmltest.cpp
256
257 There are fundamentally 2 ways of writing a key-value
258 pair into an XML file. (Something that's always annoyed
259 me about XML.) Either by using attributes, or by writing
260 the key name into an element and the value into
261 the text node wrapped by the element. Both approaches
262 are illustrated in this example, which shows two ways
263 to encode the value "2" into the key "v":
264
265 @skip example_4()
266 @until "</information>";
267
268 TinyXML-2 has accessors for both approaches.
269
270 When using an attribute, you navigate to the XMLElement
271 with that attribute and use the QueryIntAttribute()
272 group of methods. (Also QueryFloatAttribute(), etc.)
273
274 @skip XMLElement* attributeApproachElement
275 @until &v0 );
276
277 When using the text approach, you need to navigate
278 down one more step to the XMLElement that contains
279 the text. Note the extra FirstChildElement( "v" )
280 in the code below. The value of the text can then
281 be safely queried with the QueryIntText() group
282 of methods. (Also QueryFloatText(), etc.)
283
284 @skip XMLElement* textApproachElement
285 @until &v1 );
286*/
Lee Thomason21be8822012-07-15 17:27:22 -0700287
288
Lee Thomason178e4cc2013-01-25 16:19:05 -0800289int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800290{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800291 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800292 _CrtMemCheckpoint( &startMemState );
Dmitry-Me99916592014-10-23 11:37:03 +0400293 // Enable MS Visual C++ debug heap memory leaks dump on exit
294 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
Dmitry-Meed785702017-06-15 13:39:53 +0300295 {
296 int leaksOnStart = _CrtDumpMemoryLeaks();
297 XMLTest( "No leaks on start?", FALSE, leaksOnStart );
298 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700299 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800300
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300301 {
302 TIXMLASSERT( true );
303 }
304
Lee Thomason178e4cc2013-01-25 16:19:05 -0800305 if ( argc > 1 ) {
306 XMLDocument* doc = new XMLDocument();
307 clock_t startTime = clock();
308 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100309 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800310 int errorID = doc->ErrorID();
311 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100312 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800313
314 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
315 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700316 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
317 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
318 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800319 }
320 exit(0);
321 }
322
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300323 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700324 if ( !fp ) {
325 printf( "Error opening test file 'dream.xml'.\n"
326 "Is your working directory the same as where \n"
327 "the xmltest.cpp and dream.xml file are?\n\n"
328 #if defined( _MSC_VER )
329 "In windows Visual Studio you may need to set\n"
330 "Properties->Debugging->Working Directory to '..'\n"
331 #endif
332 );
333 exit( 1 );
334 }
335 fclose( fp );
336
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700337 XMLTest( "Example-1", 0, example_1() );
338 XMLTest( "Example-2", 0, example_2() );
339 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700340 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700341
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700342 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700343
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800344 {
Lee Thomason43f59302012-02-06 18:18:11 -0800345 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400346 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800347 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400348 "<element><subelement></subelement></element>",
349 "<element><subelement><subsub/></subelement></element>",
350 "<!--comment beside elements--><element><subelement></subelement></element>",
351 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
352 "<element attrib1='foo' attrib2=\"bar\" ></element>",
353 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800354 "<element>Text inside element.</element>",
355 "<element><b></b></element>",
356 "<element>Text inside and <b>bolded</b> in the element.</element>",
357 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800358 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800359 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800360 0
361 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800362 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800363 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800364 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800365 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800366 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800367 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800368 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800369#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800370 {
371 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400372 " line 2\r"
373 " line 3\r\n"
374 " line 4\n\r"
375 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800376
377 XMLDocument doc;
378 doc.Parse( test );
379 doc.Print();
380 }
381
Lee Thomason2c85a712012-01-31 08:24:24 -0800382 {
383 static const char* test = "<element>Text before.</element>";
384 XMLDocument doc;
385 doc.Parse( test );
386 XMLElement* root = doc.FirstChildElement();
387 XMLElement* newElement = doc.NewElement( "Subelement" );
388 root->InsertEndChild( newElement );
389 doc.Print();
390 }
Lee Thomasond1983222012-02-06 08:41:24 -0800391 {
392 XMLDocument* doc = new XMLDocument();
393 static const char* test = "<element><sub/></element>";
394 doc->Parse( test );
395 delete doc;
396 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800397 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800398 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800399 // Build:
400 // <element>
401 // <!--comment-->
402 // <sub attrib="1" />
403 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800404 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800405 // <element>
406
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800407 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800408 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
409
410 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
411 for( int i=0; i<3; ++i ) {
412 sub[i]->SetAttribute( "attrib", i );
413 }
414 element->InsertEndChild( sub[2] );
415 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700416 comment->SetUserData((void*)2);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800417 element->InsertAfterChild( comment, sub[0] );
418 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800419 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800420 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800421 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
422 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
423 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700424 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800425 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Lee Thomasonc9445462016-07-17 22:53:48 -0700426 XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800427
428 // And now deletion:
429 element->DeleteChild( sub[2] );
430 doc->DeleteNode( comment );
431
432 element->FirstChildElement()->SetAttribute( "attrib", true );
433 element->LastChildElement()->DeleteAttribute( "attrib" );
434
435 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700436 int value1 = 10;
437 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", 10 );
438 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
Lee Thomason21be8822012-07-15 17:27:22 -0700439 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700440 XMLTest( "Programmatic DOM", value1, 10 );
441 XMLTest( "Programmatic DOM", value2, 10 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800442
443 doc->Print();
444
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700445 {
446 XMLPrinter streamer;
447 doc->Print( &streamer );
448 printf( "%s", streamer.CStr() );
449 }
450 {
451 XMLPrinter streamer( 0, true );
452 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200453 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700454 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700455 doc->SaveFile( "./resources/out/pretty.xml" );
456 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800457 delete doc;
458 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800459 {
460 // Test: Dream
461 // XML1 : 1,187,569 bytes in 31,209 allocations
462 // XML2 : 469,073 bytes in 323 allocations
463 //int newStart = gNew;
464 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300465 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800466
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400467 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800468 doc.PrintError();
469
470 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400471 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800472 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
473 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
474 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
475 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400476 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800477 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400478 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800479
480 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400481 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800482 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400483 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800484 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
485 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
486 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
487 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400488 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800489
490 //gNewTotal = gNew - newStart;
491 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800492
493
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800494 {
495 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
496 "<passages count=\"006\" formatversion=\"20020620\">\n"
497 " <wrong error>\n"
498 "</passages>";
499
500 XMLDocument doc;
501 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800502 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800503 }
504
505 {
506 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
507
508 XMLDocument doc;
509 doc.Parse( str );
510
511 XMLElement* ele = doc.FirstChildElement();
512
513 int iVal, result;
514 double dVal;
515
516 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700517 XMLTest( "Query attribute: int as double", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800518 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700519 XMLTest( "Query attribute: int as double", (int)ele->DoubleAttribute("attr0"), 1);
520
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800521 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700522 XMLTest( "Query attribute: double as double", result, (int)XML_SUCCESS);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700523 XMLTest( "Query attribute: double as double", dVal, 2.0 );
524 XMLTest( "Query attribute: double as double", ele->DoubleAttribute("attr1"), 2.0 );
525
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800526 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason85536252016-06-04 19:10:53 -0700527 XMLTest( "Query attribute: double as int", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800528 XMLTest( "Query attribute: double as int", iVal, 2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700529
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800530 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700531 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700532 XMLTest( "Query attribute: not a number", ele->DoubleAttribute("attr2", 4.0), 4.0 );
533
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800534 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700535 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700536 XMLTest( "Query attribute: does not exist", ele->BoolAttribute("bar", true), true );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800537 }
538
539 {
540 const char* str = "<doc/>";
541
542 XMLDocument doc;
543 doc.Parse( str );
544
545 XMLElement* ele = doc.FirstChildElement();
546
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800547 int iVal, iVal2;
548 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800549
550 ele->SetAttribute( "str", "strValue" );
551 ele->SetAttribute( "int", 1 );
552 ele->SetAttribute( "double", -1.0 );
553
554 const char* cStr = ele->Attribute( "str" );
555 ele->QueryIntAttribute( "int", &iVal );
556 ele->QueryDoubleAttribute( "double", &dVal );
557
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800558 ele->QueryAttribute( "int", &iVal2 );
559 ele->QueryAttribute( "double", &dVal2 );
560
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700561 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800562 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
563 XMLTest( "Attribute round trip. int.", 1, iVal );
564 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800565 XMLTest( "Alternate query", true, iVal == iVal2 );
566 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700567 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
568 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800569 }
570
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800571 {
572 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300573 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800574
575 // Get the attribute "value" from the "Russian" element and check it.
576 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700577 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800578 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
579
580 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
581
582 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
583 0xd1U, 0x81U, 0xd1U, 0x81U,
584 0xd0U, 0xbaU, 0xd0U, 0xb8U,
585 0xd0U, 0xb9U, 0 };
586 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
587
588 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
589 XMLTest( "UTF-8: Browsing russian element name.",
590 russianText,
591 text->Value() );
592
593 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400594 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800595
596 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800597 int okay = 0;
598
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200599 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300600 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800601
602 if ( saved && verify )
603 {
604 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700605 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800606 while ( fgets( verifyBuf, 256, verify ) )
607 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700608 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800609 fgets( savedBuf, 256, saved );
610 NullLineEndings( verifyBuf );
611 NullLineEndings( savedBuf );
612
613 if ( strcmp( verifyBuf, savedBuf ) )
614 {
615 printf( "verify:%s<\n", verifyBuf );
616 printf( "saved :%s<\n", savedBuf );
617 okay = 0;
618 break;
619 }
620 }
621 }
622 if ( saved )
623 fclose( saved );
624 if ( verify )
625 fclose( verify );
626 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
627 }
628
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800629 // --------GetText()-----------
630 {
631 const char* str = "<foo>This is text</foo>";
632 XMLDocument doc;
633 doc.Parse( str );
634 const XMLElement* element = doc.RootElement();
635
636 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
637
638 str = "<foo><b>This is text</b></foo>";
639 doc.Parse( str );
640 element = doc.RootElement();
641
642 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
643 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800644
Lee Thomasond6277762012-02-22 16:00:12 -0800645
Uli Kusterer321072e2014-01-21 01:57:38 +0100646 // --------SetText()-----------
647 {
648 const char* str = "<foo></foo>";
649 XMLDocument doc;
650 doc.Parse( str );
651 XMLElement* element = doc.RootElement();
652
Lee Thomason9c0678a2014-01-24 10:18:27 -0800653 element->SetText("darkness.");
654 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100655
Lee Thomason9c0678a2014-01-24 10:18:27 -0800656 element->SetText("blue flame.");
657 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100658
659 str = "<foo/>";
660 doc.Parse( str );
661 element = doc.RootElement();
662
Lee Thomason9c0678a2014-01-24 10:18:27 -0800663 element->SetText("The driver");
664 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100665
Lee Thomason9c0678a2014-01-24 10:18:27 -0800666 element->SetText("<b>horses</b>");
667 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
668 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100669
670 str = "<foo><bar>Text in nested element</bar></foo>";
671 doc.Parse( str );
672 element = doc.RootElement();
673
Lee Thomason9c0678a2014-01-24 10:18:27 -0800674 element->SetText("wolves");
675 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800676
677 str = "<foo/>";
678 doc.Parse( str );
679 element = doc.RootElement();
680
681 element->SetText( "str" );
682 XMLTest( "SetText types", "str", element->GetText() );
683
684 element->SetText( 1 );
685 XMLTest( "SetText types", "1", element->GetText() );
686
687 element->SetText( 1U );
688 XMLTest( "SetText types", "1", element->GetText() );
689
690 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200691 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800692
693 element->SetText( 1.5f );
694 XMLTest( "SetText types", "1.5", element->GetText() );
695
696 element->SetText( 1.5 );
697 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100698 }
699
Lee Thomason51c12712016-06-04 20:18:49 -0700700 // ---------- Attributes ---------
701 {
702 static const int64_t BIG = -123456789012345678;
703 XMLDocument doc;
704 XMLElement* element = doc.NewElement("element");
705 doc.InsertFirstChild(element);
706
707 {
708 element->SetAttribute("attrib", int(-100));
709 int v = 0;
710 element->QueryIntAttribute("attrib", &v);
711 XMLTest("Attribute: int", -100, v, true);
712 element->QueryAttribute("attrib", &v);
713 XMLTest("Attribute: int", -100, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700714 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700715 }
716 {
717 element->SetAttribute("attrib", unsigned(100));
718 unsigned v = 0;
719 element->QueryUnsignedAttribute("attrib", &v);
720 XMLTest("Attribute: unsigned", unsigned(100), v, true);
721 element->QueryAttribute("attrib", &v);
722 XMLTest("Attribute: unsigned", unsigned(100), v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700723 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700724 }
725 {
726 element->SetAttribute("attrib", BIG);
727 int64_t v = 0;
728 element->QueryInt64Attribute("attrib", &v);
729 XMLTest("Attribute: int64_t", BIG, v, true);
730 element->QueryAttribute("attrib", &v);
731 XMLTest("Attribute: int64_t", BIG, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700732 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700733 }
734 {
735 element->SetAttribute("attrib", true);
736 bool v = false;
737 element->QueryBoolAttribute("attrib", &v);
738 XMLTest("Attribute: bool", true, v, true);
739 element->QueryAttribute("attrib", &v);
740 XMLTest("Attribute: bool", true, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700741 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700742 }
743 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800744 element->SetAttribute("attrib", true);
745 const char* result = element->Attribute("attrib");
746 XMLTest("Bool true is 'true'", "true", result);
747
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800748 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800749 element->SetAttribute("attrib", true);
750 result = element->Attribute("attrib");
751 XMLTest("Bool true is '1'", "1", result);
752
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800753 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800754 }
755 {
Lee Thomason51c12712016-06-04 20:18:49 -0700756 element->SetAttribute("attrib", 100.0);
757 double v = 0;
758 element->QueryDoubleAttribute("attrib", &v);
759 XMLTest("Attribute: double", 100.0, v, true);
760 element->QueryAttribute("attrib", &v);
761 XMLTest("Attribute: double", 100.0, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700762 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700763 }
764 {
765 element->SetAttribute("attrib", 100.0f);
766 float v = 0;
767 element->QueryFloatAttribute("attrib", &v);
768 XMLTest("Attribute: float", 100.0f, v, true);
769 element->QueryAttribute("attrib", &v);
770 XMLTest("Attribute: float", 100.0f, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700771 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700772 }
773 {
774 element->SetText(BIG);
775 int64_t v = 0;
776 element->QueryInt64Text(&v);
777 XMLTest("Element: int64_t", BIG, v, true);
778 }
779 }
780
781 // ---------- XMLPrinter stream mode ------
782 {
783 {
784 FILE* printerfp = fopen("resources/printer.xml", "w");
785 XMLPrinter printer(printerfp);
786 printer.OpenElement("foo");
787 printer.PushAttribute("attrib-text", "text");
788 printer.PushAttribute("attrib-int", int(1));
789 printer.PushAttribute("attrib-unsigned", unsigned(2));
790 printer.PushAttribute("attrib-int64", int64_t(3));
791 printer.PushAttribute("attrib-bool", true);
792 printer.PushAttribute("attrib-double", 4.0);
793 printer.CloseElement();
794 fclose(printerfp);
795 }
796 {
797 XMLDocument doc;
798 doc.LoadFile("resources/printer.xml");
799 XMLTest("XMLPrinter Stream mode: load", doc.ErrorID(), XML_SUCCESS, true);
800
801 const XMLDocument& cdoc = doc;
802
803 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
804 XMLTest("attrib-text", "text", attrib->Value(), true);
805 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
806 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
807 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
808 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
809 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
810 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
811 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
812 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
813 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
814 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
815 }
816
817 }
818
Uli Kusterer321072e2014-01-21 01:57:38 +0100819
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800820 // ---------- CDATA ---------------
821 {
822 const char* str = "<xmlElement>"
823 "<![CDATA["
824 "I am > the rules!\n"
825 "...since I make symbolic puns"
826 "]]>"
827 "</xmlElement>";
828 XMLDocument doc;
829 doc.Parse( str );
830 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800831
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700832 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800833 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800834 false );
835 }
836
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800837 // ----------- CDATA -------------
838 {
839 const char* str = "<xmlElement>"
840 "<![CDATA["
841 "<b>I am > the rules!</b>\n"
842 "...since I make symbolic puns"
843 "]]>"
844 "</xmlElement>";
845 XMLDocument doc;
846 doc.Parse( str );
847 doc.Print();
848
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700849 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800850 "<b>I am > the rules!</b>\n...since I make symbolic puns",
851 false );
852 }
853
854 // InsertAfterChild causes crash.
855 {
856 // InsertBeforeChild and InsertAfterChild causes crash.
857 XMLDocument doc;
858 XMLElement* parent = doc.NewElement( "Parent" );
859 doc.InsertFirstChild( parent );
860
861 XMLElement* childText0 = doc.NewElement( "childText0" );
862 XMLElement* childText1 = doc.NewElement( "childText1" );
863
864 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
865 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
866
867 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
868 }
Lee Thomasond6277762012-02-22 16:00:12 -0800869
870 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800871 // Entities not being written correctly.
872 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800873
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800874 const char* passages =
875 "<?xml version=\"1.0\" standalone=\"no\" ?>"
876 "<passages count=\"006\" formatversion=\"20020620\">"
877 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
878 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
879 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800880
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800881 XMLDocument doc;
882 doc.Parse( passages );
883 XMLElement* psg = doc.RootElement()->FirstChildElement();
884 const char* context = psg->Attribute( "context" );
885 const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9.";
Lee Thomasond6277762012-02-22 16:00:12 -0800886
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800887 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800888
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400889 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800890 if ( textfile )
891 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800892 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800893 psg->Accept( &streamer );
894 fclose( textfile );
895 }
Thomas Roß0922b732012-09-23 16:31:22 +0200896
897 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800898 TIXMLASSERT( textfile );
899 if ( textfile )
900 {
901 char buf[ 1024 ];
902 fgets( buf, 1024, textfile );
903 XMLTest( "Entity transformation: write. ",
904 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
905 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
906 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700907 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800908 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800909 }
910
911 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800912 // Suppress entities.
913 const char* passages =
914 "<?xml version=\"1.0\" standalone=\"no\" ?>"
915 "<passages count=\"006\" formatversion=\"20020620\">"
916 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
917 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700918
Lee Thomason6f381b72012-03-02 12:59:39 -0800919 XMLDocument doc( false );
920 doc.Parse( passages );
921
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700922 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800923 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
924 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
925 "Crazy &ttk;" );
926 doc.Print();
927 }
928
929 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400930 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800931
932 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400933 doc.Parse( test );
934 XMLTest( "dot in names", doc.Error(), false );
935 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
936 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800937 }
938
939 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400940 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800941
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400942 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800943 doc.Parse( test );
944
945 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
946 XMLTest( "Entity with one digit.",
947 text->Value(), "1.1 Start easy ignore fin thickness\n",
948 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400949 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800950
951 {
952 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700953 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800954 const char* doctype =
955 "<?xml version=\"1.0\" ?>"
956 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
957 "<!ELEMENT title (#PCDATA)>"
958 "<!ELEMENT books (title,authors)>"
959 "<element />";
960
961 XMLDocument doc;
962 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400963 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800964 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400965 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800966 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700967
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800968 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
969 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
970
971 }
972
973 {
974 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700975 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976 "<!-- Somewhat<evil> -->";
977 XMLDocument doc;
978 doc.Parse( doctype );
979
980 XMLComment* comment = doc.FirstChild()->ToComment();
981
982 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
983 }
984 {
985 // Double attributes
986 const char* doctype = "<element attr='red' attr='blue' />";
987
988 XMLDocument doc;
989 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700990
Lee Thomason2fa81722012-11-09 12:37:46 -0800991 XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues)
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800992 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800993 }
994
995 {
996 // Embedded null in stream.
997 const char* doctype = "<element att\0r='red' attr='blue' />";
998
999 XMLDocument doc;
1000 doc.Parse( doctype );
1001 XMLTest( "Embedded null throws error.", true, doc.Error() );
1002 }
1003
1004 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001005 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001006 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001007 XMLDocument doc;
1008 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001009 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001010 }
1011
1012 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001013 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1014 const char* str = " ";
1015 XMLDocument doc;
1016 doc.Parse( str );
1017 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1018 }
1019
1020 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001021 // Low entities
1022 XMLDocument doc;
1023 doc.Parse( "<test>&#x0e;</test>" );
1024 const char result[] = { 0x0e, 0 };
1025 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
1026 doc.Print();
1027 }
1028
1029 {
1030 // Attribute values with trailing quotes not handled correctly
1031 XMLDocument doc;
1032 doc.Parse( "<foo attribute=bar\" />" );
1033 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
1034 }
1035
1036 {
1037 // [ 1663758 ] Failure to report error on bad XML
1038 XMLDocument xml;
1039 xml.Parse("<x>");
1040 XMLTest("Missing end tag at end of input", xml.Error(), true);
1041 xml.Parse("<x> ");
1042 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
1043 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -08001044 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001045 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001046
1047
1048 {
1049 // [ 1475201 ] TinyXML parses entities in comments
1050 XMLDocument xml;
1051 xml.Parse("<!-- declarations for <head> & <body> -->"
1052 "<!-- far &amp; away -->" );
1053
1054 XMLNode* e0 = xml.FirstChild();
1055 XMLNode* e1 = e0->NextSibling();
1056 XMLComment* c0 = e0->ToComment();
1057 XMLComment* c1 = e1->ToComment();
1058
1059 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1060 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1061 }
1062
1063 {
1064 XMLDocument xml;
1065 xml.Parse( "<Parent>"
1066 "<child1 att=''/>"
1067 "<!-- With this comment, child2 will not be parsed! -->"
1068 "<child2 att=''/>"
1069 "</Parent>" );
1070 xml.Print();
1071
1072 int count = 0;
1073
1074 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1075 ele;
1076 ele = ele->NextSibling() )
1077 {
1078 ++count;
1079 }
1080
1081 XMLTest( "Comments iterate correctly.", 3, count );
1082 }
1083
1084 {
1085 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1086 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1087 buf[60] = 239;
1088 buf[61] = 0;
1089
1090 XMLDocument doc;
1091 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001092 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001093
1094
1095 {
1096 // bug 1827248 Error while parsing a little bit malformed file
1097 // Actually not malformed - should work.
1098 XMLDocument xml;
1099 xml.Parse( "<attributelist> </attributelist >" );
1100 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1101 }
1102
1103 {
1104 // This one must not result in an infinite loop
1105 XMLDocument xml;
1106 xml.Parse( "<infinite>loop" );
1107 XMLTest( "Infinite loop test.", true, true );
1108 }
1109#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001110 {
1111 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1112 XMLDocument doc;
1113 doc.Parse( pub );
1114
1115 XMLDocument clone;
1116 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1117 XMLNode* copy = node->ShallowClone( &clone );
1118 clone.InsertEndChild( copy );
1119 }
1120
1121 clone.Print();
1122
1123 int count=0;
1124 const XMLNode* a=clone.FirstChild();
1125 const XMLNode* b=doc.FirstChild();
1126 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1127 ++count;
1128 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1129 }
1130 XMLTest( "Clone and Equal", 4, count );
1131 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001132
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001133 {
Lee Thomason7085f002017-06-01 18:09:43 -07001134 // Deep Cloning of root element.
1135 XMLDocument doc2;
1136 XMLPrinter printer1;
1137 {
1138 // Make sure doc1 is deleted before we test doc2
1139 const char* xml =
1140 "<root>"
1141 " <child1 foo='bar'/>"
1142 " <!-- comment thing -->"
1143 " <child2 val='1'>Text</child2>"
1144 "</root>";
1145 XMLDocument doc;
1146 doc.Parse(xml);
1147
1148 doc.Print(&printer1);
1149 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1150 doc2.InsertFirstChild(root);
1151 }
1152 XMLPrinter printer2;
1153 doc2.Print(&printer2);
1154
1155 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1156 }
1157
1158 {
1159 // Deep Cloning of sub element.
1160 XMLDocument doc2;
1161 XMLPrinter printer1;
1162 {
1163 // Make sure doc1 is deleted before we test doc2
1164 const char* xml =
1165 "<?xml version ='1.0'?>"
1166 "<root>"
1167 " <child1 foo='bar'/>"
1168 " <!-- comment thing -->"
1169 " <child2 val='1'>Text</child2>"
1170 "</root>";
1171 XMLDocument doc;
1172 doc.Parse(xml);
1173
1174 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1175 subElement->Accept(&printer1);
1176
1177 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1178 doc2.InsertFirstChild(clonedSubElement);
1179 }
1180 XMLPrinter printer2;
1181 doc2.Print(&printer2);
1182
1183 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1184 }
1185
1186 {
1187 // Deep cloning of document.
1188 XMLDocument doc2;
1189 XMLPrinter printer1;
1190 {
1191 // Make sure doc1 is deleted before we test doc2
1192 const char* xml =
1193 "<?xml version ='1.0'?>"
1194 "<!-- Top level comment. -->"
1195 "<root>"
1196 " <child1 foo='bar'/>"
1197 " <!-- comment thing -->"
1198 " <child2 val='1'>Text</child2>"
1199 "</root>";
1200 XMLDocument doc;
1201 doc.Parse(xml);
1202 doc.Print(&printer1);
1203
1204 doc.DeepCopy(&doc2);
1205 }
1206 XMLPrinter printer2;
1207 doc2.Print(&printer2);
1208
1209 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1210 }
1211
1212
1213 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001214 // This shouldn't crash.
1215 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001216 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001217 {
1218 doc.PrintError();
1219 }
1220 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1221 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001222
Lee Thomason5e3803c2012-04-16 08:57:05 -07001223 {
1224 // Attribute ordering.
1225 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1226 XMLDocument doc;
1227 doc.Parse( xml );
1228 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001229
Lee Thomason5e3803c2012-04-16 08:57:05 -07001230 const XMLAttribute* a = ele->FirstAttribute();
1231 XMLTest( "Attribute order", "1", a->Value() );
1232 a = a->Next();
1233 XMLTest( "Attribute order", "2", a->Value() );
1234 a = a->Next();
1235 XMLTest( "Attribute order", "3", a->Value() );
1236 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001237
Lee Thomason5e3803c2012-04-16 08:57:05 -07001238 ele->DeleteAttribute( "attrib2" );
1239 a = ele->FirstAttribute();
1240 XMLTest( "Attribute order", "1", a->Value() );
1241 a = a->Next();
1242 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001243
Lee Thomason5e3803c2012-04-16 08:57:05 -07001244 ele->DeleteAttribute( "attrib1" );
1245 ele->DeleteAttribute( "attrib3" );
1246 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1247 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001248
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001249 {
1250 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001251 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1252 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1253 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1254 XMLDocument doc0;
1255 doc0.Parse( xml0 );
1256 XMLDocument doc1;
1257 doc1.Parse( xml1 );
1258 XMLDocument doc2;
1259 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001260
Lee Thomason78a773d2012-07-02 10:10:19 -07001261 XMLElement* ele = 0;
1262 ele = doc0.FirstChildElement();
1263 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1264 ele = doc1.FirstChildElement();
1265 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1266 ele = doc2.FirstChildElement();
1267 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001268 }
1269
1270 {
1271 // Make sure we don't go into an infinite loop.
1272 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1273 XMLDocument doc;
1274 doc.Parse( xml );
1275 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1276 XMLElement* ele1 = ele0->NextSiblingElement();
1277 bool equal = ele0->ShallowEqual( ele1 );
1278
1279 XMLTest( "Infinite loop in shallow equal.", true, equal );
1280 }
1281
Lee Thomason5708f812012-03-28 17:46:41 -07001282 // -------- Handles ------------
1283 {
1284 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1285 XMLDocument doc;
1286 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -07001287
1288 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1289 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
1290
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001291 XMLHandle docH( doc );
1292 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001293 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001294 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001295
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001296 {
1297 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1298 XMLDocument doc;
1299 doc.Parse( xml );
1300 XMLConstHandle docH( doc );
1301
1302 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1303 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1304
1305 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001306 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001307 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001308 {
1309 // Default Declaration & BOM
1310 XMLDocument doc;
1311 doc.InsertEndChild( doc.NewDeclaration() );
1312 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001313
Lee Thomasonf68c4382012-04-28 14:37:11 -07001314 XMLPrinter printer;
1315 doc.Print( &printer );
1316
1317 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1318 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001319 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001320 }
Lee Thomason21be8822012-07-15 17:27:22 -07001321 {
1322 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1323 XMLDocument doc;
1324 doc.Parse( xml );
1325 XMLTest( "Ill formed XML", true, doc.Error() );
1326 }
1327
1328 // QueryXYZText
1329 {
1330 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1331 XMLDocument doc;
1332 doc.Parse( xml );
1333
1334 const XMLElement* pointElement = doc.RootElement();
1335
1336 int intValue = 0;
1337 unsigned unsignedValue = 0;
1338 float floatValue = 0;
1339 double doubleValue = 0;
1340 bool boolValue = false;
1341
1342 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1343 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1344 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1345 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1346 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1347
1348
1349 XMLTest( "QueryIntText", intValue, 1, false );
1350 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1351 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1352 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1353 XMLTest( "QueryBoolText", boolValue, true, false );
1354 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001355
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001356 {
1357 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1358 XMLDocument doc;
1359 doc.Parse( xml );
1360 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1361 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001362
1363 {
1364 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1365 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001366 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001367 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1368 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001369
1370 {
1371 const char* xml = "<3lement></3lement>";
1372 XMLDocument doc;
1373 doc.Parse( xml );
1374 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1375 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001376
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001377 {
1378 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1379 XMLDocument doc;
1380 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001381 XMLTest( "Set length of incoming data", doc.Error(), false );
1382 }
1383
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001384 {
1385 XMLDocument doc;
Dmitry-Me48b5df02015-04-06 18:20:25 +03001386 XMLTest( "Document is initially empty", doc.NoChildren(), true );
1387 doc.Clear();
1388 XMLTest( "Empty is empty after Clear()", doc.NoChildren(), true );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001389 doc.LoadFile( "resources/dream.xml" );
Dmitry-Meaaa4cea2015-02-06 16:00:46 +03001390 XMLTest( "Document has something to Clear()", doc.NoChildren(), false );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001391 doc.Clear();
1392 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1393 }
1394
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001395 // ----------- Whitespace ------------
1396 {
1397 const char* xml = "<element>"
1398 "<a> This \nis &apos; text &apos; </a>"
1399 "<b> This is &apos; text &apos; \n</b>"
1400 "<c>This is &apos; \n\n text &apos;</c>"
1401 "</element>";
1402 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1403 doc.Parse( xml );
1404
1405 const XMLElement* element = doc.FirstChildElement();
1406 for( const XMLElement* parent = element->FirstChildElement();
1407 parent;
1408 parent = parent->NextSiblingElement() )
1409 {
1410 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1411 }
1412 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001413
Lee Thomasonae9ab072012-10-24 10:17:53 -07001414#if 0
1415 {
1416 // Passes if assert doesn't fire.
1417 XMLDocument xmlDoc;
1418
1419 xmlDoc.NewDeclaration();
1420 xmlDoc.NewComment("Configuration file");
1421
1422 XMLElement *root = xmlDoc.NewElement("settings");
1423 root->SetAttribute("version", 2);
1424 }
1425#endif
1426
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001427 {
1428 const char* xml = "<element> </element>";
1429 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1430 doc.Parse( xml );
1431 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1432 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001433
Lee Thomason5b0a6772012-11-19 13:54:42 -08001434 {
1435 // An assert should not fire.
1436 const char* xml = "<element/>";
1437 XMLDocument doc;
1438 doc.Parse( xml );
1439 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1440 XMLTest( "Tracking unused elements", true, ele != 0, false );
1441 }
1442
Lee Thomasona6412ac2012-12-13 15:39:11 -08001443
1444 {
1445 const char* xml = "<parent><child>abc</child></parent>";
1446 XMLDocument doc;
1447 doc.Parse( xml );
1448 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1449
1450 XMLPrinter printer;
1451 ele->Accept( &printer );
1452 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1453 }
1454
1455
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001456 {
1457 XMLDocument doc;
1458 XMLError error = doc.LoadFile( "resources/empty.xml" );
1459 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001460 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001461 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001462 }
1463
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001464 {
1465 // BOM preservation
1466 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1467 {
1468 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001469 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001470 XMLPrinter printer;
1471 doc.Print( &printer );
1472
1473 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1474 doc.SaveFile( "resources/bomtest.xml" );
1475 }
1476 {
1477 XMLDocument doc;
1478 doc.LoadFile( "resources/bomtest.xml" );
1479 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1480
1481 XMLPrinter printer;
1482 doc.Print( &printer );
1483 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1484 }
1485 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001486
Michael Daumlinged523282013-10-23 07:47:29 +02001487 {
1488 // Insertion with Removal
1489 const char* xml = "<?xml version=\"1.0\" ?>"
1490 "<root>"
1491 "<one>"
1492 "<subtree>"
1493 "<elem>element 1</elem>text<!-- comment -->"
1494 "</subtree>"
1495 "</one>"
1496 "<two/>"
1497 "</root>";
1498 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1499 "<root>"
1500 "<one/>"
1501 "<two>"
1502 "<subtree>"
1503 "<elem>element 1</elem>text<!-- comment -->"
1504 "</subtree>"
1505 "</two>"
1506 "</root>";
1507 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1508 "<root>"
1509 "<one/>"
1510 "<subtree>"
1511 "<elem>element 1</elem>text<!-- comment -->"
1512 "</subtree>"
1513 "<two/>"
1514 "</root>";
1515 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1516 "<root>"
1517 "<one/>"
1518 "<two/>"
1519 "<subtree>"
1520 "<elem>element 1</elem>text<!-- comment -->"
1521 "</subtree>"
1522 "</root>";
1523
1524 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001525 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001526 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1527 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1528 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001529 XMLPrinter printer1(0, true);
1530 doc.Accept(&printer1);
1531 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001532
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001533 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001534 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1535 two = doc.RootElement()->FirstChildElement("two");
1536 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001537 XMLPrinter printer2(0, true);
1538 doc.Accept(&printer2);
1539 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001540
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001541 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001542 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1543 subtree = one->FirstChildElement("subtree");
1544 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001545 XMLPrinter printer3(0, true);
1546 doc.Accept(&printer3);
1547 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001548
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001549 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001550 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1551 two = doc.RootElement()->FirstChildElement("two");
1552 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001553 XMLPrinter printer4(0, true);
1554 doc.Accept(&printer4);
1555 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001556 }
1557
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001558 {
1559 const char* xml = "<svg width = \"128\" height = \"128\">"
1560 " <text> </text>"
1561 "</svg>";
1562 XMLDocument doc;
1563 doc.Parse(xml);
1564 doc.Print();
1565 }
1566
Lee Thomason92e521b2014-11-15 17:45:51 -08001567 {
1568 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001569 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1570 XMLDocument doc;
1571 doc.Parse(xml);
1572 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001573 }
1574
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001575#if 1
1576 // the question being explored is what kind of print to use:
1577 // https://github.com/leethomason/tinyxml2/issues/63
1578 {
1579 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1580 const char* xml = "<element/>";
1581 XMLDocument doc;
1582 doc.Parse( xml );
1583 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1584 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1585 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1586 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1587 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1588 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1589
1590 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1591 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1592 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1593 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1594 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1595 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1596
1597 doc.Print();
1598
1599 /* The result of this test is platform, compiler, and library version dependent. :("
1600 XMLPrinter printer;
1601 doc.Print( &printer );
1602 XMLTest( "Float and double formatting.",
1603 "<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",
1604 printer.CStr(),
1605 true );
1606 */
1607 }
1608#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001609
1610 {
1611 // Issue #184
1612 // If it doesn't assert, it passes. Caused by objects
1613 // getting created during parsing which are then
1614 // inaccessible in the memory pools.
1615 {
1616 XMLDocument doc;
1617 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1618 }
1619 {
1620 XMLDocument doc;
1621 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1622 doc.Clear();
1623 }
1624 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001625
1626 {
1627 // If this doesn't assert in DEBUG, all is well.
1628 tinyxml2::XMLDocument doc;
1629 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1630 doc.DeleteNode(pRoot);
1631 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001632
Dmitry-Me8b67d742014-12-22 11:35:12 +03001633 {
1634 // Should not assert in DEBUG
1635 XMLPrinter printer;
1636 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001637
Dmitry-Me6f51c802015-03-14 13:25:03 +03001638 {
1639 // Issue 291. Should not crash
1640 const char* xml = "&#0</a>";
1641 XMLDocument doc;
1642 doc.Parse( xml );
1643
1644 XMLPrinter printer;
1645 doc.Print( &printer );
1646 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001647 {
1648 // Issue 299. Can print elements that are not linked in.
1649 // Will crash if issue not fixed.
1650 XMLDocument doc;
1651 XMLElement* newElement = doc.NewElement( "printme" );
1652 XMLPrinter printer;
1653 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001654 // Delete the node to avoid possible memory leak report in debug output
1655 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001656 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001657 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001658 // Issue 302. Clear errors from LoadFile/SaveFile
1659 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001660 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001661 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001662 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001663 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001664 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001665 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001666
Dmitry-Med9852a52015-03-25 10:17:49 +03001667 {
1668 // If a document fails to load then subsequent
1669 // successful loads should clear the error
1670 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001671 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001672 doc.LoadFile( "resources/no-such-file.xml" );
1673 XMLTest( "No such file - should fail", true, doc.Error() );
1674
1675 doc.LoadFile( "resources/dream.xml" );
1676 XMLTest( "Error should be cleared", false, doc.Error() );
1677 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301678
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301679 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001680 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001681 const char* xml0 = "<?xml version=\"1.0\" ?>"
1682 " <!-- xml version=\"1.1\" -->"
1683 "<first />";
1684 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001685 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001686 "<first />";
1687 const char* xml2 = "<first />"
1688 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001689 const char* xml3 = "<first></first>"
1690 "<?xml version=\"1.0\" ?>";
1691
1692 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1693
Lee Thomason85492022015-05-22 11:07:45 -07001694 XMLDocument doc;
1695 doc.Parse(xml0);
1696 XMLTest("Test that the code changes do not affect normal parsing", doc.Error(), false);
1697 doc.Parse(xml1);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001698 XMLTest("Test that the second declaration is allowed", doc.Error(), false);
Lee Thomason85492022015-05-22 11:07:45 -07001699 doc.Parse(xml2);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001700 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1701 doc.Parse(xml3);
1702 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1703 doc.Parse(xml4);
1704 XMLTest("Test that declaration inside a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301705 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001706
Lee Thomason85492022015-05-22 11:07:45 -07001707 {
1708 // No matter - before or after successfully parsing a text -
1709 // calling XMLDocument::Value() causes an assert in debug.
1710 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1711 "<first />"
1712 "<second />";
1713 XMLDocument* doc = new XMLDocument();
1714 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1715 doc->Parse( validXml );
1716 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1717 delete doc;
1718 }
1719
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001720 {
1721 XMLDocument doc;
1722 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001723 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001724 doc.ErrorName();
1725 }
1726 }
1727
Lee Thomason816d3fa2017-06-05 14:35:55 -07001728 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001729 // Evil memory leaks.
1730 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1731 // and NOT added to the XMLDocument, what happens?
1732 //
1733 // Previously (buggy):
1734 // The memory would be free'd when the XMLDocument is
1735 // destructed. But the destructor wasn't called, so that
1736 // memory allocated by the XMLElement would not be free'd.
1737 // In practice this meant strings allocated by the XMLElement
1738 // would leak. An edge case, but annoying.
1739 // Now:
1740 // The destructor is called. But the list of unlinked nodes
1741 // has to be tracked. This has a minor performance impact
1742 // that can become significant if you have a lot. (But why
1743 // would you do that?)
1744 // The only way to see this bug is in a leak tracker. This
1745 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001746 {
1747 XMLDocument doc;
1748 doc.NewElement("LEAK 1");
1749 }
1750 {
1751 XMLDocument doc;
1752 XMLElement* ele = doc.NewElement("LEAK 2");
1753 doc.DeleteNode(ele);
1754 }
1755 }
1756
Lee Thomason224ef772017-06-16 09:45:26 -07001757 {
1758 // Crashing reported via email.
1759 const char* xml =
1760 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001761 "<property name='track_name'>voice</property>"
1762 "<property name='audio_track'>1</property>"
1763 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1764 "<blank length = '1' />"
1765 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1766 "<blank length = '2' />"
1767 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1768 "<blank length = '1' />"
1769 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001770 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001771
Lee Thomason224ef772017-06-16 09:45:26 -07001772 // It's not a good idea to delete elements as you walk the
1773 // list. I'm not sure this technically should work; but it's
1774 // an interesting test case.
1775 XMLDocument doc;
1776 XMLError err = doc.Parse(xml);
Lee Thomason9e2d29b2017-06-16 09:51:11 -07001777 XMLTest("Crash bug parsing", err, XML_SUCCESS);
Dmitry-Meaea64c42017-06-20 18:20:15 +03001778
1779 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001780 XMLTest("Crash bug parsing", true, playlist != 0);
1781
1782 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1783 XMLTest("Crash bug parsing", true, entry != 0);
1784 while (entry) {
1785 tinyxml2::XMLElement* todelete = entry;
1786 entry = entry->NextSiblingElement("entry");
1787 playlist->DeleteChild(todelete);
1788 };
1789 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1790 while (blank) {
1791 tinyxml2::XMLElement* todelete = blank;
1792 blank = blank->NextSiblingElement("blank");
1793 playlist->DeleteChild(todelete);
1794 };
1795
1796 tinyxml2::XMLPrinter printer;
1797 playlist->Accept(&printer);
1798 printf("%s\n", printer.CStr());
1799
Lee Thomason82bb0742017-06-16 09:48:20 -07001800 // No test; it only need to not crash.
1801 // Still, wrap it up with a sanity check
1802 int nProperty = 0;
1803 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1804 nProperty++;
1805 }
1806 XMLTest("Crash bug parsing", nProperty, 2);
Lee Thomason224ef772017-06-16 09:45:26 -07001807 }
1808
kezenatorec694152016-11-26 17:21:43 +10001809 // ----------- Line Number Tracking --------------
1810 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001811 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001812 {
1813 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1814 {
1815 XMLDocument doc;
1816 XMLError err = doc.Parse(docStr);
1817
1818 XMLTest(testString, true, doc.Error());
1819 XMLTest(testString, expected_error, err);
1820 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1821 };
1822
1823 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1824 {
1825 XMLDocument doc;
1826 doc.Parse(docStr);
1827 XMLTest(testString, false, doc.Error());
1828 TestDocLines(testString, doc, expectedLines);
1829 }
1830
1831 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1832 {
1833 XMLDocument doc;
1834 doc.LoadFile(file_name);
1835 XMLTest(testString, false, doc.Error());
1836 TestDocLines(testString, doc, expectedLines);
1837 }
1838
1839 private:
1840 DynArray<char, 10> str;
1841
1842 void Push(char type, int lineNum)
1843 {
1844 str.Push(type);
1845 str.Push(char('0' + (lineNum / 10)));
1846 str.Push(char('0' + (lineNum % 10)));
1847 }
1848
1849 bool VisitEnter(const XMLDocument& doc)
1850 {
kezenator19d8ea82016-11-29 19:50:27 +10001851 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001852 return true;
1853 }
1854 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
1855 {
kezenator19d8ea82016-11-29 19:50:27 +10001856 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001857 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10001858 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001859 return true;
1860 }
1861 bool Visit(const XMLDeclaration& declaration)
1862 {
kezenator19d8ea82016-11-29 19:50:27 +10001863 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001864 return true;
1865 }
1866 bool Visit(const XMLText& text)
1867 {
kezenator19d8ea82016-11-29 19:50:27 +10001868 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001869 return true;
1870 }
1871 bool Visit(const XMLComment& comment)
1872 {
kezenator19d8ea82016-11-29 19:50:27 +10001873 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001874 return true;
1875 }
1876 bool Visit(const XMLUnknown& unknown)
1877 {
kezenator19d8ea82016-11-29 19:50:27 +10001878 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001879 return true;
1880 }
1881
1882 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
1883 {
1884 str.Clear();
1885 doc.Accept(this);
1886 str.Push(0);
1887 XMLTest(testString, expectedLines, str.Mem());
1888 }
Lee Thomasone90e9012016-12-24 07:34:39 -08001889 } tester;
kezenatorec694152016-11-26 17:21:43 +10001890
Lee Thomasone90e9012016-12-24 07:34:39 -08001891 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
1892 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
1893 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
1894 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
1895 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
1896 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
1897 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
1898 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
1899 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
1900 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
1901 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10001902
Lee Thomasone90e9012016-12-24 07:34:39 -08001903 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001904 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08001905
1906 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
1907 "<root a='b' \n" // 2 Element Attribute
1908 "c='d'> d <blah/> \n" // 3 Attribute Text Element
1909 "newline in text \n" // 4 Text
1910 "and second <zxcv/><![CDATA[\n" // 5 Element Text
1911 " cdata test ]]><!-- comment -->\n" // 6 Comment
1912 "<! unknown></root>", // 7 Unknown
1913
kezenatorec694152016-11-26 17:21:43 +10001914 "D01L01E02A02A03T03E03T04E05T05C06U07");
1915
Lee Thomasone90e9012016-12-24 07:34:39 -08001916 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001917 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08001918
1919 "\r\n" // 1 Doc (arguably should be line 2)
1920 "<?xml version=\"1.0\"?>\n" // 2 DecL
1921 "<root>\r\n" // 3 Element
1922 "\n" // 4
1923 "text contining new line \n" // 5 Text
1924 " and also containing crlf \r\n" // 6
1925 "<sub><![CDATA[\n" // 7 Element Text
1926 "cdata containing new line \n" // 8
1927 " and also containing cflr\r\n" // 9
1928 "]]></sub><sub2/></root>", // 10 Element
1929
kezenatorec694152016-11-26 17:21:43 +10001930 "D01L02E03T05E07T07E10");
1931
Lee Thomasone90e9012016-12-24 07:34:39 -08001932 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10001933 "LineNumbers-File",
1934 "resources/utf8test.xml",
1935 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
1936 }
1937
Lee Thomason85492022015-05-22 11:07:45 -07001938 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08001939 {
1940#if defined( _MSC_VER )
1941 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001942 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08001943#endif
1944
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001945 FILE* perfFP = fopen("resources/dream.xml", "r");
1946 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02001947 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001948 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08001949
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001950 char* mem = new char[size + 1];
1951 fread(mem, size, 1, perfFP);
1952 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08001953 mem[size] = 0;
1954
1955#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001956 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08001957#else
1958 clock_t cstart = clock();
1959#endif
1960 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001961 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001962 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001963 doc.Parse(mem);
Lee Thomason6f381b72012-03-02 12:59:39 -08001964 }
1965#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001966 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08001967#else
1968 clock_t cend = clock();
1969#endif
1970
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001971 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08001972
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001973 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001974#ifdef DEBUG
1975 "DEBUG";
1976#else
1977 "Release";
1978#endif
1979
1980#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001981 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT));
Lee Thomason6f381b72012-03-02 12:59:39 -08001982#else
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001983 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08001984#endif
1985 }
1986
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001987 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001988 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001989
1990 _CrtMemState diffMemState;
1991 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1992 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03001993
1994 {
1995 int leaksBeforeExit = _CrtDumpMemoryLeaks();
1996 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
1997 }
Lee Thomason1ff38e02012-02-14 18:18:16 -08001998 #endif
1999
2000 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002001
2002 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002003}