blob: 0e8de619871a8b351e075f9cd047a2d9647ca5b9 [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}
Lee Thomasoncf100692017-12-10 20:03:39 -0800115/** @page Example_1 Load an XML File
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200116 * @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}
Lee Thomasoncf100692017-12-10 20:03:39 -0800134/** @page Example_2 Parse an XML from char buffer
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200135 * @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}
Lee Thomasoncf100692017-12-10 20:03:39 -0800167/** @page Example_3 Get information out of XML
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200168 @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}
Lee Thomasoncf100692017-12-10 20:03:39 -0800258/** @page Example_4 Read attributes and text information.
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200259 @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 Thomasoncf100692017-12-10 20:03:39 -0800341 XMLTest( "Example_1", 0, example_1() );
342 XMLTest( "Example_2", 0, example_2() );
343 XMLTest( "Example_3", 0, example_3() );
344 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 {
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300389 // This test is pre-test for the next one
390 // (where Element1 is inserted "after itself".
391 // This code didn't use to crash.
392 XMLDocument doc;
393 XMLElement* element1 = doc.NewElement("Element1");
394 XMLElement* element2 = doc.NewElement("Element2");
395 doc.InsertEndChild(element1);
396 doc.InsertEndChild(element2);
397 doc.InsertAfterChild(element2, element2);
398 doc.InsertAfterChild(element2, element2);
399 }
400
401 {
402 XMLDocument doc;
403 XMLElement* element1 = doc.NewElement("Element1");
404 XMLElement* element2 = doc.NewElement("Element2");
405 doc.InsertEndChild(element1);
406 doc.InsertEndChild(element2);
407
408 // This insertion "after itself"
409 // used to cause invalid memory access and crash
410 doc.InsertAfterChild(element1, element1);
411 doc.InsertAfterChild(element1, element1);
412 doc.InsertAfterChild(element2, element2);
413 doc.InsertAfterChild(element2, element2);
414 }
415
416 {
Lee Thomason2c85a712012-01-31 08:24:24 -0800417 static const char* test = "<element>Text before.</element>";
418 XMLDocument doc;
419 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300420 XMLTest( "Element text before", false, doc.Error() );
Lee Thomason2c85a712012-01-31 08:24:24 -0800421 XMLElement* root = doc.FirstChildElement();
422 XMLElement* newElement = doc.NewElement( "Subelement" );
423 root->InsertEndChild( newElement );
424 doc.Print();
425 }
Lee Thomasond1983222012-02-06 08:41:24 -0800426 {
427 XMLDocument* doc = new XMLDocument();
428 static const char* test = "<element><sub/></element>";
429 doc->Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300430 XMLTest( "Element with sub element", false, doc->Error() );
Lee Thomasond1983222012-02-06 08:41:24 -0800431 delete doc;
432 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800433 {
Dmitry-Me8e063702017-08-01 17:40:40 +0300434 // Test: Programmatic DOM nodes insertion return values
435 XMLDocument doc;
436
437 XMLNode* first = doc.NewElement( "firstElement" );
438 XMLTest( "New element", true, first != 0 );
439 XMLNode* firstAfterInsertion = doc.InsertFirstChild( first );
440 XMLTest( "New element inserted first", true, firstAfterInsertion == first );
441
442 XMLNode* last = doc.NewElement( "lastElement" );
443 XMLTest( "New element", true, last != 0 );
444 XMLNode* lastAfterInsertion = doc.InsertEndChild( last );
445 XMLTest( "New element inserted last", true, lastAfterInsertion == last );
446
447 XMLNode* middle = doc.NewElement( "middleElement" );
448 XMLTest( "New element", true, middle != 0 );
449 XMLNode* middleAfterInsertion = doc.InsertAfterChild( first, middle );
450 XMLTest( "New element inserted middle", true, middleAfterInsertion == middle );
451 }
452 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800453 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800454 // Build:
455 // <element>
456 // <!--comment-->
457 // <sub attrib="1" />
458 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800459 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800460 // <element>
461
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800462 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800463 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
464
465 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
466 for( int i=0; i<3; ++i ) {
467 sub[i]->SetAttribute( "attrib", i );
468 }
469 element->InsertEndChild( sub[2] );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300470
471 const int dummyInitialValue = 1000;
472 int dummyValue = dummyInitialValue;
473
Lee Thomason1ff38e02012-02-14 18:18:16 -0800474 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300475 comment->SetUserData(&dummyValue);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800476 element->InsertAfterChild( comment, sub[0] );
477 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800478 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800479 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800480 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
481 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
482 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700483 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800484 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Dmitry-Mecaed4ec2017-08-11 17:39:47 +0300485 XMLTest("User data - pointer", true, &dummyValue == comment->GetUserData(), false);
486 XMLTest("User data - value behind pointer", dummyInitialValue, dummyValue, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800487
488 // And now deletion:
489 element->DeleteChild( sub[2] );
490 doc->DeleteNode( comment );
491
492 element->FirstChildElement()->SetAttribute( "attrib", true );
493 element->LastChildElement()->DeleteAttribute( "attrib" );
494
495 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300496 const int defaultIntValue = 10;
497 const int replacementIntValue = 20;
498 int value1 = defaultIntValue;
499 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300500 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
501 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300502 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
503 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800504
505 doc->Print();
506
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700507 {
508 XMLPrinter streamer;
509 doc->Print( &streamer );
510 printf( "%s", streamer.CStr() );
511 }
512 {
513 XMLPrinter streamer( 0, true );
514 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200515 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700516 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700517 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300518 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700519 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300520 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800521 delete doc;
522 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800523 {
524 // Test: Dream
525 // XML1 : 1,187,569 bytes in 31,209 allocations
526 // XML2 : 469,073 bytes in 323 allocations
527 //int newStart = gNew;
528 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300529 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300530 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800531
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400532 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300533 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800534 doc.PrintError();
535
536 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400537 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800538 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
539 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
540 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
541 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400542 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800543 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400544 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800545
546 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400547 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300548 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800549 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400550 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800551 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
552 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
553 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
554 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400555 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800556
557 //gNewTotal = gNew - newStart;
558 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800559
560
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800561 {
562 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
563 "<passages count=\"006\" formatversion=\"20020620\">\n"
564 " <wrong error>\n"
565 "</passages>";
566
567 XMLDocument doc;
568 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300569 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800570 }
571
572 {
573 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
574
575 XMLDocument doc;
576 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300577 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800578
579 XMLElement* ele = doc.FirstChildElement();
580
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300581 int iVal;
582 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800583 double dVal;
584
585 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300586 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
587 XMLTest( "Query attribute: int as double", 1, (int)dVal );
588 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700589
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800590 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300591 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
592 XMLTest( "Query attribute: double as double", 2.0, dVal );
593 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700594
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800595 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300596 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
597 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700598
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800599 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300600 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
601 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700602
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800603 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300604 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
605 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800606 }
607
608 {
609 const char* str = "<doc/>";
610
611 XMLDocument doc;
612 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300613 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800614
615 XMLElement* ele = doc.FirstChildElement();
616
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800617 int iVal, iVal2;
618 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800619
620 ele->SetAttribute( "str", "strValue" );
621 ele->SetAttribute( "int", 1 );
622 ele->SetAttribute( "double", -1.0 );
623
624 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300625 {
626 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
627 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
628 }
629 {
630 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
631 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
632 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800633
Dmitry-Me2087a272017-07-10 18:13:07 +0300634 {
635 int queryResult = ele->QueryAttribute( "int", &iVal2 );
636 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
637 }
638 {
639 int queryResult = ele->QueryAttribute( "double", &dVal2 );
640 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
641 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800642
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300643 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800644 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
645 XMLTest( "Attribute round trip. int.", 1, iVal );
646 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800647 XMLTest( "Alternate query", true, iVal == iVal2 );
648 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700649 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
650 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800651 }
652
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800653 {
654 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300655 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300656 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800657
658 // Get the attribute "value" from the "Russian" element and check it.
659 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700660 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800661 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
662
663 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
664
665 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
666 0xd1U, 0x81U, 0xd1U, 0x81U,
667 0xd0U, 0xbaU, 0xd0U, 0xb8U,
668 0xd0U, 0xb9U, 0 };
669 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
670
671 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
672 XMLTest( "UTF-8: Browsing russian element name.",
673 russianText,
674 text->Value() );
675
676 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400677 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300678 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800679
680 // Check the round trip.
Dmitry-Me520009e2017-08-10 17:50:03 +0300681 bool roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800682
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200683 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300684 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
685
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300686 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300687 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800688
689 if ( saved && verify )
690 {
Dmitry-Me520009e2017-08-10 17:50:03 +0300691 roundTripOkay = true;
PKEuSc28ba3a2012-07-16 03:08:47 -0700692 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800693 while ( fgets( verifyBuf, 256, verify ) )
694 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700695 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800696 fgets( savedBuf, 256, saved );
697 NullLineEndings( verifyBuf );
698 NullLineEndings( savedBuf );
699
700 if ( strcmp( verifyBuf, savedBuf ) )
701 {
702 printf( "verify:%s<\n", verifyBuf );
703 printf( "saved :%s<\n", savedBuf );
Dmitry-Me520009e2017-08-10 17:50:03 +0300704 roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800705 break;
706 }
707 }
708 }
709 if ( saved )
710 fclose( saved );
711 if ( verify )
712 fclose( verify );
Dmitry-Me520009e2017-08-10 17:50:03 +0300713 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800714 }
715
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800716 // --------GetText()-----------
717 {
718 const char* str = "<foo>This is text</foo>";
719 XMLDocument doc;
720 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300721 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800722 const XMLElement* element = doc.RootElement();
723
724 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
725
726 str = "<foo><b>This is text</b></foo>";
727 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300728 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800729 element = doc.RootElement();
730
731 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
732 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800733
Lee Thomasond6277762012-02-22 16:00:12 -0800734
Uli Kusterer321072e2014-01-21 01:57:38 +0100735 // --------SetText()-----------
736 {
737 const char* str = "<foo></foo>";
738 XMLDocument doc;
739 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300740 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100741 XMLElement* element = doc.RootElement();
742
Lee Thomason9c0678a2014-01-24 10:18:27 -0800743 element->SetText("darkness.");
744 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100745
Lee Thomason9c0678a2014-01-24 10:18:27 -0800746 element->SetText("blue flame.");
747 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100748
749 str = "<foo/>";
750 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300751 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100752 element = doc.RootElement();
753
Lee Thomason9c0678a2014-01-24 10:18:27 -0800754 element->SetText("The driver");
755 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100756
Lee Thomason9c0678a2014-01-24 10:18:27 -0800757 element->SetText("<b>horses</b>");
758 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
759 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100760
761 str = "<foo><bar>Text in nested element</bar></foo>";
762 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300763 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100764 element = doc.RootElement();
765
Lee Thomason9c0678a2014-01-24 10:18:27 -0800766 element->SetText("wolves");
767 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800768
769 str = "<foo/>";
770 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300771 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800772 element = doc.RootElement();
773
774 element->SetText( "str" );
775 XMLTest( "SetText types", "str", element->GetText() );
776
777 element->SetText( 1 );
778 XMLTest( "SetText types", "1", element->GetText() );
779
780 element->SetText( 1U );
781 XMLTest( "SetText types", "1", element->GetText() );
782
783 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200784 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800785
786 element->SetText( 1.5f );
787 XMLTest( "SetText types", "1.5", element->GetText() );
788
789 element->SetText( 1.5 );
790 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100791 }
792
Lee Thomason51c12712016-06-04 20:18:49 -0700793 // ---------- Attributes ---------
794 {
795 static const int64_t BIG = -123456789012345678;
796 XMLDocument doc;
797 XMLElement* element = doc.NewElement("element");
798 doc.InsertFirstChild(element);
799
800 {
801 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300802 {
803 int v = 0;
804 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
805 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
806 XMLTest("Attribute: int", -100, v, true);
807 }
808 {
809 int v = 0;
810 int queryResult = element->QueryAttribute("attrib", &v);
811 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
812 XMLTest("Attribute: int", -100, v, true);
813 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700814 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700815 }
816 {
817 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300818 {
819 unsigned v = 0;
820 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
821 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
822 XMLTest("Attribute: unsigned", unsigned(100), v, true);
823 }
824 {
825 unsigned v = 0;
826 int queryResult = element->QueryAttribute("attrib", &v);
827 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
828 XMLTest("Attribute: unsigned", unsigned(100), v, true);
829 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700830 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700831 }
832 {
833 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300834 {
835 int64_t v = 0;
836 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
837 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
838 XMLTest("Attribute: int64_t", BIG, v, true);
839 }
840 {
841 int64_t v = 0;
842 int queryResult = element->QueryAttribute("attrib", &v);
843 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
844 XMLTest("Attribute: int64_t", BIG, v, true);
845 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700846 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700847 }
848 {
849 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300850 {
851 bool v = false;
852 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
853 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
854 XMLTest("Attribute: bool", true, v, true);
855 }
856 {
857 bool v = false;
858 int queryResult = element->QueryAttribute("attrib", &v);
859 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
860 XMLTest("Attribute: bool", true, v, true);
861 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700862 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700863 }
864 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800865 element->SetAttribute("attrib", true);
866 const char* result = element->Attribute("attrib");
867 XMLTest("Bool true is 'true'", "true", result);
868
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800869 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800870 element->SetAttribute("attrib", true);
871 result = element->Attribute("attrib");
872 XMLTest("Bool true is '1'", "1", result);
873
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800874 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800875 }
876 {
Lee Thomason51c12712016-06-04 20:18:49 -0700877 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300878 {
879 double v = 0;
880 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
881 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
882 XMLTest("Attribute: double", 100.0, v, true);
883 }
884 {
885 double v = 0;
886 int queryResult = element->QueryAttribute("attrib", &v);
887 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
888 XMLTest("Attribute: double", 100.0, v, true);
889 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700890 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700891 }
892 {
893 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300894 {
895 float v = 0;
896 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
897 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
898 XMLTest("Attribute: float", 100.0f, v, true);
899 }
900 {
901 float v = 0;
902 int queryResult = element->QueryAttribute("attrib", &v);
903 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
904 XMLTest("Attribute: float", 100.0f, v, true);
905 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700906 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700907 }
908 {
909 element->SetText(BIG);
910 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300911 XMLError queryResult = element->QueryInt64Text(&v);
912 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700913 XMLTest("Element: int64_t", BIG, v, true);
914 }
915 }
916
917 // ---------- XMLPrinter stream mode ------
918 {
919 {
Dmitry-Mec0fad292017-08-09 19:05:42 +0300920 FILE* printerfp = fopen("resources/out/printer.xml", "w");
921 XMLTest("Open printer.xml", true, printerfp != 0);
Lee Thomason51c12712016-06-04 20:18:49 -0700922 XMLPrinter printer(printerfp);
923 printer.OpenElement("foo");
924 printer.PushAttribute("attrib-text", "text");
925 printer.PushAttribute("attrib-int", int(1));
926 printer.PushAttribute("attrib-unsigned", unsigned(2));
927 printer.PushAttribute("attrib-int64", int64_t(3));
928 printer.PushAttribute("attrib-bool", true);
929 printer.PushAttribute("attrib-double", 4.0);
930 printer.CloseElement();
931 fclose(printerfp);
932 }
933 {
934 XMLDocument doc;
Dmitry-Mec0fad292017-08-09 19:05:42 +0300935 doc.LoadFile("resources/out/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300936 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700937
938 const XMLDocument& cdoc = doc;
939
940 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
941 XMLTest("attrib-text", "text", attrib->Value(), true);
942 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
943 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
944 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
945 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
946 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
947 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
948 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
949 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
950 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
951 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
952 }
953
954 }
955
Uli Kusterer321072e2014-01-21 01:57:38 +0100956
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800957 // ---------- CDATA ---------------
958 {
959 const char* str = "<xmlElement>"
960 "<![CDATA["
961 "I am > the rules!\n"
962 "...since I make symbolic puns"
963 "]]>"
964 "</xmlElement>";
965 XMLDocument doc;
966 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300967 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800968 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800969
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300970 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
971 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800972 false );
973 }
974
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800975 // ----------- CDATA -------------
976 {
977 const char* str = "<xmlElement>"
978 "<![CDATA["
979 "<b>I am > the rules!</b>\n"
980 "...since I make symbolic puns"
981 "]]>"
982 "</xmlElement>";
983 XMLDocument doc;
984 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300985 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800986 doc.Print();
987
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300988 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800989 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300990 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800991 false );
992 }
993
994 // InsertAfterChild causes crash.
995 {
996 // InsertBeforeChild and InsertAfterChild causes crash.
997 XMLDocument doc;
998 XMLElement* parent = doc.NewElement( "Parent" );
999 doc.InsertFirstChild( parent );
1000
1001 XMLElement* childText0 = doc.NewElement( "childText0" );
1002 XMLElement* childText1 = doc.NewElement( "childText1" );
1003
1004 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001005 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001006 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001007 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001008
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001009 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001010 }
Lee Thomasond6277762012-02-22 16:00:12 -08001011
1012 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001013 // Entities not being written correctly.
1014 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -08001015
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001016 const char* passages =
1017 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1018 "<passages count=\"006\" formatversion=\"20020620\">"
1019 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1020 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
1021 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -08001022
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001023 XMLDocument doc;
1024 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001025 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001026 XMLElement* psg = doc.RootElement()->FirstChildElement();
1027 const char* context = psg->Attribute( "context" );
1028 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 -08001029
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001030 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -08001031
Dmitry-Me520009e2017-08-10 17:50:03 +03001032 const char* textFilePath = "resources/out/textfile.txt";
1033 FILE* textfile = fopen( textFilePath, "w" );
1034 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001035 if ( textfile )
1036 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001037 XMLPrinter streamer( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001038 bool acceptResult = psg->Accept( &streamer );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001039 fclose( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001040 XMLTest( "Entity transformation: Accept", true, acceptResult );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001041 }
Thomas Roß0922b732012-09-23 16:31:22 +02001042
Dmitry-Me520009e2017-08-10 17:50:03 +03001043 textfile = fopen( textFilePath, "r" );
1044 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001045 if ( textfile )
1046 {
1047 char buf[ 1024 ];
1048 fgets( buf, 1024, textfile );
1049 XMLTest( "Entity transformation: write. ",
1050 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1051 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1052 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001053 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001054 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001055 }
1056
1057 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001058 // Suppress entities.
1059 const char* passages =
1060 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1061 "<passages count=\"006\" formatversion=\"20020620\">"
1062 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1063 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001064
Lee Thomason6f381b72012-03-02 12:59:39 -08001065 XMLDocument doc( false );
1066 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001067 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001068
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001069 XMLTest( "No entity parsing.",
1070 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1071 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1072 XMLTest( "No entity parsing.", "Crazy &ttk;",
1073 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001074 doc.Print();
1075 }
1076
1077 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001078 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001079
1080 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001081 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001082 XMLTest( "dot in names", false, doc.Error() );
1083 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1084 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001085 }
1086
1087 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001088 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001089
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001090 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001091 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001092 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001093
1094 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1095 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001096 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001097 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001098 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001099
1100 {
1101 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001102 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001103 const char* doctype =
1104 "<?xml version=\"1.0\" ?>"
1105 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1106 "<!ELEMENT title (#PCDATA)>"
1107 "<!ELEMENT books (title,authors)>"
1108 "<element />";
1109
1110 XMLDocument doc;
1111 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001112 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001113 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001114 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001115 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001116 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001117 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001118 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001119
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001120 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1121 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1122
1123 }
1124
1125 {
1126 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001127 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001128 "<!-- Somewhat<evil> -->";
1129 XMLDocument doc;
1130 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001131 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001132
1133 XMLComment* comment = doc.FirstChild()->ToComment();
1134
1135 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1136 }
1137 {
1138 // Double attributes
1139 const char* doctype = "<element attr='red' attr='blue' />";
1140
1141 XMLDocument doc;
1142 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001143
Lee Thomason2fa81722012-11-09 12:37:46 -08001144 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 -08001145 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001146 }
1147
1148 {
1149 // Embedded null in stream.
1150 const char* doctype = "<element att\0r='red' attr='blue' />";
1151
1152 XMLDocument doc;
1153 doc.Parse( doctype );
1154 XMLTest( "Embedded null throws error.", true, doc.Error() );
1155 }
1156
1157 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001158 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001159 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001160 XMLDocument doc;
1161 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001162 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001163 }
1164
1165 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001166 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1167 const char* str = " ";
1168 XMLDocument doc;
1169 doc.Parse( str );
1170 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1171 }
1172
1173 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001174 // Low entities
1175 XMLDocument doc;
1176 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001177 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001178 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001179 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001180 doc.Print();
1181 }
1182
1183 {
1184 // Attribute values with trailing quotes not handled correctly
1185 XMLDocument doc;
1186 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001187 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001188 }
1189
1190 {
1191 // [ 1663758 ] Failure to report error on bad XML
1192 XMLDocument xml;
1193 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001194 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001195 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001196 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001197 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001198 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001199 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001200
1201
1202 {
1203 // [ 1475201 ] TinyXML parses entities in comments
1204 XMLDocument xml;
1205 xml.Parse("<!-- declarations for <head> & <body> -->"
1206 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001207 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001208
1209 XMLNode* e0 = xml.FirstChild();
1210 XMLNode* e1 = e0->NextSibling();
1211 XMLComment* c0 = e0->ToComment();
1212 XMLComment* c1 = e1->ToComment();
1213
1214 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1215 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1216 }
1217
1218 {
1219 XMLDocument xml;
1220 xml.Parse( "<Parent>"
1221 "<child1 att=''/>"
1222 "<!-- With this comment, child2 will not be parsed! -->"
1223 "<child2 att=''/>"
1224 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001225 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001226 xml.Print();
1227
1228 int count = 0;
1229
1230 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1231 ele;
1232 ele = ele->NextSibling() )
1233 {
1234 ++count;
1235 }
1236
1237 XMLTest( "Comments iterate correctly.", 3, count );
1238 }
1239
1240 {
1241 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1242 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1243 buf[60] = 239;
1244 buf[61] = 0;
1245
1246 XMLDocument doc;
1247 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001248 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001249 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001250
1251
1252 {
1253 // bug 1827248 Error while parsing a little bit malformed file
1254 // Actually not malformed - should work.
1255 XMLDocument xml;
1256 xml.Parse( "<attributelist> </attributelist >" );
1257 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1258 }
1259
1260 {
1261 // This one must not result in an infinite loop
1262 XMLDocument xml;
1263 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001264 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001265 XMLTest( "Infinite loop test.", true, true );
1266 }
1267#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001268 {
1269 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1270 XMLDocument doc;
1271 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001272 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001273
1274 XMLDocument clone;
1275 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1276 XMLNode* copy = node->ShallowClone( &clone );
1277 clone.InsertEndChild( copy );
1278 }
1279
1280 clone.Print();
1281
1282 int count=0;
1283 const XMLNode* a=clone.FirstChild();
1284 const XMLNode* b=doc.FirstChild();
1285 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1286 ++count;
1287 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1288 }
1289 XMLTest( "Clone and Equal", 4, count );
1290 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001291
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001292 {
Lee Thomason7085f002017-06-01 18:09:43 -07001293 // Deep Cloning of root element.
1294 XMLDocument doc2;
1295 XMLPrinter printer1;
1296 {
1297 // Make sure doc1 is deleted before we test doc2
1298 const char* xml =
1299 "<root>"
1300 " <child1 foo='bar'/>"
1301 " <!-- comment thing -->"
1302 " <child2 val='1'>Text</child2>"
1303 "</root>";
1304 XMLDocument doc;
1305 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001306 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001307
1308 doc.Print(&printer1);
1309 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1310 doc2.InsertFirstChild(root);
1311 }
1312 XMLPrinter printer2;
1313 doc2.Print(&printer2);
1314
1315 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1316 }
1317
1318 {
1319 // Deep Cloning of sub element.
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 "<root>"
1327 " <child1 foo='bar'/>"
1328 " <!-- comment thing -->"
1329 " <child2 val='1'>Text</child2>"
1330 "</root>";
1331 XMLDocument doc;
1332 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001333 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001334
1335 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001336 bool acceptResult = subElement->Accept(&printer1);
1337 XMLTest( "Accept before deep cloning", true, acceptResult );
Lee Thomason7085f002017-06-01 18:09:43 -07001338
1339 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1340 doc2.InsertFirstChild(clonedSubElement);
1341 }
1342 XMLPrinter printer2;
1343 doc2.Print(&printer2);
1344
1345 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1346 }
1347
1348 {
1349 // Deep cloning of document.
1350 XMLDocument doc2;
1351 XMLPrinter printer1;
1352 {
1353 // Make sure doc1 is deleted before we test doc2
1354 const char* xml =
1355 "<?xml version ='1.0'?>"
1356 "<!-- Top level comment. -->"
1357 "<root>"
1358 " <child1 foo='bar'/>"
1359 " <!-- comment thing -->"
1360 " <child2 val='1'>Text</child2>"
1361 "</root>";
1362 XMLDocument doc;
1363 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001364 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001365 doc.Print(&printer1);
1366
1367 doc.DeepCopy(&doc2);
1368 }
1369 XMLPrinter printer2;
1370 doc2.Print(&printer2);
1371
1372 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1373 }
1374
1375
1376 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001377 // This shouldn't crash.
1378 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001379 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001380 {
1381 doc.PrintError();
1382 }
1383 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1384 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001385
Lee Thomason5e3803c2012-04-16 08:57:05 -07001386 {
1387 // Attribute ordering.
1388 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1389 XMLDocument doc;
1390 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001391 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001392 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001393
Lee Thomason5e3803c2012-04-16 08:57:05 -07001394 const XMLAttribute* a = ele->FirstAttribute();
1395 XMLTest( "Attribute order", "1", a->Value() );
1396 a = a->Next();
1397 XMLTest( "Attribute order", "2", a->Value() );
1398 a = a->Next();
1399 XMLTest( "Attribute order", "3", a->Value() );
1400 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001401
Lee Thomason5e3803c2012-04-16 08:57:05 -07001402 ele->DeleteAttribute( "attrib2" );
1403 a = ele->FirstAttribute();
1404 XMLTest( "Attribute order", "1", a->Value() );
1405 a = a->Next();
1406 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001407
Lee Thomason5e3803c2012-04-16 08:57:05 -07001408 ele->DeleteAttribute( "attrib1" );
1409 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001410 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001411 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001412
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001413 {
1414 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001415 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1416 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1417 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1418 XMLDocument doc0;
1419 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001420 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001421 XMLDocument doc1;
1422 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001423 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001424 XMLDocument doc2;
1425 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001426 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001427
Lee Thomason78a773d2012-07-02 10:10:19 -07001428 XMLElement* ele = 0;
1429 ele = doc0.FirstChildElement();
1430 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1431 ele = doc1.FirstChildElement();
1432 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1433 ele = doc2.FirstChildElement();
1434 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001435 }
1436
1437 {
1438 // Make sure we don't go into an infinite loop.
1439 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1440 XMLDocument doc;
1441 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001442 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001443 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1444 XMLElement* ele1 = ele0->NextSiblingElement();
1445 bool equal = ele0->ShallowEqual( ele1 );
1446
1447 XMLTest( "Infinite loop in shallow equal.", true, equal );
1448 }
1449
Lee Thomason5708f812012-03-28 17:46:41 -07001450 // -------- Handles ------------
1451 {
1452 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1453 XMLDocument doc;
1454 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001455 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001456
1457 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001458 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001459
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001460 XMLHandle docH( doc );
1461 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001462 XMLTest( "Handle, dne, mutable", true, ele == 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001463 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001464
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001465 {
1466 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1467 XMLDocument doc;
1468 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001469 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001470 XMLConstHandle docH( doc );
1471
1472 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001473 XMLTest( "Handle, success, const", "sub", ele->Value() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001474
1475 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001476 XMLTest( "Handle, dne, const", true, ele == 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001477 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001478 {
1479 // Default Declaration & BOM
1480 XMLDocument doc;
1481 doc.InsertEndChild( doc.NewDeclaration() );
1482 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001483
Lee Thomasonf68c4382012-04-28 14:37:11 -07001484 XMLPrinter printer;
1485 doc.Print( &printer );
1486
1487 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001488 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1489 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001490 }
Lee Thomason21be8822012-07-15 17:27:22 -07001491 {
1492 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1493 XMLDocument doc;
1494 doc.Parse( xml );
1495 XMLTest( "Ill formed XML", true, doc.Error() );
1496 }
1497
1498 // QueryXYZText
1499 {
1500 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1501 XMLDocument doc;
1502 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001503 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001504
1505 const XMLElement* pointElement = doc.RootElement();
1506
Dmitry-Me43c019d2017-08-02 18:05:23 +03001507 {
1508 int intValue = 0;
1509 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1510 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1511 XMLTest( "QueryIntText", 1, intValue, false );
1512 }
Lee Thomason21be8822012-07-15 17:27:22 -07001513
Dmitry-Me43c019d2017-08-02 18:05:23 +03001514 {
1515 unsigned unsignedValue = 0;
1516 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1517 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1518 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1519 }
Lee Thomason21be8822012-07-15 17:27:22 -07001520
Dmitry-Me43c019d2017-08-02 18:05:23 +03001521 {
1522 float floatValue = 0;
1523 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1524 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1525 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1526 }
Lee Thomason21be8822012-07-15 17:27:22 -07001527
Dmitry-Me43c019d2017-08-02 18:05:23 +03001528 {
1529 double doubleValue = 0;
1530 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1531 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1532 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1533 }
1534
1535 {
1536 bool boolValue = false;
1537 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1538 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1539 XMLTest( "QueryBoolText", true, boolValue, false );
1540 }
Lee Thomason21be8822012-07-15 17:27:22 -07001541 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001542
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001543 {
1544 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1545 XMLDocument doc;
1546 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001547 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001548 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001549
1550 {
1551 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1552 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001553 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001554 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001555 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001556
1557 {
1558 const char* xml = "<3lement></3lement>";
1559 XMLDocument doc;
1560 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001561 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001562 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001563
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001564 {
1565 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1566 XMLDocument doc;
1567 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001568 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001569 }
1570
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001571 {
1572 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001573 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001574 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001575 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001576 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001577 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001578 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001579 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001580 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001581 }
Dmitry-Me985ea1f2017-08-28 18:36:29 +03001582
1583 {
1584 XMLDocument doc;
1585 XMLTest( "No error initially", false, doc.Error() );
1586 XMLError error = doc.Parse( "This is not XML" );
1587 XMLTest( "Error after invalid XML", true, doc.Error() );
1588 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1589 doc.Clear();
1590 XMLTest( "No error after Clear()", false, doc.Error() );
1591 }
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001592
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001593 // ----------- Whitespace ------------
1594 {
1595 const char* xml = "<element>"
1596 "<a> This \nis &apos; text &apos; </a>"
1597 "<b> This is &apos; text &apos; \n</b>"
1598 "<c>This is &apos; \n\n text &apos;</c>"
1599 "</element>";
1600 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1601 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001602 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001603
1604 const XMLElement* element = doc.FirstChildElement();
1605 for( const XMLElement* parent = element->FirstChildElement();
1606 parent;
1607 parent = parent->NextSiblingElement() )
1608 {
1609 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1610 }
1611 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001612
Lee Thomasonae9ab072012-10-24 10:17:53 -07001613#if 0
1614 {
1615 // Passes if assert doesn't fire.
1616 XMLDocument xmlDoc;
1617
1618 xmlDoc.NewDeclaration();
1619 xmlDoc.NewComment("Configuration file");
1620
1621 XMLElement *root = xmlDoc.NewElement("settings");
1622 root->SetAttribute("version", 2);
1623 }
1624#endif
1625
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001626 {
1627 const char* xml = "<element> </element>";
1628 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1629 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001630 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001631 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1632 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001633
Lee Thomason5b0a6772012-11-19 13:54:42 -08001634 {
1635 // An assert should not fire.
1636 const char* xml = "<element/>";
1637 XMLDocument doc;
1638 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001639 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001640 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1641 XMLTest( "Tracking unused elements", true, ele != 0, false );
1642 }
1643
Lee Thomasona6412ac2012-12-13 15:39:11 -08001644
1645 {
1646 const char* xml = "<parent><child>abc</child></parent>";
1647 XMLDocument doc;
1648 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001649 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001650 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1651
1652 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001653 bool acceptResult = ele->Accept( &printer );
1654 XMLTest( "Accept of sub-element", true, acceptResult );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001655 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1656 }
1657
1658
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001659 {
1660 XMLDocument doc;
1661 XMLError error = doc.LoadFile( "resources/empty.xml" );
1662 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001663 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001664 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001665 }
1666
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001667 {
1668 // BOM preservation
1669 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1670 {
1671 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001672 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001673 XMLPrinter printer;
1674 doc.Print( &printer );
1675
1676 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1677 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001678 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001679 }
1680 {
1681 XMLDocument doc;
1682 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001683 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001684 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1685
1686 XMLPrinter printer;
1687 doc.Print( &printer );
1688 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1689 }
1690 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001691
Michael Daumlinged523282013-10-23 07:47:29 +02001692 {
1693 // Insertion with Removal
1694 const char* xml = "<?xml version=\"1.0\" ?>"
1695 "<root>"
1696 "<one>"
1697 "<subtree>"
1698 "<elem>element 1</elem>text<!-- comment -->"
1699 "</subtree>"
1700 "</one>"
1701 "<two/>"
1702 "</root>";
1703 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1704 "<root>"
1705 "<one/>"
1706 "<two>"
1707 "<subtree>"
1708 "<elem>element 1</elem>text<!-- comment -->"
1709 "</subtree>"
1710 "</two>"
1711 "</root>";
1712 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1713 "<root>"
1714 "<one/>"
1715 "<subtree>"
1716 "<elem>element 1</elem>text<!-- comment -->"
1717 "</subtree>"
1718 "<two/>"
1719 "</root>";
1720 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1721 "<root>"
1722 "<one/>"
1723 "<two/>"
1724 "<subtree>"
1725 "<elem>element 1</elem>text<!-- comment -->"
1726 "</subtree>"
1727 "</root>";
1728
1729 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001730 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001731 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001732 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1733 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1734 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001735 XMLPrinter printer1(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001736 bool acceptResult = doc.Accept(&printer1);
1737 XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001738 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001739
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001740 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001741 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001742 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1743 two = doc.RootElement()->FirstChildElement("two");
1744 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001745 XMLPrinter printer2(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001746 acceptResult = doc.Accept(&printer2);
1747 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001748 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001749
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001750 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001751 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001752 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1753 subtree = one->FirstChildElement("subtree");
1754 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001755 XMLPrinter printer3(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001756 acceptResult = doc.Accept(&printer3);
1757 XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001758 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001759
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001760 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001761 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001762 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1763 two = doc.RootElement()->FirstChildElement("two");
1764 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001765 XMLPrinter printer4(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001766 acceptResult = doc.Accept(&printer4);
1767 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001768 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001769 }
1770
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001771 {
1772 const char* xml = "<svg width = \"128\" height = \"128\">"
1773 " <text> </text>"
1774 "</svg>";
1775 XMLDocument doc;
1776 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001777 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001778 doc.Print();
1779 }
1780
Lee Thomason92e521b2014-11-15 17:45:51 -08001781 {
1782 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001783 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1784 XMLDocument doc;
1785 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001786 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001787 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001788 }
1789
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001790#if 1
1791 // the question being explored is what kind of print to use:
1792 // https://github.com/leethomason/tinyxml2/issues/63
1793 {
1794 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1795 const char* xml = "<element/>";
1796 XMLDocument doc;
1797 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001798 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001799 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1800 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1801 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1802 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1803 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1804 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1805
1806 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1807 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1808 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1809 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1810 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1811 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1812
1813 doc.Print();
1814
1815 /* The result of this test is platform, compiler, and library version dependent. :("
1816 XMLPrinter printer;
1817 doc.Print( &printer );
1818 XMLTest( "Float and double formatting.",
1819 "<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",
1820 printer.CStr(),
1821 true );
1822 */
1823 }
1824#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001825
1826 {
1827 // Issue #184
1828 // If it doesn't assert, it passes. Caused by objects
1829 // getting created during parsing which are then
1830 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001831 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001832 {
1833 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001834 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001835 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001836 }
1837 {
1838 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001839 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001840 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001841 doc.Clear();
1842 }
1843 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001844
1845 {
1846 // If this doesn't assert in DEBUG, all is well.
1847 tinyxml2::XMLDocument doc;
1848 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1849 doc.DeleteNode(pRoot);
1850 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001851
Dmitry-Mee5790db2017-07-28 17:54:38 +03001852 {
1853 XMLDocument doc;
1854 XMLElement* root = doc.NewElement( "Root" );
1855 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1856 doc.InsertEndChild( root );
1857 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1858 }
1859
1860 {
1861 // If this doesn't assert in DEBUG, all is well.
1862 XMLDocument doc;
1863 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1864 XMLElement* linkedRoot = doc.NewElement( "Root" );
1865 doc.InsertFirstChild( linkedRoot );
1866 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1867 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1868 }
1869
Dmitry-Me8b67d742014-12-22 11:35:12 +03001870 {
1871 // Should not assert in DEBUG
1872 XMLPrinter printer;
1873 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001874
Dmitry-Me6f51c802015-03-14 13:25:03 +03001875 {
1876 // Issue 291. Should not crash
1877 const char* xml = "&#0</a>";
1878 XMLDocument doc;
1879 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001880 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001881
1882 XMLPrinter printer;
1883 doc.Print( &printer );
1884 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001885 {
1886 // Issue 299. Can print elements that are not linked in.
1887 // Will crash if issue not fixed.
1888 XMLDocument doc;
1889 XMLElement* newElement = doc.NewElement( "printme" );
1890 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001891 bool acceptResult = newElement->Accept( &printer );
1892 XMLTest( "printme - Accept()", true, acceptResult );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001893 // Delete the node to avoid possible memory leak report in debug output
1894 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001895 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001896 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001897 // Issue 302. Clear errors from LoadFile/SaveFile
1898 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001899 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001900 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001901 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001902 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001903 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001904 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001905
Dmitry-Med9852a52015-03-25 10:17:49 +03001906 {
1907 // If a document fails to load then subsequent
1908 // successful loads should clear the error
1909 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001910 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001911 doc.LoadFile( "resources/no-such-file.xml" );
1912 XMLTest( "No such file - should fail", true, doc.Error() );
1913
1914 doc.LoadFile( "resources/dream.xml" );
1915 XMLTest( "Error should be cleared", false, doc.Error() );
1916 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301917
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301918 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001919 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001920 const char* xml0 = "<?xml version=\"1.0\" ?>"
1921 " <!-- xml version=\"1.1\" -->"
1922 "<first />";
1923 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001924 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001925 "<first />";
1926 const char* xml2 = "<first />"
1927 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001928 const char* xml3 = "<first></first>"
1929 "<?xml version=\"1.0\" ?>";
1930
1931 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1932
Lee Thomason85492022015-05-22 11:07:45 -07001933 XMLDocument doc;
1934 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001935 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001936 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001937 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001938 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001939 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001940 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001941 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001942 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001943 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301944 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001945
Lee Thomason85492022015-05-22 11:07:45 -07001946 {
1947 // No matter - before or after successfully parsing a text -
Dmitry-Me26043362017-08-30 17:40:15 +03001948 // calling XMLDocument::Value() used to cause an assert in debug.
1949 // Null must be retured.
Lee Thomason85492022015-05-22 11:07:45 -07001950 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1951 "<first />"
1952 "<second />";
1953 XMLDocument* doc = new XMLDocument();
1954 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1955 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001956 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001957 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1958 delete doc;
1959 }
1960
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001961 {
1962 XMLDocument doc;
1963 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
Dmitry-Med3f6c632017-08-30 17:43:14 +03001964 const XMLError error = static_cast<XMLError>(i);
Lee Thomasonf49b9652017-10-11 10:57:49 -07001965 const char* name = XMLDocument::ErrorIDToName(error);
1966 XMLTest( "ErrorName() after ClearError()", true, name != 0 );
1967 XMLTest( "ErrorName() after ClearError()", true, strlen(name) > 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001968 }
1969 }
1970
Lee Thomason816d3fa2017-06-05 14:35:55 -07001971 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001972 // Evil memory leaks.
1973 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1974 // and NOT added to the XMLDocument, what happens?
1975 //
1976 // Previously (buggy):
1977 // The memory would be free'd when the XMLDocument is
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001978 // destructed. But the XMLElement destructor wasn't called, so
1979 // memory allocated for the XMLElement text would not be free'd.
1980 // In practice this meant strings allocated for the XMLElement
1981 // text would be leaked. An edge case, but annoying.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001982 // Now:
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001983 // The XMLElement destructor is called. But the unlinked nodes
1984 // have to be tracked using a list. This has a minor performance
1985 // impact that can become significant if you have a lot of
1986 // unlinked nodes. (But why would you do that?)
1987 // The only way to see this bug was in a Visual C++ runtime debug heap
1988 // leak tracker. This is compiled in by default on Windows Debug and
1989 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
Lee Thomason816d3fa2017-06-05 14:35:55 -07001990 {
1991 XMLDocument doc;
1992 doc.NewElement("LEAK 1");
1993 }
1994 {
1995 XMLDocument doc;
1996 XMLElement* ele = doc.NewElement("LEAK 2");
1997 doc.DeleteNode(ele);
1998 }
1999 }
2000
Lee Thomason224ef772017-06-16 09:45:26 -07002001 {
2002 // Crashing reported via email.
2003 const char* xml =
2004 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07002005 "<property name='track_name'>voice</property>"
2006 "<property name='audio_track'>1</property>"
2007 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2008 "<blank length = '1' />"
2009 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2010 "<blank length = '2' />"
2011 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2012 "<blank length = '1' />"
2013 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07002014 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07002015
Lee Thomason224ef772017-06-16 09:45:26 -07002016 // It's not a good idea to delete elements as you walk the
2017 // list. I'm not sure this technically should work; but it's
2018 // an interesting test case.
2019 XMLDocument doc;
2020 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002021 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03002022
2023 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07002024 XMLTest("Crash bug parsing", true, playlist != 0);
2025
Dmitry-Meb41e24a2017-09-27 18:51:01 +03002026 {
2027 const char* elementName = "entry";
2028 XMLElement* entry = playlist->FirstChildElement(elementName);
2029 XMLTest("Crash bug parsing", true, entry != 0);
2030 while (entry) {
2031 XMLElement* todelete = entry;
2032 entry = entry->NextSiblingElement(elementName);
2033 playlist->DeleteChild(todelete);
2034 }
2035 entry = playlist->FirstChildElement(elementName);
2036 XMLTest("Crash bug parsing", true, entry == 0);
2037 }
2038 {
2039 const char* elementName = "blank";
2040 XMLElement* blank = playlist->FirstChildElement(elementName);
2041 XMLTest("Crash bug parsing", true, blank != 0);
2042 while (blank) {
2043 XMLElement* todelete = blank;
2044 blank = blank->NextSiblingElement(elementName);
2045 playlist->DeleteChild(todelete);
2046 }
2047 XMLTest("Crash bug parsing", true, blank == 0);
2048 }
Lee Thomason224ef772017-06-16 09:45:26 -07002049
2050 tinyxml2::XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002051 const bool acceptResult = playlist->Accept(&printer);
2052 XMLTest("Crash bug parsing - Accept()", true, acceptResult);
Lee Thomason224ef772017-06-16 09:45:26 -07002053 printf("%s\n", printer.CStr());
2054
Lee Thomason82bb0742017-06-16 09:48:20 -07002055 // No test; it only need to not crash.
2056 // Still, wrap it up with a sanity check
2057 int nProperty = 0;
2058 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2059 nProperty++;
2060 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002061 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07002062 }
2063
kezenatorec694152016-11-26 17:21:43 +10002064 // ----------- Line Number Tracking --------------
2065 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002066 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002067 {
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002068 TestUtil() : str() {}
2069
kezenatorec694152016-11-26 17:21:43 +10002070 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2071 {
2072 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002073 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002074
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002075 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002076 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002077 XMLTest(testString, expected_error, parseError);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002078 XMLTest(testString, expectedLine, doc.ErrorLineNum());
kezenatorec694152016-11-26 17:21:43 +10002079 };
2080
2081 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2082 {
2083 XMLDocument doc;
2084 doc.Parse(docStr);
2085 XMLTest(testString, false, doc.Error());
2086 TestDocLines(testString, doc, expectedLines);
2087 }
2088
2089 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2090 {
2091 XMLDocument doc;
2092 doc.LoadFile(file_name);
2093 XMLTest(testString, false, doc.Error());
2094 TestDocLines(testString, doc, expectedLines);
2095 }
2096
2097 private:
2098 DynArray<char, 10> str;
2099
2100 void Push(char type, int lineNum)
2101 {
2102 str.Push(type);
2103 str.Push(char('0' + (lineNum / 10)));
2104 str.Push(char('0' + (lineNum % 10)));
2105 }
2106
2107 bool VisitEnter(const XMLDocument& doc)
2108 {
kezenator19d8ea82016-11-29 19:50:27 +10002109 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002110 return true;
2111 }
2112 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2113 {
kezenator19d8ea82016-11-29 19:50:27 +10002114 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002115 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002116 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002117 return true;
2118 }
2119 bool Visit(const XMLDeclaration& declaration)
2120 {
kezenator19d8ea82016-11-29 19:50:27 +10002121 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002122 return true;
2123 }
2124 bool Visit(const XMLText& text)
2125 {
kezenator19d8ea82016-11-29 19:50:27 +10002126 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002127 return true;
2128 }
2129 bool Visit(const XMLComment& comment)
2130 {
kezenator19d8ea82016-11-29 19:50:27 +10002131 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002132 return true;
2133 }
2134 bool Visit(const XMLUnknown& unknown)
2135 {
kezenator19d8ea82016-11-29 19:50:27 +10002136 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002137 return true;
2138 }
2139
2140 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2141 {
2142 str.Clear();
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002143 const bool acceptResult = doc.Accept(this);
2144 XMLTest(testString, true, acceptResult);
kezenatorec694152016-11-26 17:21:43 +10002145 str.Push(0);
2146 XMLTest(testString, expectedLines, str.Mem());
2147 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002148 } tester;
kezenatorec694152016-11-26 17:21:43 +10002149
Lee Thomasone90e9012016-12-24 07:34:39 -08002150 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2151 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2152 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2153 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2154 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2155 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2156 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2157 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2158 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2159 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2160 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002161
Lee Thomasone90e9012016-12-24 07:34:39 -08002162 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002163 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002164
2165 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2166 "<root a='b' \n" // 2 Element Attribute
2167 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2168 "newline in text \n" // 4 Text
2169 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2170 " cdata test ]]><!-- comment -->\n" // 6 Comment
2171 "<! unknown></root>", // 7 Unknown
2172
kezenatorec694152016-11-26 17:21:43 +10002173 "D01L01E02A02A03T03E03T04E05T05C06U07");
2174
Lee Thomasone90e9012016-12-24 07:34:39 -08002175 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002176 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002177
2178 "\r\n" // 1 Doc (arguably should be line 2)
2179 "<?xml version=\"1.0\"?>\n" // 2 DecL
2180 "<root>\r\n" // 3 Element
2181 "\n" // 4
2182 "text contining new line \n" // 5 Text
2183 " and also containing crlf \r\n" // 6
2184 "<sub><![CDATA[\n" // 7 Element Text
2185 "cdata containing new line \n" // 8
2186 " and also containing cflr\r\n" // 9
2187 "]]></sub><sub2/></root>", // 10 Element
2188
kezenatorec694152016-11-26 17:21:43 +10002189 "D01L02E03T05E07T07E10");
2190
Lee Thomasone90e9012016-12-24 07:34:39 -08002191 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002192 "LineNumbers-File",
2193 "resources/utf8test.xml",
2194 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2195 }
2196
Lee Thomasonf49b9652017-10-11 10:57:49 -07002197 {
2198 const char* xml = "<Hello>Text</Error>";
2199 XMLDocument doc;
2200 doc.Parse(xml);
2201 XMLTest("Test mismatched elements.", true, doc.Error());
2202 XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2203 // For now just make sure calls work & doesn't crash.
2204 // May solidify the error output in the future.
2205 printf("%s\n", doc.ErrorStr());
2206 doc.PrintError();
2207 }
2208
Lee Thomason85492022015-05-22 11:07:45 -07002209 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002210 {
2211#if defined( _MSC_VER )
2212 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002213 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002214#endif
2215
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002216 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002217 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002218 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002219 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002220 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002221
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002222 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002223 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002224 size_t bytesRead = fread(mem, 1, size, perfFP);
2225 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002226 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002227 mem[size] = 0;
2228
2229#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002230 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002231#else
2232 clock_t cstart = clock();
2233#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002234 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002235 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002236 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002237 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002238 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002239 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002240 }
2241#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002242 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002243#else
2244 clock_t cend = clock();
2245#endif
Dmitry-Me1ab85872017-08-10 17:28:10 +03002246 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002247
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002248 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002249
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002250 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002251#ifdef DEBUG
2252 "DEBUG";
2253#else
2254 "Release";
2255#endif
2256
2257#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002258 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002259#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002260 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002261#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002262 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002263 }
2264
Dmitry-Mede381df2017-07-26 18:05:25 +03002265#if defined( _MSC_VER ) && defined( DEBUG )
2266 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002267 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002268
2269 _CrtMemState diffMemState;
2270 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2271 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002272
2273 {
2274 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2275 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2276 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002277 }
2278#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002279
2280 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002281
2282 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002283}