blob: 799433af7907f895f729c724f0ac2245b8d8319a [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 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300438 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
439 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
440 XMLTest( "Programmatic DOM", 10, value1 );
441 XMLTest( "Programmatic DOM", 10, value2 );
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 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300502 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
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
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300513 int iVal;
514 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800515 double dVal;
516
517 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300518 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
519 XMLTest( "Query attribute: int as double", 1, (int)dVal );
520 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700521
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800522 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300523 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
524 XMLTest( "Query attribute: double as double", 2.0, dVal );
525 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700526
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800527 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300528 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
529 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700530
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800531 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300532 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
533 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700534
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800535 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300536 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
537 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800538 }
539
540 {
541 const char* str = "<doc/>";
542
543 XMLDocument doc;
544 doc.Parse( str );
545
546 XMLElement* ele = doc.FirstChildElement();
547
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800548 int iVal, iVal2;
549 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550
551 ele->SetAttribute( "str", "strValue" );
552 ele->SetAttribute( "int", 1 );
553 ele->SetAttribute( "double", -1.0 );
554
555 const char* cStr = ele->Attribute( "str" );
556 ele->QueryIntAttribute( "int", &iVal );
557 ele->QueryDoubleAttribute( "double", &dVal );
558
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800559 ele->QueryAttribute( "int", &iVal2 );
560 ele->QueryAttribute( "double", &dVal2 );
561
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300562 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800563 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
564 XMLTest( "Attribute round trip. int.", 1, iVal );
565 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800566 XMLTest( "Alternate query", true, iVal == iVal2 );
567 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700568 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
569 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800570 }
571
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800572 {
573 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300574 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800575
576 // Get the attribute "value" from the "Russian" element and check it.
577 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700578 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800579 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
580
581 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
582
583 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
584 0xd1U, 0x81U, 0xd1U, 0x81U,
585 0xd0U, 0xbaU, 0xd0U, 0xb8U,
586 0xd0U, 0xb9U, 0 };
587 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
588
589 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
590 XMLTest( "UTF-8: Browsing russian element name.",
591 russianText,
592 text->Value() );
593
594 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400595 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800596
597 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800598 int okay = 0;
599
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200600 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300601 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800602
603 if ( saved && verify )
604 {
605 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700606 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800607 while ( fgets( verifyBuf, 256, verify ) )
608 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700609 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800610 fgets( savedBuf, 256, saved );
611 NullLineEndings( verifyBuf );
612 NullLineEndings( savedBuf );
613
614 if ( strcmp( verifyBuf, savedBuf ) )
615 {
616 printf( "verify:%s<\n", verifyBuf );
617 printf( "saved :%s<\n", savedBuf );
618 okay = 0;
619 break;
620 }
621 }
622 }
623 if ( saved )
624 fclose( saved );
625 if ( verify )
626 fclose( verify );
627 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
628 }
629
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800630 // --------GetText()-----------
631 {
632 const char* str = "<foo>This is text</foo>";
633 XMLDocument doc;
634 doc.Parse( str );
635 const XMLElement* element = doc.RootElement();
636
637 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
638
639 str = "<foo><b>This is text</b></foo>";
640 doc.Parse( str );
641 element = doc.RootElement();
642
643 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
644 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800645
Lee Thomasond6277762012-02-22 16:00:12 -0800646
Uli Kusterer321072e2014-01-21 01:57:38 +0100647 // --------SetText()-----------
648 {
649 const char* str = "<foo></foo>";
650 XMLDocument doc;
651 doc.Parse( str );
652 XMLElement* element = doc.RootElement();
653
Lee Thomason9c0678a2014-01-24 10:18:27 -0800654 element->SetText("darkness.");
655 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100656
Lee Thomason9c0678a2014-01-24 10:18:27 -0800657 element->SetText("blue flame.");
658 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100659
660 str = "<foo/>";
661 doc.Parse( str );
662 element = doc.RootElement();
663
Lee Thomason9c0678a2014-01-24 10:18:27 -0800664 element->SetText("The driver");
665 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100666
Lee Thomason9c0678a2014-01-24 10:18:27 -0800667 element->SetText("<b>horses</b>");
668 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
669 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100670
671 str = "<foo><bar>Text in nested element</bar></foo>";
672 doc.Parse( str );
673 element = doc.RootElement();
674
Lee Thomason9c0678a2014-01-24 10:18:27 -0800675 element->SetText("wolves");
676 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800677
678 str = "<foo/>";
679 doc.Parse( str );
680 element = doc.RootElement();
681
682 element->SetText( "str" );
683 XMLTest( "SetText types", "str", element->GetText() );
684
685 element->SetText( 1 );
686 XMLTest( "SetText types", "1", element->GetText() );
687
688 element->SetText( 1U );
689 XMLTest( "SetText types", "1", element->GetText() );
690
691 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200692 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800693
694 element->SetText( 1.5f );
695 XMLTest( "SetText types", "1.5", element->GetText() );
696
697 element->SetText( 1.5 );
698 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100699 }
700
Lee Thomason51c12712016-06-04 20:18:49 -0700701 // ---------- Attributes ---------
702 {
703 static const int64_t BIG = -123456789012345678;
704 XMLDocument doc;
705 XMLElement* element = doc.NewElement("element");
706 doc.InsertFirstChild(element);
707
708 {
709 element->SetAttribute("attrib", int(-100));
710 int v = 0;
711 element->QueryIntAttribute("attrib", &v);
712 XMLTest("Attribute: int", -100, v, true);
713 element->QueryAttribute("attrib", &v);
714 XMLTest("Attribute: int", -100, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700715 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700716 }
717 {
718 element->SetAttribute("attrib", unsigned(100));
719 unsigned v = 0;
720 element->QueryUnsignedAttribute("attrib", &v);
721 XMLTest("Attribute: unsigned", unsigned(100), v, true);
722 element->QueryAttribute("attrib", &v);
723 XMLTest("Attribute: unsigned", unsigned(100), v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700724 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700725 }
726 {
727 element->SetAttribute("attrib", BIG);
728 int64_t v = 0;
729 element->QueryInt64Attribute("attrib", &v);
730 XMLTest("Attribute: int64_t", BIG, v, true);
731 element->QueryAttribute("attrib", &v);
732 XMLTest("Attribute: int64_t", BIG, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700733 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700734 }
735 {
736 element->SetAttribute("attrib", true);
737 bool v = false;
738 element->QueryBoolAttribute("attrib", &v);
739 XMLTest("Attribute: bool", true, v, true);
740 element->QueryAttribute("attrib", &v);
741 XMLTest("Attribute: bool", true, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700742 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700743 }
744 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800745 element->SetAttribute("attrib", true);
746 const char* result = element->Attribute("attrib");
747 XMLTest("Bool true is 'true'", "true", result);
748
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800749 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800750 element->SetAttribute("attrib", true);
751 result = element->Attribute("attrib");
752 XMLTest("Bool true is '1'", "1", result);
753
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800754 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800755 }
756 {
Lee Thomason51c12712016-06-04 20:18:49 -0700757 element->SetAttribute("attrib", 100.0);
758 double v = 0;
759 element->QueryDoubleAttribute("attrib", &v);
760 XMLTest("Attribute: double", 100.0, v, true);
761 element->QueryAttribute("attrib", &v);
762 XMLTest("Attribute: double", 100.0, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700763 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700764 }
765 {
766 element->SetAttribute("attrib", 100.0f);
767 float v = 0;
768 element->QueryFloatAttribute("attrib", &v);
769 XMLTest("Attribute: float", 100.0f, v, true);
770 element->QueryAttribute("attrib", &v);
771 XMLTest("Attribute: float", 100.0f, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700772 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700773 }
774 {
775 element->SetText(BIG);
776 int64_t v = 0;
777 element->QueryInt64Text(&v);
778 XMLTest("Element: int64_t", BIG, v, true);
779 }
780 }
781
782 // ---------- XMLPrinter stream mode ------
783 {
784 {
785 FILE* printerfp = fopen("resources/printer.xml", "w");
786 XMLPrinter printer(printerfp);
787 printer.OpenElement("foo");
788 printer.PushAttribute("attrib-text", "text");
789 printer.PushAttribute("attrib-int", int(1));
790 printer.PushAttribute("attrib-unsigned", unsigned(2));
791 printer.PushAttribute("attrib-int64", int64_t(3));
792 printer.PushAttribute("attrib-bool", true);
793 printer.PushAttribute("attrib-double", 4.0);
794 printer.CloseElement();
795 fclose(printerfp);
796 }
797 {
798 XMLDocument doc;
799 doc.LoadFile("resources/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300800 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700801
802 const XMLDocument& cdoc = doc;
803
804 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
805 XMLTest("attrib-text", "text", attrib->Value(), true);
806 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
807 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
808 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
809 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
810 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
811 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
812 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
813 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
814 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
815 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
816 }
817
818 }
819
Uli Kusterer321072e2014-01-21 01:57:38 +0100820
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800821 // ---------- CDATA ---------------
822 {
823 const char* str = "<xmlElement>"
824 "<![CDATA["
825 "I am > the rules!\n"
826 "...since I make symbolic puns"
827 "]]>"
828 "</xmlElement>";
829 XMLDocument doc;
830 doc.Parse( str );
831 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800832
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300833 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
834 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800835 false );
836 }
837
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800838 // ----------- CDATA -------------
839 {
840 const char* str = "<xmlElement>"
841 "<![CDATA["
842 "<b>I am > the rules!</b>\n"
843 "...since I make symbolic puns"
844 "]]>"
845 "</xmlElement>";
846 XMLDocument doc;
847 doc.Parse( str );
848 doc.Print();
849
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300850 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800851 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300852 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800853 false );
854 }
855
856 // InsertAfterChild causes crash.
857 {
858 // InsertBeforeChild and InsertAfterChild causes crash.
859 XMLDocument doc;
860 XMLElement* parent = doc.NewElement( "Parent" );
861 doc.InsertFirstChild( parent );
862
863 XMLElement* childText0 = doc.NewElement( "childText0" );
864 XMLElement* childText1 = doc.NewElement( "childText1" );
865
866 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
867 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
868
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300869 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800870 }
Lee Thomasond6277762012-02-22 16:00:12 -0800871
872 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800873 // Entities not being written correctly.
874 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800875
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800876 const char* passages =
877 "<?xml version=\"1.0\" standalone=\"no\" ?>"
878 "<passages count=\"006\" formatversion=\"20020620\">"
879 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
880 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
881 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800882
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800883 XMLDocument doc;
884 doc.Parse( passages );
885 XMLElement* psg = doc.RootElement()->FirstChildElement();
886 const char* context = psg->Attribute( "context" );
887 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 -0800888
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800889 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800890
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400891 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800892 if ( textfile )
893 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800894 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800895 psg->Accept( &streamer );
896 fclose( textfile );
897 }
Thomas Roß0922b732012-09-23 16:31:22 +0200898
899 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800900 TIXMLASSERT( textfile );
901 if ( textfile )
902 {
903 char buf[ 1024 ];
904 fgets( buf, 1024, textfile );
905 XMLTest( "Entity transformation: write. ",
906 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
907 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
908 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700909 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800910 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800911 }
912
913 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800914 // Suppress entities.
915 const char* passages =
916 "<?xml version=\"1.0\" standalone=\"no\" ?>"
917 "<passages count=\"006\" formatversion=\"20020620\">"
918 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
919 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700920
Lee Thomason6f381b72012-03-02 12:59:39 -0800921 XMLDocument doc( false );
922 doc.Parse( passages );
923
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300924 XMLTest( "No entity parsing.",
925 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
926 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
927 XMLTest( "No entity parsing.", "Crazy &ttk;",
928 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -0800929 doc.Print();
930 }
931
932 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400933 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800934
935 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400936 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300937 XMLTest( "dot in names", false, doc.Error() );
938 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
939 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800940 }
941
942 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400943 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800944
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400945 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800946 doc.Parse( test );
947
948 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
949 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300950 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800951 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400952 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800953
954 {
955 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700956 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800957 const char* doctype =
958 "<?xml version=\"1.0\" ?>"
959 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
960 "<!ELEMENT title (#PCDATA)>"
961 "<!ELEMENT books (title,authors)>"
962 "<element />";
963
964 XMLDocument doc;
965 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400966 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800967 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400968 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800969 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700970
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800971 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
972 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
973
974 }
975
976 {
977 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700978 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800979 "<!-- Somewhat<evil> -->";
980 XMLDocument doc;
981 doc.Parse( doctype );
982
983 XMLComment* comment = doc.FirstChild()->ToComment();
984
985 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
986 }
987 {
988 // Double attributes
989 const char* doctype = "<element attr='red' attr='blue' />";
990
991 XMLDocument doc;
992 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700993
Lee Thomason2fa81722012-11-09 12:37:46 -0800994 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 -0800995 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800996 }
997
998 {
999 // Embedded null in stream.
1000 const char* doctype = "<element att\0r='red' attr='blue' />";
1001
1002 XMLDocument doc;
1003 doc.Parse( doctype );
1004 XMLTest( "Embedded null throws error.", true, doc.Error() );
1005 }
1006
1007 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001008 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001009 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001010 XMLDocument doc;
1011 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001012 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001013 }
1014
1015 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001016 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1017 const char* str = " ";
1018 XMLDocument doc;
1019 doc.Parse( str );
1020 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1021 }
1022
1023 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001024 // Low entities
1025 XMLDocument doc;
1026 doc.Parse( "<test>&#x0e;</test>" );
1027 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001028 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001029 doc.Print();
1030 }
1031
1032 {
1033 // Attribute values with trailing quotes not handled correctly
1034 XMLDocument doc;
1035 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001036 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001037 }
1038
1039 {
1040 // [ 1663758 ] Failure to report error on bad XML
1041 XMLDocument xml;
1042 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001043 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001044 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001045 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001046 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001047 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001048 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001049
1050
1051 {
1052 // [ 1475201 ] TinyXML parses entities in comments
1053 XMLDocument xml;
1054 xml.Parse("<!-- declarations for <head> & <body> -->"
1055 "<!-- far &amp; away -->" );
1056
1057 XMLNode* e0 = xml.FirstChild();
1058 XMLNode* e1 = e0->NextSibling();
1059 XMLComment* c0 = e0->ToComment();
1060 XMLComment* c1 = e1->ToComment();
1061
1062 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1063 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1064 }
1065
1066 {
1067 XMLDocument xml;
1068 xml.Parse( "<Parent>"
1069 "<child1 att=''/>"
1070 "<!-- With this comment, child2 will not be parsed! -->"
1071 "<child2 att=''/>"
1072 "</Parent>" );
1073 xml.Print();
1074
1075 int count = 0;
1076
1077 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1078 ele;
1079 ele = ele->NextSibling() )
1080 {
1081 ++count;
1082 }
1083
1084 XMLTest( "Comments iterate correctly.", 3, count );
1085 }
1086
1087 {
1088 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1089 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1090 buf[60] = 239;
1091 buf[61] = 0;
1092
1093 XMLDocument doc;
1094 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001095 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001096
1097
1098 {
1099 // bug 1827248 Error while parsing a little bit malformed file
1100 // Actually not malformed - should work.
1101 XMLDocument xml;
1102 xml.Parse( "<attributelist> </attributelist >" );
1103 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1104 }
1105
1106 {
1107 // This one must not result in an infinite loop
1108 XMLDocument xml;
1109 xml.Parse( "<infinite>loop" );
1110 XMLTest( "Infinite loop test.", true, true );
1111 }
1112#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001113 {
1114 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1115 XMLDocument doc;
1116 doc.Parse( pub );
1117
1118 XMLDocument clone;
1119 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1120 XMLNode* copy = node->ShallowClone( &clone );
1121 clone.InsertEndChild( copy );
1122 }
1123
1124 clone.Print();
1125
1126 int count=0;
1127 const XMLNode* a=clone.FirstChild();
1128 const XMLNode* b=doc.FirstChild();
1129 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1130 ++count;
1131 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1132 }
1133 XMLTest( "Clone and Equal", 4, count );
1134 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001135
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001136 {
Lee Thomason7085f002017-06-01 18:09:43 -07001137 // Deep Cloning of root element.
1138 XMLDocument doc2;
1139 XMLPrinter printer1;
1140 {
1141 // Make sure doc1 is deleted before we test doc2
1142 const char* xml =
1143 "<root>"
1144 " <child1 foo='bar'/>"
1145 " <!-- comment thing -->"
1146 " <child2 val='1'>Text</child2>"
1147 "</root>";
1148 XMLDocument doc;
1149 doc.Parse(xml);
1150
1151 doc.Print(&printer1);
1152 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1153 doc2.InsertFirstChild(root);
1154 }
1155 XMLPrinter printer2;
1156 doc2.Print(&printer2);
1157
1158 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1159 }
1160
1161 {
1162 // Deep Cloning of sub element.
1163 XMLDocument doc2;
1164 XMLPrinter printer1;
1165 {
1166 // Make sure doc1 is deleted before we test doc2
1167 const char* xml =
1168 "<?xml version ='1.0'?>"
1169 "<root>"
1170 " <child1 foo='bar'/>"
1171 " <!-- comment thing -->"
1172 " <child2 val='1'>Text</child2>"
1173 "</root>";
1174 XMLDocument doc;
1175 doc.Parse(xml);
1176
1177 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1178 subElement->Accept(&printer1);
1179
1180 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1181 doc2.InsertFirstChild(clonedSubElement);
1182 }
1183 XMLPrinter printer2;
1184 doc2.Print(&printer2);
1185
1186 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1187 }
1188
1189 {
1190 // Deep cloning of document.
1191 XMLDocument doc2;
1192 XMLPrinter printer1;
1193 {
1194 // Make sure doc1 is deleted before we test doc2
1195 const char* xml =
1196 "<?xml version ='1.0'?>"
1197 "<!-- Top level comment. -->"
1198 "<root>"
1199 " <child1 foo='bar'/>"
1200 " <!-- comment thing -->"
1201 " <child2 val='1'>Text</child2>"
1202 "</root>";
1203 XMLDocument doc;
1204 doc.Parse(xml);
1205 doc.Print(&printer1);
1206
1207 doc.DeepCopy(&doc2);
1208 }
1209 XMLPrinter printer2;
1210 doc2.Print(&printer2);
1211
1212 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1213 }
1214
1215
1216 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001217 // This shouldn't crash.
1218 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001219 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001220 {
1221 doc.PrintError();
1222 }
1223 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1224 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001225
Lee Thomason5e3803c2012-04-16 08:57:05 -07001226 {
1227 // Attribute ordering.
1228 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1229 XMLDocument doc;
1230 doc.Parse( xml );
1231 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001232
Lee Thomason5e3803c2012-04-16 08:57:05 -07001233 const XMLAttribute* a = ele->FirstAttribute();
1234 XMLTest( "Attribute order", "1", a->Value() );
1235 a = a->Next();
1236 XMLTest( "Attribute order", "2", a->Value() );
1237 a = a->Next();
1238 XMLTest( "Attribute order", "3", a->Value() );
1239 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001240
Lee Thomason5e3803c2012-04-16 08:57:05 -07001241 ele->DeleteAttribute( "attrib2" );
1242 a = ele->FirstAttribute();
1243 XMLTest( "Attribute order", "1", a->Value() );
1244 a = a->Next();
1245 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001246
Lee Thomason5e3803c2012-04-16 08:57:05 -07001247 ele->DeleteAttribute( "attrib1" );
1248 ele->DeleteAttribute( "attrib3" );
1249 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1250 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001251
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001252 {
1253 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001254 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1255 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1256 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1257 XMLDocument doc0;
1258 doc0.Parse( xml0 );
1259 XMLDocument doc1;
1260 doc1.Parse( xml1 );
1261 XMLDocument doc2;
1262 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001263
Lee Thomason78a773d2012-07-02 10:10:19 -07001264 XMLElement* ele = 0;
1265 ele = doc0.FirstChildElement();
1266 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1267 ele = doc1.FirstChildElement();
1268 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1269 ele = doc2.FirstChildElement();
1270 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001271 }
1272
1273 {
1274 // Make sure we don't go into an infinite loop.
1275 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1276 XMLDocument doc;
1277 doc.Parse( xml );
1278 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1279 XMLElement* ele1 = ele0->NextSiblingElement();
1280 bool equal = ele0->ShallowEqual( ele1 );
1281
1282 XMLTest( "Infinite loop in shallow equal.", true, equal );
1283 }
1284
Lee Thomason5708f812012-03-28 17:46:41 -07001285 // -------- Handles ------------
1286 {
1287 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1288 XMLDocument doc;
1289 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -07001290
1291 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001292 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001293
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001294 XMLHandle docH( doc );
1295 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001296 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001297 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001298
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001299 {
1300 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1301 XMLDocument doc;
1302 doc.Parse( xml );
1303 XMLConstHandle docH( doc );
1304
1305 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1306 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1307
1308 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001309 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001310 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001311 {
1312 // Default Declaration & BOM
1313 XMLDocument doc;
1314 doc.InsertEndChild( doc.NewDeclaration() );
1315 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001316
Lee Thomasonf68c4382012-04-28 14:37:11 -07001317 XMLPrinter printer;
1318 doc.Print( &printer );
1319
1320 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001321 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1322 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001323 }
Lee Thomason21be8822012-07-15 17:27:22 -07001324 {
1325 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1326 XMLDocument doc;
1327 doc.Parse( xml );
1328 XMLTest( "Ill formed XML", true, doc.Error() );
1329 }
1330
1331 // QueryXYZText
1332 {
1333 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1334 XMLDocument doc;
1335 doc.Parse( xml );
1336
1337 const XMLElement* pointElement = doc.RootElement();
1338
1339 int intValue = 0;
1340 unsigned unsignedValue = 0;
1341 float floatValue = 0;
1342 double doubleValue = 0;
1343 bool boolValue = false;
1344
1345 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1346 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1347 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1348 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1349 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1350
1351
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001352 XMLTest( "QueryIntText", 1, intValue, false );
1353 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1354 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1355 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1356 XMLTest( "QueryBoolText", true, boolValue, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001357 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001358
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001359 {
1360 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1361 XMLDocument doc;
1362 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001363 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001364 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001365
1366 {
1367 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1368 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001369 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001370 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001371 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001372
1373 {
1374 const char* xml = "<3lement></3lement>";
1375 XMLDocument doc;
1376 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001377 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001378 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001379
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001380 {
1381 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1382 XMLDocument doc;
1383 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001384 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001385 }
1386
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001387 {
1388 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001389 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001390 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001391 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001392 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001393 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001394 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001395 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001396 }
1397
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001398 // ----------- Whitespace ------------
1399 {
1400 const char* xml = "<element>"
1401 "<a> This \nis &apos; text &apos; </a>"
1402 "<b> This is &apos; text &apos; \n</b>"
1403 "<c>This is &apos; \n\n text &apos;</c>"
1404 "</element>";
1405 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1406 doc.Parse( xml );
1407
1408 const XMLElement* element = doc.FirstChildElement();
1409 for( const XMLElement* parent = element->FirstChildElement();
1410 parent;
1411 parent = parent->NextSiblingElement() )
1412 {
1413 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1414 }
1415 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001416
Lee Thomasonae9ab072012-10-24 10:17:53 -07001417#if 0
1418 {
1419 // Passes if assert doesn't fire.
1420 XMLDocument xmlDoc;
1421
1422 xmlDoc.NewDeclaration();
1423 xmlDoc.NewComment("Configuration file");
1424
1425 XMLElement *root = xmlDoc.NewElement("settings");
1426 root->SetAttribute("version", 2);
1427 }
1428#endif
1429
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001430 {
1431 const char* xml = "<element> </element>";
1432 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1433 doc.Parse( xml );
1434 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1435 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001436
Lee Thomason5b0a6772012-11-19 13:54:42 -08001437 {
1438 // An assert should not fire.
1439 const char* xml = "<element/>";
1440 XMLDocument doc;
1441 doc.Parse( xml );
1442 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1443 XMLTest( "Tracking unused elements", true, ele != 0, false );
1444 }
1445
Lee Thomasona6412ac2012-12-13 15:39:11 -08001446
1447 {
1448 const char* xml = "<parent><child>abc</child></parent>";
1449 XMLDocument doc;
1450 doc.Parse( xml );
1451 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1452
1453 XMLPrinter printer;
1454 ele->Accept( &printer );
1455 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1456 }
1457
1458
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001459 {
1460 XMLDocument doc;
1461 XMLError error = doc.LoadFile( "resources/empty.xml" );
1462 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001463 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001464 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001465 }
1466
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001467 {
1468 // BOM preservation
1469 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1470 {
1471 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001472 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001473 XMLPrinter printer;
1474 doc.Print( &printer );
1475
1476 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1477 doc.SaveFile( "resources/bomtest.xml" );
1478 }
1479 {
1480 XMLDocument doc;
1481 doc.LoadFile( "resources/bomtest.xml" );
1482 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1483
1484 XMLPrinter printer;
1485 doc.Print( &printer );
1486 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1487 }
1488 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001489
Michael Daumlinged523282013-10-23 07:47:29 +02001490 {
1491 // Insertion with Removal
1492 const char* xml = "<?xml version=\"1.0\" ?>"
1493 "<root>"
1494 "<one>"
1495 "<subtree>"
1496 "<elem>element 1</elem>text<!-- comment -->"
1497 "</subtree>"
1498 "</one>"
1499 "<two/>"
1500 "</root>";
1501 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1502 "<root>"
1503 "<one/>"
1504 "<two>"
1505 "<subtree>"
1506 "<elem>element 1</elem>text<!-- comment -->"
1507 "</subtree>"
1508 "</two>"
1509 "</root>";
1510 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1511 "<root>"
1512 "<one/>"
1513 "<subtree>"
1514 "<elem>element 1</elem>text<!-- comment -->"
1515 "</subtree>"
1516 "<two/>"
1517 "</root>";
1518 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1519 "<root>"
1520 "<one/>"
1521 "<two/>"
1522 "<subtree>"
1523 "<elem>element 1</elem>text<!-- comment -->"
1524 "</subtree>"
1525 "</root>";
1526
1527 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001528 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001529 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1530 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1531 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001532 XMLPrinter printer1(0, true);
1533 doc.Accept(&printer1);
1534 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001535
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001536 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001537 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1538 two = doc.RootElement()->FirstChildElement("two");
1539 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001540 XMLPrinter printer2(0, true);
1541 doc.Accept(&printer2);
1542 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001543
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001544 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001545 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1546 subtree = one->FirstChildElement("subtree");
1547 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001548 XMLPrinter printer3(0, true);
1549 doc.Accept(&printer3);
1550 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001551
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001552 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001553 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1554 two = doc.RootElement()->FirstChildElement("two");
1555 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001556 XMLPrinter printer4(0, true);
1557 doc.Accept(&printer4);
1558 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001559 }
1560
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001561 {
1562 const char* xml = "<svg width = \"128\" height = \"128\">"
1563 " <text> </text>"
1564 "</svg>";
1565 XMLDocument doc;
1566 doc.Parse(xml);
1567 doc.Print();
1568 }
1569
Lee Thomason92e521b2014-11-15 17:45:51 -08001570 {
1571 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001572 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1573 XMLDocument doc;
1574 doc.Parse(xml);
1575 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001576 }
1577
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001578#if 1
1579 // the question being explored is what kind of print to use:
1580 // https://github.com/leethomason/tinyxml2/issues/63
1581 {
1582 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1583 const char* xml = "<element/>";
1584 XMLDocument doc;
1585 doc.Parse( xml );
1586 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1587 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1588 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1589 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1590 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1591 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1592
1593 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1594 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1595 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1596 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1597 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1598 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1599
1600 doc.Print();
1601
1602 /* The result of this test is platform, compiler, and library version dependent. :("
1603 XMLPrinter printer;
1604 doc.Print( &printer );
1605 XMLTest( "Float and double formatting.",
1606 "<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",
1607 printer.CStr(),
1608 true );
1609 */
1610 }
1611#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001612
1613 {
1614 // Issue #184
1615 // If it doesn't assert, it passes. Caused by objects
1616 // getting created during parsing which are then
1617 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001618 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001619 {
1620 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001621 doc.Parse(xmlText);
Lee Thomasonf07b9522014-10-30 13:25:12 -07001622 }
1623 {
1624 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001625 doc.Parse(xmlText);
Lee Thomasonf07b9522014-10-30 13:25:12 -07001626 doc.Clear();
1627 }
1628 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001629
1630 {
1631 // If this doesn't assert in DEBUG, all is well.
1632 tinyxml2::XMLDocument doc;
1633 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1634 doc.DeleteNode(pRoot);
1635 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001636
Dmitry-Me8b67d742014-12-22 11:35:12 +03001637 {
1638 // Should not assert in DEBUG
1639 XMLPrinter printer;
1640 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001641
Dmitry-Me6f51c802015-03-14 13:25:03 +03001642 {
1643 // Issue 291. Should not crash
1644 const char* xml = "&#0</a>";
1645 XMLDocument doc;
1646 doc.Parse( xml );
1647
1648 XMLPrinter printer;
1649 doc.Print( &printer );
1650 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001651 {
1652 // Issue 299. Can print elements that are not linked in.
1653 // Will crash if issue not fixed.
1654 XMLDocument doc;
1655 XMLElement* newElement = doc.NewElement( "printme" );
1656 XMLPrinter printer;
1657 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001658 // Delete the node to avoid possible memory leak report in debug output
1659 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001660 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001661 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001662 // Issue 302. Clear errors from LoadFile/SaveFile
1663 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001664 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001665 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001666 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001667 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001668 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001669 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001670
Dmitry-Med9852a52015-03-25 10:17:49 +03001671 {
1672 // If a document fails to load then subsequent
1673 // successful loads should clear the error
1674 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001675 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001676 doc.LoadFile( "resources/no-such-file.xml" );
1677 XMLTest( "No such file - should fail", true, doc.Error() );
1678
1679 doc.LoadFile( "resources/dream.xml" );
1680 XMLTest( "Error should be cleared", false, doc.Error() );
1681 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301682
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301683 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001684 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001685 const char* xml0 = "<?xml version=\"1.0\" ?>"
1686 " <!-- xml version=\"1.1\" -->"
1687 "<first />";
1688 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001689 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001690 "<first />";
1691 const char* xml2 = "<first />"
1692 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001693 const char* xml3 = "<first></first>"
1694 "<?xml version=\"1.0\" ?>";
1695
1696 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1697
Lee Thomason85492022015-05-22 11:07:45 -07001698 XMLDocument doc;
1699 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001700 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001701 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001702 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001703 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001704 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001705 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001706 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001707 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001708 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301709 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001710
Lee Thomason85492022015-05-22 11:07:45 -07001711 {
1712 // No matter - before or after successfully parsing a text -
1713 // calling XMLDocument::Value() causes an assert in debug.
1714 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1715 "<first />"
1716 "<second />";
1717 XMLDocument* doc = new XMLDocument();
1718 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1719 doc->Parse( validXml );
1720 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1721 delete doc;
1722 }
1723
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001724 {
1725 XMLDocument doc;
1726 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001727 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001728 doc.ErrorName();
1729 }
1730 }
1731
Lee Thomason816d3fa2017-06-05 14:35:55 -07001732 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001733 // Evil memory leaks.
1734 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1735 // and NOT added to the XMLDocument, what happens?
1736 //
1737 // Previously (buggy):
1738 // The memory would be free'd when the XMLDocument is
1739 // destructed. But the destructor wasn't called, so that
1740 // memory allocated by the XMLElement would not be free'd.
1741 // In practice this meant strings allocated by the XMLElement
1742 // would leak. An edge case, but annoying.
1743 // Now:
1744 // The destructor is called. But the list of unlinked nodes
1745 // has to be tracked. This has a minor performance impact
1746 // that can become significant if you have a lot. (But why
1747 // would you do that?)
1748 // The only way to see this bug is in a leak tracker. This
1749 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001750 {
1751 XMLDocument doc;
1752 doc.NewElement("LEAK 1");
1753 }
1754 {
1755 XMLDocument doc;
1756 XMLElement* ele = doc.NewElement("LEAK 2");
1757 doc.DeleteNode(ele);
1758 }
1759 }
1760
Lee Thomason224ef772017-06-16 09:45:26 -07001761 {
1762 // Crashing reported via email.
1763 const char* xml =
1764 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001765 "<property name='track_name'>voice</property>"
1766 "<property name='audio_track'>1</property>"
1767 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1768 "<blank length = '1' />"
1769 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1770 "<blank length = '2' />"
1771 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1772 "<blank length = '1' />"
1773 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001774 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001775
Lee Thomason224ef772017-06-16 09:45:26 -07001776 // It's not a good idea to delete elements as you walk the
1777 // list. I'm not sure this technically should work; but it's
1778 // an interesting test case.
1779 XMLDocument doc;
1780 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001781 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03001782
1783 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001784 XMLTest("Crash bug parsing", true, playlist != 0);
1785
1786 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1787 XMLTest("Crash bug parsing", true, entry != 0);
1788 while (entry) {
1789 tinyxml2::XMLElement* todelete = entry;
1790 entry = entry->NextSiblingElement("entry");
1791 playlist->DeleteChild(todelete);
1792 };
1793 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1794 while (blank) {
1795 tinyxml2::XMLElement* todelete = blank;
1796 blank = blank->NextSiblingElement("blank");
1797 playlist->DeleteChild(todelete);
1798 };
1799
1800 tinyxml2::XMLPrinter printer;
1801 playlist->Accept(&printer);
1802 printf("%s\n", printer.CStr());
1803
Lee Thomason82bb0742017-06-16 09:48:20 -07001804 // No test; it only need to not crash.
1805 // Still, wrap it up with a sanity check
1806 int nProperty = 0;
1807 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1808 nProperty++;
1809 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001810 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07001811 }
1812
kezenatorec694152016-11-26 17:21:43 +10001813 // ----------- Line Number Tracking --------------
1814 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001815 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001816 {
1817 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1818 {
1819 XMLDocument doc;
1820 XMLError err = doc.Parse(docStr);
1821
1822 XMLTest(testString, true, doc.Error());
1823 XMLTest(testString, expected_error, err);
1824 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1825 };
1826
1827 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1828 {
1829 XMLDocument doc;
1830 doc.Parse(docStr);
1831 XMLTest(testString, false, doc.Error());
1832 TestDocLines(testString, doc, expectedLines);
1833 }
1834
1835 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1836 {
1837 XMLDocument doc;
1838 doc.LoadFile(file_name);
1839 XMLTest(testString, false, doc.Error());
1840 TestDocLines(testString, doc, expectedLines);
1841 }
1842
1843 private:
1844 DynArray<char, 10> str;
1845
1846 void Push(char type, int lineNum)
1847 {
1848 str.Push(type);
1849 str.Push(char('0' + (lineNum / 10)));
1850 str.Push(char('0' + (lineNum % 10)));
1851 }
1852
1853 bool VisitEnter(const XMLDocument& doc)
1854 {
kezenator19d8ea82016-11-29 19:50:27 +10001855 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001856 return true;
1857 }
1858 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
1859 {
kezenator19d8ea82016-11-29 19:50:27 +10001860 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001861 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10001862 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001863 return true;
1864 }
1865 bool Visit(const XMLDeclaration& declaration)
1866 {
kezenator19d8ea82016-11-29 19:50:27 +10001867 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001868 return true;
1869 }
1870 bool Visit(const XMLText& text)
1871 {
kezenator19d8ea82016-11-29 19:50:27 +10001872 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001873 return true;
1874 }
1875 bool Visit(const XMLComment& comment)
1876 {
kezenator19d8ea82016-11-29 19:50:27 +10001877 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001878 return true;
1879 }
1880 bool Visit(const XMLUnknown& unknown)
1881 {
kezenator19d8ea82016-11-29 19:50:27 +10001882 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001883 return true;
1884 }
1885
1886 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
1887 {
1888 str.Clear();
1889 doc.Accept(this);
1890 str.Push(0);
1891 XMLTest(testString, expectedLines, str.Mem());
1892 }
Lee Thomasone90e9012016-12-24 07:34:39 -08001893 } tester;
kezenatorec694152016-11-26 17:21:43 +10001894
Lee Thomasone90e9012016-12-24 07:34:39 -08001895 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
1896 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
1897 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
1898 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
1899 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
1900 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
1901 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
1902 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
1903 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
1904 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
1905 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10001906
Lee Thomasone90e9012016-12-24 07:34:39 -08001907 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001908 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08001909
1910 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
1911 "<root a='b' \n" // 2 Element Attribute
1912 "c='d'> d <blah/> \n" // 3 Attribute Text Element
1913 "newline in text \n" // 4 Text
1914 "and second <zxcv/><![CDATA[\n" // 5 Element Text
1915 " cdata test ]]><!-- comment -->\n" // 6 Comment
1916 "<! unknown></root>", // 7 Unknown
1917
kezenatorec694152016-11-26 17:21:43 +10001918 "D01L01E02A02A03T03E03T04E05T05C06U07");
1919
Lee Thomasone90e9012016-12-24 07:34:39 -08001920 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001921 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08001922
1923 "\r\n" // 1 Doc (arguably should be line 2)
1924 "<?xml version=\"1.0\"?>\n" // 2 DecL
1925 "<root>\r\n" // 3 Element
1926 "\n" // 4
1927 "text contining new line \n" // 5 Text
1928 " and also containing crlf \r\n" // 6
1929 "<sub><![CDATA[\n" // 7 Element Text
1930 "cdata containing new line \n" // 8
1931 " and also containing cflr\r\n" // 9
1932 "]]></sub><sub2/></root>", // 10 Element
1933
kezenatorec694152016-11-26 17:21:43 +10001934 "D01L02E03T05E07T07E10");
1935
Lee Thomasone90e9012016-12-24 07:34:39 -08001936 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10001937 "LineNumbers-File",
1938 "resources/utf8test.xml",
1939 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
1940 }
1941
Lee Thomason85492022015-05-22 11:07:45 -07001942 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08001943 {
1944#if defined( _MSC_VER )
1945 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001946 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08001947#endif
1948
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001949 FILE* perfFP = fopen("resources/dream.xml", "r");
1950 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02001951 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001952 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08001953
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001954 char* mem = new char[size + 1];
1955 fread(mem, size, 1, perfFP);
1956 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08001957 mem[size] = 0;
1958
1959#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001960 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08001961#else
1962 clock_t cstart = clock();
1963#endif
1964 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001965 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001966 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001967 doc.Parse(mem);
Lee Thomason6f381b72012-03-02 12:59:39 -08001968 }
1969#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001970 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08001971#else
1972 clock_t cend = clock();
1973#endif
1974
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001975 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08001976
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001977 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001978#ifdef DEBUG
1979 "DEBUG";
1980#else
1981 "Release";
1982#endif
1983
1984#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001985 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 -08001986#else
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001987 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08001988#endif
1989 }
1990
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001991 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001992 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001993
1994 _CrtMemState diffMemState;
1995 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1996 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03001997
1998 {
1999 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2000 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2001 }
Lee Thomason1ff38e02012-02-14 18:18:16 -08002002 #endif
2003
2004 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002005
2006 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002007}