blob: a297722683741129735ddefdec3ddfa6e8104b5b [file] [log] [blame]
Lee Thomason5b0a6772012-11-19 13:54:42 -08001#if defined( _MSC_VER )
Serhat Eser Erdemca5d6842014-04-17 14:06:15 +02002 #if !defined( _CRT_SECURE_NO_WARNINGS )
3 #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
4 #endif
Lee Thomason5b0a6772012-11-19 13:54:42 -08005#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08006
Lee Thomason5b0a6772012-11-19 13:54:42 -08007#include "tinyxml2.h"
kbinny62bf29a152017-06-23 18:15:25 +00008#include <cerrno>
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07009#include <cstdlib>
10#include <cstring>
11#include <ctime>
U-Lama\Leee13c3e62011-12-28 14:36:55 -080012
kbinny62bf29a152017-06-23 18:15:25 +000013#if defined( _MSC_VER ) || defined (WIN32)
Lee Thomason1ff38e02012-02-14 18:18:16 -080014 #include <crtdbg.h>
Lee Thomason6f381b72012-03-02 12:59:39 -080015 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080017 _CrtMemState startMemState;
Lee Thomason53858b42017-06-01 19:09:16 -070018 _CrtMemState endMemState;
kbinny62bf29a152017-06-23 18:15:25 +000019#else
20 #include <sys/stat.h>
21 #include <sys/types.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080022#endif
Lee Thomasone9ecdab2012-02-13 18:11:20 -080023
U-Lama\Leee13c3e62011-12-28 14:36:55 -080024using namespace tinyxml2;
Anton Indrawan8a0006c2014-11-20 18:27:07 +010025using namespace std;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080026int gPass = 0;
27int gFail = 0;
28
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080029
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070030bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080031{
Sarat Addepalli13b2d732015-05-19 12:44:57 +053032 bool pass;
33 if ( !expected && !found )
34 pass = true;
35 else if ( !expected || !found )
36 pass = false;
Sarat Addepallid608c562015-05-20 10:19:00 +053037 else
38 pass = !strcmp( expected, found );
Lee Thomason1ff38e02012-02-14 18:18:16 -080039 if ( pass )
40 printf ("[pass]");
41 else
42 printf ("[fail]");
43
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070044 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080045 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070046 }
47 else {
48 if ( extraNL ) {
49 printf( " %s\n", testString );
50 printf( "%s\n", expected );
51 printf( "%s\n", found );
52 }
53 else {
54 printf (" %s [%s][%s]\n", testString, expected, found);
55 }
56 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080057
58 if ( pass )
59 ++gPass;
60 else
61 ++gFail;
62 return pass;
63}
64
kezenator5a700712016-11-26 13:54:42 +100065bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
66{
Lee Thomasone90e9012016-12-24 07:34:39 -080067 return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
kezenator5a700712016-11-26 13:54:42 +100068}
69
70bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
71{
72 return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
73}
Lee Thomason1ff38e02012-02-14 18:18:16 -080074
Lee Thomason21be8822012-07-15 17:27:22 -070075template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080076{
77 bool pass = ( expected == found );
78 if ( pass )
79 printf ("[pass]");
80 else
81 printf ("[fail]");
82
U-Stream\Lee09a11c52012-02-17 08:31:16 -080083 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080084 printf (" %s\n", testString);
85 else
Lee Thomasonc8312792012-07-16 12:44:41 -070086 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080087
88 if ( pass )
89 ++gPass;
90 else
91 ++gFail;
92 return pass;
93}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080094
U-Lama\Leee13c3e62011-12-28 14:36:55 -080095
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080096void NullLineEndings( char* p )
97{
98 while( p && *p ) {
99 if ( *p == '\n' || *p == '\r' ) {
100 *p = 0;
101 return;
102 }
103 ++p;
104 }
105}
106
107
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700108int example_1()
109{
110 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300111 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700112
113 return doc.ErrorID();
114}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200115/** @page Example-1 Load an XML File
116 * @dontinclude ./xmltest.cpp
117 * Basic XML file loading.
118 * The basic syntax to load an XML file from
119 * disk and check for an error. (ErrorID()
120 * will return 0 for no error.)
121 * @skip example_1()
122 * @until }
123 */
124
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700125
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700126int example_2()
127{
128 static const char* xml = "<element/>";
129 XMLDocument doc;
130 doc.Parse( xml );
131
132 return doc.ErrorID();
133}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200134/** @page Example-2 Parse an XML from char buffer
135 * @dontinclude ./xmltest.cpp
136 * Basic XML string parsing.
137 * The basic syntax to parse an XML for
138 * a char* and check for an error. (ErrorID()
139 * will return 0 for no error.)
140 * @skip example_2()
141 * @until }
142 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700143
144
145int example_3()
146{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700147 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700148 "<?xml version=\"1.0\"?>"
149 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
150 "<PLAY>"
151 "<TITLE>A Midsummer Night's Dream</TITLE>"
152 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700153
154 XMLDocument doc;
155 doc.Parse( xml );
156
157 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
158 const char* title = titleElement->GetText();
159 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700160
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700161 XMLText* textNode = titleElement->FirstChild()->ToText();
162 title = textNode->Value();
163 printf( "Name of play (2): %s\n", title );
164
165 return doc.ErrorID();
166}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200167/** @page Example-3 Get information out of XML
168 @dontinclude ./xmltest.cpp
169 In this example, we navigate a simple XML
170 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700171 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200172 checking; working code should check for null
173 pointers when walking an XML tree, or use
174 XMLHandle.
175
176 (The XML is an excerpt from "dream.xml").
177
178 @skip example_3()
179 @until </PLAY>";
180
181 The structure of the XML file is:
182
183 <ul>
184 <li>(declaration)</li>
185 <li>(dtd stuff)</li>
186 <li>Element "PLAY"</li>
187 <ul>
188 <li>Element "TITLE"</li>
189 <ul>
190 <li>Text "A Midsummer Night's Dream"</li>
191 </ul>
192 </ul>
193 </ul>
194
195 For this example, we want to print out the
196 title of the play. The text of the title (what
197 we want) is child of the "TITLE" element which
198 is a child of the "PLAY" element.
199
200 We want to skip the declaration and dtd, so the
201 method FirstChildElement() is a good choice. The
202 FirstChildElement() of the Document is the "PLAY"
203 Element, the FirstChildElement() of the "PLAY" Element
204 is the "TITLE" Element.
205
206 @until ( "TITLE" );
207
208 We can then use the convenience function GetText()
209 to get the title of the play.
210
211 @until title );
212
213 Text is just another Node in the XML DOM. And in
214 fact you should be a little cautious with it, as
215 text nodes can contain elements.
216
217 @verbatim
218 Consider: A Midsummer Night's <b>Dream</b>
219 @endverbatim
220
221 It is more correct to actually query the Text Node
222 if in doubt:
223
224 @until title );
225
226 Noting that here we use FirstChild() since we are
227 looking for XMLText, not an element, and ToText()
228 is a cast from a Node to a XMLText.
229*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700230
231
Lee Thomason21be8822012-07-15 17:27:22 -0700232bool example_4()
233{
234 static const char* xml =
235 "<information>"
236 " <attributeApproach v='2' />"
237 " <textApproach>"
238 " <v>2</v>"
239 " </textApproach>"
240 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700241
Lee Thomason21be8822012-07-15 17:27:22 -0700242 XMLDocument doc;
243 doc.Parse( xml );
244
245 int v0 = 0;
246 int v1 = 0;
247
248 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
249 attributeApproachElement->QueryIntAttribute( "v", &v0 );
250
251 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
252 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
253
254 printf( "Both values are the same: %d and %d\n", v0, v1 );
255
256 return !doc.Error() && ( v0 == v1 );
257}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200258/** @page Example-4 Read attributes and text information.
259 @dontinclude ./xmltest.cpp
260
261 There are fundamentally 2 ways of writing a key-value
262 pair into an XML file. (Something that's always annoyed
263 me about XML.) Either by using attributes, or by writing
264 the key name into an element and the value into
265 the text node wrapped by the element. Both approaches
266 are illustrated in this example, which shows two ways
267 to encode the value "2" into the key "v":
268
269 @skip example_4()
270 @until "</information>";
271
272 TinyXML-2 has accessors for both approaches.
273
274 When using an attribute, you navigate to the XMLElement
275 with that attribute and use the QueryIntAttribute()
276 group of methods. (Also QueryFloatAttribute(), etc.)
277
278 @skip XMLElement* attributeApproachElement
279 @until &v0 );
280
281 When using the text approach, you need to navigate
282 down one more step to the XMLElement that contains
283 the text. Note the extra FirstChildElement( "v" )
284 in the code below. The value of the text can then
285 be safely queried with the QueryIntText() group
286 of methods. (Also QueryFloatText(), etc.)
287
288 @skip XMLElement* textApproachElement
289 @until &v1 );
290*/
Lee Thomason21be8822012-07-15 17:27:22 -0700291
292
Lee Thomason178e4cc2013-01-25 16:19:05 -0800293int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800294{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800295 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800296 _CrtMemCheckpoint( &startMemState );
Dmitry-Me99916592014-10-23 11:37:03 +0400297 // Enable MS Visual C++ debug heap memory leaks dump on exit
298 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
Dmitry-Meed785702017-06-15 13:39:53 +0300299 {
300 int leaksOnStart = _CrtDumpMemoryLeaks();
301 XMLTest( "No leaks on start?", FALSE, leaksOnStart );
302 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700303 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800304
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300305 {
306 TIXMLASSERT( true );
307 }
308
Lee Thomason178e4cc2013-01-25 16:19:05 -0800309 if ( argc > 1 ) {
310 XMLDocument* doc = new XMLDocument();
311 clock_t startTime = clock();
312 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100313 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800314 int errorID = doc->ErrorID();
315 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100316 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800317
318 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
319 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700320 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
321 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
322 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800323 }
324 exit(0);
325 }
326
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300327 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700328 if ( !fp ) {
329 printf( "Error opening test file 'dream.xml'.\n"
330 "Is your working directory the same as where \n"
331 "the xmltest.cpp and dream.xml file are?\n\n"
332 #if defined( _MSC_VER )
333 "In windows Visual Studio you may need to set\n"
334 "Properties->Debugging->Working Directory to '..'\n"
335 #endif
336 );
337 exit( 1 );
338 }
339 fclose( fp );
340
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700341 XMLTest( "Example-1", 0, example_1() );
342 XMLTest( "Example-2", 0, example_2() );
343 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700344 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700345
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700346 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700347
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800348 {
Lee Thomason43f59302012-02-06 18:18:11 -0800349 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400350 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800351 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400352 "<element><subelement></subelement></element>",
353 "<element><subelement><subsub/></subelement></element>",
354 "<!--comment beside elements--><element><subelement></subelement></element>",
355 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
356 "<element attrib1='foo' attrib2=\"bar\" ></element>",
357 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800358 "<element>Text inside element.</element>",
359 "<element><b></b></element>",
360 "<element>Text inside and <b>bolded</b> in the element.</element>",
361 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800362 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800363 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800364 0
365 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800366 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800367 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800368 doc.Parse( test[i] );
Dmitry-Me68578f42017-07-03 18:21:23 +0300369 XMLTest( "Element test", false, doc.Error() );
Lee Thomason5cae8972012-01-24 18:03:07 -0800370 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800371 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800372 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800373 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800374#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800375 {
376 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400377 " line 2\r"
378 " line 3\r\n"
379 " line 4\n\r"
380 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800381
382 XMLDocument doc;
383 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300384 XMLTest( "Hello world declaration", false, doc.Error() );
Lee Thomasond6277762012-02-22 16:00:12 -0800385 doc.Print();
386 }
387
Lee Thomason2c85a712012-01-31 08:24:24 -0800388 {
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 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001038 psg->Accept( &streamer );
1039 fclose( textfile );
1040 }
Thomas Roß0922b732012-09-23 16:31:22 +02001041
Dmitry-Me520009e2017-08-10 17:50:03 +03001042 textfile = fopen( textFilePath, "r" );
1043 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001044 if ( textfile )
1045 {
1046 char buf[ 1024 ];
1047 fgets( buf, 1024, textfile );
1048 XMLTest( "Entity transformation: write. ",
1049 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1050 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1051 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001052 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001053 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001054 }
1055
1056 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001057 // Suppress entities.
1058 const char* passages =
1059 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1060 "<passages count=\"006\" formatversion=\"20020620\">"
1061 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1062 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001063
Lee Thomason6f381b72012-03-02 12:59:39 -08001064 XMLDocument doc( false );
1065 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001066 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001067
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001068 XMLTest( "No entity parsing.",
1069 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1070 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1071 XMLTest( "No entity parsing.", "Crazy &ttk;",
1072 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001073 doc.Print();
1074 }
1075
1076 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001077 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001078
1079 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001080 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001081 XMLTest( "dot in names", false, doc.Error() );
1082 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1083 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001084 }
1085
1086 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001087 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001088
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001089 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001090 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001091 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001092
1093 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1094 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001095 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001096 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001097 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001098
1099 {
1100 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001101 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001102 const char* doctype =
1103 "<?xml version=\"1.0\" ?>"
1104 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1105 "<!ELEMENT title (#PCDATA)>"
1106 "<!ELEMENT books (title,authors)>"
1107 "<element />";
1108
1109 XMLDocument doc;
1110 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001111 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001112 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001113 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001114 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001115 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001116 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001117 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001118
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001119 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1120 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1121
1122 }
1123
1124 {
1125 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001126 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001127 "<!-- Somewhat<evil> -->";
1128 XMLDocument doc;
1129 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001130 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001131
1132 XMLComment* comment = doc.FirstChild()->ToComment();
1133
1134 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1135 }
1136 {
1137 // Double attributes
1138 const char* doctype = "<element attr='red' attr='blue' />";
1139
1140 XMLDocument doc;
1141 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001142
Lee Thomason2fa81722012-11-09 12:37:46 -08001143 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 -08001144 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001145 }
1146
1147 {
1148 // Embedded null in stream.
1149 const char* doctype = "<element att\0r='red' attr='blue' />";
1150
1151 XMLDocument doc;
1152 doc.Parse( doctype );
1153 XMLTest( "Embedded null throws error.", true, doc.Error() );
1154 }
1155
1156 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001157 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001158 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001159 XMLDocument doc;
1160 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001161 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001162 }
1163
1164 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001165 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1166 const char* str = " ";
1167 XMLDocument doc;
1168 doc.Parse( str );
1169 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1170 }
1171
1172 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001173 // Low entities
1174 XMLDocument doc;
1175 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001176 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001177 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001178 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001179 doc.Print();
1180 }
1181
1182 {
1183 // Attribute values with trailing quotes not handled correctly
1184 XMLDocument doc;
1185 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001186 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001187 }
1188
1189 {
1190 // [ 1663758 ] Failure to report error on bad XML
1191 XMLDocument xml;
1192 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001193 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001194 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001195 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001196 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001197 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001198 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001199
1200
1201 {
1202 // [ 1475201 ] TinyXML parses entities in comments
1203 XMLDocument xml;
1204 xml.Parse("<!-- declarations for <head> & <body> -->"
1205 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001206 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001207
1208 XMLNode* e0 = xml.FirstChild();
1209 XMLNode* e1 = e0->NextSibling();
1210 XMLComment* c0 = e0->ToComment();
1211 XMLComment* c1 = e1->ToComment();
1212
1213 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1214 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1215 }
1216
1217 {
1218 XMLDocument xml;
1219 xml.Parse( "<Parent>"
1220 "<child1 att=''/>"
1221 "<!-- With this comment, child2 will not be parsed! -->"
1222 "<child2 att=''/>"
1223 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001224 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001225 xml.Print();
1226
1227 int count = 0;
1228
1229 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1230 ele;
1231 ele = ele->NextSibling() )
1232 {
1233 ++count;
1234 }
1235
1236 XMLTest( "Comments iterate correctly.", 3, count );
1237 }
1238
1239 {
1240 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1241 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1242 buf[60] = 239;
1243 buf[61] = 0;
1244
1245 XMLDocument doc;
1246 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001247 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001248 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001249
1250
1251 {
1252 // bug 1827248 Error while parsing a little bit malformed file
1253 // Actually not malformed - should work.
1254 XMLDocument xml;
1255 xml.Parse( "<attributelist> </attributelist >" );
1256 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1257 }
1258
1259 {
1260 // This one must not result in an infinite loop
1261 XMLDocument xml;
1262 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001263 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001264 XMLTest( "Infinite loop test.", true, true );
1265 }
1266#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001267 {
1268 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1269 XMLDocument doc;
1270 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001271 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001272
1273 XMLDocument clone;
1274 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1275 XMLNode* copy = node->ShallowClone( &clone );
1276 clone.InsertEndChild( copy );
1277 }
1278
1279 clone.Print();
1280
1281 int count=0;
1282 const XMLNode* a=clone.FirstChild();
1283 const XMLNode* b=doc.FirstChild();
1284 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1285 ++count;
1286 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1287 }
1288 XMLTest( "Clone and Equal", 4, count );
1289 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001290
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001291 {
Lee Thomason7085f002017-06-01 18:09:43 -07001292 // Deep Cloning of root element.
1293 XMLDocument doc2;
1294 XMLPrinter printer1;
1295 {
1296 // Make sure doc1 is deleted before we test doc2
1297 const char* xml =
1298 "<root>"
1299 " <child1 foo='bar'/>"
1300 " <!-- comment thing -->"
1301 " <child2 val='1'>Text</child2>"
1302 "</root>";
1303 XMLDocument doc;
1304 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001305 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001306
1307 doc.Print(&printer1);
1308 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1309 doc2.InsertFirstChild(root);
1310 }
1311 XMLPrinter printer2;
1312 doc2.Print(&printer2);
1313
1314 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1315 }
1316
1317 {
1318 // Deep Cloning of sub element.
1319 XMLDocument doc2;
1320 XMLPrinter printer1;
1321 {
1322 // Make sure doc1 is deleted before we test doc2
1323 const char* xml =
1324 "<?xml version ='1.0'?>"
1325 "<root>"
1326 " <child1 foo='bar'/>"
1327 " <!-- comment thing -->"
1328 " <child2 val='1'>Text</child2>"
1329 "</root>";
1330 XMLDocument doc;
1331 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001332 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001333
1334 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1335 subElement->Accept(&printer1);
1336
1337 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1338 doc2.InsertFirstChild(clonedSubElement);
1339 }
1340 XMLPrinter printer2;
1341 doc2.Print(&printer2);
1342
1343 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1344 }
1345
1346 {
1347 // Deep cloning of document.
1348 XMLDocument doc2;
1349 XMLPrinter printer1;
1350 {
1351 // Make sure doc1 is deleted before we test doc2
1352 const char* xml =
1353 "<?xml version ='1.0'?>"
1354 "<!-- Top level comment. -->"
1355 "<root>"
1356 " <child1 foo='bar'/>"
1357 " <!-- comment thing -->"
1358 " <child2 val='1'>Text</child2>"
1359 "</root>";
1360 XMLDocument doc;
1361 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001362 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001363 doc.Print(&printer1);
1364
1365 doc.DeepCopy(&doc2);
1366 }
1367 XMLPrinter printer2;
1368 doc2.Print(&printer2);
1369
1370 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1371 }
1372
1373
1374 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001375 // This shouldn't crash.
1376 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001377 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001378 {
1379 doc.PrintError();
1380 }
1381 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1382 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001383
Lee Thomason5e3803c2012-04-16 08:57:05 -07001384 {
1385 // Attribute ordering.
1386 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1387 XMLDocument doc;
1388 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001389 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001390 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001391
Lee Thomason5e3803c2012-04-16 08:57:05 -07001392 const XMLAttribute* a = ele->FirstAttribute();
1393 XMLTest( "Attribute order", "1", a->Value() );
1394 a = a->Next();
1395 XMLTest( "Attribute order", "2", a->Value() );
1396 a = a->Next();
1397 XMLTest( "Attribute order", "3", a->Value() );
1398 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001399
Lee Thomason5e3803c2012-04-16 08:57:05 -07001400 ele->DeleteAttribute( "attrib2" );
1401 a = ele->FirstAttribute();
1402 XMLTest( "Attribute order", "1", a->Value() );
1403 a = a->Next();
1404 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001405
Lee Thomason5e3803c2012-04-16 08:57:05 -07001406 ele->DeleteAttribute( "attrib1" );
1407 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001408 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001409 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001410
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001411 {
1412 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001413 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1414 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1415 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1416 XMLDocument doc0;
1417 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001418 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001419 XMLDocument doc1;
1420 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001421 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001422 XMLDocument doc2;
1423 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001424 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001425
Lee Thomason78a773d2012-07-02 10:10:19 -07001426 XMLElement* ele = 0;
1427 ele = doc0.FirstChildElement();
1428 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1429 ele = doc1.FirstChildElement();
1430 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1431 ele = doc2.FirstChildElement();
1432 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001433 }
1434
1435 {
1436 // Make sure we don't go into an infinite loop.
1437 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1438 XMLDocument doc;
1439 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001440 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001441 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1442 XMLElement* ele1 = ele0->NextSiblingElement();
1443 bool equal = ele0->ShallowEqual( ele1 );
1444
1445 XMLTest( "Infinite loop in shallow equal.", true, equal );
1446 }
1447
Lee Thomason5708f812012-03-28 17:46:41 -07001448 // -------- Handles ------------
1449 {
1450 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1451 XMLDocument doc;
1452 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001453 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001454
1455 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001456 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001457
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001458 XMLHandle docH( doc );
1459 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001460 XMLTest( "Handle, dne, mutable", true, ele == 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001461 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001462
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001463 {
1464 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1465 XMLDocument doc;
1466 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001467 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001468 XMLConstHandle docH( doc );
1469
1470 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001471 XMLTest( "Handle, success, const", "sub", ele->Value() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001472
1473 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001474 XMLTest( "Handle, dne, const", true, ele == 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001475 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001476 {
1477 // Default Declaration & BOM
1478 XMLDocument doc;
1479 doc.InsertEndChild( doc.NewDeclaration() );
1480 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001481
Lee Thomasonf68c4382012-04-28 14:37:11 -07001482 XMLPrinter printer;
1483 doc.Print( &printer );
1484
1485 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001486 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1487 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001488 }
Lee Thomason21be8822012-07-15 17:27:22 -07001489 {
1490 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1491 XMLDocument doc;
1492 doc.Parse( xml );
1493 XMLTest( "Ill formed XML", true, doc.Error() );
1494 }
1495
1496 // QueryXYZText
1497 {
1498 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1499 XMLDocument doc;
1500 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001501 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001502
1503 const XMLElement* pointElement = doc.RootElement();
1504
Dmitry-Me43c019d2017-08-02 18:05:23 +03001505 {
1506 int intValue = 0;
1507 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1508 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1509 XMLTest( "QueryIntText", 1, intValue, false );
1510 }
Lee Thomason21be8822012-07-15 17:27:22 -07001511
Dmitry-Me43c019d2017-08-02 18:05:23 +03001512 {
1513 unsigned unsignedValue = 0;
1514 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1515 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1516 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1517 }
Lee Thomason21be8822012-07-15 17:27:22 -07001518
Dmitry-Me43c019d2017-08-02 18:05:23 +03001519 {
1520 float floatValue = 0;
1521 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1522 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1523 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1524 }
Lee Thomason21be8822012-07-15 17:27:22 -07001525
Dmitry-Me43c019d2017-08-02 18:05:23 +03001526 {
1527 double doubleValue = 0;
1528 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1529 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1530 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1531 }
1532
1533 {
1534 bool boolValue = false;
1535 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1536 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1537 XMLTest( "QueryBoolText", true, boolValue, false );
1538 }
Lee Thomason21be8822012-07-15 17:27:22 -07001539 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001540
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001541 {
1542 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1543 XMLDocument doc;
1544 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001545 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001546 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001547
1548 {
1549 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1550 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001551 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001552 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001553 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001554
1555 {
1556 const char* xml = "<3lement></3lement>";
1557 XMLDocument doc;
1558 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001559 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001560 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001561
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001562 {
1563 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1564 XMLDocument doc;
1565 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001566 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001567 }
1568
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001569 {
1570 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001571 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001572 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001573 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001574 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001575 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001576 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001577 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001578 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001579 }
Dmitry-Me985ea1f2017-08-28 18:36:29 +03001580
1581 {
1582 XMLDocument doc;
1583 XMLTest( "No error initially", false, doc.Error() );
1584 XMLError error = doc.Parse( "This is not XML" );
1585 XMLTest( "Error after invalid XML", true, doc.Error() );
1586 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1587 doc.Clear();
1588 XMLTest( "No error after Clear()", false, doc.Error() );
1589 }
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001590
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001591 // ----------- Whitespace ------------
1592 {
1593 const char* xml = "<element>"
1594 "<a> This \nis &apos; text &apos; </a>"
1595 "<b> This is &apos; text &apos; \n</b>"
1596 "<c>This is &apos; \n\n text &apos;</c>"
1597 "</element>";
1598 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1599 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001600 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001601
1602 const XMLElement* element = doc.FirstChildElement();
1603 for( const XMLElement* parent = element->FirstChildElement();
1604 parent;
1605 parent = parent->NextSiblingElement() )
1606 {
1607 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1608 }
1609 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001610
Lee Thomasonae9ab072012-10-24 10:17:53 -07001611#if 0
1612 {
1613 // Passes if assert doesn't fire.
1614 XMLDocument xmlDoc;
1615
1616 xmlDoc.NewDeclaration();
1617 xmlDoc.NewComment("Configuration file");
1618
1619 XMLElement *root = xmlDoc.NewElement("settings");
1620 root->SetAttribute("version", 2);
1621 }
1622#endif
1623
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001624 {
1625 const char* xml = "<element> </element>";
1626 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1627 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001628 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001629 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1630 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001631
Lee Thomason5b0a6772012-11-19 13:54:42 -08001632 {
1633 // An assert should not fire.
1634 const char* xml = "<element/>";
1635 XMLDocument doc;
1636 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001637 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001638 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1639 XMLTest( "Tracking unused elements", true, ele != 0, false );
1640 }
1641
Lee Thomasona6412ac2012-12-13 15:39:11 -08001642
1643 {
1644 const char* xml = "<parent><child>abc</child></parent>";
1645 XMLDocument doc;
1646 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001647 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001648 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1649
1650 XMLPrinter printer;
1651 ele->Accept( &printer );
1652 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1653 }
1654
1655
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001656 {
1657 XMLDocument doc;
1658 XMLError error = doc.LoadFile( "resources/empty.xml" );
1659 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001660 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001661 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001662 }
1663
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001664 {
1665 // BOM preservation
1666 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1667 {
1668 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001669 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001670 XMLPrinter printer;
1671 doc.Print( &printer );
1672
1673 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1674 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001675 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001676 }
1677 {
1678 XMLDocument doc;
1679 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001680 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001681 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1682
1683 XMLPrinter printer;
1684 doc.Print( &printer );
1685 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1686 }
1687 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001688
Michael Daumlinged523282013-10-23 07:47:29 +02001689 {
1690 // Insertion with Removal
1691 const char* xml = "<?xml version=\"1.0\" ?>"
1692 "<root>"
1693 "<one>"
1694 "<subtree>"
1695 "<elem>element 1</elem>text<!-- comment -->"
1696 "</subtree>"
1697 "</one>"
1698 "<two/>"
1699 "</root>";
1700 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1701 "<root>"
1702 "<one/>"
1703 "<two>"
1704 "<subtree>"
1705 "<elem>element 1</elem>text<!-- comment -->"
1706 "</subtree>"
1707 "</two>"
1708 "</root>";
1709 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1710 "<root>"
1711 "<one/>"
1712 "<subtree>"
1713 "<elem>element 1</elem>text<!-- comment -->"
1714 "</subtree>"
1715 "<two/>"
1716 "</root>";
1717 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1718 "<root>"
1719 "<one/>"
1720 "<two/>"
1721 "<subtree>"
1722 "<elem>element 1</elem>text<!-- comment -->"
1723 "</subtree>"
1724 "</root>";
1725
1726 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001727 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001728 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001729 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1730 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1731 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001732 XMLPrinter printer1(0, true);
1733 doc.Accept(&printer1);
1734 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001735
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001736 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001737 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001738 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1739 two = doc.RootElement()->FirstChildElement("two");
1740 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001741 XMLPrinter printer2(0, true);
1742 doc.Accept(&printer2);
1743 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001744
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001745 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001746 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001747 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1748 subtree = one->FirstChildElement("subtree");
1749 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001750 XMLPrinter printer3(0, true);
1751 doc.Accept(&printer3);
1752 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001753
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001754 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001755 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001756 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1757 two = doc.RootElement()->FirstChildElement("two");
1758 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001759 XMLPrinter printer4(0, true);
1760 doc.Accept(&printer4);
1761 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001762 }
1763
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001764 {
1765 const char* xml = "<svg width = \"128\" height = \"128\">"
1766 " <text> </text>"
1767 "</svg>";
1768 XMLDocument doc;
1769 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001770 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001771 doc.Print();
1772 }
1773
Lee Thomason92e521b2014-11-15 17:45:51 -08001774 {
1775 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001776 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1777 XMLDocument doc;
1778 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001779 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001780 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001781 }
1782
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001783#if 1
1784 // the question being explored is what kind of print to use:
1785 // https://github.com/leethomason/tinyxml2/issues/63
1786 {
1787 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1788 const char* xml = "<element/>";
1789 XMLDocument doc;
1790 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001791 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001792 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1793 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1794 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1795 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1796 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1797 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1798
1799 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1800 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1801 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1802 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1803 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1804 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1805
1806 doc.Print();
1807
1808 /* The result of this test is platform, compiler, and library version dependent. :("
1809 XMLPrinter printer;
1810 doc.Print( &printer );
1811 XMLTest( "Float and double formatting.",
1812 "<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",
1813 printer.CStr(),
1814 true );
1815 */
1816 }
1817#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001818
1819 {
1820 // Issue #184
1821 // If it doesn't assert, it passes. Caused by objects
1822 // getting created during parsing which are then
1823 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001824 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001825 {
1826 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001827 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001828 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001829 }
1830 {
1831 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001832 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001833 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001834 doc.Clear();
1835 }
1836 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001837
1838 {
1839 // If this doesn't assert in DEBUG, all is well.
1840 tinyxml2::XMLDocument doc;
1841 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1842 doc.DeleteNode(pRoot);
1843 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001844
Dmitry-Mee5790db2017-07-28 17:54:38 +03001845 {
1846 XMLDocument doc;
1847 XMLElement* root = doc.NewElement( "Root" );
1848 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1849 doc.InsertEndChild( root );
1850 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1851 }
1852
1853 {
1854 // If this doesn't assert in DEBUG, all is well.
1855 XMLDocument doc;
1856 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1857 XMLElement* linkedRoot = doc.NewElement( "Root" );
1858 doc.InsertFirstChild( linkedRoot );
1859 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1860 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1861 }
1862
Dmitry-Me8b67d742014-12-22 11:35:12 +03001863 {
1864 // Should not assert in DEBUG
1865 XMLPrinter printer;
1866 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001867
Dmitry-Me6f51c802015-03-14 13:25:03 +03001868 {
1869 // Issue 291. Should not crash
1870 const char* xml = "&#0</a>";
1871 XMLDocument doc;
1872 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001873 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001874
1875 XMLPrinter printer;
1876 doc.Print( &printer );
1877 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001878 {
1879 // Issue 299. Can print elements that are not linked in.
1880 // Will crash if issue not fixed.
1881 XMLDocument doc;
1882 XMLElement* newElement = doc.NewElement( "printme" );
1883 XMLPrinter printer;
1884 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001885 // Delete the node to avoid possible memory leak report in debug output
1886 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001887 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001888 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001889 // Issue 302. Clear errors from LoadFile/SaveFile
1890 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001891 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001892 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001893 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001894 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001895 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001896 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001897
Dmitry-Med9852a52015-03-25 10:17:49 +03001898 {
1899 // If a document fails to load then subsequent
1900 // successful loads should clear the error
1901 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001902 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001903 doc.LoadFile( "resources/no-such-file.xml" );
1904 XMLTest( "No such file - should fail", true, doc.Error() );
1905
1906 doc.LoadFile( "resources/dream.xml" );
1907 XMLTest( "Error should be cleared", false, doc.Error() );
1908 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301909
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301910 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001911 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001912 const char* xml0 = "<?xml version=\"1.0\" ?>"
1913 " <!-- xml version=\"1.1\" -->"
1914 "<first />";
1915 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001916 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001917 "<first />";
1918 const char* xml2 = "<first />"
1919 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001920 const char* xml3 = "<first></first>"
1921 "<?xml version=\"1.0\" ?>";
1922
1923 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1924
Lee Thomason85492022015-05-22 11:07:45 -07001925 XMLDocument doc;
1926 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001927 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001928 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001929 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001930 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001931 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001932 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001933 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001934 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001935 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301936 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001937
Lee Thomason85492022015-05-22 11:07:45 -07001938 {
1939 // No matter - before or after successfully parsing a text -
Dmitry-Me26043362017-08-30 17:40:15 +03001940 // calling XMLDocument::Value() used to cause an assert in debug.
1941 // Null must be retured.
Lee Thomason85492022015-05-22 11:07:45 -07001942 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1943 "<first />"
1944 "<second />";
1945 XMLDocument* doc = new XMLDocument();
1946 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1947 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001948 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001949 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1950 delete doc;
1951 }
1952
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001953 {
1954 XMLDocument doc;
1955 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
Dmitry-Med3f6c632017-08-30 17:43:14 +03001956 const XMLError error = static_cast<XMLError>(i);
Lee Thomasonf49b9652017-10-11 10:57:49 -07001957 const char* name = XMLDocument::ErrorIDToName(error);
1958 XMLTest( "ErrorName() after ClearError()", true, name != 0 );
1959 XMLTest( "ErrorName() after ClearError()", true, strlen(name) > 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001960 }
1961 }
1962
Lee Thomason816d3fa2017-06-05 14:35:55 -07001963 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001964 // Evil memory leaks.
1965 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1966 // and NOT added to the XMLDocument, what happens?
1967 //
1968 // Previously (buggy):
1969 // The memory would be free'd when the XMLDocument is
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001970 // destructed. But the XMLElement destructor wasn't called, so
1971 // memory allocated for the XMLElement text would not be free'd.
1972 // In practice this meant strings allocated for the XMLElement
1973 // text would be leaked. An edge case, but annoying.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001974 // Now:
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001975 // The XMLElement destructor is called. But the unlinked nodes
1976 // have to be tracked using a list. This has a minor performance
1977 // impact that can become significant if you have a lot of
1978 // unlinked nodes. (But why would you do that?)
1979 // The only way to see this bug was in a Visual C++ runtime debug heap
1980 // leak tracker. This is compiled in by default on Windows Debug and
1981 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
Lee Thomason816d3fa2017-06-05 14:35:55 -07001982 {
1983 XMLDocument doc;
1984 doc.NewElement("LEAK 1");
1985 }
1986 {
1987 XMLDocument doc;
1988 XMLElement* ele = doc.NewElement("LEAK 2");
1989 doc.DeleteNode(ele);
1990 }
1991 }
1992
Lee Thomason224ef772017-06-16 09:45:26 -07001993 {
1994 // Crashing reported via email.
1995 const char* xml =
1996 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001997 "<property name='track_name'>voice</property>"
1998 "<property name='audio_track'>1</property>"
1999 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2000 "<blank length = '1' />"
2001 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2002 "<blank length = '2' />"
2003 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2004 "<blank length = '1' />"
2005 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07002006 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07002007
Lee Thomason224ef772017-06-16 09:45:26 -07002008 // It's not a good idea to delete elements as you walk the
2009 // list. I'm not sure this technically should work; but it's
2010 // an interesting test case.
2011 XMLDocument doc;
2012 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002013 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03002014
2015 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07002016 XMLTest("Crash bug parsing", true, playlist != 0);
2017
2018 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
2019 XMLTest("Crash bug parsing", true, entry != 0);
2020 while (entry) {
2021 tinyxml2::XMLElement* todelete = entry;
2022 entry = entry->NextSiblingElement("entry");
2023 playlist->DeleteChild(todelete);
2024 };
2025 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
2026 while (blank) {
2027 tinyxml2::XMLElement* todelete = blank;
2028 blank = blank->NextSiblingElement("blank");
2029 playlist->DeleteChild(todelete);
2030 };
2031
2032 tinyxml2::XMLPrinter printer;
2033 playlist->Accept(&printer);
2034 printf("%s\n", printer.CStr());
2035
Lee Thomason82bb0742017-06-16 09:48:20 -07002036 // No test; it only need to not crash.
2037 // Still, wrap it up with a sanity check
2038 int nProperty = 0;
2039 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2040 nProperty++;
2041 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002042 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07002043 }
2044
kezenatorec694152016-11-26 17:21:43 +10002045 // ----------- Line Number Tracking --------------
2046 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002047 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002048 {
2049 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2050 {
2051 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002052 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002053
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002054 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002055 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002056 XMLTest(testString, expected_error, parseError);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002057 XMLTest(testString, expectedLine, doc.ErrorLineNum());
kezenatorec694152016-11-26 17:21:43 +10002058 };
2059
2060 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2061 {
2062 XMLDocument doc;
2063 doc.Parse(docStr);
2064 XMLTest(testString, false, doc.Error());
2065 TestDocLines(testString, doc, expectedLines);
2066 }
2067
2068 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2069 {
2070 XMLDocument doc;
2071 doc.LoadFile(file_name);
2072 XMLTest(testString, false, doc.Error());
2073 TestDocLines(testString, doc, expectedLines);
2074 }
2075
2076 private:
2077 DynArray<char, 10> str;
2078
2079 void Push(char type, int lineNum)
2080 {
2081 str.Push(type);
2082 str.Push(char('0' + (lineNum / 10)));
2083 str.Push(char('0' + (lineNum % 10)));
2084 }
2085
2086 bool VisitEnter(const XMLDocument& doc)
2087 {
kezenator19d8ea82016-11-29 19:50:27 +10002088 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002089 return true;
2090 }
2091 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2092 {
kezenator19d8ea82016-11-29 19:50:27 +10002093 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002094 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002095 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002096 return true;
2097 }
2098 bool Visit(const XMLDeclaration& declaration)
2099 {
kezenator19d8ea82016-11-29 19:50:27 +10002100 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002101 return true;
2102 }
2103 bool Visit(const XMLText& text)
2104 {
kezenator19d8ea82016-11-29 19:50:27 +10002105 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002106 return true;
2107 }
2108 bool Visit(const XMLComment& comment)
2109 {
kezenator19d8ea82016-11-29 19:50:27 +10002110 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002111 return true;
2112 }
2113 bool Visit(const XMLUnknown& unknown)
2114 {
kezenator19d8ea82016-11-29 19:50:27 +10002115 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002116 return true;
2117 }
2118
2119 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2120 {
2121 str.Clear();
2122 doc.Accept(this);
2123 str.Push(0);
2124 XMLTest(testString, expectedLines, str.Mem());
2125 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002126 } tester;
kezenatorec694152016-11-26 17:21:43 +10002127
Lee Thomasone90e9012016-12-24 07:34:39 -08002128 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2129 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2130 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2131 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2132 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2133 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2134 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2135 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2136 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2137 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2138 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002139
Lee Thomasone90e9012016-12-24 07:34:39 -08002140 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002141 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002142
2143 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2144 "<root a='b' \n" // 2 Element Attribute
2145 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2146 "newline in text \n" // 4 Text
2147 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2148 " cdata test ]]><!-- comment -->\n" // 6 Comment
2149 "<! unknown></root>", // 7 Unknown
2150
kezenatorec694152016-11-26 17:21:43 +10002151 "D01L01E02A02A03T03E03T04E05T05C06U07");
2152
Lee Thomasone90e9012016-12-24 07:34:39 -08002153 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002154 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002155
2156 "\r\n" // 1 Doc (arguably should be line 2)
2157 "<?xml version=\"1.0\"?>\n" // 2 DecL
2158 "<root>\r\n" // 3 Element
2159 "\n" // 4
2160 "text contining new line \n" // 5 Text
2161 " and also containing crlf \r\n" // 6
2162 "<sub><![CDATA[\n" // 7 Element Text
2163 "cdata containing new line \n" // 8
2164 " and also containing cflr\r\n" // 9
2165 "]]></sub><sub2/></root>", // 10 Element
2166
kezenatorec694152016-11-26 17:21:43 +10002167 "D01L02E03T05E07T07E10");
2168
Lee Thomasone90e9012016-12-24 07:34:39 -08002169 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002170 "LineNumbers-File",
2171 "resources/utf8test.xml",
2172 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2173 }
2174
Lee Thomasonf49b9652017-10-11 10:57:49 -07002175 {
2176 const char* xml = "<Hello>Text</Error>";
2177 XMLDocument doc;
2178 doc.Parse(xml);
2179 XMLTest("Test mismatched elements.", true, doc.Error());
2180 XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2181 // For now just make sure calls work & doesn't crash.
2182 // May solidify the error output in the future.
2183 printf("%s\n", doc.ErrorStr());
2184 doc.PrintError();
2185 }
2186
Lee Thomason85492022015-05-22 11:07:45 -07002187 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002188 {
2189#if defined( _MSC_VER )
2190 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002191 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002192#endif
2193
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002194 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002195 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002196 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002197 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002198 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002199
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002200 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002201 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002202 size_t bytesRead = fread(mem, 1, size, perfFP);
2203 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002204 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002205 mem[size] = 0;
2206
2207#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002208 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002209#else
2210 clock_t cstart = clock();
2211#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002212 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002213 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002214 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002215 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002216 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002217 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002218 }
2219#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002220 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002221#else
2222 clock_t cend = clock();
2223#endif
Dmitry-Me1ab85872017-08-10 17:28:10 +03002224 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002225
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002226 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002227
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002228 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002229#ifdef DEBUG
2230 "DEBUG";
2231#else
2232 "Release";
2233#endif
2234
2235#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002236 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002237#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002238 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002239#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002240 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002241 }
2242
Dmitry-Mede381df2017-07-26 18:05:25 +03002243#if defined( _MSC_VER ) && defined( DEBUG )
2244 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002245 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002246
2247 _CrtMemState diffMemState;
2248 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2249 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002250
2251 {
2252 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2253 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2254 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002255 }
2256#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002257
2258 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002259
2260 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002261}