blob: 01b5011ad0cdec5497e13428af3dff4fac49dfc4 [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 );
Lee Thomason714ccfe2017-10-10 17:08:12 -0700502 doc->PrintError();
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300503 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
504 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800505
Lee Thomason714ccfe2017-10-10 17:08:12 -0700506
507 exit(0);
508
U-Stream\Leeae25a442012-02-17 17:48:16 -0800509 doc->Print();
510
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700511 {
512 XMLPrinter streamer;
513 doc->Print( &streamer );
514 printf( "%s", streamer.CStr() );
515 }
516 {
517 XMLPrinter streamer( 0, true );
518 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200519 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700520 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700521 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300522 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700523 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300524 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800525 delete doc;
526 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800527 {
528 // Test: Dream
529 // XML1 : 1,187,569 bytes in 31,209 allocations
530 // XML2 : 469,073 bytes in 323 allocations
531 //int newStart = gNew;
532 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300533 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300534 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800535
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400536 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300537 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800538 doc.PrintError();
539
540 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400541 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800542 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
543 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
544 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
545 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400546 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800547 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400548 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800549
550 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400551 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300552 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800553 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400554 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800555 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
556 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
557 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
558 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400559 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800560
561 //gNewTotal = gNew - newStart;
562 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800563
564
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800565 {
566 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
567 "<passages count=\"006\" formatversion=\"20020620\">\n"
568 " <wrong error>\n"
569 "</passages>";
570
571 XMLDocument doc;
572 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300573 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800574 }
575
576 {
577 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
578
579 XMLDocument doc;
580 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300581 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800582
583 XMLElement* ele = doc.FirstChildElement();
584
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300585 int iVal;
586 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800587 double dVal;
588
589 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300590 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
591 XMLTest( "Query attribute: int as double", 1, (int)dVal );
592 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700593
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800594 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300595 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
596 XMLTest( "Query attribute: double as double", 2.0, dVal );
597 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700598
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800599 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300600 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
601 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700602
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800603 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300604 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
605 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700606
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800607 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300608 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
609 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800610 }
611
612 {
613 const char* str = "<doc/>";
614
615 XMLDocument doc;
616 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300617 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800618
619 XMLElement* ele = doc.FirstChildElement();
620
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800621 int iVal, iVal2;
622 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800623
624 ele->SetAttribute( "str", "strValue" );
625 ele->SetAttribute( "int", 1 );
626 ele->SetAttribute( "double", -1.0 );
627
628 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300629 {
630 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
631 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
632 }
633 {
634 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
635 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
636 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800637
Dmitry-Me2087a272017-07-10 18:13:07 +0300638 {
639 int queryResult = ele->QueryAttribute( "int", &iVal2 );
640 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
641 }
642 {
643 int queryResult = ele->QueryAttribute( "double", &dVal2 );
644 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
645 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800646
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300647 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800648 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
649 XMLTest( "Attribute round trip. int.", 1, iVal );
650 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800651 XMLTest( "Alternate query", true, iVal == iVal2 );
652 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700653 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
654 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800655 }
656
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800657 {
658 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300659 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300660 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800661
662 // Get the attribute "value" from the "Russian" element and check it.
663 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700664 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800665 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
666
667 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
668
669 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
670 0xd1U, 0x81U, 0xd1U, 0x81U,
671 0xd0U, 0xbaU, 0xd0U, 0xb8U,
672 0xd0U, 0xb9U, 0 };
673 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
674
675 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
676 XMLTest( "UTF-8: Browsing russian element name.",
677 russianText,
678 text->Value() );
679
680 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400681 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300682 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800683
684 // Check the round trip.
Dmitry-Me520009e2017-08-10 17:50:03 +0300685 bool roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800686
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200687 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300688 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
689
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300690 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300691 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800692
693 if ( saved && verify )
694 {
Dmitry-Me520009e2017-08-10 17:50:03 +0300695 roundTripOkay = true;
PKEuSc28ba3a2012-07-16 03:08:47 -0700696 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800697 while ( fgets( verifyBuf, 256, verify ) )
698 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700699 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800700 fgets( savedBuf, 256, saved );
701 NullLineEndings( verifyBuf );
702 NullLineEndings( savedBuf );
703
704 if ( strcmp( verifyBuf, savedBuf ) )
705 {
706 printf( "verify:%s<\n", verifyBuf );
707 printf( "saved :%s<\n", savedBuf );
Dmitry-Me520009e2017-08-10 17:50:03 +0300708 roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800709 break;
710 }
711 }
712 }
713 if ( saved )
714 fclose( saved );
715 if ( verify )
716 fclose( verify );
Dmitry-Me520009e2017-08-10 17:50:03 +0300717 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800718 }
719
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800720 // --------GetText()-----------
721 {
722 const char* str = "<foo>This is text</foo>";
723 XMLDocument doc;
724 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300725 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800726 const XMLElement* element = doc.RootElement();
727
728 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
729
730 str = "<foo><b>This is text</b></foo>";
731 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300732 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800733 element = doc.RootElement();
734
735 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
736 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800737
Lee Thomasond6277762012-02-22 16:00:12 -0800738
Uli Kusterer321072e2014-01-21 01:57:38 +0100739 // --------SetText()-----------
740 {
741 const char* str = "<foo></foo>";
742 XMLDocument doc;
743 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300744 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100745 XMLElement* element = doc.RootElement();
746
Lee Thomason9c0678a2014-01-24 10:18:27 -0800747 element->SetText("darkness.");
748 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100749
Lee Thomason9c0678a2014-01-24 10:18:27 -0800750 element->SetText("blue flame.");
751 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100752
753 str = "<foo/>";
754 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300755 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100756 element = doc.RootElement();
757
Lee Thomason9c0678a2014-01-24 10:18:27 -0800758 element->SetText("The driver");
759 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100760
Lee Thomason9c0678a2014-01-24 10:18:27 -0800761 element->SetText("<b>horses</b>");
762 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
763 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100764
765 str = "<foo><bar>Text in nested element</bar></foo>";
766 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300767 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100768 element = doc.RootElement();
769
Lee Thomason9c0678a2014-01-24 10:18:27 -0800770 element->SetText("wolves");
771 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800772
773 str = "<foo/>";
774 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300775 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800776 element = doc.RootElement();
777
778 element->SetText( "str" );
779 XMLTest( "SetText types", "str", element->GetText() );
780
781 element->SetText( 1 );
782 XMLTest( "SetText types", "1", element->GetText() );
783
784 element->SetText( 1U );
785 XMLTest( "SetText types", "1", element->GetText() );
786
787 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200788 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800789
790 element->SetText( 1.5f );
791 XMLTest( "SetText types", "1.5", element->GetText() );
792
793 element->SetText( 1.5 );
794 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100795 }
796
Lee Thomason51c12712016-06-04 20:18:49 -0700797 // ---------- Attributes ---------
798 {
799 static const int64_t BIG = -123456789012345678;
800 XMLDocument doc;
801 XMLElement* element = doc.NewElement("element");
802 doc.InsertFirstChild(element);
803
804 {
805 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300806 {
807 int v = 0;
808 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
809 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
810 XMLTest("Attribute: int", -100, v, true);
811 }
812 {
813 int v = 0;
814 int queryResult = element->QueryAttribute("attrib", &v);
815 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
816 XMLTest("Attribute: int", -100, v, true);
817 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700818 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700819 }
820 {
821 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300822 {
823 unsigned v = 0;
824 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
825 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
826 XMLTest("Attribute: unsigned", unsigned(100), v, true);
827 }
828 {
829 unsigned v = 0;
830 int queryResult = element->QueryAttribute("attrib", &v);
831 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
832 XMLTest("Attribute: unsigned", unsigned(100), v, true);
833 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700834 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700835 }
836 {
837 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300838 {
839 int64_t v = 0;
840 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
841 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
842 XMLTest("Attribute: int64_t", BIG, v, true);
843 }
844 {
845 int64_t v = 0;
846 int queryResult = element->QueryAttribute("attrib", &v);
847 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
848 XMLTest("Attribute: int64_t", BIG, v, true);
849 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700850 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700851 }
852 {
853 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300854 {
855 bool v = false;
856 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
857 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
858 XMLTest("Attribute: bool", true, v, true);
859 }
860 {
861 bool v = false;
862 int queryResult = element->QueryAttribute("attrib", &v);
863 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
864 XMLTest("Attribute: bool", true, v, true);
865 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700866 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700867 }
868 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800869 element->SetAttribute("attrib", true);
870 const char* result = element->Attribute("attrib");
871 XMLTest("Bool true is 'true'", "true", result);
872
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800873 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800874 element->SetAttribute("attrib", true);
875 result = element->Attribute("attrib");
876 XMLTest("Bool true is '1'", "1", result);
877
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800878 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800879 }
880 {
Lee Thomason51c12712016-06-04 20:18:49 -0700881 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300882 {
883 double v = 0;
884 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
885 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
886 XMLTest("Attribute: double", 100.0, v, true);
887 }
888 {
889 double v = 0;
890 int queryResult = element->QueryAttribute("attrib", &v);
891 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
892 XMLTest("Attribute: double", 100.0, v, true);
893 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700894 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700895 }
896 {
897 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300898 {
899 float v = 0;
900 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
901 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
902 XMLTest("Attribute: float", 100.0f, v, true);
903 }
904 {
905 float v = 0;
906 int queryResult = element->QueryAttribute("attrib", &v);
907 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
908 XMLTest("Attribute: float", 100.0f, v, true);
909 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700910 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700911 }
912 {
913 element->SetText(BIG);
914 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300915 XMLError queryResult = element->QueryInt64Text(&v);
916 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700917 XMLTest("Element: int64_t", BIG, v, true);
918 }
919 }
920
921 // ---------- XMLPrinter stream mode ------
922 {
923 {
Dmitry-Mec0fad292017-08-09 19:05:42 +0300924 FILE* printerfp = fopen("resources/out/printer.xml", "w");
925 XMLTest("Open printer.xml", true, printerfp != 0);
Lee Thomason51c12712016-06-04 20:18:49 -0700926 XMLPrinter printer(printerfp);
927 printer.OpenElement("foo");
928 printer.PushAttribute("attrib-text", "text");
929 printer.PushAttribute("attrib-int", int(1));
930 printer.PushAttribute("attrib-unsigned", unsigned(2));
931 printer.PushAttribute("attrib-int64", int64_t(3));
932 printer.PushAttribute("attrib-bool", true);
933 printer.PushAttribute("attrib-double", 4.0);
934 printer.CloseElement();
935 fclose(printerfp);
936 }
937 {
938 XMLDocument doc;
Dmitry-Mec0fad292017-08-09 19:05:42 +0300939 doc.LoadFile("resources/out/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300940 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700941
942 const XMLDocument& cdoc = doc;
943
944 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
945 XMLTest("attrib-text", "text", attrib->Value(), true);
946 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
947 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
948 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
949 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
950 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
951 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
952 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
953 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
954 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
955 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
956 }
957
958 }
959
Uli Kusterer321072e2014-01-21 01:57:38 +0100960
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800961 // ---------- CDATA ---------------
962 {
963 const char* str = "<xmlElement>"
964 "<![CDATA["
965 "I am > the rules!\n"
966 "...since I make symbolic puns"
967 "]]>"
968 "</xmlElement>";
969 XMLDocument doc;
970 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300971 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800972 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800973
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300974 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
975 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800976 false );
977 }
978
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800979 // ----------- CDATA -------------
980 {
981 const char* str = "<xmlElement>"
982 "<![CDATA["
983 "<b>I am > the rules!</b>\n"
984 "...since I make symbolic puns"
985 "]]>"
986 "</xmlElement>";
987 XMLDocument doc;
988 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300989 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800990 doc.Print();
991
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300992 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800993 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300994 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800995 false );
996 }
997
998 // InsertAfterChild causes crash.
999 {
1000 // InsertBeforeChild and InsertAfterChild causes crash.
1001 XMLDocument doc;
1002 XMLElement* parent = doc.NewElement( "Parent" );
1003 doc.InsertFirstChild( parent );
1004
1005 XMLElement* childText0 = doc.NewElement( "childText0" );
1006 XMLElement* childText1 = doc.NewElement( "childText1" );
1007
1008 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001009 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001010 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001011 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001012
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001013 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001014 }
Lee Thomasond6277762012-02-22 16:00:12 -08001015
1016 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001017 // Entities not being written correctly.
1018 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -08001019
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001020 const char* passages =
1021 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1022 "<passages count=\"006\" formatversion=\"20020620\">"
1023 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1024 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
1025 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -08001026
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001027 XMLDocument doc;
1028 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001029 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001030 XMLElement* psg = doc.RootElement()->FirstChildElement();
1031 const char* context = psg->Attribute( "context" );
1032 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 -08001033
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001034 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -08001035
Dmitry-Me520009e2017-08-10 17:50:03 +03001036 const char* textFilePath = "resources/out/textfile.txt";
1037 FILE* textfile = fopen( textFilePath, "w" );
1038 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001039 if ( textfile )
1040 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001041 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001042 psg->Accept( &streamer );
1043 fclose( textfile );
1044 }
Thomas Roß0922b732012-09-23 16:31:22 +02001045
Dmitry-Me520009e2017-08-10 17:50:03 +03001046 textfile = fopen( textFilePath, "r" );
1047 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001048 if ( textfile )
1049 {
1050 char buf[ 1024 ];
1051 fgets( buf, 1024, textfile );
1052 XMLTest( "Entity transformation: write. ",
1053 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1054 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1055 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001056 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001057 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001058 }
1059
1060 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001061 // Suppress entities.
1062 const char* passages =
1063 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1064 "<passages count=\"006\" formatversion=\"20020620\">"
1065 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1066 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001067
Lee Thomason6f381b72012-03-02 12:59:39 -08001068 XMLDocument doc( false );
1069 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001070 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001071
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001072 XMLTest( "No entity parsing.",
1073 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1074 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1075 XMLTest( "No entity parsing.", "Crazy &ttk;",
1076 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001077 doc.Print();
1078 }
1079
1080 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001081 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001082
1083 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001084 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001085 XMLTest( "dot in names", false, doc.Error() );
1086 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1087 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001088 }
1089
1090 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001091 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001092
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001093 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001094 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001095 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001096
1097 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1098 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001099 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001100 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001101 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001102
1103 {
1104 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001105 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001106 const char* doctype =
1107 "<?xml version=\"1.0\" ?>"
1108 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1109 "<!ELEMENT title (#PCDATA)>"
1110 "<!ELEMENT books (title,authors)>"
1111 "<element />";
1112
1113 XMLDocument doc;
1114 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001115 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001116 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001117 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001118 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001119 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001120 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001121 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001122
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001123 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1124 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1125
1126 }
1127
1128 {
1129 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001130 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001131 "<!-- Somewhat<evil> -->";
1132 XMLDocument doc;
1133 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001134 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001135
1136 XMLComment* comment = doc.FirstChild()->ToComment();
1137
1138 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1139 }
1140 {
1141 // Double attributes
1142 const char* doctype = "<element attr='red' attr='blue' />";
1143
1144 XMLDocument doc;
1145 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001146
Lee Thomason2fa81722012-11-09 12:37:46 -08001147 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 -08001148 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001149 }
1150
1151 {
1152 // Embedded null in stream.
1153 const char* doctype = "<element att\0r='red' attr='blue' />";
1154
1155 XMLDocument doc;
1156 doc.Parse( doctype );
1157 XMLTest( "Embedded null throws error.", true, doc.Error() );
1158 }
1159
1160 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001161 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001162 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001163 XMLDocument doc;
1164 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001165 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001166 }
1167
1168 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001169 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1170 const char* str = " ";
1171 XMLDocument doc;
1172 doc.Parse( str );
1173 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1174 }
1175
1176 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001177 // Low entities
1178 XMLDocument doc;
1179 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001180 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001181 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001182 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001183 doc.Print();
1184 }
1185
1186 {
1187 // Attribute values with trailing quotes not handled correctly
1188 XMLDocument doc;
1189 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001190 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001191 }
1192
1193 {
1194 // [ 1663758 ] Failure to report error on bad XML
1195 XMLDocument xml;
1196 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001197 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001198 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001199 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001200 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001201 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001202 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001203
1204
1205 {
1206 // [ 1475201 ] TinyXML parses entities in comments
1207 XMLDocument xml;
1208 xml.Parse("<!-- declarations for <head> & <body> -->"
1209 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001210 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001211
1212 XMLNode* e0 = xml.FirstChild();
1213 XMLNode* e1 = e0->NextSibling();
1214 XMLComment* c0 = e0->ToComment();
1215 XMLComment* c1 = e1->ToComment();
1216
1217 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1218 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1219 }
1220
1221 {
1222 XMLDocument xml;
1223 xml.Parse( "<Parent>"
1224 "<child1 att=''/>"
1225 "<!-- With this comment, child2 will not be parsed! -->"
1226 "<child2 att=''/>"
1227 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001228 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001229 xml.Print();
1230
1231 int count = 0;
1232
1233 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1234 ele;
1235 ele = ele->NextSibling() )
1236 {
1237 ++count;
1238 }
1239
1240 XMLTest( "Comments iterate correctly.", 3, count );
1241 }
1242
1243 {
1244 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1245 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1246 buf[60] = 239;
1247 buf[61] = 0;
1248
1249 XMLDocument doc;
1250 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001251 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001252 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001253
1254
1255 {
1256 // bug 1827248 Error while parsing a little bit malformed file
1257 // Actually not malformed - should work.
1258 XMLDocument xml;
1259 xml.Parse( "<attributelist> </attributelist >" );
1260 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1261 }
1262
1263 {
1264 // This one must not result in an infinite loop
1265 XMLDocument xml;
1266 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001267 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001268 XMLTest( "Infinite loop test.", true, true );
1269 }
1270#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001271 {
1272 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1273 XMLDocument doc;
1274 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001275 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001276
1277 XMLDocument clone;
1278 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1279 XMLNode* copy = node->ShallowClone( &clone );
1280 clone.InsertEndChild( copy );
1281 }
1282
1283 clone.Print();
1284
1285 int count=0;
1286 const XMLNode* a=clone.FirstChild();
1287 const XMLNode* b=doc.FirstChild();
1288 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1289 ++count;
1290 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1291 }
1292 XMLTest( "Clone and Equal", 4, count );
1293 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001294
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001295 {
Lee Thomason7085f002017-06-01 18:09:43 -07001296 // Deep Cloning of root element.
1297 XMLDocument doc2;
1298 XMLPrinter printer1;
1299 {
1300 // Make sure doc1 is deleted before we test doc2
1301 const char* xml =
1302 "<root>"
1303 " <child1 foo='bar'/>"
1304 " <!-- comment thing -->"
1305 " <child2 val='1'>Text</child2>"
1306 "</root>";
1307 XMLDocument doc;
1308 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001309 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001310
1311 doc.Print(&printer1);
1312 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1313 doc2.InsertFirstChild(root);
1314 }
1315 XMLPrinter printer2;
1316 doc2.Print(&printer2);
1317
1318 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1319 }
1320
1321 {
1322 // Deep Cloning of sub element.
1323 XMLDocument doc2;
1324 XMLPrinter printer1;
1325 {
1326 // Make sure doc1 is deleted before we test doc2
1327 const char* xml =
1328 "<?xml version ='1.0'?>"
1329 "<root>"
1330 " <child1 foo='bar'/>"
1331 " <!-- comment thing -->"
1332 " <child2 val='1'>Text</child2>"
1333 "</root>";
1334 XMLDocument doc;
1335 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001336 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001337
1338 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1339 subElement->Accept(&printer1);
1340
1341 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1342 doc2.InsertFirstChild(clonedSubElement);
1343 }
1344 XMLPrinter printer2;
1345 doc2.Print(&printer2);
1346
1347 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1348 }
1349
1350 {
1351 // Deep cloning of document.
1352 XMLDocument doc2;
1353 XMLPrinter printer1;
1354 {
1355 // Make sure doc1 is deleted before we test doc2
1356 const char* xml =
1357 "<?xml version ='1.0'?>"
1358 "<!-- Top level comment. -->"
1359 "<root>"
1360 " <child1 foo='bar'/>"
1361 " <!-- comment thing -->"
1362 " <child2 val='1'>Text</child2>"
1363 "</root>";
1364 XMLDocument doc;
1365 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001366 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001367 doc.Print(&printer1);
1368
1369 doc.DeepCopy(&doc2);
1370 }
1371 XMLPrinter printer2;
1372 doc2.Print(&printer2);
1373
1374 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1375 }
1376
1377
1378 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001379 // This shouldn't crash.
1380 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001381 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001382 {
1383 doc.PrintError();
1384 }
1385 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1386 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001387
Lee Thomason5e3803c2012-04-16 08:57:05 -07001388 {
1389 // Attribute ordering.
1390 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1391 XMLDocument doc;
1392 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001393 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001394 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001395
Lee Thomason5e3803c2012-04-16 08:57:05 -07001396 const XMLAttribute* a = ele->FirstAttribute();
1397 XMLTest( "Attribute order", "1", a->Value() );
1398 a = a->Next();
1399 XMLTest( "Attribute order", "2", a->Value() );
1400 a = a->Next();
1401 XMLTest( "Attribute order", "3", a->Value() );
1402 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001403
Lee Thomason5e3803c2012-04-16 08:57:05 -07001404 ele->DeleteAttribute( "attrib2" );
1405 a = ele->FirstAttribute();
1406 XMLTest( "Attribute order", "1", a->Value() );
1407 a = a->Next();
1408 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001409
Lee Thomason5e3803c2012-04-16 08:57:05 -07001410 ele->DeleteAttribute( "attrib1" );
1411 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001412 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001413 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001414
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001415 {
1416 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001417 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1418 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1419 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1420 XMLDocument doc0;
1421 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001422 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001423 XMLDocument doc1;
1424 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001425 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001426 XMLDocument doc2;
1427 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001428 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001429
Lee Thomason78a773d2012-07-02 10:10:19 -07001430 XMLElement* ele = 0;
1431 ele = doc0.FirstChildElement();
1432 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1433 ele = doc1.FirstChildElement();
1434 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1435 ele = doc2.FirstChildElement();
1436 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001437 }
1438
1439 {
1440 // Make sure we don't go into an infinite loop.
1441 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1442 XMLDocument doc;
1443 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001444 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001445 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1446 XMLElement* ele1 = ele0->NextSiblingElement();
1447 bool equal = ele0->ShallowEqual( ele1 );
1448
1449 XMLTest( "Infinite loop in shallow equal.", true, equal );
1450 }
1451
Lee Thomason5708f812012-03-28 17:46:41 -07001452 // -------- Handles ------------
1453 {
1454 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1455 XMLDocument doc;
1456 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001457 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001458
1459 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001460 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001461
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001462 XMLHandle docH( doc );
1463 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001464 XMLTest( "Handle, dne, mutable", true, ele == 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001465 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001466
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001467 {
1468 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1469 XMLDocument doc;
1470 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001471 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001472 XMLConstHandle docH( doc );
1473
1474 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001475 XMLTest( "Handle, success, const", "sub", ele->Value() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001476
1477 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001478 XMLTest( "Handle, dne, const", true, ele == 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001479 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001480 {
1481 // Default Declaration & BOM
1482 XMLDocument doc;
1483 doc.InsertEndChild( doc.NewDeclaration() );
1484 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001485
Lee Thomasonf68c4382012-04-28 14:37:11 -07001486 XMLPrinter printer;
1487 doc.Print( &printer );
1488
1489 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001490 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1491 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001492 }
Lee Thomason21be8822012-07-15 17:27:22 -07001493 {
1494 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1495 XMLDocument doc;
1496 doc.Parse( xml );
1497 XMLTest( "Ill formed XML", true, doc.Error() );
1498 }
1499
1500 // QueryXYZText
1501 {
1502 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1503 XMLDocument doc;
1504 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001505 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001506
1507 const XMLElement* pointElement = doc.RootElement();
1508
Dmitry-Me43c019d2017-08-02 18:05:23 +03001509 {
1510 int intValue = 0;
1511 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1512 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1513 XMLTest( "QueryIntText", 1, intValue, false );
1514 }
Lee Thomason21be8822012-07-15 17:27:22 -07001515
Dmitry-Me43c019d2017-08-02 18:05:23 +03001516 {
1517 unsigned unsignedValue = 0;
1518 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1519 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1520 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1521 }
Lee Thomason21be8822012-07-15 17:27:22 -07001522
Dmitry-Me43c019d2017-08-02 18:05:23 +03001523 {
1524 float floatValue = 0;
1525 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1526 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1527 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1528 }
Lee Thomason21be8822012-07-15 17:27:22 -07001529
Dmitry-Me43c019d2017-08-02 18:05:23 +03001530 {
1531 double doubleValue = 0;
1532 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1533 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1534 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1535 }
1536
1537 {
1538 bool boolValue = false;
1539 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1540 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1541 XMLTest( "QueryBoolText", true, boolValue, false );
1542 }
Lee Thomason21be8822012-07-15 17:27:22 -07001543 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001544
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001545 {
1546 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1547 XMLDocument doc;
1548 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001549 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001550 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001551
1552 {
1553 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1554 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001555 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001556 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001557 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001558
1559 {
1560 const char* xml = "<3lement></3lement>";
1561 XMLDocument doc;
1562 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001563 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001564 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001565
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001566 {
1567 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1568 XMLDocument doc;
1569 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001570 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001571 }
1572
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001573 {
1574 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001575 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001576 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001577 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001578 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001579 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001580 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001581 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001582 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001583 }
Dmitry-Me985ea1f2017-08-28 18:36:29 +03001584
1585 {
1586 XMLDocument doc;
1587 XMLTest( "No error initially", false, doc.Error() );
1588 XMLError error = doc.Parse( "This is not XML" );
1589 XMLTest( "Error after invalid XML", true, doc.Error() );
1590 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1591 doc.Clear();
1592 XMLTest( "No error after Clear()", false, doc.Error() );
1593 }
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001594
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001595 // ----------- Whitespace ------------
1596 {
1597 const char* xml = "<element>"
1598 "<a> This \nis &apos; text &apos; </a>"
1599 "<b> This is &apos; text &apos; \n</b>"
1600 "<c>This is &apos; \n\n text &apos;</c>"
1601 "</element>";
1602 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1603 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001604 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001605
1606 const XMLElement* element = doc.FirstChildElement();
1607 for( const XMLElement* parent = element->FirstChildElement();
1608 parent;
1609 parent = parent->NextSiblingElement() )
1610 {
1611 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1612 }
1613 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001614
Lee Thomasonae9ab072012-10-24 10:17:53 -07001615#if 0
1616 {
1617 // Passes if assert doesn't fire.
1618 XMLDocument xmlDoc;
1619
1620 xmlDoc.NewDeclaration();
1621 xmlDoc.NewComment("Configuration file");
1622
1623 XMLElement *root = xmlDoc.NewElement("settings");
1624 root->SetAttribute("version", 2);
1625 }
1626#endif
1627
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001628 {
1629 const char* xml = "<element> </element>";
1630 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1631 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001632 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001633 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1634 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001635
Lee Thomason5b0a6772012-11-19 13:54:42 -08001636 {
1637 // An assert should not fire.
1638 const char* xml = "<element/>";
1639 XMLDocument doc;
1640 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001641 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001642 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1643 XMLTest( "Tracking unused elements", true, ele != 0, false );
1644 }
1645
Lee Thomasona6412ac2012-12-13 15:39:11 -08001646
1647 {
1648 const char* xml = "<parent><child>abc</child></parent>";
1649 XMLDocument doc;
1650 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001651 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001652 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1653
1654 XMLPrinter printer;
1655 ele->Accept( &printer );
1656 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1657 }
1658
1659
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001660 {
1661 XMLDocument doc;
1662 XMLError error = doc.LoadFile( "resources/empty.xml" );
1663 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001664 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001665 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001666 }
1667
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001668 {
1669 // BOM preservation
1670 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1671 {
1672 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001673 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001674 XMLPrinter printer;
1675 doc.Print( &printer );
1676
1677 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1678 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001679 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001680 }
1681 {
1682 XMLDocument doc;
1683 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001684 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001685 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1686
1687 XMLPrinter printer;
1688 doc.Print( &printer );
1689 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1690 }
1691 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001692
Michael Daumlinged523282013-10-23 07:47:29 +02001693 {
1694 // Insertion with Removal
1695 const char* xml = "<?xml version=\"1.0\" ?>"
1696 "<root>"
1697 "<one>"
1698 "<subtree>"
1699 "<elem>element 1</elem>text<!-- comment -->"
1700 "</subtree>"
1701 "</one>"
1702 "<two/>"
1703 "</root>";
1704 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1705 "<root>"
1706 "<one/>"
1707 "<two>"
1708 "<subtree>"
1709 "<elem>element 1</elem>text<!-- comment -->"
1710 "</subtree>"
1711 "</two>"
1712 "</root>";
1713 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1714 "<root>"
1715 "<one/>"
1716 "<subtree>"
1717 "<elem>element 1</elem>text<!-- comment -->"
1718 "</subtree>"
1719 "<two/>"
1720 "</root>";
1721 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1722 "<root>"
1723 "<one/>"
1724 "<two/>"
1725 "<subtree>"
1726 "<elem>element 1</elem>text<!-- comment -->"
1727 "</subtree>"
1728 "</root>";
1729
1730 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001731 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001732 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001733 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1734 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1735 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001736 XMLPrinter printer1(0, true);
1737 doc.Accept(&printer1);
1738 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001739
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001740 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001741 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001742 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1743 two = doc.RootElement()->FirstChildElement("two");
1744 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001745 XMLPrinter printer2(0, true);
1746 doc.Accept(&printer2);
1747 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001748
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001749 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001750 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001751 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1752 subtree = one->FirstChildElement("subtree");
1753 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001754 XMLPrinter printer3(0, true);
1755 doc.Accept(&printer3);
1756 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001757
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001758 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001759 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001760 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1761 two = doc.RootElement()->FirstChildElement("two");
1762 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001763 XMLPrinter printer4(0, true);
1764 doc.Accept(&printer4);
1765 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001766 }
1767
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001768 {
1769 const char* xml = "<svg width = \"128\" height = \"128\">"
1770 " <text> </text>"
1771 "</svg>";
1772 XMLDocument doc;
1773 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001774 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001775 doc.Print();
1776 }
1777
Lee Thomason92e521b2014-11-15 17:45:51 -08001778 {
1779 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001780 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1781 XMLDocument doc;
1782 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001783 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001784 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001785 }
1786
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001787#if 1
1788 // the question being explored is what kind of print to use:
1789 // https://github.com/leethomason/tinyxml2/issues/63
1790 {
1791 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1792 const char* xml = "<element/>";
1793 XMLDocument doc;
1794 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001795 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001796 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1797 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1798 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1799 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1800 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1801 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1802
1803 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1804 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1805 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1806 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1807 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1808 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1809
1810 doc.Print();
1811
1812 /* The result of this test is platform, compiler, and library version dependent. :("
1813 XMLPrinter printer;
1814 doc.Print( &printer );
1815 XMLTest( "Float and double formatting.",
1816 "<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",
1817 printer.CStr(),
1818 true );
1819 */
1820 }
1821#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001822
1823 {
1824 // Issue #184
1825 // If it doesn't assert, it passes. Caused by objects
1826 // getting created during parsing which are then
1827 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001828 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001829 {
1830 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001831 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001832 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001833 }
1834 {
1835 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001836 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001837 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001838 doc.Clear();
1839 }
1840 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001841
1842 {
1843 // If this doesn't assert in DEBUG, all is well.
1844 tinyxml2::XMLDocument doc;
1845 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1846 doc.DeleteNode(pRoot);
1847 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001848
Dmitry-Mee5790db2017-07-28 17:54:38 +03001849 {
1850 XMLDocument doc;
1851 XMLElement* root = doc.NewElement( "Root" );
1852 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1853 doc.InsertEndChild( root );
1854 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1855 }
1856
1857 {
1858 // If this doesn't assert in DEBUG, all is well.
1859 XMLDocument doc;
1860 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1861 XMLElement* linkedRoot = doc.NewElement( "Root" );
1862 doc.InsertFirstChild( linkedRoot );
1863 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1864 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1865 }
1866
Dmitry-Me8b67d742014-12-22 11:35:12 +03001867 {
1868 // Should not assert in DEBUG
1869 XMLPrinter printer;
1870 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001871
Dmitry-Me6f51c802015-03-14 13:25:03 +03001872 {
1873 // Issue 291. Should not crash
1874 const char* xml = "&#0</a>";
1875 XMLDocument doc;
1876 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001877 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001878
1879 XMLPrinter printer;
1880 doc.Print( &printer );
1881 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001882 {
1883 // Issue 299. Can print elements that are not linked in.
1884 // Will crash if issue not fixed.
1885 XMLDocument doc;
1886 XMLElement* newElement = doc.NewElement( "printme" );
1887 XMLPrinter printer;
1888 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001889 // Delete the node to avoid possible memory leak report in debug output
1890 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001891 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001892 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001893 // Issue 302. Clear errors from LoadFile/SaveFile
1894 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001895 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001896 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001897 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001898 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001899 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001900 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001901
Dmitry-Med9852a52015-03-25 10:17:49 +03001902 {
1903 // If a document fails to load then subsequent
1904 // successful loads should clear the error
1905 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001906 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001907 doc.LoadFile( "resources/no-such-file.xml" );
1908 XMLTest( "No such file - should fail", true, doc.Error() );
1909
1910 doc.LoadFile( "resources/dream.xml" );
1911 XMLTest( "Error should be cleared", false, doc.Error() );
1912 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301913
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301914 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001915 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001916 const char* xml0 = "<?xml version=\"1.0\" ?>"
1917 " <!-- xml version=\"1.1\" -->"
1918 "<first />";
1919 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001920 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001921 "<first />";
1922 const char* xml2 = "<first />"
1923 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001924 const char* xml3 = "<first></first>"
1925 "<?xml version=\"1.0\" ?>";
1926
1927 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1928
Lee Thomason85492022015-05-22 11:07:45 -07001929 XMLDocument doc;
1930 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001931 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001932 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001933 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001934 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001935 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001936 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001937 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001938 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001939 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301940 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001941
Lee Thomason85492022015-05-22 11:07:45 -07001942 {
1943 // No matter - before or after successfully parsing a text -
Dmitry-Me26043362017-08-30 17:40:15 +03001944 // calling XMLDocument::Value() used to cause an assert in debug.
1945 // Null must be retured.
Lee Thomason85492022015-05-22 11:07:45 -07001946 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1947 "<first />"
1948 "<second />";
1949 XMLDocument* doc = new XMLDocument();
1950 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1951 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001952 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001953 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1954 delete doc;
1955 }
1956
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001957 {
1958 XMLDocument doc;
1959 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
Dmitry-Med3f6c632017-08-30 17:43:14 +03001960 const XMLError error = static_cast<XMLError>(i);
1961 doc.SetError( error, 0, 0, 0 );
1962 XMLTest( "ErrorID() after SetError()", error, doc.ErrorID() );
Dmitry-Me47845b62017-09-15 19:03:02 +03001963 const char* name = doc.ErrorName();
1964 XMLTest( "ErrorName() after SetError()", true, name != 0 );
1965 XMLTest( "ErrorName() after SetError()", true, strlen(name) > 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001966 }
1967 }
1968
Lee Thomason816d3fa2017-06-05 14:35:55 -07001969 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001970 // Evil memory leaks.
1971 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1972 // and NOT added to the XMLDocument, what happens?
1973 //
1974 // Previously (buggy):
1975 // The memory would be free'd when the XMLDocument is
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001976 // destructed. But the XMLElement destructor wasn't called, so
1977 // memory allocated for the XMLElement text would not be free'd.
1978 // In practice this meant strings allocated for the XMLElement
1979 // text would be leaked. An edge case, but annoying.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001980 // Now:
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001981 // The XMLElement destructor is called. But the unlinked nodes
1982 // have to be tracked using a list. This has a minor performance
1983 // impact that can become significant if you have a lot of
1984 // unlinked nodes. (But why would you do that?)
1985 // The only way to see this bug was in a Visual C++ runtime debug heap
1986 // leak tracker. This is compiled in by default on Windows Debug and
1987 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
Lee Thomason816d3fa2017-06-05 14:35:55 -07001988 {
1989 XMLDocument doc;
1990 doc.NewElement("LEAK 1");
1991 }
1992 {
1993 XMLDocument doc;
1994 XMLElement* ele = doc.NewElement("LEAK 2");
1995 doc.DeleteNode(ele);
1996 }
1997 }
1998
Lee Thomason224ef772017-06-16 09:45:26 -07001999 {
2000 // Crashing reported via email.
2001 const char* xml =
2002 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07002003 "<property name='track_name'>voice</property>"
2004 "<property name='audio_track'>1</property>"
2005 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2006 "<blank length = '1' />"
2007 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2008 "<blank length = '2' />"
2009 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2010 "<blank length = '1' />"
2011 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07002012 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07002013
Lee Thomason224ef772017-06-16 09:45:26 -07002014 // It's not a good idea to delete elements as you walk the
2015 // list. I'm not sure this technically should work; but it's
2016 // an interesting test case.
2017 XMLDocument doc;
2018 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002019 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03002020
2021 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07002022 XMLTest("Crash bug parsing", true, playlist != 0);
2023
2024 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
2025 XMLTest("Crash bug parsing", true, entry != 0);
2026 while (entry) {
2027 tinyxml2::XMLElement* todelete = entry;
2028 entry = entry->NextSiblingElement("entry");
2029 playlist->DeleteChild(todelete);
2030 };
2031 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
2032 while (blank) {
2033 tinyxml2::XMLElement* todelete = blank;
2034 blank = blank->NextSiblingElement("blank");
2035 playlist->DeleteChild(todelete);
2036 };
2037
2038 tinyxml2::XMLPrinter printer;
2039 playlist->Accept(&printer);
2040 printf("%s\n", printer.CStr());
2041
Lee Thomason82bb0742017-06-16 09:48:20 -07002042 // No test; it only need to not crash.
2043 // Still, wrap it up with a sanity check
2044 int nProperty = 0;
2045 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2046 nProperty++;
2047 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002048 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07002049 }
2050
kezenatorec694152016-11-26 17:21:43 +10002051 // ----------- Line Number Tracking --------------
2052 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002053 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002054 {
2055 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2056 {
2057 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002058 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002059
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002060 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002061 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002062 XMLTest(testString, expected_error, parseError);
kezenatorec694152016-11-26 17:21:43 +10002063 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
2064 };
2065
2066 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2067 {
2068 XMLDocument doc;
2069 doc.Parse(docStr);
2070 XMLTest(testString, false, doc.Error());
2071 TestDocLines(testString, doc, expectedLines);
2072 }
2073
2074 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2075 {
2076 XMLDocument doc;
2077 doc.LoadFile(file_name);
2078 XMLTest(testString, false, doc.Error());
2079 TestDocLines(testString, doc, expectedLines);
2080 }
2081
2082 private:
2083 DynArray<char, 10> str;
2084
2085 void Push(char type, int lineNum)
2086 {
2087 str.Push(type);
2088 str.Push(char('0' + (lineNum / 10)));
2089 str.Push(char('0' + (lineNum % 10)));
2090 }
2091
2092 bool VisitEnter(const XMLDocument& doc)
2093 {
kezenator19d8ea82016-11-29 19:50:27 +10002094 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002095 return true;
2096 }
2097 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2098 {
kezenator19d8ea82016-11-29 19:50:27 +10002099 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002100 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002101 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002102 return true;
2103 }
2104 bool Visit(const XMLDeclaration& declaration)
2105 {
kezenator19d8ea82016-11-29 19:50:27 +10002106 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002107 return true;
2108 }
2109 bool Visit(const XMLText& text)
2110 {
kezenator19d8ea82016-11-29 19:50:27 +10002111 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002112 return true;
2113 }
2114 bool Visit(const XMLComment& comment)
2115 {
kezenator19d8ea82016-11-29 19:50:27 +10002116 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002117 return true;
2118 }
2119 bool Visit(const XMLUnknown& unknown)
2120 {
kezenator19d8ea82016-11-29 19:50:27 +10002121 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002122 return true;
2123 }
2124
2125 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2126 {
2127 str.Clear();
2128 doc.Accept(this);
2129 str.Push(0);
2130 XMLTest(testString, expectedLines, str.Mem());
2131 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002132 } tester;
kezenatorec694152016-11-26 17:21:43 +10002133
Lee Thomasone90e9012016-12-24 07:34:39 -08002134 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2135 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2136 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2137 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2138 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2139 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2140 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2141 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2142 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2143 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2144 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002145
Lee Thomasone90e9012016-12-24 07:34:39 -08002146 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002147 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002148
2149 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2150 "<root a='b' \n" // 2 Element Attribute
2151 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2152 "newline in text \n" // 4 Text
2153 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2154 " cdata test ]]><!-- comment -->\n" // 6 Comment
2155 "<! unknown></root>", // 7 Unknown
2156
kezenatorec694152016-11-26 17:21:43 +10002157 "D01L01E02A02A03T03E03T04E05T05C06U07");
2158
Lee Thomasone90e9012016-12-24 07:34:39 -08002159 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002160 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002161
2162 "\r\n" // 1 Doc (arguably should be line 2)
2163 "<?xml version=\"1.0\"?>\n" // 2 DecL
2164 "<root>\r\n" // 3 Element
2165 "\n" // 4
2166 "text contining new line \n" // 5 Text
2167 " and also containing crlf \r\n" // 6
2168 "<sub><![CDATA[\n" // 7 Element Text
2169 "cdata containing new line \n" // 8
2170 " and also containing cflr\r\n" // 9
2171 "]]></sub><sub2/></root>", // 10 Element
2172
kezenatorec694152016-11-26 17:21:43 +10002173 "D01L02E03T05E07T07E10");
2174
Lee Thomasone90e9012016-12-24 07:34:39 -08002175 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002176 "LineNumbers-File",
2177 "resources/utf8test.xml",
2178 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2179 }
2180
Lee Thomason85492022015-05-22 11:07:45 -07002181 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002182 {
2183#if defined( _MSC_VER )
2184 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002185 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002186#endif
2187
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002188 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002189 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002190 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002191 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002192 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002193
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002194 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002195 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002196 size_t bytesRead = fread(mem, 1, size, perfFP);
2197 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002198 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002199 mem[size] = 0;
2200
2201#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002202 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002203#else
2204 clock_t cstart = clock();
2205#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002206 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002207 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002208 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002209 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002210 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002211 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002212 }
2213#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002214 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002215#else
2216 clock_t cend = clock();
2217#endif
Dmitry-Me1ab85872017-08-10 17:28:10 +03002218 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002219
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002220 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002221
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002222 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002223#ifdef DEBUG
2224 "DEBUG";
2225#else
2226 "Release";
2227#endif
2228
2229#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002230 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002231#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002232 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002233#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002234 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002235 }
2236
Dmitry-Mede381df2017-07-26 18:05:25 +03002237#if defined( _MSC_VER ) && defined( DEBUG )
2238 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002239 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002240
2241 _CrtMemState diffMemState;
2242 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2243 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002244
2245 {
2246 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2247 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2248 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002249 }
2250#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002251
2252 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002253
2254 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002255}