blob: ca8995d931362292d1e3ff6528e37ab020dc2da2 [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"
kbinny62bf29a152017-06-23 18:15:25 +00008#include <cerrno>
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07009#include <cstdlib>
10#include <cstring>
11#include <ctime>
U-Lama\Leee13c3e62011-12-28 14:36:55 -080012
kbinny62bf29a152017-06-23 18:15:25 +000013#if defined( _MSC_VER ) || defined (WIN32)
Lee Thomason1ff38e02012-02-14 18:18:16 -080014 #include <crtdbg.h>
Lee Thomason6f381b72012-03-02 12:59:39 -080015 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080017 _CrtMemState startMemState;
Lee Thomason53858b42017-06-01 19:09:16 -070018 _CrtMemState endMemState;
kbinny62bf29a152017-06-23 18:15:25 +000019#else
20 #include <sys/stat.h>
21 #include <sys/types.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080022#endif
Lee Thomasone9ecdab2012-02-13 18:11:20 -080023
U-Lama\Leee13c3e62011-12-28 14:36:55 -080024using namespace tinyxml2;
Anton Indrawan8a0006c2014-11-20 18:27:07 +010025using namespace std;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080026int gPass = 0;
27int gFail = 0;
28
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080029
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070030bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080031{
Sarat Addepalli13b2d732015-05-19 12:44:57 +053032 bool pass;
33 if ( !expected && !found )
34 pass = true;
35 else if ( !expected || !found )
36 pass = false;
Sarat Addepallid608c562015-05-20 10:19:00 +053037 else
38 pass = !strcmp( expected, found );
Lee Thomason1ff38e02012-02-14 18:18:16 -080039 if ( pass )
40 printf ("[pass]");
41 else
42 printf ("[fail]");
43
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070044 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080045 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070046 }
47 else {
48 if ( extraNL ) {
49 printf( " %s\n", testString );
50 printf( "%s\n", expected );
51 printf( "%s\n", found );
52 }
53 else {
54 printf (" %s [%s][%s]\n", testString, expected, found);
55 }
56 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080057
58 if ( pass )
59 ++gPass;
60 else
61 ++gFail;
62 return pass;
63}
64
kezenator5a700712016-11-26 13:54:42 +100065bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
66{
Lee Thomasone90e9012016-12-24 07:34:39 -080067 return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
kezenator5a700712016-11-26 13:54:42 +100068}
69
70bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
71{
72 return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
73}
Lee Thomason1ff38e02012-02-14 18:18:16 -080074
Lee Thomason21be8822012-07-15 17:27:22 -070075template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080076{
77 bool pass = ( expected == found );
78 if ( pass )
79 printf ("[pass]");
80 else
81 printf ("[fail]");
82
U-Stream\Lee09a11c52012-02-17 08:31:16 -080083 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080084 printf (" %s\n", testString);
85 else
Lee Thomasonc8312792012-07-16 12:44:41 -070086 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080087
88 if ( pass )
89 ++gPass;
90 else
91 ++gFail;
92 return pass;
93}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080094
U-Lama\Leee13c3e62011-12-28 14:36:55 -080095
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080096void NullLineEndings( char* p )
97{
98 while( p && *p ) {
99 if ( *p == '\n' || *p == '\r' ) {
100 *p = 0;
101 return;
102 }
103 ++p;
104 }
105}
106
107
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700108int example_1()
109{
110 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300111 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700112
113 return doc.ErrorID();
114}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200115/** @page Example-1 Load an XML File
116 * @dontinclude ./xmltest.cpp
117 * Basic XML file loading.
118 * The basic syntax to load an XML file from
119 * disk and check for an error. (ErrorID()
120 * will return 0 for no error.)
121 * @skip example_1()
122 * @until }
123 */
124
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700125
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700126int example_2()
127{
128 static const char* xml = "<element/>";
129 XMLDocument doc;
130 doc.Parse( xml );
131
132 return doc.ErrorID();
133}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200134/** @page Example-2 Parse an XML from char buffer
135 * @dontinclude ./xmltest.cpp
136 * Basic XML string parsing.
137 * The basic syntax to parse an XML for
138 * a char* and check for an error. (ErrorID()
139 * will return 0 for no error.)
140 * @skip example_2()
141 * @until }
142 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700143
144
145int example_3()
146{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700147 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700148 "<?xml version=\"1.0\"?>"
149 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
150 "<PLAY>"
151 "<TITLE>A Midsummer Night's Dream</TITLE>"
152 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700153
154 XMLDocument doc;
155 doc.Parse( xml );
156
157 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
158 const char* title = titleElement->GetText();
159 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700160
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700161 XMLText* textNode = titleElement->FirstChild()->ToText();
162 title = textNode->Value();
163 printf( "Name of play (2): %s\n", title );
164
165 return doc.ErrorID();
166}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200167/** @page Example-3 Get information out of XML
168 @dontinclude ./xmltest.cpp
169 In this example, we navigate a simple XML
170 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700171 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200172 checking; working code should check for null
173 pointers when walking an XML tree, or use
174 XMLHandle.
175
176 (The XML is an excerpt from "dream.xml").
177
178 @skip example_3()
179 @until </PLAY>";
180
181 The structure of the XML file is:
182
183 <ul>
184 <li>(declaration)</li>
185 <li>(dtd stuff)</li>
186 <li>Element "PLAY"</li>
187 <ul>
188 <li>Element "TITLE"</li>
189 <ul>
190 <li>Text "A Midsummer Night's Dream"</li>
191 </ul>
192 </ul>
193 </ul>
194
195 For this example, we want to print out the
196 title of the play. The text of the title (what
197 we want) is child of the "TITLE" element which
198 is a child of the "PLAY" element.
199
200 We want to skip the declaration and dtd, so the
201 method FirstChildElement() is a good choice. The
202 FirstChildElement() of the Document is the "PLAY"
203 Element, the FirstChildElement() of the "PLAY" Element
204 is the "TITLE" Element.
205
206 @until ( "TITLE" );
207
208 We can then use the convenience function GetText()
209 to get the title of the play.
210
211 @until title );
212
213 Text is just another Node in the XML DOM. And in
214 fact you should be a little cautious with it, as
215 text nodes can contain elements.
216
217 @verbatim
218 Consider: A Midsummer Night's <b>Dream</b>
219 @endverbatim
220
221 It is more correct to actually query the Text Node
222 if in doubt:
223
224 @until title );
225
226 Noting that here we use FirstChild() since we are
227 looking for XMLText, not an element, and ToText()
228 is a cast from a Node to a XMLText.
229*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700230
231
Lee Thomason21be8822012-07-15 17:27:22 -0700232bool example_4()
233{
234 static const char* xml =
235 "<information>"
236 " <attributeApproach v='2' />"
237 " <textApproach>"
238 " <v>2</v>"
239 " </textApproach>"
240 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700241
Lee Thomason21be8822012-07-15 17:27:22 -0700242 XMLDocument doc;
243 doc.Parse( xml );
244
245 int v0 = 0;
246 int v1 = 0;
247
248 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
249 attributeApproachElement->QueryIntAttribute( "v", &v0 );
250
251 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
252 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
253
254 printf( "Both values are the same: %d and %d\n", v0, v1 );
255
256 return !doc.Error() && ( v0 == v1 );
257}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200258/** @page Example-4 Read attributes and text information.
259 @dontinclude ./xmltest.cpp
260
261 There are fundamentally 2 ways of writing a key-value
262 pair into an XML file. (Something that's always annoyed
263 me about XML.) Either by using attributes, or by writing
264 the key name into an element and the value into
265 the text node wrapped by the element. Both approaches
266 are illustrated in this example, which shows two ways
267 to encode the value "2" into the key "v":
268
269 @skip example_4()
270 @until "</information>";
271
272 TinyXML-2 has accessors for both approaches.
273
274 When using an attribute, you navigate to the XMLElement
275 with that attribute and use the QueryIntAttribute()
276 group of methods. (Also QueryFloatAttribute(), etc.)
277
278 @skip XMLElement* attributeApproachElement
279 @until &v0 );
280
281 When using the text approach, you need to navigate
282 down one more step to the XMLElement that contains
283 the text. Note the extra FirstChildElement( "v" )
284 in the code below. The value of the text can then
285 be safely queried with the QueryIntText() group
286 of methods. (Also QueryFloatText(), etc.)
287
288 @skip XMLElement* textApproachElement
289 @until &v1 );
290*/
Lee Thomason21be8822012-07-15 17:27:22 -0700291
292
Lee Thomason178e4cc2013-01-25 16:19:05 -0800293int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800294{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800295 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800296 _CrtMemCheckpoint( &startMemState );
Dmitry-Me99916592014-10-23 11:37:03 +0400297 // Enable MS Visual C++ debug heap memory leaks dump on exit
298 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
Dmitry-Meed785702017-06-15 13:39:53 +0300299 {
300 int leaksOnStart = _CrtDumpMemoryLeaks();
301 XMLTest( "No leaks on start?", FALSE, leaksOnStart );
302 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700303 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800304
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300305 {
306 TIXMLASSERT( true );
307 }
308
Lee Thomason178e4cc2013-01-25 16:19:05 -0800309 if ( argc > 1 ) {
310 XMLDocument* doc = new XMLDocument();
311 clock_t startTime = clock();
312 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100313 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800314 int errorID = doc->ErrorID();
315 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100316 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800317
318 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
319 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700320 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
321 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
322 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800323 }
324 exit(0);
325 }
326
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300327 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700328 if ( !fp ) {
329 printf( "Error opening test file 'dream.xml'.\n"
330 "Is your working directory the same as where \n"
331 "the xmltest.cpp and dream.xml file are?\n\n"
332 #if defined( _MSC_VER )
333 "In windows Visual Studio you may need to set\n"
334 "Properties->Debugging->Working Directory to '..'\n"
335 #endif
336 );
337 exit( 1 );
338 }
339 fclose( fp );
340
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700341 XMLTest( "Example-1", 0, example_1() );
342 XMLTest( "Example-2", 0, example_2() );
343 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700344 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700345
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700346 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700347
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800348 {
Lee Thomason43f59302012-02-06 18:18:11 -0800349 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400350 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800351 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400352 "<element><subelement></subelement></element>",
353 "<element><subelement><subsub/></subelement></element>",
354 "<!--comment beside elements--><element><subelement></subelement></element>",
355 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
356 "<element attrib1='foo' attrib2=\"bar\" ></element>",
357 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800358 "<element>Text inside element.</element>",
359 "<element><b></b></element>",
360 "<element>Text inside and <b>bolded</b> in the element.</element>",
361 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800362 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800363 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800364 0
365 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800366 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800367 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800368 doc.Parse( test[i] );
Dmitry-Me68578f42017-07-03 18:21:23 +0300369 XMLTest( "Element test", false, doc.Error() );
Lee Thomason5cae8972012-01-24 18:03:07 -0800370 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800371 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800372 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800373 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800374#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800375 {
376 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400377 " line 2\r"
378 " line 3\r\n"
379 " line 4\n\r"
380 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800381
382 XMLDocument doc;
383 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300384 XMLTest( "Hello world declaration", false, doc.Error() );
Lee Thomasond6277762012-02-22 16:00:12 -0800385 doc.Print();
386 }
387
Lee Thomason2c85a712012-01-31 08:24:24 -0800388 {
389 static const char* test = "<element>Text before.</element>";
390 XMLDocument doc;
391 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300392 XMLTest( "Element text before", false, doc.Error() );
Lee Thomason2c85a712012-01-31 08:24:24 -0800393 XMLElement* root = doc.FirstChildElement();
394 XMLElement* newElement = doc.NewElement( "Subelement" );
395 root->InsertEndChild( newElement );
396 doc.Print();
397 }
Lee Thomasond1983222012-02-06 08:41:24 -0800398 {
399 XMLDocument* doc = new XMLDocument();
400 static const char* test = "<element><sub/></element>";
401 doc->Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300402 XMLTest( "Element with sub element", false, doc->Error() );
Lee Thomasond1983222012-02-06 08:41:24 -0800403 delete doc;
404 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800405 {
Dmitry-Me8e063702017-08-01 17:40:40 +0300406 // Test: Programmatic DOM nodes insertion return values
407 XMLDocument doc;
408
409 XMLNode* first = doc.NewElement( "firstElement" );
410 XMLTest( "New element", true, first != 0 );
411 XMLNode* firstAfterInsertion = doc.InsertFirstChild( first );
412 XMLTest( "New element inserted first", true, firstAfterInsertion == first );
413
414 XMLNode* last = doc.NewElement( "lastElement" );
415 XMLTest( "New element", true, last != 0 );
416 XMLNode* lastAfterInsertion = doc.InsertEndChild( last );
417 XMLTest( "New element inserted last", true, lastAfterInsertion == last );
418
419 XMLNode* middle = doc.NewElement( "middleElement" );
420 XMLTest( "New element", true, middle != 0 );
421 XMLNode* middleAfterInsertion = doc.InsertAfterChild( first, middle );
422 XMLTest( "New element inserted middle", true, middleAfterInsertion == middle );
423 }
424 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800425 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800426 // Build:
427 // <element>
428 // <!--comment-->
429 // <sub attrib="1" />
430 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800431 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800432 // <element>
433
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800434 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800435 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
436
437 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
438 for( int i=0; i<3; ++i ) {
439 sub[i]->SetAttribute( "attrib", i );
440 }
441 element->InsertEndChild( sub[2] );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300442
443 const int dummyInitialValue = 1000;
444 int dummyValue = dummyInitialValue;
445
Lee Thomason1ff38e02012-02-14 18:18:16 -0800446 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300447 comment->SetUserData(&dummyValue);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800448 element->InsertAfterChild( comment, sub[0] );
449 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800450 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800451 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800452 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
453 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
454 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700455 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800456 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Dmitry-Mecaed4ec2017-08-11 17:39:47 +0300457 XMLTest("User data - pointer", true, &dummyValue == comment->GetUserData(), false);
458 XMLTest("User data - value behind pointer", dummyInitialValue, dummyValue, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800459
460 // And now deletion:
461 element->DeleteChild( sub[2] );
462 doc->DeleteNode( comment );
463
464 element->FirstChildElement()->SetAttribute( "attrib", true );
465 element->LastChildElement()->DeleteAttribute( "attrib" );
466
467 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300468 const int defaultIntValue = 10;
469 const int replacementIntValue = 20;
470 int value1 = defaultIntValue;
471 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300472 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
473 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300474 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
475 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800476
477 doc->Print();
478
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700479 {
480 XMLPrinter streamer;
481 doc->Print( &streamer );
482 printf( "%s", streamer.CStr() );
483 }
484 {
485 XMLPrinter streamer( 0, true );
486 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200487 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700488 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700489 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300490 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700491 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300492 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800493 delete doc;
494 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800495 {
496 // Test: Dream
497 // XML1 : 1,187,569 bytes in 31,209 allocations
498 // XML2 : 469,073 bytes in 323 allocations
499 //int newStart = gNew;
500 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300501 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300502 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800503
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400504 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300505 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800506 doc.PrintError();
507
508 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400509 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800510 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
511 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
512 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
513 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400514 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800515 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400516 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800517
518 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400519 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300520 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800521 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400522 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800523 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
524 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
525 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
526 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400527 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800528
529 //gNewTotal = gNew - newStart;
530 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800531
532
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800533 {
534 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
535 "<passages count=\"006\" formatversion=\"20020620\">\n"
536 " <wrong error>\n"
537 "</passages>";
538
539 XMLDocument doc;
540 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300541 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800542 }
543
544 {
545 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
546
547 XMLDocument doc;
548 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300549 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550
551 XMLElement* ele = doc.FirstChildElement();
552
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300553 int iVal;
554 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800555 double dVal;
556
557 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300558 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
559 XMLTest( "Query attribute: int as double", 1, (int)dVal );
560 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700561
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800562 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300563 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
564 XMLTest( "Query attribute: double as double", 2.0, dVal );
565 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700566
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800567 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300568 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
569 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700570
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800571 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300572 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
573 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700574
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800575 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300576 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
577 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800578 }
579
580 {
581 const char* str = "<doc/>";
582
583 XMLDocument doc;
584 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300585 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800586
587 XMLElement* ele = doc.FirstChildElement();
588
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800589 int iVal, iVal2;
590 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800591
592 ele->SetAttribute( "str", "strValue" );
593 ele->SetAttribute( "int", 1 );
594 ele->SetAttribute( "double", -1.0 );
595
596 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300597 {
598 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
599 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
600 }
601 {
602 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
603 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
604 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800605
Dmitry-Me2087a272017-07-10 18:13:07 +0300606 {
607 int queryResult = ele->QueryAttribute( "int", &iVal2 );
608 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
609 }
610 {
611 int queryResult = ele->QueryAttribute( "double", &dVal2 );
612 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
613 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800614
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300615 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800616 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
617 XMLTest( "Attribute round trip. int.", 1, iVal );
618 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800619 XMLTest( "Alternate query", true, iVal == iVal2 );
620 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700621 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
622 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800623 }
624
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800625 {
626 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300627 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300628 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800629
630 // Get the attribute "value" from the "Russian" element and check it.
631 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700632 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800633 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
634
635 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
636
637 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
638 0xd1U, 0x81U, 0xd1U, 0x81U,
639 0xd0U, 0xbaU, 0xd0U, 0xb8U,
640 0xd0U, 0xb9U, 0 };
641 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
642
643 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
644 XMLTest( "UTF-8: Browsing russian element name.",
645 russianText,
646 text->Value() );
647
648 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400649 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300650 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800651
652 // Check the round trip.
Dmitry-Me520009e2017-08-10 17:50:03 +0300653 bool roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800654
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200655 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300656 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
657
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300658 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300659 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800660
661 if ( saved && verify )
662 {
Dmitry-Me520009e2017-08-10 17:50:03 +0300663 roundTripOkay = true;
PKEuSc28ba3a2012-07-16 03:08:47 -0700664 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800665 while ( fgets( verifyBuf, 256, verify ) )
666 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700667 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800668 fgets( savedBuf, 256, saved );
669 NullLineEndings( verifyBuf );
670 NullLineEndings( savedBuf );
671
672 if ( strcmp( verifyBuf, savedBuf ) )
673 {
674 printf( "verify:%s<\n", verifyBuf );
675 printf( "saved :%s<\n", savedBuf );
Dmitry-Me520009e2017-08-10 17:50:03 +0300676 roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800677 break;
678 }
679 }
680 }
681 if ( saved )
682 fclose( saved );
683 if ( verify )
684 fclose( verify );
Dmitry-Me520009e2017-08-10 17:50:03 +0300685 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800686 }
687
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800688 // --------GetText()-----------
689 {
690 const char* str = "<foo>This is text</foo>";
691 XMLDocument doc;
692 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300693 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800694 const XMLElement* element = doc.RootElement();
695
696 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
697
698 str = "<foo><b>This is text</b></foo>";
699 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300700 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800701 element = doc.RootElement();
702
703 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
704 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800705
Lee Thomasond6277762012-02-22 16:00:12 -0800706
Uli Kusterer321072e2014-01-21 01:57:38 +0100707 // --------SetText()-----------
708 {
709 const char* str = "<foo></foo>";
710 XMLDocument doc;
711 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300712 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100713 XMLElement* element = doc.RootElement();
714
Lee Thomason9c0678a2014-01-24 10:18:27 -0800715 element->SetText("darkness.");
716 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100717
Lee Thomason9c0678a2014-01-24 10:18:27 -0800718 element->SetText("blue flame.");
719 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100720
721 str = "<foo/>";
722 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300723 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100724 element = doc.RootElement();
725
Lee Thomason9c0678a2014-01-24 10:18:27 -0800726 element->SetText("The driver");
727 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100728
Lee Thomason9c0678a2014-01-24 10:18:27 -0800729 element->SetText("<b>horses</b>");
730 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
731 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100732
733 str = "<foo><bar>Text in nested element</bar></foo>";
734 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300735 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100736 element = doc.RootElement();
737
Lee Thomason9c0678a2014-01-24 10:18:27 -0800738 element->SetText("wolves");
739 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800740
741 str = "<foo/>";
742 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300743 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800744 element = doc.RootElement();
745
746 element->SetText( "str" );
747 XMLTest( "SetText types", "str", element->GetText() );
748
749 element->SetText( 1 );
750 XMLTest( "SetText types", "1", element->GetText() );
751
752 element->SetText( 1U );
753 XMLTest( "SetText types", "1", element->GetText() );
754
755 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200756 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800757
758 element->SetText( 1.5f );
759 XMLTest( "SetText types", "1.5", element->GetText() );
760
761 element->SetText( 1.5 );
762 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100763 }
764
Lee Thomason51c12712016-06-04 20:18:49 -0700765 // ---------- Attributes ---------
766 {
767 static const int64_t BIG = -123456789012345678;
768 XMLDocument doc;
769 XMLElement* element = doc.NewElement("element");
770 doc.InsertFirstChild(element);
771
772 {
773 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300774 {
775 int v = 0;
776 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
777 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
778 XMLTest("Attribute: int", -100, v, true);
779 }
780 {
781 int v = 0;
782 int queryResult = element->QueryAttribute("attrib", &v);
783 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
784 XMLTest("Attribute: int", -100, v, true);
785 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700786 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700787 }
788 {
789 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300790 {
791 unsigned v = 0;
792 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
793 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
794 XMLTest("Attribute: unsigned", unsigned(100), v, true);
795 }
796 {
797 unsigned v = 0;
798 int queryResult = element->QueryAttribute("attrib", &v);
799 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
800 XMLTest("Attribute: unsigned", unsigned(100), v, true);
801 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700802 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700803 }
804 {
805 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300806 {
807 int64_t v = 0;
808 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
809 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
810 XMLTest("Attribute: int64_t", BIG, v, true);
811 }
812 {
813 int64_t v = 0;
814 int queryResult = element->QueryAttribute("attrib", &v);
815 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
816 XMLTest("Attribute: int64_t", BIG, v, true);
817 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700818 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700819 }
820 {
821 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300822 {
823 bool v = false;
824 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
825 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
826 XMLTest("Attribute: bool", true, v, true);
827 }
828 {
829 bool v = false;
830 int queryResult = element->QueryAttribute("attrib", &v);
831 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
832 XMLTest("Attribute: bool", true, v, true);
833 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700834 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700835 }
836 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800837 element->SetAttribute("attrib", true);
838 const char* result = element->Attribute("attrib");
839 XMLTest("Bool true is 'true'", "true", result);
840
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800841 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800842 element->SetAttribute("attrib", true);
843 result = element->Attribute("attrib");
844 XMLTest("Bool true is '1'", "1", result);
845
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800846 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800847 }
848 {
Lee Thomason51c12712016-06-04 20:18:49 -0700849 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300850 {
851 double v = 0;
852 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
853 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
854 XMLTest("Attribute: double", 100.0, v, true);
855 }
856 {
857 double v = 0;
858 int queryResult = element->QueryAttribute("attrib", &v);
859 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
860 XMLTest("Attribute: double", 100.0, v, true);
861 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700862 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700863 }
864 {
865 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300866 {
867 float v = 0;
868 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
869 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
870 XMLTest("Attribute: float", 100.0f, v, true);
871 }
872 {
873 float v = 0;
874 int queryResult = element->QueryAttribute("attrib", &v);
875 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
876 XMLTest("Attribute: float", 100.0f, v, true);
877 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700878 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700879 }
880 {
881 element->SetText(BIG);
882 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300883 XMLError queryResult = element->QueryInt64Text(&v);
884 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700885 XMLTest("Element: int64_t", BIG, v, true);
886 }
887 }
888
889 // ---------- XMLPrinter stream mode ------
890 {
891 {
Dmitry-Mec0fad292017-08-09 19:05:42 +0300892 FILE* printerfp = fopen("resources/out/printer.xml", "w");
893 XMLTest("Open printer.xml", true, printerfp != 0);
Lee Thomason51c12712016-06-04 20:18:49 -0700894 XMLPrinter printer(printerfp);
895 printer.OpenElement("foo");
896 printer.PushAttribute("attrib-text", "text");
897 printer.PushAttribute("attrib-int", int(1));
898 printer.PushAttribute("attrib-unsigned", unsigned(2));
899 printer.PushAttribute("attrib-int64", int64_t(3));
900 printer.PushAttribute("attrib-bool", true);
901 printer.PushAttribute("attrib-double", 4.0);
902 printer.CloseElement();
903 fclose(printerfp);
904 }
905 {
906 XMLDocument doc;
Dmitry-Mec0fad292017-08-09 19:05:42 +0300907 doc.LoadFile("resources/out/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300908 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700909
910 const XMLDocument& cdoc = doc;
911
912 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
913 XMLTest("attrib-text", "text", attrib->Value(), true);
914 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
915 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
916 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
917 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
918 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
919 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
920 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
921 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
922 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
923 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
924 }
925
926 }
927
Uli Kusterer321072e2014-01-21 01:57:38 +0100928
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800929 // ---------- CDATA ---------------
930 {
931 const char* str = "<xmlElement>"
932 "<![CDATA["
933 "I am > the rules!\n"
934 "...since I make symbolic puns"
935 "]]>"
936 "</xmlElement>";
937 XMLDocument doc;
938 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300939 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800940 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800941
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300942 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
943 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800944 false );
945 }
946
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800947 // ----------- CDATA -------------
948 {
949 const char* str = "<xmlElement>"
950 "<![CDATA["
951 "<b>I am > the rules!</b>\n"
952 "...since I make symbolic puns"
953 "]]>"
954 "</xmlElement>";
955 XMLDocument doc;
956 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300957 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800958 doc.Print();
959
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300960 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800961 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300962 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800963 false );
964 }
965
966 // InsertAfterChild causes crash.
967 {
968 // InsertBeforeChild and InsertAfterChild causes crash.
969 XMLDocument doc;
970 XMLElement* parent = doc.NewElement( "Parent" );
971 doc.InsertFirstChild( parent );
972
973 XMLElement* childText0 = doc.NewElement( "childText0" );
974 XMLElement* childText1 = doc.NewElement( "childText1" );
975
976 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +0300977 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800978 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +0300979 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800980
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300981 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800982 }
Lee Thomasond6277762012-02-22 16:00:12 -0800983
984 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800985 // Entities not being written correctly.
986 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800987
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800988 const char* passages =
989 "<?xml version=\"1.0\" standalone=\"no\" ?>"
990 "<passages count=\"006\" formatversion=\"20020620\">"
991 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
992 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
993 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800994
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800995 XMLDocument doc;
996 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +0300997 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800998 XMLElement* psg = doc.RootElement()->FirstChildElement();
999 const char* context = psg->Attribute( "context" );
1000 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 -08001001
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001002 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -08001003
Dmitry-Me520009e2017-08-10 17:50:03 +03001004 const char* textFilePath = "resources/out/textfile.txt";
1005 FILE* textfile = fopen( textFilePath, "w" );
1006 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001007 if ( textfile )
1008 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001009 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001010 psg->Accept( &streamer );
1011 fclose( textfile );
1012 }
Thomas Roß0922b732012-09-23 16:31:22 +02001013
Dmitry-Me520009e2017-08-10 17:50:03 +03001014 textfile = fopen( textFilePath, "r" );
1015 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001016 if ( textfile )
1017 {
1018 char buf[ 1024 ];
1019 fgets( buf, 1024, textfile );
1020 XMLTest( "Entity transformation: write. ",
1021 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1022 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1023 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001024 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001025 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001026 }
1027
1028 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001029 // Suppress entities.
1030 const char* passages =
1031 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1032 "<passages count=\"006\" formatversion=\"20020620\">"
1033 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1034 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001035
Lee Thomason6f381b72012-03-02 12:59:39 -08001036 XMLDocument doc( false );
1037 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001038 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001039
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001040 XMLTest( "No entity parsing.",
1041 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1042 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1043 XMLTest( "No entity parsing.", "Crazy &ttk;",
1044 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001045 doc.Print();
1046 }
1047
1048 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001049 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001050
1051 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001052 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001053 XMLTest( "dot in names", false, doc.Error() );
1054 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1055 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001056 }
1057
1058 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001059 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001060
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001061 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001062 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001063 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001064
1065 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1066 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001067 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001068 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001069 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001070
1071 {
1072 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001073 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001074 const char* doctype =
1075 "<?xml version=\"1.0\" ?>"
1076 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1077 "<!ELEMENT title (#PCDATA)>"
1078 "<!ELEMENT books (title,authors)>"
1079 "<element />";
1080
1081 XMLDocument doc;
1082 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001083 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001084 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001085 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001086 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001087 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001088 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001089 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001090
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001091 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1092 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1093
1094 }
1095
1096 {
1097 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001098 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001099 "<!-- Somewhat<evil> -->";
1100 XMLDocument doc;
1101 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001102 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001103
1104 XMLComment* comment = doc.FirstChild()->ToComment();
1105
1106 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1107 }
1108 {
1109 // Double attributes
1110 const char* doctype = "<element attr='red' attr='blue' />";
1111
1112 XMLDocument doc;
1113 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001114
Lee Thomason2fa81722012-11-09 12:37:46 -08001115 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 -08001116 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001117 }
1118
1119 {
1120 // Embedded null in stream.
1121 const char* doctype = "<element att\0r='red' attr='blue' />";
1122
1123 XMLDocument doc;
1124 doc.Parse( doctype );
1125 XMLTest( "Embedded null throws error.", true, doc.Error() );
1126 }
1127
1128 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001129 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001130 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001131 XMLDocument doc;
1132 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001133 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001134 }
1135
1136 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001137 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1138 const char* str = " ";
1139 XMLDocument doc;
1140 doc.Parse( str );
1141 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1142 }
1143
1144 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001145 // Low entities
1146 XMLDocument doc;
1147 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001148 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001149 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001150 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001151 doc.Print();
1152 }
1153
1154 {
1155 // Attribute values with trailing quotes not handled correctly
1156 XMLDocument doc;
1157 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001158 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001159 }
1160
1161 {
1162 // [ 1663758 ] Failure to report error on bad XML
1163 XMLDocument xml;
1164 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001165 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001166 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001167 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001168 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001169 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001170 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001171
1172
1173 {
1174 // [ 1475201 ] TinyXML parses entities in comments
1175 XMLDocument xml;
1176 xml.Parse("<!-- declarations for <head> & <body> -->"
1177 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001178 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001179
1180 XMLNode* e0 = xml.FirstChild();
1181 XMLNode* e1 = e0->NextSibling();
1182 XMLComment* c0 = e0->ToComment();
1183 XMLComment* c1 = e1->ToComment();
1184
1185 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1186 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1187 }
1188
1189 {
1190 XMLDocument xml;
1191 xml.Parse( "<Parent>"
1192 "<child1 att=''/>"
1193 "<!-- With this comment, child2 will not be parsed! -->"
1194 "<child2 att=''/>"
1195 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001196 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001197 xml.Print();
1198
1199 int count = 0;
1200
1201 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1202 ele;
1203 ele = ele->NextSibling() )
1204 {
1205 ++count;
1206 }
1207
1208 XMLTest( "Comments iterate correctly.", 3, count );
1209 }
1210
1211 {
1212 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1213 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1214 buf[60] = 239;
1215 buf[61] = 0;
1216
1217 XMLDocument doc;
1218 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001219 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001220 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001221
1222
1223 {
1224 // bug 1827248 Error while parsing a little bit malformed file
1225 // Actually not malformed - should work.
1226 XMLDocument xml;
1227 xml.Parse( "<attributelist> </attributelist >" );
1228 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1229 }
1230
1231 {
1232 // This one must not result in an infinite loop
1233 XMLDocument xml;
1234 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001235 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001236 XMLTest( "Infinite loop test.", true, true );
1237 }
1238#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001239 {
1240 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1241 XMLDocument doc;
1242 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001243 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001244
1245 XMLDocument clone;
1246 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1247 XMLNode* copy = node->ShallowClone( &clone );
1248 clone.InsertEndChild( copy );
1249 }
1250
1251 clone.Print();
1252
1253 int count=0;
1254 const XMLNode* a=clone.FirstChild();
1255 const XMLNode* b=doc.FirstChild();
1256 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1257 ++count;
1258 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1259 }
1260 XMLTest( "Clone and Equal", 4, count );
1261 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001262
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001263 {
Lee Thomason7085f002017-06-01 18:09:43 -07001264 // Deep Cloning of root element.
1265 XMLDocument doc2;
1266 XMLPrinter printer1;
1267 {
1268 // Make sure doc1 is deleted before we test doc2
1269 const char* xml =
1270 "<root>"
1271 " <child1 foo='bar'/>"
1272 " <!-- comment thing -->"
1273 " <child2 val='1'>Text</child2>"
1274 "</root>";
1275 XMLDocument doc;
1276 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001277 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001278
1279 doc.Print(&printer1);
1280 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1281 doc2.InsertFirstChild(root);
1282 }
1283 XMLPrinter printer2;
1284 doc2.Print(&printer2);
1285
1286 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1287 }
1288
1289 {
1290 // Deep Cloning of sub element.
1291 XMLDocument doc2;
1292 XMLPrinter printer1;
1293 {
1294 // Make sure doc1 is deleted before we test doc2
1295 const char* xml =
1296 "<?xml version ='1.0'?>"
1297 "<root>"
1298 " <child1 foo='bar'/>"
1299 " <!-- comment thing -->"
1300 " <child2 val='1'>Text</child2>"
1301 "</root>";
1302 XMLDocument doc;
1303 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001304 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001305
1306 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1307 subElement->Accept(&printer1);
1308
1309 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1310 doc2.InsertFirstChild(clonedSubElement);
1311 }
1312 XMLPrinter printer2;
1313 doc2.Print(&printer2);
1314
1315 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1316 }
1317
1318 {
1319 // Deep cloning of document.
1320 XMLDocument doc2;
1321 XMLPrinter printer1;
1322 {
1323 // Make sure doc1 is deleted before we test doc2
1324 const char* xml =
1325 "<?xml version ='1.0'?>"
1326 "<!-- Top level comment. -->"
1327 "<root>"
1328 " <child1 foo='bar'/>"
1329 " <!-- comment thing -->"
1330 " <child2 val='1'>Text</child2>"
1331 "</root>";
1332 XMLDocument doc;
1333 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001334 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001335 doc.Print(&printer1);
1336
1337 doc.DeepCopy(&doc2);
1338 }
1339 XMLPrinter printer2;
1340 doc2.Print(&printer2);
1341
1342 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1343 }
1344
1345
1346 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001347 // This shouldn't crash.
1348 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001349 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001350 {
1351 doc.PrintError();
1352 }
1353 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1354 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001355
Lee Thomason5e3803c2012-04-16 08:57:05 -07001356 {
1357 // Attribute ordering.
1358 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1359 XMLDocument doc;
1360 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001361 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001362 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001363
Lee Thomason5e3803c2012-04-16 08:57:05 -07001364 const XMLAttribute* a = ele->FirstAttribute();
1365 XMLTest( "Attribute order", "1", a->Value() );
1366 a = a->Next();
1367 XMLTest( "Attribute order", "2", a->Value() );
1368 a = a->Next();
1369 XMLTest( "Attribute order", "3", a->Value() );
1370 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001371
Lee Thomason5e3803c2012-04-16 08:57:05 -07001372 ele->DeleteAttribute( "attrib2" );
1373 a = ele->FirstAttribute();
1374 XMLTest( "Attribute order", "1", a->Value() );
1375 a = a->Next();
1376 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001377
Lee Thomason5e3803c2012-04-16 08:57:05 -07001378 ele->DeleteAttribute( "attrib1" );
1379 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001380 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001381 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001382
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001383 {
1384 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001385 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1386 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1387 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1388 XMLDocument doc0;
1389 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001390 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001391 XMLDocument doc1;
1392 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001393 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001394 XMLDocument doc2;
1395 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001396 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001397
Lee Thomason78a773d2012-07-02 10:10:19 -07001398 XMLElement* ele = 0;
1399 ele = doc0.FirstChildElement();
1400 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1401 ele = doc1.FirstChildElement();
1402 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1403 ele = doc2.FirstChildElement();
1404 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001405 }
1406
1407 {
1408 // Make sure we don't go into an infinite loop.
1409 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1410 XMLDocument doc;
1411 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001412 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001413 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1414 XMLElement* ele1 = ele0->NextSiblingElement();
1415 bool equal = ele0->ShallowEqual( ele1 );
1416
1417 XMLTest( "Infinite loop in shallow equal.", true, equal );
1418 }
1419
Lee Thomason5708f812012-03-28 17:46:41 -07001420 // -------- Handles ------------
1421 {
1422 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1423 XMLDocument doc;
1424 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001425 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001426
1427 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001428 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001429
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001430 XMLHandle docH( doc );
1431 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001432 XMLTest( "Handle, dne, mutable", true, ele == 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001433 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001434
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001435 {
1436 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1437 XMLDocument doc;
1438 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001439 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001440 XMLConstHandle docH( doc );
1441
1442 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001443 XMLTest( "Handle, success, const", "sub", ele->Value() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001444
1445 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001446 XMLTest( "Handle, dne, const", true, ele == 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001447 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001448 {
1449 // Default Declaration & BOM
1450 XMLDocument doc;
1451 doc.InsertEndChild( doc.NewDeclaration() );
1452 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001453
Lee Thomasonf68c4382012-04-28 14:37:11 -07001454 XMLPrinter printer;
1455 doc.Print( &printer );
1456
1457 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001458 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1459 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001460 }
Lee Thomason21be8822012-07-15 17:27:22 -07001461 {
1462 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1463 XMLDocument doc;
1464 doc.Parse( xml );
1465 XMLTest( "Ill formed XML", true, doc.Error() );
1466 }
1467
1468 // QueryXYZText
1469 {
1470 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1471 XMLDocument doc;
1472 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001473 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001474
1475 const XMLElement* pointElement = doc.RootElement();
1476
Dmitry-Me43c019d2017-08-02 18:05:23 +03001477 {
1478 int intValue = 0;
1479 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1480 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1481 XMLTest( "QueryIntText", 1, intValue, false );
1482 }
Lee Thomason21be8822012-07-15 17:27:22 -07001483
Dmitry-Me43c019d2017-08-02 18:05:23 +03001484 {
1485 unsigned unsignedValue = 0;
1486 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1487 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1488 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1489 }
Lee Thomason21be8822012-07-15 17:27:22 -07001490
Dmitry-Me43c019d2017-08-02 18:05:23 +03001491 {
1492 float floatValue = 0;
1493 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1494 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1495 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1496 }
Lee Thomason21be8822012-07-15 17:27:22 -07001497
Dmitry-Me43c019d2017-08-02 18:05:23 +03001498 {
1499 double doubleValue = 0;
1500 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1501 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1502 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1503 }
1504
1505 {
1506 bool boolValue = false;
1507 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1508 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1509 XMLTest( "QueryBoolText", true, boolValue, false );
1510 }
Lee Thomason21be8822012-07-15 17:27:22 -07001511 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001512
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001513 {
1514 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1515 XMLDocument doc;
1516 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001517 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001518 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001519
1520 {
1521 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1522 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001523 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001524 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001525 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001526
1527 {
1528 const char* xml = "<3lement></3lement>";
1529 XMLDocument doc;
1530 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001531 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001532 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001533
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001534 {
1535 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1536 XMLDocument doc;
1537 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001538 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001539 }
1540
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001541 {
1542 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001543 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001544 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001545 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001546 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001547 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001548 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001549 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001550 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001551 }
Dmitry-Me985ea1f2017-08-28 18:36:29 +03001552
1553 {
1554 XMLDocument doc;
1555 XMLTest( "No error initially", false, doc.Error() );
1556 XMLError error = doc.Parse( "This is not XML" );
1557 XMLTest( "Error after invalid XML", true, doc.Error() );
1558 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1559 doc.Clear();
1560 XMLTest( "No error after Clear()", false, doc.Error() );
1561 }
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001562
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001563 // ----------- Whitespace ------------
1564 {
1565 const char* xml = "<element>"
1566 "<a> This \nis &apos; text &apos; </a>"
1567 "<b> This is &apos; text &apos; \n</b>"
1568 "<c>This is &apos; \n\n text &apos;</c>"
1569 "</element>";
1570 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1571 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001572 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001573
1574 const XMLElement* element = doc.FirstChildElement();
1575 for( const XMLElement* parent = element->FirstChildElement();
1576 parent;
1577 parent = parent->NextSiblingElement() )
1578 {
1579 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1580 }
1581 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001582
Lee Thomasonae9ab072012-10-24 10:17:53 -07001583#if 0
1584 {
1585 // Passes if assert doesn't fire.
1586 XMLDocument xmlDoc;
1587
1588 xmlDoc.NewDeclaration();
1589 xmlDoc.NewComment("Configuration file");
1590
1591 XMLElement *root = xmlDoc.NewElement("settings");
1592 root->SetAttribute("version", 2);
1593 }
1594#endif
1595
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001596 {
1597 const char* xml = "<element> </element>";
1598 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1599 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001600 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001601 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1602 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001603
Lee Thomason5b0a6772012-11-19 13:54:42 -08001604 {
1605 // An assert should not fire.
1606 const char* xml = "<element/>";
1607 XMLDocument doc;
1608 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001609 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001610 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1611 XMLTest( "Tracking unused elements", true, ele != 0, false );
1612 }
1613
Lee Thomasona6412ac2012-12-13 15:39:11 -08001614
1615 {
1616 const char* xml = "<parent><child>abc</child></parent>";
1617 XMLDocument doc;
1618 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001619 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001620 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1621
1622 XMLPrinter printer;
1623 ele->Accept( &printer );
1624 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1625 }
1626
1627
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001628 {
1629 XMLDocument doc;
1630 XMLError error = doc.LoadFile( "resources/empty.xml" );
1631 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001632 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001633 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001634 }
1635
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001636 {
1637 // BOM preservation
1638 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1639 {
1640 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001641 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001642 XMLPrinter printer;
1643 doc.Print( &printer );
1644
1645 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1646 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001647 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001648 }
1649 {
1650 XMLDocument doc;
1651 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001652 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001653 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1654
1655 XMLPrinter printer;
1656 doc.Print( &printer );
1657 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1658 }
1659 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001660
Michael Daumlinged523282013-10-23 07:47:29 +02001661 {
1662 // Insertion with Removal
1663 const char* xml = "<?xml version=\"1.0\" ?>"
1664 "<root>"
1665 "<one>"
1666 "<subtree>"
1667 "<elem>element 1</elem>text<!-- comment -->"
1668 "</subtree>"
1669 "</one>"
1670 "<two/>"
1671 "</root>";
1672 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1673 "<root>"
1674 "<one/>"
1675 "<two>"
1676 "<subtree>"
1677 "<elem>element 1</elem>text<!-- comment -->"
1678 "</subtree>"
1679 "</two>"
1680 "</root>";
1681 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1682 "<root>"
1683 "<one/>"
1684 "<subtree>"
1685 "<elem>element 1</elem>text<!-- comment -->"
1686 "</subtree>"
1687 "<two/>"
1688 "</root>";
1689 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1690 "<root>"
1691 "<one/>"
1692 "<two/>"
1693 "<subtree>"
1694 "<elem>element 1</elem>text<!-- comment -->"
1695 "</subtree>"
1696 "</root>";
1697
1698 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001699 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001700 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001701 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1702 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1703 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001704 XMLPrinter printer1(0, true);
1705 doc.Accept(&printer1);
1706 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001707
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001708 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001709 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001710 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1711 two = doc.RootElement()->FirstChildElement("two");
1712 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001713 XMLPrinter printer2(0, true);
1714 doc.Accept(&printer2);
1715 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001716
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001717 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001718 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001719 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1720 subtree = one->FirstChildElement("subtree");
1721 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001722 XMLPrinter printer3(0, true);
1723 doc.Accept(&printer3);
1724 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001725
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001726 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001727 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001728 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1729 two = doc.RootElement()->FirstChildElement("two");
1730 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001731 XMLPrinter printer4(0, true);
1732 doc.Accept(&printer4);
1733 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001734 }
1735
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001736 {
1737 const char* xml = "<svg width = \"128\" height = \"128\">"
1738 " <text> </text>"
1739 "</svg>";
1740 XMLDocument doc;
1741 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001742 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001743 doc.Print();
1744 }
1745
Lee Thomason92e521b2014-11-15 17:45:51 -08001746 {
1747 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001748 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1749 XMLDocument doc;
1750 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001751 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001752 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001753 }
1754
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001755#if 1
1756 // the question being explored is what kind of print to use:
1757 // https://github.com/leethomason/tinyxml2/issues/63
1758 {
1759 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1760 const char* xml = "<element/>";
1761 XMLDocument doc;
1762 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001763 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001764 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1765 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1766 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1767 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1768 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1769 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1770
1771 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1772 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1773 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1774 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1775 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1776 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1777
1778 doc.Print();
1779
1780 /* The result of this test is platform, compiler, and library version dependent. :("
1781 XMLPrinter printer;
1782 doc.Print( &printer );
1783 XMLTest( "Float and double formatting.",
1784 "<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",
1785 printer.CStr(),
1786 true );
1787 */
1788 }
1789#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001790
1791 {
1792 // Issue #184
1793 // If it doesn't assert, it passes. Caused by objects
1794 // getting created during parsing which are then
1795 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001796 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001797 {
1798 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001799 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001800 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001801 }
1802 {
1803 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001804 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001805 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001806 doc.Clear();
1807 }
1808 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001809
1810 {
1811 // If this doesn't assert in DEBUG, all is well.
1812 tinyxml2::XMLDocument doc;
1813 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1814 doc.DeleteNode(pRoot);
1815 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001816
Dmitry-Mee5790db2017-07-28 17:54:38 +03001817 {
1818 XMLDocument doc;
1819 XMLElement* root = doc.NewElement( "Root" );
1820 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1821 doc.InsertEndChild( root );
1822 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1823 }
1824
1825 {
1826 // If this doesn't assert in DEBUG, all is well.
1827 XMLDocument doc;
1828 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1829 XMLElement* linkedRoot = doc.NewElement( "Root" );
1830 doc.InsertFirstChild( linkedRoot );
1831 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1832 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1833 }
1834
Dmitry-Me8b67d742014-12-22 11:35:12 +03001835 {
1836 // Should not assert in DEBUG
1837 XMLPrinter printer;
1838 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001839
Dmitry-Me6f51c802015-03-14 13:25:03 +03001840 {
1841 // Issue 291. Should not crash
1842 const char* xml = "&#0</a>";
1843 XMLDocument doc;
1844 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001845 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001846
1847 XMLPrinter printer;
1848 doc.Print( &printer );
1849 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001850 {
1851 // Issue 299. Can print elements that are not linked in.
1852 // Will crash if issue not fixed.
1853 XMLDocument doc;
1854 XMLElement* newElement = doc.NewElement( "printme" );
1855 XMLPrinter printer;
1856 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001857 // Delete the node to avoid possible memory leak report in debug output
1858 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001859 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001860 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001861 // Issue 302. Clear errors from LoadFile/SaveFile
1862 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001863 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001864 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001865 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001866 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001867 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001868 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001869
Dmitry-Med9852a52015-03-25 10:17:49 +03001870 {
1871 // If a document fails to load then subsequent
1872 // successful loads should clear the error
1873 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001874 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001875 doc.LoadFile( "resources/no-such-file.xml" );
1876 XMLTest( "No such file - should fail", true, doc.Error() );
1877
1878 doc.LoadFile( "resources/dream.xml" );
1879 XMLTest( "Error should be cleared", false, doc.Error() );
1880 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301881
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301882 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001883 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001884 const char* xml0 = "<?xml version=\"1.0\" ?>"
1885 " <!-- xml version=\"1.1\" -->"
1886 "<first />";
1887 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001888 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001889 "<first />";
1890 const char* xml2 = "<first />"
1891 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001892 const char* xml3 = "<first></first>"
1893 "<?xml version=\"1.0\" ?>";
1894
1895 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1896
Lee Thomason85492022015-05-22 11:07:45 -07001897 XMLDocument doc;
1898 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001899 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001900 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001901 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001902 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001903 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001904 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001905 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001906 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001907 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301908 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001909
Lee Thomason85492022015-05-22 11:07:45 -07001910 {
1911 // No matter - before or after successfully parsing a text -
1912 // calling XMLDocument::Value() causes an assert in debug.
1913 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1914 "<first />"
1915 "<second />";
1916 XMLDocument* doc = new XMLDocument();
1917 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1918 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001919 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001920 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1921 delete doc;
1922 }
1923
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001924 {
1925 XMLDocument doc;
1926 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
Dmitry-Med3f6c632017-08-30 17:43:14 +03001927 const XMLError error = static_cast<XMLError>(i);
1928 doc.SetError( error, 0, 0, 0 );
1929 XMLTest( "ErrorID() after SetError()", error, doc.ErrorID() );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001930 doc.ErrorName();
1931 }
1932 }
1933
Lee Thomason816d3fa2017-06-05 14:35:55 -07001934 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001935 // Evil memory leaks.
1936 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1937 // and NOT added to the XMLDocument, what happens?
1938 //
1939 // Previously (buggy):
1940 // The memory would be free'd when the XMLDocument is
1941 // destructed. But the destructor wasn't called, so that
1942 // memory allocated by the XMLElement would not be free'd.
1943 // In practice this meant strings allocated by the XMLElement
1944 // would leak. An edge case, but annoying.
1945 // Now:
1946 // The destructor is called. But the list of unlinked nodes
1947 // has to be tracked. This has a minor performance impact
1948 // that can become significant if you have a lot. (But why
1949 // would you do that?)
1950 // The only way to see this bug is in a leak tracker. This
1951 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001952 {
1953 XMLDocument doc;
1954 doc.NewElement("LEAK 1");
1955 }
1956 {
1957 XMLDocument doc;
1958 XMLElement* ele = doc.NewElement("LEAK 2");
1959 doc.DeleteNode(ele);
1960 }
1961 }
1962
Lee Thomason224ef772017-06-16 09:45:26 -07001963 {
1964 // Crashing reported via email.
1965 const char* xml =
1966 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001967 "<property name='track_name'>voice</property>"
1968 "<property name='audio_track'>1</property>"
1969 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1970 "<blank length = '1' />"
1971 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1972 "<blank length = '2' />"
1973 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1974 "<blank length = '1' />"
1975 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001976 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001977
Lee Thomason224ef772017-06-16 09:45:26 -07001978 // It's not a good idea to delete elements as you walk the
1979 // list. I'm not sure this technically should work; but it's
1980 // an interesting test case.
1981 XMLDocument doc;
1982 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001983 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03001984
1985 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001986 XMLTest("Crash bug parsing", true, playlist != 0);
1987
1988 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1989 XMLTest("Crash bug parsing", true, entry != 0);
1990 while (entry) {
1991 tinyxml2::XMLElement* todelete = entry;
1992 entry = entry->NextSiblingElement("entry");
1993 playlist->DeleteChild(todelete);
1994 };
1995 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1996 while (blank) {
1997 tinyxml2::XMLElement* todelete = blank;
1998 blank = blank->NextSiblingElement("blank");
1999 playlist->DeleteChild(todelete);
2000 };
2001
2002 tinyxml2::XMLPrinter printer;
2003 playlist->Accept(&printer);
2004 printf("%s\n", printer.CStr());
2005
Lee Thomason82bb0742017-06-16 09:48:20 -07002006 // No test; it only need to not crash.
2007 // Still, wrap it up with a sanity check
2008 int nProperty = 0;
2009 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2010 nProperty++;
2011 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002012 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07002013 }
2014
kezenatorec694152016-11-26 17:21:43 +10002015 // ----------- Line Number Tracking --------------
2016 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002017 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002018 {
2019 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2020 {
2021 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002022 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002023
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002024 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002025 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002026 XMLTest(testString, expected_error, parseError);
kezenatorec694152016-11-26 17:21:43 +10002027 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
2028 };
2029
2030 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2031 {
2032 XMLDocument doc;
2033 doc.Parse(docStr);
2034 XMLTest(testString, false, doc.Error());
2035 TestDocLines(testString, doc, expectedLines);
2036 }
2037
2038 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2039 {
2040 XMLDocument doc;
2041 doc.LoadFile(file_name);
2042 XMLTest(testString, false, doc.Error());
2043 TestDocLines(testString, doc, expectedLines);
2044 }
2045
2046 private:
2047 DynArray<char, 10> str;
2048
2049 void Push(char type, int lineNum)
2050 {
2051 str.Push(type);
2052 str.Push(char('0' + (lineNum / 10)));
2053 str.Push(char('0' + (lineNum % 10)));
2054 }
2055
2056 bool VisitEnter(const XMLDocument& doc)
2057 {
kezenator19d8ea82016-11-29 19:50:27 +10002058 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002059 return true;
2060 }
2061 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2062 {
kezenator19d8ea82016-11-29 19:50:27 +10002063 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002064 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002065 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002066 return true;
2067 }
2068 bool Visit(const XMLDeclaration& declaration)
2069 {
kezenator19d8ea82016-11-29 19:50:27 +10002070 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002071 return true;
2072 }
2073 bool Visit(const XMLText& text)
2074 {
kezenator19d8ea82016-11-29 19:50:27 +10002075 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002076 return true;
2077 }
2078 bool Visit(const XMLComment& comment)
2079 {
kezenator19d8ea82016-11-29 19:50:27 +10002080 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002081 return true;
2082 }
2083 bool Visit(const XMLUnknown& unknown)
2084 {
kezenator19d8ea82016-11-29 19:50:27 +10002085 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002086 return true;
2087 }
2088
2089 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2090 {
2091 str.Clear();
2092 doc.Accept(this);
2093 str.Push(0);
2094 XMLTest(testString, expectedLines, str.Mem());
2095 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002096 } tester;
kezenatorec694152016-11-26 17:21:43 +10002097
Lee Thomasone90e9012016-12-24 07:34:39 -08002098 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2099 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2100 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2101 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2102 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2103 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2104 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2105 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2106 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2107 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2108 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002109
Lee Thomasone90e9012016-12-24 07:34:39 -08002110 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002111 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002112
2113 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2114 "<root a='b' \n" // 2 Element Attribute
2115 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2116 "newline in text \n" // 4 Text
2117 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2118 " cdata test ]]><!-- comment -->\n" // 6 Comment
2119 "<! unknown></root>", // 7 Unknown
2120
kezenatorec694152016-11-26 17:21:43 +10002121 "D01L01E02A02A03T03E03T04E05T05C06U07");
2122
Lee Thomasone90e9012016-12-24 07:34:39 -08002123 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002124 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002125
2126 "\r\n" // 1 Doc (arguably should be line 2)
2127 "<?xml version=\"1.0\"?>\n" // 2 DecL
2128 "<root>\r\n" // 3 Element
2129 "\n" // 4
2130 "text contining new line \n" // 5 Text
2131 " and also containing crlf \r\n" // 6
2132 "<sub><![CDATA[\n" // 7 Element Text
2133 "cdata containing new line \n" // 8
2134 " and also containing cflr\r\n" // 9
2135 "]]></sub><sub2/></root>", // 10 Element
2136
kezenatorec694152016-11-26 17:21:43 +10002137 "D01L02E03T05E07T07E10");
2138
Lee Thomasone90e9012016-12-24 07:34:39 -08002139 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002140 "LineNumbers-File",
2141 "resources/utf8test.xml",
2142 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2143 }
2144
Lee Thomason85492022015-05-22 11:07:45 -07002145 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002146 {
2147#if defined( _MSC_VER )
2148 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002149 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002150#endif
2151
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002152 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002153 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002154 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002155 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002156 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002157
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002158 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002159 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002160 size_t bytesRead = fread(mem, 1, size, perfFP);
2161 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002162 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002163 mem[size] = 0;
2164
2165#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002166 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002167#else
2168 clock_t cstart = clock();
2169#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002170 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002171 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002172 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002173 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002174 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002175 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002176 }
2177#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002178 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002179#else
2180 clock_t cend = clock();
2181#endif
Dmitry-Me1ab85872017-08-10 17:28:10 +03002182 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002183
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002184 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002185
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002186 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002187#ifdef DEBUG
2188 "DEBUG";
2189#else
2190 "Release";
2191#endif
2192
2193#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002194 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002195#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002196 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002197#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002198 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002199 }
2200
Dmitry-Mede381df2017-07-26 18:05:25 +03002201#if defined( _MSC_VER ) && defined( DEBUG )
2202 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002203 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002204
2205 _CrtMemState diffMemState;
2206 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2207 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002208
2209 {
2210 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2211 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2212 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002213 }
2214#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002215
2216 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002217
2218 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002219}