blob: bb589866dbd9a633eb3c55dfaff9ab7d9aefa1b8 [file] [log] [blame]
Lee Thomason5b0a6772012-11-19 13:54:42 -08001#if defined( _MSC_VER )
Serhat Eser Erdemca5d6842014-04-17 14:06:15 +02002 #if !defined( _CRT_SECURE_NO_WARNINGS )
3 #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
4 #endif
Lee Thomason5b0a6772012-11-19 13:54:42 -08005#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08006
Lee Thomason5b0a6772012-11-19 13:54:42 -08007#include "tinyxml2.h"
kbinny62bf29a152017-06-23 18:15:25 +00008#include <cerrno>
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07009#include <cstdlib>
10#include <cstring>
11#include <ctime>
U-Lama\Leee13c3e62011-12-28 14:36:55 -080012
kbinny62bf29a152017-06-23 18:15:25 +000013#if defined( _MSC_VER ) || defined (WIN32)
Lee Thomason1ff38e02012-02-14 18:18:16 -080014 #include <crtdbg.h>
Lee Thomason6f381b72012-03-02 12:59:39 -080015 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080017 _CrtMemState startMemState;
Lee Thomason53858b42017-06-01 19:09:16 -070018 _CrtMemState endMemState;
kbinny62bf29a152017-06-23 18:15:25 +000019#else
20 #include <sys/stat.h>
21 #include <sys/types.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080022#endif
Lee Thomasone9ecdab2012-02-13 18:11:20 -080023
U-Lama\Leee13c3e62011-12-28 14:36:55 -080024using namespace tinyxml2;
Anton Indrawan8a0006c2014-11-20 18:27:07 +010025using namespace std;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080026int gPass = 0;
27int gFail = 0;
28
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080029
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070030bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080031{
Sarat Addepalli13b2d732015-05-19 12:44:57 +053032 bool pass;
33 if ( !expected && !found )
34 pass = true;
35 else if ( !expected || !found )
36 pass = false;
Sarat Addepallid608c562015-05-20 10:19:00 +053037 else
38 pass = !strcmp( expected, found );
Lee Thomason1ff38e02012-02-14 18:18:16 -080039 if ( pass )
40 printf ("[pass]");
41 else
42 printf ("[fail]");
43
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070044 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080045 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070046 }
47 else {
48 if ( extraNL ) {
49 printf( " %s\n", testString );
50 printf( "%s\n", expected );
51 printf( "%s\n", found );
52 }
53 else {
54 printf (" %s [%s][%s]\n", testString, expected, found);
55 }
56 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080057
58 if ( pass )
59 ++gPass;
60 else
61 ++gFail;
62 return pass;
63}
64
kezenator5a700712016-11-26 13:54:42 +100065bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
66{
Lee Thomasone90e9012016-12-24 07:34:39 -080067 return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
kezenator5a700712016-11-26 13:54:42 +100068}
69
70bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
71{
72 return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
73}
Lee Thomason1ff38e02012-02-14 18:18:16 -080074
Lee Thomason21be8822012-07-15 17:27:22 -070075template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080076{
77 bool pass = ( expected == found );
78 if ( pass )
79 printf ("[pass]");
80 else
81 printf ("[fail]");
82
U-Stream\Lee09a11c52012-02-17 08:31:16 -080083 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080084 printf (" %s\n", testString);
85 else
Lee Thomasonc8312792012-07-16 12:44:41 -070086 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080087
88 if ( pass )
89 ++gPass;
90 else
91 ++gFail;
92 return pass;
93}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080094
U-Lama\Leee13c3e62011-12-28 14:36:55 -080095
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080096void NullLineEndings( char* p )
97{
98 while( p && *p ) {
99 if ( *p == '\n' || *p == '\r' ) {
100 *p = 0;
101 return;
102 }
103 ++p;
104 }
105}
106
107
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700108int example_1()
109{
110 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300111 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700112
113 return doc.ErrorID();
114}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200115/** @page Example-1 Load an XML File
116 * @dontinclude ./xmltest.cpp
117 * Basic XML file loading.
118 * The basic syntax to load an XML file from
119 * disk and check for an error. (ErrorID()
120 * will return 0 for no error.)
121 * @skip example_1()
122 * @until }
123 */
124
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700125
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700126int example_2()
127{
128 static const char* xml = "<element/>";
129 XMLDocument doc;
130 doc.Parse( xml );
131
132 return doc.ErrorID();
133}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200134/** @page Example-2 Parse an XML from char buffer
135 * @dontinclude ./xmltest.cpp
136 * Basic XML string parsing.
137 * The basic syntax to parse an XML for
138 * a char* and check for an error. (ErrorID()
139 * will return 0 for no error.)
140 * @skip example_2()
141 * @until }
142 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700143
144
145int example_3()
146{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700147 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700148 "<?xml version=\"1.0\"?>"
149 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
150 "<PLAY>"
151 "<TITLE>A Midsummer Night's Dream</TITLE>"
152 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700153
154 XMLDocument doc;
155 doc.Parse( xml );
156
157 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
158 const char* title = titleElement->GetText();
159 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700160
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700161 XMLText* textNode = titleElement->FirstChild()->ToText();
162 title = textNode->Value();
163 printf( "Name of play (2): %s\n", title );
164
165 return doc.ErrorID();
166}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200167/** @page Example-3 Get information out of XML
168 @dontinclude ./xmltest.cpp
169 In this example, we navigate a simple XML
170 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700171 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200172 checking; working code should check for null
173 pointers when walking an XML tree, or use
174 XMLHandle.
175
176 (The XML is an excerpt from "dream.xml").
177
178 @skip example_3()
179 @until </PLAY>";
180
181 The structure of the XML file is:
182
183 <ul>
184 <li>(declaration)</li>
185 <li>(dtd stuff)</li>
186 <li>Element "PLAY"</li>
187 <ul>
188 <li>Element "TITLE"</li>
189 <ul>
190 <li>Text "A Midsummer Night's Dream"</li>
191 </ul>
192 </ul>
193 </ul>
194
195 For this example, we want to print out the
196 title of the play. The text of the title (what
197 we want) is child of the "TITLE" element which
198 is a child of the "PLAY" element.
199
200 We want to skip the declaration and dtd, so the
201 method FirstChildElement() is a good choice. The
202 FirstChildElement() of the Document is the "PLAY"
203 Element, the FirstChildElement() of the "PLAY" Element
204 is the "TITLE" Element.
205
206 @until ( "TITLE" );
207
208 We can then use the convenience function GetText()
209 to get the title of the play.
210
211 @until title );
212
213 Text is just another Node in the XML DOM. And in
214 fact you should be a little cautious with it, as
215 text nodes can contain elements.
216
217 @verbatim
218 Consider: A Midsummer Night's <b>Dream</b>
219 @endverbatim
220
221 It is more correct to actually query the Text Node
222 if in doubt:
223
224 @until title );
225
226 Noting that here we use FirstChild() since we are
227 looking for XMLText, not an element, and ToText()
228 is a cast from a Node to a XMLText.
229*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700230
231
Lee Thomason21be8822012-07-15 17:27:22 -0700232bool example_4()
233{
234 static const char* xml =
235 "<information>"
236 " <attributeApproach v='2' />"
237 " <textApproach>"
238 " <v>2</v>"
239 " </textApproach>"
240 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700241
Lee Thomason21be8822012-07-15 17:27:22 -0700242 XMLDocument doc;
243 doc.Parse( xml );
244
245 int v0 = 0;
246 int v1 = 0;
247
248 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
249 attributeApproachElement->QueryIntAttribute( "v", &v0 );
250
251 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
252 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
253
254 printf( "Both values are the same: %d and %d\n", v0, v1 );
255
256 return !doc.Error() && ( v0 == v1 );
257}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200258/** @page Example-4 Read attributes and text information.
259 @dontinclude ./xmltest.cpp
260
261 There are fundamentally 2 ways of writing a key-value
262 pair into an XML file. (Something that's always annoyed
263 me about XML.) Either by using attributes, or by writing
264 the key name into an element and the value into
265 the text node wrapped by the element. Both approaches
266 are illustrated in this example, which shows two ways
267 to encode the value "2" into the key "v":
268
269 @skip example_4()
270 @until "</information>";
271
272 TinyXML-2 has accessors for both approaches.
273
274 When using an attribute, you navigate to the XMLElement
275 with that attribute and use the QueryIntAttribute()
276 group of methods. (Also QueryFloatAttribute(), etc.)
277
278 @skip XMLElement* attributeApproachElement
279 @until &v0 );
280
281 When using the text approach, you need to navigate
282 down one more step to the XMLElement that contains
283 the text. Note the extra FirstChildElement( "v" )
284 in the code below. The value of the text can then
285 be safely queried with the QueryIntText() group
286 of methods. (Also QueryFloatText(), etc.)
287
288 @skip XMLElement* textApproachElement
289 @until &v1 );
290*/
Lee Thomason21be8822012-07-15 17:27:22 -0700291
292
Lee Thomason178e4cc2013-01-25 16:19:05 -0800293int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800294{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800295 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800296 _CrtMemCheckpoint( &startMemState );
Dmitry-Me99916592014-10-23 11:37:03 +0400297 // Enable MS Visual C++ debug heap memory leaks dump on exit
298 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
Dmitry-Meed785702017-06-15 13:39:53 +0300299 {
300 int leaksOnStart = _CrtDumpMemoryLeaks();
301 XMLTest( "No leaks on start?", FALSE, leaksOnStart );
302 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700303 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800304
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300305 {
306 TIXMLASSERT( true );
307 }
308
Lee Thomason178e4cc2013-01-25 16:19:05 -0800309 if ( argc > 1 ) {
310 XMLDocument* doc = new XMLDocument();
311 clock_t startTime = clock();
312 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100313 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800314 int errorID = doc->ErrorID();
315 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100316 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800317
318 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
319 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700320 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
321 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
322 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800323 }
324 exit(0);
325 }
326
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300327 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700328 if ( !fp ) {
329 printf( "Error opening test file 'dream.xml'.\n"
330 "Is your working directory the same as where \n"
331 "the xmltest.cpp and dream.xml file are?\n\n"
332 #if defined( _MSC_VER )
333 "In windows Visual Studio you may need to set\n"
334 "Properties->Debugging->Working Directory to '..'\n"
335 #endif
336 );
337 exit( 1 );
338 }
339 fclose( fp );
340
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700341 XMLTest( "Example-1", 0, example_1() );
342 XMLTest( "Example-2", 0, example_2() );
343 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700344 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700345
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700346 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700347
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800348 {
Lee Thomason43f59302012-02-06 18:18:11 -0800349 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400350 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800351 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400352 "<element><subelement></subelement></element>",
353 "<element><subelement><subsub/></subelement></element>",
354 "<!--comment beside elements--><element><subelement></subelement></element>",
355 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
356 "<element attrib1='foo' attrib2=\"bar\" ></element>",
357 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800358 "<element>Text inside element.</element>",
359 "<element><b></b></element>",
360 "<element>Text inside and <b>bolded</b> in the element.</element>",
361 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800362 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800363 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800364 0
365 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800366 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800367 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800368 doc.Parse( test[i] );
Dmitry-Me68578f42017-07-03 18:21:23 +0300369 XMLTest( "Element test", false, doc.Error() );
Lee Thomason5cae8972012-01-24 18:03:07 -0800370 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800371 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800372 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800373 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800374#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800375 {
376 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400377 " line 2\r"
378 " line 3\r\n"
379 " line 4\n\r"
380 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800381
382 XMLDocument doc;
383 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300384 XMLTest( "Hello world declaration", false, doc.Error() );
Lee Thomasond6277762012-02-22 16:00:12 -0800385 doc.Print();
386 }
387
Lee Thomason2c85a712012-01-31 08:24:24 -0800388 {
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300389 // This test is pre-test for the next one
390 // (where Element1 is inserted "after itself".
391 // This code didn't use to crash.
392 XMLDocument doc;
393 XMLElement* element1 = doc.NewElement("Element1");
394 XMLElement* element2 = doc.NewElement("Element2");
395 doc.InsertEndChild(element1);
396 doc.InsertEndChild(element2);
397 doc.InsertAfterChild(element2, element2);
398 doc.InsertAfterChild(element2, element2);
399 }
400
401 {
402 XMLDocument doc;
403 XMLElement* element1 = doc.NewElement("Element1");
404 XMLElement* element2 = doc.NewElement("Element2");
405 doc.InsertEndChild(element1);
406 doc.InsertEndChild(element2);
407
408 // This insertion "after itself"
409 // used to cause invalid memory access and crash
410 doc.InsertAfterChild(element1, element1);
411 doc.InsertAfterChild(element1, element1);
412 doc.InsertAfterChild(element2, element2);
413 doc.InsertAfterChild(element2, element2);
414 }
415
416 {
Lee Thomason2c85a712012-01-31 08:24:24 -0800417 static const char* test = "<element>Text before.</element>";
418 XMLDocument doc;
419 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300420 XMLTest( "Element text before", false, doc.Error() );
Lee Thomason2c85a712012-01-31 08:24:24 -0800421 XMLElement* root = doc.FirstChildElement();
422 XMLElement* newElement = doc.NewElement( "Subelement" );
423 root->InsertEndChild( newElement );
424 doc.Print();
425 }
Lee Thomasond1983222012-02-06 08:41:24 -0800426 {
427 XMLDocument* doc = new XMLDocument();
428 static const char* test = "<element><sub/></element>";
429 doc->Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300430 XMLTest( "Element with sub element", false, doc->Error() );
Lee Thomasond1983222012-02-06 08:41:24 -0800431 delete doc;
432 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800433 {
Dmitry-Me8e063702017-08-01 17:40:40 +0300434 // Test: Programmatic DOM nodes insertion return values
435 XMLDocument doc;
436
437 XMLNode* first = doc.NewElement( "firstElement" );
438 XMLTest( "New element", true, first != 0 );
439 XMLNode* firstAfterInsertion = doc.InsertFirstChild( first );
440 XMLTest( "New element inserted first", true, firstAfterInsertion == first );
441
442 XMLNode* last = doc.NewElement( "lastElement" );
443 XMLTest( "New element", true, last != 0 );
444 XMLNode* lastAfterInsertion = doc.InsertEndChild( last );
445 XMLTest( "New element inserted last", true, lastAfterInsertion == last );
446
447 XMLNode* middle = doc.NewElement( "middleElement" );
448 XMLTest( "New element", true, middle != 0 );
449 XMLNode* middleAfterInsertion = doc.InsertAfterChild( first, middle );
450 XMLTest( "New element inserted middle", true, middleAfterInsertion == middle );
451 }
452 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800453 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800454 // Build:
455 // <element>
456 // <!--comment-->
457 // <sub attrib="1" />
458 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800459 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800460 // <element>
461
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800462 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800463 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
464
465 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
466 for( int i=0; i<3; ++i ) {
467 sub[i]->SetAttribute( "attrib", i );
468 }
469 element->InsertEndChild( sub[2] );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300470
471 const int dummyInitialValue = 1000;
472 int dummyValue = dummyInitialValue;
473
Lee Thomason1ff38e02012-02-14 18:18:16 -0800474 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300475 comment->SetUserData(&dummyValue);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800476 element->InsertAfterChild( comment, sub[0] );
477 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800478 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800479 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800480 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
481 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
482 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700483 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800484 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Dmitry-Mecaed4ec2017-08-11 17:39:47 +0300485 XMLTest("User data - pointer", true, &dummyValue == comment->GetUserData(), false);
486 XMLTest("User data - value behind pointer", dummyInitialValue, dummyValue, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800487
488 // And now deletion:
489 element->DeleteChild( sub[2] );
490 doc->DeleteNode( comment );
491
492 element->FirstChildElement()->SetAttribute( "attrib", true );
493 element->LastChildElement()->DeleteAttribute( "attrib" );
494
495 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300496 const int defaultIntValue = 10;
497 const int replacementIntValue = 20;
498 int value1 = defaultIntValue;
499 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300500 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
501 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300502 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
503 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800504
505 doc->Print();
506
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700507 {
508 XMLPrinter streamer;
509 doc->Print( &streamer );
510 printf( "%s", streamer.CStr() );
511 }
512 {
513 XMLPrinter streamer( 0, true );
514 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200515 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700516 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700517 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300518 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700519 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300520 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800521 delete doc;
522 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800523 {
524 // Test: Dream
525 // XML1 : 1,187,569 bytes in 31,209 allocations
526 // XML2 : 469,073 bytes in 323 allocations
527 //int newStart = gNew;
528 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300529 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300530 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800531
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400532 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300533 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800534 doc.PrintError();
535
536 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400537 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800538 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
539 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
540 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
541 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400542 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800543 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400544 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800545
546 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400547 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300548 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800549 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400550 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800551 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
552 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
553 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
554 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400555 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800556
557 //gNewTotal = gNew - newStart;
558 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800559
560
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800561 {
562 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
563 "<passages count=\"006\" formatversion=\"20020620\">\n"
564 " <wrong error>\n"
565 "</passages>";
566
567 XMLDocument doc;
568 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300569 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomasona36f7ac2017-12-28 13:48:54 -0800570 const char* errorStr = doc.ErrorStr();
571 XMLTest("Formatted error string",
572 "Error=XML_ERROR_PARSING_ATTRIBUTE ErrorID=8 (0x8) Line number=3: XMLElement name=wrong",
573 errorStr);
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 );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001042 bool acceptResult = psg->Accept( &streamer );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001043 fclose( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001044 XMLTest( "Entity transformation: Accept", true, acceptResult );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001045 }
Thomas Roß0922b732012-09-23 16:31:22 +02001046
Dmitry-Me520009e2017-08-10 17:50:03 +03001047 textfile = fopen( textFilePath, "r" );
1048 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001049 if ( textfile )
1050 {
1051 char buf[ 1024 ];
1052 fgets( buf, 1024, textfile );
1053 XMLTest( "Entity transformation: write. ",
1054 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1055 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1056 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001057 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001058 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001059 }
1060
1061 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001062 // Suppress entities.
1063 const char* passages =
1064 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1065 "<passages count=\"006\" formatversion=\"20020620\">"
1066 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1067 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001068
Lee Thomason6f381b72012-03-02 12:59:39 -08001069 XMLDocument doc( false );
1070 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001071 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001072
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001073 XMLTest( "No entity parsing.",
1074 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1075 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1076 XMLTest( "No entity parsing.", "Crazy &ttk;",
1077 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001078 doc.Print();
1079 }
1080
1081 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001082 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001083
1084 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001085 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001086 XMLTest( "dot in names", false, doc.Error() );
1087 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1088 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001089 }
1090
1091 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001092 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001093
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001094 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001095 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001096 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001097
1098 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1099 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001100 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001101 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001102 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001103
1104 {
1105 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001106 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001107 const char* doctype =
1108 "<?xml version=\"1.0\" ?>"
1109 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1110 "<!ELEMENT title (#PCDATA)>"
1111 "<!ELEMENT books (title,authors)>"
1112 "<element />";
1113
1114 XMLDocument doc;
1115 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001116 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001117 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001118 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001119 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001120 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001121 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001122 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001123
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001124 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1125 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1126
1127 }
1128
1129 {
1130 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001131 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001132 "<!-- Somewhat<evil> -->";
1133 XMLDocument doc;
1134 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001135 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001136
1137 XMLComment* comment = doc.FirstChild()->ToComment();
1138
1139 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1140 }
1141 {
1142 // Double attributes
1143 const char* doctype = "<element attr='red' attr='blue' />";
1144
1145 XMLDocument doc;
1146 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001147
Lee Thomason2fa81722012-11-09 12:37:46 -08001148 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 -08001149 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001150 }
1151
1152 {
1153 // Embedded null in stream.
1154 const char* doctype = "<element att\0r='red' attr='blue' />";
1155
1156 XMLDocument doc;
1157 doc.Parse( doctype );
1158 XMLTest( "Embedded null throws error.", true, doc.Error() );
1159 }
1160
1161 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001162 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001163 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001164 XMLDocument doc;
1165 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001166 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomasona36f7ac2017-12-28 13:48:54 -08001167
1168 // But be sure there is an error string!
1169 const char* errorStr = doc.ErrorStr();
1170 XMLTest("Error string should be set",
1171 "Error=XML_ERROR_EMPTY_DOCUMENT ErrorID=15 (0xf) Line number=0",
1172 errorStr);
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001173 }
1174
1175 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001176 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1177 const char* str = " ";
1178 XMLDocument doc;
1179 doc.Parse( str );
1180 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1181 }
1182
1183 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001184 // Low entities
1185 XMLDocument doc;
1186 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001187 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001188 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001189 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001190 doc.Print();
1191 }
1192
1193 {
1194 // Attribute values with trailing quotes not handled correctly
1195 XMLDocument doc;
1196 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001197 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001198 }
1199
1200 {
1201 // [ 1663758 ] Failure to report error on bad XML
1202 XMLDocument xml;
1203 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001204 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001205 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001206 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001207 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001208 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001209 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001210
1211
1212 {
1213 // [ 1475201 ] TinyXML parses entities in comments
1214 XMLDocument xml;
1215 xml.Parse("<!-- declarations for <head> & <body> -->"
1216 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001217 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001218
1219 XMLNode* e0 = xml.FirstChild();
1220 XMLNode* e1 = e0->NextSibling();
1221 XMLComment* c0 = e0->ToComment();
1222 XMLComment* c1 = e1->ToComment();
1223
1224 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1225 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1226 }
1227
1228 {
1229 XMLDocument xml;
1230 xml.Parse( "<Parent>"
1231 "<child1 att=''/>"
1232 "<!-- With this comment, child2 will not be parsed! -->"
1233 "<child2 att=''/>"
1234 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001235 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001236 xml.Print();
1237
1238 int count = 0;
1239
1240 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1241 ele;
1242 ele = ele->NextSibling() )
1243 {
1244 ++count;
1245 }
1246
1247 XMLTest( "Comments iterate correctly.", 3, count );
1248 }
1249
1250 {
1251 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1252 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1253 buf[60] = 239;
1254 buf[61] = 0;
1255
1256 XMLDocument doc;
1257 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001258 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001259 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001260
1261
1262 {
1263 // bug 1827248 Error while parsing a little bit malformed file
1264 // Actually not malformed - should work.
1265 XMLDocument xml;
1266 xml.Parse( "<attributelist> </attributelist >" );
1267 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1268 }
1269
1270 {
1271 // This one must not result in an infinite loop
1272 XMLDocument xml;
1273 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001274 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001275 XMLTest( "Infinite loop test.", true, true );
1276 }
1277#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001278 {
1279 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1280 XMLDocument doc;
1281 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001282 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001283
1284 XMLDocument clone;
1285 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1286 XMLNode* copy = node->ShallowClone( &clone );
1287 clone.InsertEndChild( copy );
1288 }
1289
1290 clone.Print();
1291
1292 int count=0;
1293 const XMLNode* a=clone.FirstChild();
1294 const XMLNode* b=doc.FirstChild();
1295 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1296 ++count;
1297 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1298 }
1299 XMLTest( "Clone and Equal", 4, count );
1300 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001301
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001302 {
Lee Thomason7085f002017-06-01 18:09:43 -07001303 // Deep Cloning of root element.
1304 XMLDocument doc2;
1305 XMLPrinter printer1;
1306 {
1307 // Make sure doc1 is deleted before we test doc2
1308 const char* xml =
1309 "<root>"
1310 " <child1 foo='bar'/>"
1311 " <!-- comment thing -->"
1312 " <child2 val='1'>Text</child2>"
1313 "</root>";
1314 XMLDocument doc;
1315 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001316 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001317
1318 doc.Print(&printer1);
1319 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1320 doc2.InsertFirstChild(root);
1321 }
1322 XMLPrinter printer2;
1323 doc2.Print(&printer2);
1324
1325 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1326 }
1327
1328 {
1329 // Deep Cloning of sub element.
1330 XMLDocument doc2;
1331 XMLPrinter printer1;
1332 {
1333 // Make sure doc1 is deleted before we test doc2
1334 const char* xml =
1335 "<?xml version ='1.0'?>"
1336 "<root>"
1337 " <child1 foo='bar'/>"
1338 " <!-- comment thing -->"
1339 " <child2 val='1'>Text</child2>"
1340 "</root>";
1341 XMLDocument doc;
1342 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001343 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001344
1345 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001346 bool acceptResult = subElement->Accept(&printer1);
1347 XMLTest( "Accept before deep cloning", true, acceptResult );
Lee Thomason7085f002017-06-01 18:09:43 -07001348
1349 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1350 doc2.InsertFirstChild(clonedSubElement);
1351 }
1352 XMLPrinter printer2;
1353 doc2.Print(&printer2);
1354
1355 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1356 }
1357
1358 {
1359 // Deep cloning of document.
1360 XMLDocument doc2;
1361 XMLPrinter printer1;
1362 {
1363 // Make sure doc1 is deleted before we test doc2
1364 const char* xml =
1365 "<?xml version ='1.0'?>"
1366 "<!-- Top level comment. -->"
1367 "<root>"
1368 " <child1 foo='bar'/>"
1369 " <!-- comment thing -->"
1370 " <child2 val='1'>Text</child2>"
1371 "</root>";
1372 XMLDocument doc;
1373 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001374 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001375 doc.Print(&printer1);
1376
1377 doc.DeepCopy(&doc2);
1378 }
1379 XMLPrinter printer2;
1380 doc2.Print(&printer2);
1381
1382 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1383 }
1384
1385
1386 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001387 // This shouldn't crash.
1388 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001389 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001390 {
1391 doc.PrintError();
1392 }
1393 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1394 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001395
Lee Thomason5e3803c2012-04-16 08:57:05 -07001396 {
1397 // Attribute ordering.
1398 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1399 XMLDocument doc;
1400 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001401 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001402 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001403
Lee Thomason5e3803c2012-04-16 08:57:05 -07001404 const XMLAttribute* a = ele->FirstAttribute();
1405 XMLTest( "Attribute order", "1", a->Value() );
1406 a = a->Next();
1407 XMLTest( "Attribute order", "2", a->Value() );
1408 a = a->Next();
1409 XMLTest( "Attribute order", "3", a->Value() );
1410 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001411
Lee Thomason5e3803c2012-04-16 08:57:05 -07001412 ele->DeleteAttribute( "attrib2" );
1413 a = ele->FirstAttribute();
1414 XMLTest( "Attribute order", "1", a->Value() );
1415 a = a->Next();
1416 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001417
Lee Thomason5e3803c2012-04-16 08:57:05 -07001418 ele->DeleteAttribute( "attrib1" );
1419 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001420 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001421 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001422
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001423 {
1424 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001425 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1426 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1427 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1428 XMLDocument doc0;
1429 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001430 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001431 XMLDocument doc1;
1432 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001433 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001434 XMLDocument doc2;
1435 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001436 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001437
Lee Thomason78a773d2012-07-02 10:10:19 -07001438 XMLElement* ele = 0;
1439 ele = doc0.FirstChildElement();
1440 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1441 ele = doc1.FirstChildElement();
1442 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1443 ele = doc2.FirstChildElement();
1444 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001445 }
1446
1447 {
1448 // Make sure we don't go into an infinite loop.
1449 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1450 XMLDocument doc;
1451 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001452 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001453 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1454 XMLElement* ele1 = ele0->NextSiblingElement();
1455 bool equal = ele0->ShallowEqual( ele1 );
1456
1457 XMLTest( "Infinite loop in shallow equal.", true, equal );
1458 }
1459
Lee Thomason5708f812012-03-28 17:46:41 -07001460 // -------- Handles ------------
1461 {
1462 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1463 XMLDocument doc;
1464 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001465 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001466
1467 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001468 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001469
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001470 XMLHandle docH( doc );
1471 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001472 XMLTest( "Handle, dne, mutable", true, ele == 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001473 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001474
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001475 {
1476 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1477 XMLDocument doc;
1478 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001479 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001480 XMLConstHandle docH( doc );
1481
1482 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001483 XMLTest( "Handle, success, const", "sub", ele->Value() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001484
1485 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001486 XMLTest( "Handle, dne, const", true, ele == 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001487 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001488 {
1489 // Default Declaration & BOM
1490 XMLDocument doc;
1491 doc.InsertEndChild( doc.NewDeclaration() );
1492 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001493
Lee Thomasonf68c4382012-04-28 14:37:11 -07001494 XMLPrinter printer;
1495 doc.Print( &printer );
1496
1497 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001498 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1499 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001500 }
Lee Thomason21be8822012-07-15 17:27:22 -07001501 {
1502 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1503 XMLDocument doc;
1504 doc.Parse( xml );
1505 XMLTest( "Ill formed XML", true, doc.Error() );
1506 }
1507
1508 // QueryXYZText
1509 {
1510 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1511 XMLDocument doc;
1512 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001513 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001514
1515 const XMLElement* pointElement = doc.RootElement();
1516
Dmitry-Me43c019d2017-08-02 18:05:23 +03001517 {
1518 int intValue = 0;
1519 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1520 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1521 XMLTest( "QueryIntText", 1, intValue, false );
1522 }
Lee Thomason21be8822012-07-15 17:27:22 -07001523
Dmitry-Me43c019d2017-08-02 18:05:23 +03001524 {
1525 unsigned unsignedValue = 0;
1526 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1527 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1528 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1529 }
Lee Thomason21be8822012-07-15 17:27:22 -07001530
Dmitry-Me43c019d2017-08-02 18:05:23 +03001531 {
1532 float floatValue = 0;
1533 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1534 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1535 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1536 }
Lee Thomason21be8822012-07-15 17:27:22 -07001537
Dmitry-Me43c019d2017-08-02 18:05:23 +03001538 {
1539 double doubleValue = 0;
1540 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1541 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1542 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1543 }
1544
1545 {
1546 bool boolValue = false;
1547 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1548 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1549 XMLTest( "QueryBoolText", true, boolValue, false );
1550 }
Lee Thomason21be8822012-07-15 17:27:22 -07001551 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001552
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001553 {
1554 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1555 XMLDocument doc;
1556 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001557 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001558 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001559
1560 {
1561 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1562 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001563 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001564 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001565 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001566
1567 {
1568 const char* xml = "<3lement></3lement>";
1569 XMLDocument doc;
1570 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001571 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001572 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001573
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001574 {
1575 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1576 XMLDocument doc;
1577 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001578 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001579 }
1580
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001581 {
1582 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001583 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001584 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001585 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001586 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001587 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001588 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001589 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001590 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001591 }
Dmitry-Me985ea1f2017-08-28 18:36:29 +03001592
1593 {
1594 XMLDocument doc;
1595 XMLTest( "No error initially", false, doc.Error() );
1596 XMLError error = doc.Parse( "This is not XML" );
1597 XMLTest( "Error after invalid XML", true, doc.Error() );
1598 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1599 doc.Clear();
1600 XMLTest( "No error after Clear()", false, doc.Error() );
1601 }
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001602
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001603 // ----------- Whitespace ------------
1604 {
1605 const char* xml = "<element>"
1606 "<a> This \nis &apos; text &apos; </a>"
1607 "<b> This is &apos; text &apos; \n</b>"
1608 "<c>This is &apos; \n\n text &apos;</c>"
1609 "</element>";
1610 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1611 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001612 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001613
1614 const XMLElement* element = doc.FirstChildElement();
1615 for( const XMLElement* parent = element->FirstChildElement();
1616 parent;
1617 parent = parent->NextSiblingElement() )
1618 {
1619 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1620 }
1621 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001622
Lee Thomasonae9ab072012-10-24 10:17:53 -07001623#if 0
1624 {
1625 // Passes if assert doesn't fire.
1626 XMLDocument xmlDoc;
1627
1628 xmlDoc.NewDeclaration();
1629 xmlDoc.NewComment("Configuration file");
1630
1631 XMLElement *root = xmlDoc.NewElement("settings");
1632 root->SetAttribute("version", 2);
1633 }
1634#endif
1635
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001636 {
1637 const char* xml = "<element> </element>";
1638 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1639 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001640 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001641 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1642 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001643
Lee Thomason5b0a6772012-11-19 13:54:42 -08001644 {
1645 // An assert should not fire.
1646 const char* xml = "<element/>";
1647 XMLDocument doc;
1648 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001649 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001650 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1651 XMLTest( "Tracking unused elements", true, ele != 0, false );
1652 }
1653
Lee Thomasona6412ac2012-12-13 15:39:11 -08001654
1655 {
1656 const char* xml = "<parent><child>abc</child></parent>";
1657 XMLDocument doc;
1658 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001659 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001660 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1661
1662 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001663 bool acceptResult = ele->Accept( &printer );
1664 XMLTest( "Accept of sub-element", true, acceptResult );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001665 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1666 }
1667
1668
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001669 {
1670 XMLDocument doc;
1671 XMLError error = doc.LoadFile( "resources/empty.xml" );
1672 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001673 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001674 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001675 }
1676
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001677 {
1678 // BOM preservation
1679 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1680 {
1681 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001682 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001683 XMLPrinter printer;
1684 doc.Print( &printer );
1685
1686 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1687 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001688 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001689 }
1690 {
1691 XMLDocument doc;
1692 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001693 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001694 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1695
1696 XMLPrinter printer;
1697 doc.Print( &printer );
1698 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1699 }
1700 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001701
Michael Daumlinged523282013-10-23 07:47:29 +02001702 {
1703 // Insertion with Removal
1704 const char* xml = "<?xml version=\"1.0\" ?>"
1705 "<root>"
1706 "<one>"
1707 "<subtree>"
1708 "<elem>element 1</elem>text<!-- comment -->"
1709 "</subtree>"
1710 "</one>"
1711 "<two/>"
1712 "</root>";
1713 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1714 "<root>"
1715 "<one/>"
1716 "<two>"
1717 "<subtree>"
1718 "<elem>element 1</elem>text<!-- comment -->"
1719 "</subtree>"
1720 "</two>"
1721 "</root>";
1722 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1723 "<root>"
1724 "<one/>"
1725 "<subtree>"
1726 "<elem>element 1</elem>text<!-- comment -->"
1727 "</subtree>"
1728 "<two/>"
1729 "</root>";
1730 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1731 "<root>"
1732 "<one/>"
1733 "<two/>"
1734 "<subtree>"
1735 "<elem>element 1</elem>text<!-- comment -->"
1736 "</subtree>"
1737 "</root>";
1738
1739 XMLDocument doc;
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 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001742 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1743 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1744 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001745 XMLPrinter printer1(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001746 bool acceptResult = doc.Accept(&printer1);
1747 XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001748 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001749
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001750 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001751 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001752 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1753 two = doc.RootElement()->FirstChildElement("two");
1754 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001755 XMLPrinter printer2(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001756 acceptResult = doc.Accept(&printer2);
1757 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001758 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001759
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001760 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001761 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001762 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1763 subtree = one->FirstChildElement("subtree");
1764 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001765 XMLPrinter printer3(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001766 acceptResult = doc.Accept(&printer3);
1767 XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001768 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001769
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001770 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001771 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001772 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1773 two = doc.RootElement()->FirstChildElement("two");
1774 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001775 XMLPrinter printer4(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001776 acceptResult = doc.Accept(&printer4);
1777 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001778 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001779 }
1780
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001781 {
1782 const char* xml = "<svg width = \"128\" height = \"128\">"
1783 " <text> </text>"
1784 "</svg>";
1785 XMLDocument doc;
1786 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001787 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001788 doc.Print();
1789 }
1790
Lee Thomason92e521b2014-11-15 17:45:51 -08001791 {
1792 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001793 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1794 XMLDocument doc;
1795 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001796 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001797 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001798 }
1799
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001800#if 1
1801 // the question being explored is what kind of print to use:
1802 // https://github.com/leethomason/tinyxml2/issues/63
1803 {
1804 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1805 const char* xml = "<element/>";
1806 XMLDocument doc;
1807 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001808 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001809 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1810 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1811 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1812 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1813 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1814 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1815
1816 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1817 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1818 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1819 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1820 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1821 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1822
1823 doc.Print();
1824
1825 /* The result of this test is platform, compiler, and library version dependent. :("
1826 XMLPrinter printer;
1827 doc.Print( &printer );
1828 XMLTest( "Float and double formatting.",
1829 "<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",
1830 printer.CStr(),
1831 true );
1832 */
1833 }
1834#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001835
1836 {
1837 // Issue #184
1838 // If it doesn't assert, it passes. Caused by objects
1839 // getting created during parsing which are then
1840 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001841 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001842 {
1843 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001844 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001845 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001846 }
1847 {
1848 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001849 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001850 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001851 doc.Clear();
1852 }
1853 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001854
1855 {
1856 // If this doesn't assert in DEBUG, all is well.
1857 tinyxml2::XMLDocument doc;
1858 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1859 doc.DeleteNode(pRoot);
1860 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001861
Dmitry-Mee5790db2017-07-28 17:54:38 +03001862 {
1863 XMLDocument doc;
1864 XMLElement* root = doc.NewElement( "Root" );
1865 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1866 doc.InsertEndChild( root );
1867 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1868 }
1869
1870 {
1871 // If this doesn't assert in DEBUG, all is well.
1872 XMLDocument doc;
1873 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1874 XMLElement* linkedRoot = doc.NewElement( "Root" );
1875 doc.InsertFirstChild( linkedRoot );
1876 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1877 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1878 }
1879
Dmitry-Me8b67d742014-12-22 11:35:12 +03001880 {
1881 // Should not assert in DEBUG
1882 XMLPrinter printer;
1883 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001884
Dmitry-Me6f51c802015-03-14 13:25:03 +03001885 {
1886 // Issue 291. Should not crash
1887 const char* xml = "&#0</a>";
1888 XMLDocument doc;
1889 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001890 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001891
1892 XMLPrinter printer;
1893 doc.Print( &printer );
1894 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001895 {
1896 // Issue 299. Can print elements that are not linked in.
1897 // Will crash if issue not fixed.
1898 XMLDocument doc;
1899 XMLElement* newElement = doc.NewElement( "printme" );
1900 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001901 bool acceptResult = newElement->Accept( &printer );
1902 XMLTest( "printme - Accept()", true, acceptResult );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001903 // Delete the node to avoid possible memory leak report in debug output
1904 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001905 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001906 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001907 // Issue 302. Clear errors from LoadFile/SaveFile
1908 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001909 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001910 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001911 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001912 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001913 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001914 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001915
Dmitry-Med9852a52015-03-25 10:17:49 +03001916 {
1917 // If a document fails to load then subsequent
1918 // successful loads should clear the error
1919 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001920 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001921 doc.LoadFile( "resources/no-such-file.xml" );
1922 XMLTest( "No such file - should fail", true, doc.Error() );
1923
1924 doc.LoadFile( "resources/dream.xml" );
1925 XMLTest( "Error should be cleared", false, doc.Error() );
1926 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301927
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301928 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001929 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001930 const char* xml0 = "<?xml version=\"1.0\" ?>"
1931 " <!-- xml version=\"1.1\" -->"
1932 "<first />";
1933 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001934 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001935 "<first />";
1936 const char* xml2 = "<first />"
1937 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001938 const char* xml3 = "<first></first>"
1939 "<?xml version=\"1.0\" ?>";
1940
1941 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1942
Lee Thomason85492022015-05-22 11:07:45 -07001943 XMLDocument doc;
1944 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001945 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001946 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001947 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001948 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001949 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001950 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001951 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001952 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001953 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301954 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001955
Lee Thomason85492022015-05-22 11:07:45 -07001956 {
1957 // No matter - before or after successfully parsing a text -
Dmitry-Me26043362017-08-30 17:40:15 +03001958 // calling XMLDocument::Value() used to cause an assert in debug.
1959 // Null must be retured.
Lee Thomason85492022015-05-22 11:07:45 -07001960 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1961 "<first />"
1962 "<second />";
1963 XMLDocument* doc = new XMLDocument();
1964 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1965 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001966 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001967 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1968 delete doc;
1969 }
1970
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001971 {
1972 XMLDocument doc;
1973 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
Dmitry-Med3f6c632017-08-30 17:43:14 +03001974 const XMLError error = static_cast<XMLError>(i);
Lee Thomasonf49b9652017-10-11 10:57:49 -07001975 const char* name = XMLDocument::ErrorIDToName(error);
1976 XMLTest( "ErrorName() after ClearError()", true, name != 0 );
1977 XMLTest( "ErrorName() after ClearError()", true, strlen(name) > 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001978 }
1979 }
1980
Lee Thomason816d3fa2017-06-05 14:35:55 -07001981 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001982 // Evil memory leaks.
1983 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1984 // and NOT added to the XMLDocument, what happens?
1985 //
1986 // Previously (buggy):
1987 // The memory would be free'd when the XMLDocument is
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001988 // destructed. But the XMLElement destructor wasn't called, so
1989 // memory allocated for the XMLElement text would not be free'd.
1990 // In practice this meant strings allocated for the XMLElement
1991 // text would be leaked. An edge case, but annoying.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001992 // Now:
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001993 // The XMLElement destructor is called. But the unlinked nodes
1994 // have to be tracked using a list. This has a minor performance
1995 // impact that can become significant if you have a lot of
1996 // unlinked nodes. (But why would you do that?)
1997 // The only way to see this bug was in a Visual C++ runtime debug heap
1998 // leak tracker. This is compiled in by default on Windows Debug and
1999 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
Lee Thomason816d3fa2017-06-05 14:35:55 -07002000 {
2001 XMLDocument doc;
2002 doc.NewElement("LEAK 1");
2003 }
2004 {
2005 XMLDocument doc;
2006 XMLElement* ele = doc.NewElement("LEAK 2");
2007 doc.DeleteNode(ele);
2008 }
2009 }
2010
Lee Thomason224ef772017-06-16 09:45:26 -07002011 {
2012 // Crashing reported via email.
2013 const char* xml =
2014 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07002015 "<property name='track_name'>voice</property>"
2016 "<property name='audio_track'>1</property>"
2017 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2018 "<blank length = '1' />"
2019 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2020 "<blank length = '2' />"
2021 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2022 "<blank length = '1' />"
2023 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07002024 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07002025
Lee Thomason224ef772017-06-16 09:45:26 -07002026 // It's not a good idea to delete elements as you walk the
2027 // list. I'm not sure this technically should work; but it's
2028 // an interesting test case.
2029 XMLDocument doc;
2030 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002031 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03002032
2033 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07002034 XMLTest("Crash bug parsing", true, playlist != 0);
2035
Dmitry-Meb41e24a2017-09-27 18:51:01 +03002036 {
2037 const char* elementName = "entry";
2038 XMLElement* entry = playlist->FirstChildElement(elementName);
2039 XMLTest("Crash bug parsing", true, entry != 0);
2040 while (entry) {
2041 XMLElement* todelete = entry;
2042 entry = entry->NextSiblingElement(elementName);
2043 playlist->DeleteChild(todelete);
2044 }
2045 entry = playlist->FirstChildElement(elementName);
2046 XMLTest("Crash bug parsing", true, entry == 0);
2047 }
2048 {
2049 const char* elementName = "blank";
2050 XMLElement* blank = playlist->FirstChildElement(elementName);
2051 XMLTest("Crash bug parsing", true, blank != 0);
2052 while (blank) {
2053 XMLElement* todelete = blank;
2054 blank = blank->NextSiblingElement(elementName);
2055 playlist->DeleteChild(todelete);
2056 }
2057 XMLTest("Crash bug parsing", true, blank == 0);
2058 }
Lee Thomason224ef772017-06-16 09:45:26 -07002059
2060 tinyxml2::XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002061 const bool acceptResult = playlist->Accept(&printer);
2062 XMLTest("Crash bug parsing - Accept()", true, acceptResult);
Lee Thomason224ef772017-06-16 09:45:26 -07002063 printf("%s\n", printer.CStr());
2064
Lee Thomason82bb0742017-06-16 09:48:20 -07002065 // No test; it only need to not crash.
2066 // Still, wrap it up with a sanity check
2067 int nProperty = 0;
2068 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2069 nProperty++;
2070 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002071 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07002072 }
2073
kezenatorec694152016-11-26 17:21:43 +10002074 // ----------- Line Number Tracking --------------
2075 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002076 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002077 {
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002078 TestUtil() : str() {}
2079
kezenatorec694152016-11-26 17:21:43 +10002080 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2081 {
2082 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002083 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002084
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002085 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002086 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002087 XMLTest(testString, expected_error, parseError);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002088 XMLTest(testString, expectedLine, doc.ErrorLineNum());
kezenatorec694152016-11-26 17:21:43 +10002089 };
2090
2091 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2092 {
2093 XMLDocument doc;
2094 doc.Parse(docStr);
2095 XMLTest(testString, false, doc.Error());
2096 TestDocLines(testString, doc, expectedLines);
2097 }
2098
2099 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2100 {
2101 XMLDocument doc;
2102 doc.LoadFile(file_name);
2103 XMLTest(testString, false, doc.Error());
2104 TestDocLines(testString, doc, expectedLines);
2105 }
2106
2107 private:
2108 DynArray<char, 10> str;
2109
2110 void Push(char type, int lineNum)
2111 {
2112 str.Push(type);
2113 str.Push(char('0' + (lineNum / 10)));
2114 str.Push(char('0' + (lineNum % 10)));
2115 }
2116
2117 bool VisitEnter(const XMLDocument& doc)
2118 {
kezenator19d8ea82016-11-29 19:50:27 +10002119 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002120 return true;
2121 }
2122 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2123 {
kezenator19d8ea82016-11-29 19:50:27 +10002124 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002125 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002126 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002127 return true;
2128 }
2129 bool Visit(const XMLDeclaration& declaration)
2130 {
kezenator19d8ea82016-11-29 19:50:27 +10002131 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002132 return true;
2133 }
2134 bool Visit(const XMLText& text)
2135 {
kezenator19d8ea82016-11-29 19:50:27 +10002136 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002137 return true;
2138 }
2139 bool Visit(const XMLComment& comment)
2140 {
kezenator19d8ea82016-11-29 19:50:27 +10002141 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002142 return true;
2143 }
2144 bool Visit(const XMLUnknown& unknown)
2145 {
kezenator19d8ea82016-11-29 19:50:27 +10002146 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002147 return true;
2148 }
2149
2150 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2151 {
2152 str.Clear();
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002153 const bool acceptResult = doc.Accept(this);
2154 XMLTest(testString, true, acceptResult);
kezenatorec694152016-11-26 17:21:43 +10002155 str.Push(0);
2156 XMLTest(testString, expectedLines, str.Mem());
2157 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002158 } tester;
kezenatorec694152016-11-26 17:21:43 +10002159
Lee Thomasone90e9012016-12-24 07:34:39 -08002160 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2161 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2162 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2163 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2164 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2165 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2166 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2167 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2168 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2169 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2170 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002171
Lee Thomasone90e9012016-12-24 07:34:39 -08002172 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002173 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002174
2175 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2176 "<root a='b' \n" // 2 Element Attribute
2177 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2178 "newline in text \n" // 4 Text
2179 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2180 " cdata test ]]><!-- comment -->\n" // 6 Comment
2181 "<! unknown></root>", // 7 Unknown
2182
kezenatorec694152016-11-26 17:21:43 +10002183 "D01L01E02A02A03T03E03T04E05T05C06U07");
2184
Lee Thomasone90e9012016-12-24 07:34:39 -08002185 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002186 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002187
2188 "\r\n" // 1 Doc (arguably should be line 2)
2189 "<?xml version=\"1.0\"?>\n" // 2 DecL
2190 "<root>\r\n" // 3 Element
2191 "\n" // 4
2192 "text contining new line \n" // 5 Text
2193 " and also containing crlf \r\n" // 6
2194 "<sub><![CDATA[\n" // 7 Element Text
2195 "cdata containing new line \n" // 8
2196 " and also containing cflr\r\n" // 9
2197 "]]></sub><sub2/></root>", // 10 Element
2198
kezenatorec694152016-11-26 17:21:43 +10002199 "D01L02E03T05E07T07E10");
2200
Lee Thomasone90e9012016-12-24 07:34:39 -08002201 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002202 "LineNumbers-File",
2203 "resources/utf8test.xml",
2204 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2205 }
2206
Lee Thomasonf49b9652017-10-11 10:57:49 -07002207 {
2208 const char* xml = "<Hello>Text</Error>";
2209 XMLDocument doc;
2210 doc.Parse(xml);
2211 XMLTest("Test mismatched elements.", true, doc.Error());
2212 XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2213 // For now just make sure calls work & doesn't crash.
2214 // May solidify the error output in the future.
2215 printf("%s\n", doc.ErrorStr());
2216 doc.PrintError();
2217 }
2218
Lee Thomason85492022015-05-22 11:07:45 -07002219 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002220 {
2221#if defined( _MSC_VER )
2222 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002223 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002224#endif
2225
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002226 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002227 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002228 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002229 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002230 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002231
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002232 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002233 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002234 size_t bytesRead = fread(mem, 1, size, perfFP);
2235 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002236 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002237 mem[size] = 0;
2238
2239#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002240 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002241#else
2242 clock_t cstart = clock();
2243#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002244 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002245 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002246 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002247 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002248 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002249 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002250 }
2251#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002252 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002253#else
2254 clock_t cend = clock();
2255#endif
Dmitry-Me1ab85872017-08-10 17:28:10 +03002256 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002257
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002258 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002259
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002260 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002261#ifdef DEBUG
2262 "DEBUG";
2263#else
2264 "Release";
2265#endif
2266
2267#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002268 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002269#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002270 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002271#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002272 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002273 }
2274
Dmitry-Mede381df2017-07-26 18:05:25 +03002275#if defined( _MSC_VER ) && defined( DEBUG )
2276 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002277 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002278
2279 _CrtMemState diffMemState;
2280 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2281 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002282
2283 {
2284 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2285 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2286 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002287 }
2288#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002289
2290 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002291
2292 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002293}