blob: 046bef76914249b556f49f1caaee4de95c7d696b [file] [log] [blame]
Lee Thomason5b0a6772012-11-19 13:54:42 -08001#if defined( _MSC_VER )
Serhat Eser Erdemca5d6842014-04-17 14:06:15 +02002 #if !defined( _CRT_SECURE_NO_WARNINGS )
3 #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
4 #endif
Lee Thomason5b0a6772012-11-19 13:54:42 -08005#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08006
Lee Thomason5b0a6772012-11-19 13:54:42 -08007#include "tinyxml2.h"
kbinny62bf29a152017-06-23 18:15:25 +00008#include <cerrno>
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07009#include <cstdlib>
10#include <cstring>
11#include <ctime>
U-Lama\Leee13c3e62011-12-28 14:36:55 -080012
kbinny62bf29a152017-06-23 18:15:25 +000013#if defined( _MSC_VER ) || defined (WIN32)
Lee Thomason1ff38e02012-02-14 18:18:16 -080014 #include <crtdbg.h>
Lee Thomason6f381b72012-03-02 12:59:39 -080015 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080017 _CrtMemState startMemState;
Lee Thomason53858b42017-06-01 19:09:16 -070018 _CrtMemState endMemState;
kbinny62bf29a152017-06-23 18:15:25 +000019#else
20 #include <sys/stat.h>
21 #include <sys/types.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080022#endif
Lee Thomasone9ecdab2012-02-13 18:11:20 -080023
U-Lama\Leee13c3e62011-12-28 14:36:55 -080024using namespace tinyxml2;
Anton Indrawan8a0006c2014-11-20 18:27:07 +010025using namespace std;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080026int gPass = 0;
27int gFail = 0;
28
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080029
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070030bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080031{
Sarat Addepalli13b2d732015-05-19 12:44:57 +053032 bool pass;
33 if ( !expected && !found )
34 pass = true;
35 else if ( !expected || !found )
36 pass = false;
Sarat Addepallid608c562015-05-20 10:19:00 +053037 else
38 pass = !strcmp( expected, found );
Lee Thomason1ff38e02012-02-14 18:18:16 -080039 if ( pass )
40 printf ("[pass]");
41 else
42 printf ("[fail]");
43
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070044 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080045 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070046 }
47 else {
48 if ( extraNL ) {
49 printf( " %s\n", testString );
50 printf( "%s\n", expected );
51 printf( "%s\n", found );
52 }
53 else {
54 printf (" %s [%s][%s]\n", testString, expected, found);
55 }
56 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080057
58 if ( pass )
59 ++gPass;
60 else
61 ++gFail;
62 return pass;
63}
64
kezenator5a700712016-11-26 13:54:42 +100065bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
66{
Lee Thomasone90e9012016-12-24 07:34:39 -080067 return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
kezenator5a700712016-11-26 13:54:42 +100068}
69
70bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
71{
72 return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
73}
Lee Thomason1ff38e02012-02-14 18:18:16 -080074
Lee Thomason21be8822012-07-15 17:27:22 -070075template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080076{
77 bool pass = ( expected == found );
78 if ( pass )
79 printf ("[pass]");
80 else
81 printf ("[fail]");
82
U-Stream\Lee09a11c52012-02-17 08:31:16 -080083 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080084 printf (" %s\n", testString);
85 else
Lee Thomasonc8312792012-07-16 12:44:41 -070086 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080087
88 if ( pass )
89 ++gPass;
90 else
91 ++gFail;
92 return pass;
93}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080094
U-Lama\Leee13c3e62011-12-28 14:36:55 -080095
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080096void NullLineEndings( char* p )
97{
98 while( p && *p ) {
99 if ( *p == '\n' || *p == '\r' ) {
100 *p = 0;
101 return;
102 }
103 ++p;
104 }
105}
106
107
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700108int example_1()
109{
110 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300111 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700112
113 return doc.ErrorID();
114}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200115/** @page Example-1 Load an XML File
116 * @dontinclude ./xmltest.cpp
117 * Basic XML file loading.
118 * The basic syntax to load an XML file from
119 * disk and check for an error. (ErrorID()
120 * will return 0 for no error.)
121 * @skip example_1()
122 * @until }
123 */
124
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700125
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700126int example_2()
127{
128 static const char* xml = "<element/>";
129 XMLDocument doc;
130 doc.Parse( xml );
131
132 return doc.ErrorID();
133}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200134/** @page Example-2 Parse an XML from char buffer
135 * @dontinclude ./xmltest.cpp
136 * Basic XML string parsing.
137 * The basic syntax to parse an XML for
138 * a char* and check for an error. (ErrorID()
139 * will return 0 for no error.)
140 * @skip example_2()
141 * @until }
142 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700143
144
145int example_3()
146{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700147 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700148 "<?xml version=\"1.0\"?>"
149 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
150 "<PLAY>"
151 "<TITLE>A Midsummer Night's Dream</TITLE>"
152 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700153
154 XMLDocument doc;
155 doc.Parse( xml );
156
157 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
158 const char* title = titleElement->GetText();
159 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700160
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700161 XMLText* textNode = titleElement->FirstChild()->ToText();
162 title = textNode->Value();
163 printf( "Name of play (2): %s\n", title );
164
165 return doc.ErrorID();
166}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200167/** @page Example-3 Get information out of XML
168 @dontinclude ./xmltest.cpp
169 In this example, we navigate a simple XML
170 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700171 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200172 checking; working code should check for null
173 pointers when walking an XML tree, or use
174 XMLHandle.
175
176 (The XML is an excerpt from "dream.xml").
177
178 @skip example_3()
179 @until </PLAY>";
180
181 The structure of the XML file is:
182
183 <ul>
184 <li>(declaration)</li>
185 <li>(dtd stuff)</li>
186 <li>Element "PLAY"</li>
187 <ul>
188 <li>Element "TITLE"</li>
189 <ul>
190 <li>Text "A Midsummer Night's Dream"</li>
191 </ul>
192 </ul>
193 </ul>
194
195 For this example, we want to print out the
196 title of the play. The text of the title (what
197 we want) is child of the "TITLE" element which
198 is a child of the "PLAY" element.
199
200 We want to skip the declaration and dtd, so the
201 method FirstChildElement() is a good choice. The
202 FirstChildElement() of the Document is the "PLAY"
203 Element, the FirstChildElement() of the "PLAY" Element
204 is the "TITLE" Element.
205
206 @until ( "TITLE" );
207
208 We can then use the convenience function GetText()
209 to get the title of the play.
210
211 @until title );
212
213 Text is just another Node in the XML DOM. And in
214 fact you should be a little cautious with it, as
215 text nodes can contain elements.
216
217 @verbatim
218 Consider: A Midsummer Night's <b>Dream</b>
219 @endverbatim
220
221 It is more correct to actually query the Text Node
222 if in doubt:
223
224 @until title );
225
226 Noting that here we use FirstChild() since we are
227 looking for XMLText, not an element, and ToText()
228 is a cast from a Node to a XMLText.
229*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700230
231
Lee Thomason21be8822012-07-15 17:27:22 -0700232bool example_4()
233{
234 static const char* xml =
235 "<information>"
236 " <attributeApproach v='2' />"
237 " <textApproach>"
238 " <v>2</v>"
239 " </textApproach>"
240 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700241
Lee Thomason21be8822012-07-15 17:27:22 -0700242 XMLDocument doc;
243 doc.Parse( xml );
244
245 int v0 = 0;
246 int v1 = 0;
247
248 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
249 attributeApproachElement->QueryIntAttribute( "v", &v0 );
250
251 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
252 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
253
254 printf( "Both values are the same: %d and %d\n", v0, v1 );
255
256 return !doc.Error() && ( v0 == v1 );
257}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200258/** @page Example-4 Read attributes and text information.
259 @dontinclude ./xmltest.cpp
260
261 There are fundamentally 2 ways of writing a key-value
262 pair into an XML file. (Something that's always annoyed
263 me about XML.) Either by using attributes, or by writing
264 the key name into an element and the value into
265 the text node wrapped by the element. Both approaches
266 are illustrated in this example, which shows two ways
267 to encode the value "2" into the key "v":
268
269 @skip example_4()
270 @until "</information>";
271
272 TinyXML-2 has accessors for both approaches.
273
274 When using an attribute, you navigate to the XMLElement
275 with that attribute and use the QueryIntAttribute()
276 group of methods. (Also QueryFloatAttribute(), etc.)
277
278 @skip XMLElement* attributeApproachElement
279 @until &v0 );
280
281 When using the text approach, you need to navigate
282 down one more step to the XMLElement that contains
283 the text. Note the extra FirstChildElement( "v" )
284 in the code below. The value of the text can then
285 be safely queried with the QueryIntText() group
286 of methods. (Also QueryFloatText(), etc.)
287
288 @skip XMLElement* textApproachElement
289 @until &v1 );
290*/
Lee Thomason21be8822012-07-15 17:27:22 -0700291
292
Lee Thomason178e4cc2013-01-25 16:19:05 -0800293int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800294{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800295 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800296 _CrtMemCheckpoint( &startMemState );
Dmitry-Me99916592014-10-23 11:37:03 +0400297 // Enable MS Visual C++ debug heap memory leaks dump on exit
298 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
Dmitry-Meed785702017-06-15 13:39:53 +0300299 {
300 int leaksOnStart = _CrtDumpMemoryLeaks();
301 XMLTest( "No leaks on start?", FALSE, leaksOnStart );
302 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700303 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800304
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300305 {
306 TIXMLASSERT( true );
307 }
308
Lee Thomason178e4cc2013-01-25 16:19:05 -0800309 if ( argc > 1 ) {
310 XMLDocument* doc = new XMLDocument();
311 clock_t startTime = clock();
312 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100313 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800314 int errorID = doc->ErrorID();
315 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100316 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800317
318 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
319 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700320 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
321 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
322 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800323 }
324 exit(0);
325 }
326
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300327 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700328 if ( !fp ) {
329 printf( "Error opening test file 'dream.xml'.\n"
330 "Is your working directory the same as where \n"
331 "the xmltest.cpp and dream.xml file are?\n\n"
332 #if defined( _MSC_VER )
333 "In windows Visual Studio you may need to set\n"
334 "Properties->Debugging->Working Directory to '..'\n"
335 #endif
336 );
337 exit( 1 );
338 }
339 fclose( fp );
340
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700341 XMLTest( "Example-1", 0, example_1() );
342 XMLTest( "Example-2", 0, example_2() );
343 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700344 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700345
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700346 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700347
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800348 {
Lee Thomason43f59302012-02-06 18:18:11 -0800349 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400350 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800351 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400352 "<element><subelement></subelement></element>",
353 "<element><subelement><subsub/></subelement></element>",
354 "<!--comment beside elements--><element><subelement></subelement></element>",
355 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
356 "<element attrib1='foo' attrib2=\"bar\" ></element>",
357 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800358 "<element>Text inside element.</element>",
359 "<element><b></b></element>",
360 "<element>Text inside and <b>bolded</b> in the element.</element>",
361 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800362 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800363 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800364 0
365 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800366 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800367 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800368 doc.Parse( test[i] );
Dmitry-Me68578f42017-07-03 18:21:23 +0300369 XMLTest( "Element test", false, doc.Error() );
Lee Thomason5cae8972012-01-24 18:03:07 -0800370 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800371 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800372 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800373 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800374#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800375 {
376 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400377 " line 2\r"
378 " line 3\r\n"
379 " line 4\n\r"
380 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800381
382 XMLDocument doc;
383 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300384 XMLTest( "Hello world declaration", false, doc.Error() );
Lee Thomasond6277762012-02-22 16:00:12 -0800385 doc.Print();
386 }
387
Lee Thomason2c85a712012-01-31 08:24:24 -0800388 {
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300389 // This test is pre-test for the next one
390 // (where Element1 is inserted "after itself".
391 // This code didn't use to crash.
392 XMLDocument doc;
393 XMLElement* element1 = doc.NewElement("Element1");
394 XMLElement* element2 = doc.NewElement("Element2");
395 doc.InsertEndChild(element1);
396 doc.InsertEndChild(element2);
397 doc.InsertAfterChild(element2, element2);
398 doc.InsertAfterChild(element2, element2);
399 }
400
401 {
402 XMLDocument doc;
403 XMLElement* element1 = doc.NewElement("Element1");
404 XMLElement* element2 = doc.NewElement("Element2");
405 doc.InsertEndChild(element1);
406 doc.InsertEndChild(element2);
407
408 // This insertion "after itself"
409 // used to cause invalid memory access and crash
410 doc.InsertAfterChild(element1, element1);
411 doc.InsertAfterChild(element1, element1);
412 doc.InsertAfterChild(element2, element2);
413 doc.InsertAfterChild(element2, element2);
414 }
415
416 {
Lee Thomason2c85a712012-01-31 08:24:24 -0800417 static const char* test = "<element>Text before.</element>";
418 XMLDocument doc;
419 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300420 XMLTest( "Element text before", false, doc.Error() );
Lee Thomason2c85a712012-01-31 08:24:24 -0800421 XMLElement* root = doc.FirstChildElement();
422 XMLElement* newElement = doc.NewElement( "Subelement" );
423 root->InsertEndChild( newElement );
424 doc.Print();
425 }
Lee Thomasond1983222012-02-06 08:41:24 -0800426 {
427 XMLDocument* doc = new XMLDocument();
428 static const char* test = "<element><sub/></element>";
429 doc->Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300430 XMLTest( "Element with sub element", false, doc->Error() );
Lee Thomasond1983222012-02-06 08:41:24 -0800431 delete doc;
432 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800433 {
Dmitry-Me8e063702017-08-01 17:40:40 +0300434 // Test: Programmatic DOM nodes insertion return values
435 XMLDocument doc;
436
437 XMLNode* first = doc.NewElement( "firstElement" );
438 XMLTest( "New element", true, first != 0 );
439 XMLNode* firstAfterInsertion = doc.InsertFirstChild( first );
440 XMLTest( "New element inserted first", true, firstAfterInsertion == first );
441
442 XMLNode* last = doc.NewElement( "lastElement" );
443 XMLTest( "New element", true, last != 0 );
444 XMLNode* lastAfterInsertion = doc.InsertEndChild( last );
445 XMLTest( "New element inserted last", true, lastAfterInsertion == last );
446
447 XMLNode* middle = doc.NewElement( "middleElement" );
448 XMLTest( "New element", true, middle != 0 );
449 XMLNode* middleAfterInsertion = doc.InsertAfterChild( first, middle );
450 XMLTest( "New element inserted middle", true, middleAfterInsertion == middle );
451 }
452 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800453 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800454 // Build:
455 // <element>
456 // <!--comment-->
457 // <sub attrib="1" />
458 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800459 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800460 // <element>
461
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800462 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800463 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
464
465 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
466 for( int i=0; i<3; ++i ) {
467 sub[i]->SetAttribute( "attrib", i );
468 }
469 element->InsertEndChild( sub[2] );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300470
471 const int dummyInitialValue = 1000;
472 int dummyValue = dummyInitialValue;
473
Lee Thomason1ff38e02012-02-14 18:18:16 -0800474 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300475 comment->SetUserData(&dummyValue);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800476 element->InsertAfterChild( comment, sub[0] );
477 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800478 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800479 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800480 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
481 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
482 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700483 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800484 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Dmitry-Mecaed4ec2017-08-11 17:39:47 +0300485 XMLTest("User data - pointer", true, &dummyValue == comment->GetUserData(), false);
486 XMLTest("User data - value behind pointer", dummyInitialValue, dummyValue, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800487
488 // And now deletion:
489 element->DeleteChild( sub[2] );
490 doc->DeleteNode( comment );
491
492 element->FirstChildElement()->SetAttribute( "attrib", true );
493 element->LastChildElement()->DeleteAttribute( "attrib" );
494
495 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300496 const int defaultIntValue = 10;
497 const int replacementIntValue = 20;
498 int value1 = defaultIntValue;
499 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300500 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
501 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300502 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
503 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800504
505 doc->Print();
506
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700507 {
508 XMLPrinter streamer;
509 doc->Print( &streamer );
510 printf( "%s", streamer.CStr() );
511 }
512 {
513 XMLPrinter streamer( 0, true );
514 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200515 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700516 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700517 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300518 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700519 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300520 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800521 delete doc;
522 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800523 {
524 // Test: Dream
525 // XML1 : 1,187,569 bytes in 31,209 allocations
526 // XML2 : 469,073 bytes in 323 allocations
527 //int newStart = gNew;
528 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300529 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300530 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800531
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400532 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300533 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800534 doc.PrintError();
535
536 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400537 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800538 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
539 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
540 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
541 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400542 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800543 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400544 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800545
546 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400547 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300548 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800549 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400550 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800551 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
552 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
553 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
554 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400555 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800556
557 //gNewTotal = gNew - newStart;
558 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800559
560
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800561 {
562 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
563 "<passages count=\"006\" formatversion=\"20020620\">\n"
564 " <wrong error>\n"
565 "</passages>";
566
567 XMLDocument doc;
568 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300569 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800570 }
571
572 {
573 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
574
575 XMLDocument doc;
576 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300577 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800578
579 XMLElement* ele = doc.FirstChildElement();
580
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300581 int iVal;
582 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800583 double dVal;
584
585 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300586 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
587 XMLTest( "Query attribute: int as double", 1, (int)dVal );
588 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700589
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800590 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300591 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
592 XMLTest( "Query attribute: double as double", 2.0, dVal );
593 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700594
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800595 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300596 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
597 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700598
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800599 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300600 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
601 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700602
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800603 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300604 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
605 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800606 }
607
608 {
609 const char* str = "<doc/>";
610
611 XMLDocument doc;
612 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300613 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800614
615 XMLElement* ele = doc.FirstChildElement();
616
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800617 int iVal, iVal2;
618 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800619
620 ele->SetAttribute( "str", "strValue" );
621 ele->SetAttribute( "int", 1 );
622 ele->SetAttribute( "double", -1.0 );
623
624 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300625 {
626 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
627 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
628 }
629 {
630 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
631 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
632 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800633
Dmitry-Me2087a272017-07-10 18:13:07 +0300634 {
635 int queryResult = ele->QueryAttribute( "int", &iVal2 );
636 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
637 }
638 {
639 int queryResult = ele->QueryAttribute( "double", &dVal2 );
640 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
641 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800642
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300643 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800644 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
645 XMLTest( "Attribute round trip. int.", 1, iVal );
646 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800647 XMLTest( "Alternate query", true, iVal == iVal2 );
648 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700649 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
650 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800651 }
652
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800653 {
654 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300655 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300656 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800657
658 // Get the attribute "value" from the "Russian" element and check it.
659 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700660 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800661 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
662
663 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
664
665 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
666 0xd1U, 0x81U, 0xd1U, 0x81U,
667 0xd0U, 0xbaU, 0xd0U, 0xb8U,
668 0xd0U, 0xb9U, 0 };
669 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
670
671 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
672 XMLTest( "UTF-8: Browsing russian element name.",
673 russianText,
674 text->Value() );
675
676 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400677 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300678 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800679
680 // Check the round trip.
Dmitry-Me520009e2017-08-10 17:50:03 +0300681 bool roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800682
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200683 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300684 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
685
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300686 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300687 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800688
689 if ( saved && verify )
690 {
Dmitry-Me520009e2017-08-10 17:50:03 +0300691 roundTripOkay = true;
PKEuSc28ba3a2012-07-16 03:08:47 -0700692 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800693 while ( fgets( verifyBuf, 256, verify ) )
694 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700695 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800696 fgets( savedBuf, 256, saved );
697 NullLineEndings( verifyBuf );
698 NullLineEndings( savedBuf );
699
700 if ( strcmp( verifyBuf, savedBuf ) )
701 {
702 printf( "verify:%s<\n", verifyBuf );
703 printf( "saved :%s<\n", savedBuf );
Dmitry-Me520009e2017-08-10 17:50:03 +0300704 roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800705 break;
706 }
707 }
708 }
709 if ( saved )
710 fclose( saved );
711 if ( verify )
712 fclose( verify );
Dmitry-Me520009e2017-08-10 17:50:03 +0300713 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800714 }
715
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800716 // --------GetText()-----------
717 {
718 const char* str = "<foo>This is text</foo>";
719 XMLDocument doc;
720 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300721 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800722 const XMLElement* element = doc.RootElement();
723
724 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
725
726 str = "<foo><b>This is text</b></foo>";
727 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300728 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800729 element = doc.RootElement();
730
731 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
732 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800733
Lee Thomasond6277762012-02-22 16:00:12 -0800734
Uli Kusterer321072e2014-01-21 01:57:38 +0100735 // --------SetText()-----------
736 {
737 const char* str = "<foo></foo>";
738 XMLDocument doc;
739 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300740 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100741 XMLElement* element = doc.RootElement();
742
Lee Thomason9c0678a2014-01-24 10:18:27 -0800743 element->SetText("darkness.");
744 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100745
Lee Thomason9c0678a2014-01-24 10:18:27 -0800746 element->SetText("blue flame.");
747 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100748
749 str = "<foo/>";
750 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300751 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100752 element = doc.RootElement();
753
Lee Thomason9c0678a2014-01-24 10:18:27 -0800754 element->SetText("The driver");
755 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100756
Lee Thomason9c0678a2014-01-24 10:18:27 -0800757 element->SetText("<b>horses</b>");
758 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
759 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100760
761 str = "<foo><bar>Text in nested element</bar></foo>";
762 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300763 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100764 element = doc.RootElement();
765
Lee Thomason9c0678a2014-01-24 10:18:27 -0800766 element->SetText("wolves");
767 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800768
769 str = "<foo/>";
770 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300771 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800772 element = doc.RootElement();
773
774 element->SetText( "str" );
775 XMLTest( "SetText types", "str", element->GetText() );
776
777 element->SetText( 1 );
778 XMLTest( "SetText types", "1", element->GetText() );
779
780 element->SetText( 1U );
781 XMLTest( "SetText types", "1", element->GetText() );
782
783 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200784 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800785
786 element->SetText( 1.5f );
787 XMLTest( "SetText types", "1.5", element->GetText() );
788
789 element->SetText( 1.5 );
790 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100791 }
792
Lee Thomason51c12712016-06-04 20:18:49 -0700793 // ---------- Attributes ---------
794 {
795 static const int64_t BIG = -123456789012345678;
796 XMLDocument doc;
797 XMLElement* element = doc.NewElement("element");
798 doc.InsertFirstChild(element);
799
800 {
801 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300802 {
803 int v = 0;
804 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
805 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
806 XMLTest("Attribute: int", -100, v, true);
807 }
808 {
809 int v = 0;
810 int queryResult = element->QueryAttribute("attrib", &v);
811 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
812 XMLTest("Attribute: int", -100, v, true);
813 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700814 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700815 }
816 {
817 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300818 {
819 unsigned v = 0;
820 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
821 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
822 XMLTest("Attribute: unsigned", unsigned(100), v, true);
823 }
824 {
825 unsigned v = 0;
826 int queryResult = element->QueryAttribute("attrib", &v);
827 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
828 XMLTest("Attribute: unsigned", unsigned(100), v, true);
829 }
Lee Thomason5b00e062017-12-28 14:07:47 -0800830 {
831 const char* v = "failed";
832 int queryResult = element->QueryStringAttribute("not-attrib", &v);
833 XMLTest("Attribute: string default", false, queryResult == XML_SUCCESS);
834 queryResult = element->QueryStringAttribute("attrib", &v);
835 XMLTest("Attribute: string", (int)XML_SUCCESS, queryResult, true);
836 XMLTest("Attribute: string", "100", v);
837 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700838 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700839 }
840 {
841 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300842 {
843 int64_t v = 0;
844 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
845 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
846 XMLTest("Attribute: int64_t", BIG, v, true);
847 }
848 {
849 int64_t v = 0;
850 int queryResult = element->QueryAttribute("attrib", &v);
851 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
852 XMLTest("Attribute: int64_t", BIG, v, true);
853 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700854 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700855 }
856 {
857 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300858 {
859 bool v = false;
860 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
861 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
862 XMLTest("Attribute: bool", true, v, true);
863 }
864 {
865 bool v = false;
866 int queryResult = element->QueryAttribute("attrib", &v);
867 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
868 XMLTest("Attribute: bool", true, v, true);
869 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700870 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700871 }
872 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800873 element->SetAttribute("attrib", true);
874 const char* result = element->Attribute("attrib");
875 XMLTest("Bool true is 'true'", "true", result);
876
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800877 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800878 element->SetAttribute("attrib", true);
879 result = element->Attribute("attrib");
880 XMLTest("Bool true is '1'", "1", result);
881
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800882 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800883 }
884 {
Lee Thomason51c12712016-06-04 20:18:49 -0700885 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300886 {
887 double v = 0;
888 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
889 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
890 XMLTest("Attribute: double", 100.0, v, true);
891 }
892 {
893 double v = 0;
894 int queryResult = element->QueryAttribute("attrib", &v);
895 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
896 XMLTest("Attribute: double", 100.0, v, true);
897 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700898 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700899 }
900 {
901 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300902 {
903 float v = 0;
904 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
905 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
906 XMLTest("Attribute: float", 100.0f, v, true);
907 }
908 {
909 float v = 0;
910 int queryResult = element->QueryAttribute("attrib", &v);
911 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
912 XMLTest("Attribute: float", 100.0f, v, true);
913 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700914 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700915 }
916 {
917 element->SetText(BIG);
918 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300919 XMLError queryResult = element->QueryInt64Text(&v);
920 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700921 XMLTest("Element: int64_t", BIG, v, true);
922 }
923 }
924
925 // ---------- XMLPrinter stream mode ------
926 {
927 {
Dmitry-Mec0fad292017-08-09 19:05:42 +0300928 FILE* printerfp = fopen("resources/out/printer.xml", "w");
929 XMLTest("Open printer.xml", true, printerfp != 0);
Lee Thomason51c12712016-06-04 20:18:49 -0700930 XMLPrinter printer(printerfp);
931 printer.OpenElement("foo");
932 printer.PushAttribute("attrib-text", "text");
933 printer.PushAttribute("attrib-int", int(1));
934 printer.PushAttribute("attrib-unsigned", unsigned(2));
935 printer.PushAttribute("attrib-int64", int64_t(3));
936 printer.PushAttribute("attrib-bool", true);
937 printer.PushAttribute("attrib-double", 4.0);
938 printer.CloseElement();
939 fclose(printerfp);
940 }
941 {
942 XMLDocument doc;
Dmitry-Mec0fad292017-08-09 19:05:42 +0300943 doc.LoadFile("resources/out/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300944 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700945
946 const XMLDocument& cdoc = doc;
947
948 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
949 XMLTest("attrib-text", "text", attrib->Value(), true);
950 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
951 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
952 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
953 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
954 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
955 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
956 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
957 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
958 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
959 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
960 }
961
962 }
963
Uli Kusterer321072e2014-01-21 01:57:38 +0100964
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800965 // ---------- CDATA ---------------
966 {
967 const char* str = "<xmlElement>"
968 "<![CDATA["
969 "I am > the rules!\n"
970 "...since I make symbolic puns"
971 "]]>"
972 "</xmlElement>";
973 XMLDocument doc;
974 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300975 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800977
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300978 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
979 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800980 false );
981 }
982
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800983 // ----------- CDATA -------------
984 {
985 const char* str = "<xmlElement>"
986 "<![CDATA["
987 "<b>I am > the rules!</b>\n"
988 "...since I make symbolic puns"
989 "]]>"
990 "</xmlElement>";
991 XMLDocument doc;
992 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300993 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800994 doc.Print();
995
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300996 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800997 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300998 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800999 false );
1000 }
1001
1002 // InsertAfterChild causes crash.
1003 {
1004 // InsertBeforeChild and InsertAfterChild causes crash.
1005 XMLDocument doc;
1006 XMLElement* parent = doc.NewElement( "Parent" );
1007 doc.InsertFirstChild( parent );
1008
1009 XMLElement* childText0 = doc.NewElement( "childText0" );
1010 XMLElement* childText1 = doc.NewElement( "childText1" );
1011
1012 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001013 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001014 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001015 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001016
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001017 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001018 }
Lee Thomasond6277762012-02-22 16:00:12 -08001019
1020 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001021 // Entities not being written correctly.
1022 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -08001023
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001024 const char* passages =
1025 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1026 "<passages count=\"006\" formatversion=\"20020620\">"
1027 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1028 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
1029 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -08001030
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001031 XMLDocument doc;
1032 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001033 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001034 XMLElement* psg = doc.RootElement()->FirstChildElement();
1035 const char* context = psg->Attribute( "context" );
1036 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 -08001037
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001038 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -08001039
Dmitry-Me520009e2017-08-10 17:50:03 +03001040 const char* textFilePath = "resources/out/textfile.txt";
1041 FILE* textfile = fopen( textFilePath, "w" );
1042 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001043 if ( textfile )
1044 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001045 XMLPrinter streamer( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001046 bool acceptResult = psg->Accept( &streamer );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001047 fclose( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001048 XMLTest( "Entity transformation: Accept", true, acceptResult );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001049 }
Thomas Roß0922b732012-09-23 16:31:22 +02001050
Dmitry-Me520009e2017-08-10 17:50:03 +03001051 textfile = fopen( textFilePath, "r" );
1052 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001053 if ( textfile )
1054 {
1055 char buf[ 1024 ];
1056 fgets( buf, 1024, textfile );
1057 XMLTest( "Entity transformation: write. ",
1058 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1059 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1060 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001061 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001062 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001063 }
1064
1065 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001066 // Suppress entities.
1067 const char* passages =
1068 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1069 "<passages count=\"006\" formatversion=\"20020620\">"
1070 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1071 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001072
Lee Thomason6f381b72012-03-02 12:59:39 -08001073 XMLDocument doc( false );
1074 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001075 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001076
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001077 XMLTest( "No entity parsing.",
1078 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1079 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1080 XMLTest( "No entity parsing.", "Crazy &ttk;",
1081 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001082 doc.Print();
1083 }
1084
1085 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001086 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001087
1088 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001089 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001090 XMLTest( "dot in names", false, doc.Error() );
1091 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1092 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001093 }
1094
1095 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001096 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001097
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001098 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001099 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001100 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001101
1102 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1103 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001104 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001105 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001106 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001107
1108 {
1109 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001110 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001111 const char* doctype =
1112 "<?xml version=\"1.0\" ?>"
1113 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1114 "<!ELEMENT title (#PCDATA)>"
1115 "<!ELEMENT books (title,authors)>"
1116 "<element />";
1117
1118 XMLDocument doc;
1119 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001120 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001121 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001122 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001123 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001124 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001125 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001126 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001127
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001128 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1129 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1130
1131 }
1132
1133 {
1134 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001135 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001136 "<!-- Somewhat<evil> -->";
1137 XMLDocument doc;
1138 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001139 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001140
1141 XMLComment* comment = doc.FirstChild()->ToComment();
1142
1143 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1144 }
1145 {
1146 // Double attributes
1147 const char* doctype = "<element attr='red' attr='blue' />";
1148
1149 XMLDocument doc;
1150 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001151
Lee Thomason2fa81722012-11-09 12:37:46 -08001152 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 -08001153 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001154 }
1155
1156 {
1157 // Embedded null in stream.
1158 const char* doctype = "<element att\0r='red' attr='blue' />";
1159
1160 XMLDocument doc;
1161 doc.Parse( doctype );
1162 XMLTest( "Embedded null throws error.", true, doc.Error() );
1163 }
1164
1165 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001166 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001167 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001168 XMLDocument doc;
1169 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001170 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001171 }
1172
1173 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001174 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1175 const char* str = " ";
1176 XMLDocument doc;
1177 doc.Parse( str );
1178 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1179 }
1180
1181 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001182 // Low entities
1183 XMLDocument doc;
1184 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001185 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001186 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001187 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001188 doc.Print();
1189 }
1190
1191 {
1192 // Attribute values with trailing quotes not handled correctly
1193 XMLDocument doc;
1194 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001195 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001196 }
1197
1198 {
1199 // [ 1663758 ] Failure to report error on bad XML
1200 XMLDocument xml;
1201 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001202 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001203 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001204 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001205 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001206 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001207 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001208
1209
1210 {
1211 // [ 1475201 ] TinyXML parses entities in comments
1212 XMLDocument xml;
1213 xml.Parse("<!-- declarations for <head> & <body> -->"
1214 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001215 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001216
1217 XMLNode* e0 = xml.FirstChild();
1218 XMLNode* e1 = e0->NextSibling();
1219 XMLComment* c0 = e0->ToComment();
1220 XMLComment* c1 = e1->ToComment();
1221
1222 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1223 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1224 }
1225
1226 {
1227 XMLDocument xml;
1228 xml.Parse( "<Parent>"
1229 "<child1 att=''/>"
1230 "<!-- With this comment, child2 will not be parsed! -->"
1231 "<child2 att=''/>"
1232 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001233 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001234 xml.Print();
1235
1236 int count = 0;
1237
1238 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1239 ele;
1240 ele = ele->NextSibling() )
1241 {
1242 ++count;
1243 }
1244
1245 XMLTest( "Comments iterate correctly.", 3, count );
1246 }
1247
1248 {
1249 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1250 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1251 buf[60] = 239;
1252 buf[61] = 0;
1253
1254 XMLDocument doc;
1255 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001256 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001257 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001258
1259
1260 {
1261 // bug 1827248 Error while parsing a little bit malformed file
1262 // Actually not malformed - should work.
1263 XMLDocument xml;
1264 xml.Parse( "<attributelist> </attributelist >" );
1265 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1266 }
1267
1268 {
1269 // This one must not result in an infinite loop
1270 XMLDocument xml;
1271 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001272 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001273 XMLTest( "Infinite loop test.", true, true );
1274 }
1275#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001276 {
1277 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1278 XMLDocument doc;
1279 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001280 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001281
1282 XMLDocument clone;
1283 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1284 XMLNode* copy = node->ShallowClone( &clone );
1285 clone.InsertEndChild( copy );
1286 }
1287
1288 clone.Print();
1289
1290 int count=0;
1291 const XMLNode* a=clone.FirstChild();
1292 const XMLNode* b=doc.FirstChild();
1293 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1294 ++count;
1295 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1296 }
1297 XMLTest( "Clone and Equal", 4, count );
1298 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001299
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001300 {
Lee Thomason7085f002017-06-01 18:09:43 -07001301 // Deep Cloning of root element.
1302 XMLDocument doc2;
1303 XMLPrinter printer1;
1304 {
1305 // Make sure doc1 is deleted before we test doc2
1306 const char* xml =
1307 "<root>"
1308 " <child1 foo='bar'/>"
1309 " <!-- comment thing -->"
1310 " <child2 val='1'>Text</child2>"
1311 "</root>";
1312 XMLDocument doc;
1313 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001314 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001315
1316 doc.Print(&printer1);
1317 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1318 doc2.InsertFirstChild(root);
1319 }
1320 XMLPrinter printer2;
1321 doc2.Print(&printer2);
1322
1323 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1324 }
1325
1326 {
1327 // Deep Cloning of sub element.
1328 XMLDocument doc2;
1329 XMLPrinter printer1;
1330 {
1331 // Make sure doc1 is deleted before we test doc2
1332 const char* xml =
1333 "<?xml version ='1.0'?>"
1334 "<root>"
1335 " <child1 foo='bar'/>"
1336 " <!-- comment thing -->"
1337 " <child2 val='1'>Text</child2>"
1338 "</root>";
1339 XMLDocument doc;
1340 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001341 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001342
1343 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001344 bool acceptResult = subElement->Accept(&printer1);
1345 XMLTest( "Accept before deep cloning", true, acceptResult );
Lee Thomason7085f002017-06-01 18:09:43 -07001346
1347 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1348 doc2.InsertFirstChild(clonedSubElement);
1349 }
1350 XMLPrinter printer2;
1351 doc2.Print(&printer2);
1352
1353 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1354 }
1355
1356 {
1357 // Deep cloning of document.
1358 XMLDocument doc2;
1359 XMLPrinter printer1;
1360 {
1361 // Make sure doc1 is deleted before we test doc2
1362 const char* xml =
1363 "<?xml version ='1.0'?>"
1364 "<!-- Top level comment. -->"
1365 "<root>"
1366 " <child1 foo='bar'/>"
1367 " <!-- comment thing -->"
1368 " <child2 val='1'>Text</child2>"
1369 "</root>";
1370 XMLDocument doc;
1371 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001372 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001373 doc.Print(&printer1);
1374
1375 doc.DeepCopy(&doc2);
1376 }
1377 XMLPrinter printer2;
1378 doc2.Print(&printer2);
1379
1380 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1381 }
1382
1383
1384 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001385 // This shouldn't crash.
1386 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001387 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001388 {
1389 doc.PrintError();
1390 }
1391 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1392 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001393
Lee Thomason5e3803c2012-04-16 08:57:05 -07001394 {
1395 // Attribute ordering.
1396 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1397 XMLDocument doc;
1398 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001399 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001400 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001401
Lee Thomason5e3803c2012-04-16 08:57:05 -07001402 const XMLAttribute* a = ele->FirstAttribute();
1403 XMLTest( "Attribute order", "1", a->Value() );
1404 a = a->Next();
1405 XMLTest( "Attribute order", "2", a->Value() );
1406 a = a->Next();
1407 XMLTest( "Attribute order", "3", a->Value() );
1408 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001409
Lee Thomason5e3803c2012-04-16 08:57:05 -07001410 ele->DeleteAttribute( "attrib2" );
1411 a = ele->FirstAttribute();
1412 XMLTest( "Attribute order", "1", a->Value() );
1413 a = a->Next();
1414 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001415
Lee Thomason5e3803c2012-04-16 08:57:05 -07001416 ele->DeleteAttribute( "attrib1" );
1417 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001418 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001419 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001420
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001421 {
1422 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001423 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1424 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1425 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1426 XMLDocument doc0;
1427 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001428 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001429 XMLDocument doc1;
1430 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001431 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001432 XMLDocument doc2;
1433 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001434 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001435
Lee Thomason78a773d2012-07-02 10:10:19 -07001436 XMLElement* ele = 0;
1437 ele = doc0.FirstChildElement();
1438 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1439 ele = doc1.FirstChildElement();
1440 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1441 ele = doc2.FirstChildElement();
1442 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001443 }
1444
1445 {
1446 // Make sure we don't go into an infinite loop.
1447 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1448 XMLDocument doc;
1449 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001450 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001451 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1452 XMLElement* ele1 = ele0->NextSiblingElement();
1453 bool equal = ele0->ShallowEqual( ele1 );
1454
1455 XMLTest( "Infinite loop in shallow equal.", true, equal );
1456 }
1457
Lee Thomason5708f812012-03-28 17:46:41 -07001458 // -------- Handles ------------
1459 {
1460 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1461 XMLDocument doc;
1462 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001463 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001464
1465 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001466 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001467
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001468 XMLHandle docH( doc );
1469 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001470 XMLTest( "Handle, dne, mutable", true, ele == 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001471 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001472
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001473 {
1474 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1475 XMLDocument doc;
1476 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001477 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001478 XMLConstHandle docH( doc );
1479
1480 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001481 XMLTest( "Handle, success, const", "sub", ele->Value() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001482
1483 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001484 XMLTest( "Handle, dne, const", true, ele == 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001485 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001486 {
1487 // Default Declaration & BOM
1488 XMLDocument doc;
1489 doc.InsertEndChild( doc.NewDeclaration() );
1490 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001491
Lee Thomasonf68c4382012-04-28 14:37:11 -07001492 XMLPrinter printer;
1493 doc.Print( &printer );
1494
1495 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001496 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1497 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001498 }
Lee Thomason21be8822012-07-15 17:27:22 -07001499 {
1500 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1501 XMLDocument doc;
1502 doc.Parse( xml );
1503 XMLTest( "Ill formed XML", true, doc.Error() );
1504 }
1505
1506 // QueryXYZText
1507 {
1508 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1509 XMLDocument doc;
1510 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001511 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001512
1513 const XMLElement* pointElement = doc.RootElement();
1514
Dmitry-Me43c019d2017-08-02 18:05:23 +03001515 {
1516 int intValue = 0;
1517 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1518 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1519 XMLTest( "QueryIntText", 1, intValue, false );
1520 }
Lee Thomason21be8822012-07-15 17:27:22 -07001521
Dmitry-Me43c019d2017-08-02 18:05:23 +03001522 {
1523 unsigned unsignedValue = 0;
1524 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1525 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1526 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1527 }
Lee Thomason21be8822012-07-15 17:27:22 -07001528
Dmitry-Me43c019d2017-08-02 18:05:23 +03001529 {
1530 float floatValue = 0;
1531 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1532 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1533 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1534 }
Lee Thomason21be8822012-07-15 17:27:22 -07001535
Dmitry-Me43c019d2017-08-02 18:05:23 +03001536 {
1537 double doubleValue = 0;
1538 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1539 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1540 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1541 }
1542
1543 {
1544 bool boolValue = false;
1545 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1546 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1547 XMLTest( "QueryBoolText", true, boolValue, false );
1548 }
Lee Thomason21be8822012-07-15 17:27:22 -07001549 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001550
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001551 {
1552 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1553 XMLDocument doc;
1554 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001555 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001556 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001557
1558 {
1559 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1560 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001561 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001562 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001563 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001564
1565 {
1566 const char* xml = "<3lement></3lement>";
1567 XMLDocument doc;
1568 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001569 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001570 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001571
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001572 {
1573 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1574 XMLDocument doc;
1575 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001576 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001577 }
1578
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001579 {
1580 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001581 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001582 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001583 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001584 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001585 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001586 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001587 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001588 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001589 }
Dmitry-Me985ea1f2017-08-28 18:36:29 +03001590
1591 {
1592 XMLDocument doc;
1593 XMLTest( "No error initially", false, doc.Error() );
1594 XMLError error = doc.Parse( "This is not XML" );
1595 XMLTest( "Error after invalid XML", true, doc.Error() );
1596 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1597 doc.Clear();
1598 XMLTest( "No error after Clear()", false, doc.Error() );
1599 }
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001600
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001601 // ----------- Whitespace ------------
1602 {
1603 const char* xml = "<element>"
1604 "<a> This \nis &apos; text &apos; </a>"
1605 "<b> This is &apos; text &apos; \n</b>"
1606 "<c>This is &apos; \n\n text &apos;</c>"
1607 "</element>";
1608 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1609 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001610 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001611
1612 const XMLElement* element = doc.FirstChildElement();
1613 for( const XMLElement* parent = element->FirstChildElement();
1614 parent;
1615 parent = parent->NextSiblingElement() )
1616 {
1617 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1618 }
1619 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001620
Lee Thomasonae9ab072012-10-24 10:17:53 -07001621#if 0
1622 {
1623 // Passes if assert doesn't fire.
1624 XMLDocument xmlDoc;
1625
1626 xmlDoc.NewDeclaration();
1627 xmlDoc.NewComment("Configuration file");
1628
1629 XMLElement *root = xmlDoc.NewElement("settings");
1630 root->SetAttribute("version", 2);
1631 }
1632#endif
1633
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001634 {
1635 const char* xml = "<element> </element>";
1636 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1637 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001638 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001639 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1640 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001641
Lee Thomason5b0a6772012-11-19 13:54:42 -08001642 {
1643 // An assert should not fire.
1644 const char* xml = "<element/>";
1645 XMLDocument doc;
1646 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001647 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001648 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1649 XMLTest( "Tracking unused elements", true, ele != 0, false );
1650 }
1651
Lee Thomasona6412ac2012-12-13 15:39:11 -08001652
1653 {
1654 const char* xml = "<parent><child>abc</child></parent>";
1655 XMLDocument doc;
1656 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001657 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001658 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1659
1660 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001661 bool acceptResult = ele->Accept( &printer );
1662 XMLTest( "Accept of sub-element", true, acceptResult );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001663 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1664 }
1665
1666
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001667 {
1668 XMLDocument doc;
1669 XMLError error = doc.LoadFile( "resources/empty.xml" );
1670 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001671 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001672 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001673 }
1674
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001675 {
1676 // BOM preservation
1677 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1678 {
1679 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001680 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001681 XMLPrinter printer;
1682 doc.Print( &printer );
1683
1684 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1685 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001686 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001687 }
1688 {
1689 XMLDocument doc;
1690 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001691 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001692 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1693
1694 XMLPrinter printer;
1695 doc.Print( &printer );
1696 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1697 }
1698 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001699
Michael Daumlinged523282013-10-23 07:47:29 +02001700 {
1701 // Insertion with Removal
1702 const char* xml = "<?xml version=\"1.0\" ?>"
1703 "<root>"
1704 "<one>"
1705 "<subtree>"
1706 "<elem>element 1</elem>text<!-- comment -->"
1707 "</subtree>"
1708 "</one>"
1709 "<two/>"
1710 "</root>";
1711 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1712 "<root>"
1713 "<one/>"
1714 "<two>"
1715 "<subtree>"
1716 "<elem>element 1</elem>text<!-- comment -->"
1717 "</subtree>"
1718 "</two>"
1719 "</root>";
1720 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1721 "<root>"
1722 "<one/>"
1723 "<subtree>"
1724 "<elem>element 1</elem>text<!-- comment -->"
1725 "</subtree>"
1726 "<two/>"
1727 "</root>";
1728 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1729 "<root>"
1730 "<one/>"
1731 "<two/>"
1732 "<subtree>"
1733 "<elem>element 1</elem>text<!-- comment -->"
1734 "</subtree>"
1735 "</root>";
1736
1737 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001738 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001739 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001740 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1741 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1742 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001743 XMLPrinter printer1(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001744 bool acceptResult = doc.Accept(&printer1);
1745 XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001746 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001747
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001748 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001749 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001750 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1751 two = doc.RootElement()->FirstChildElement("two");
1752 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001753 XMLPrinter printer2(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001754 acceptResult = doc.Accept(&printer2);
1755 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001756 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001757
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001758 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001759 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001760 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1761 subtree = one->FirstChildElement("subtree");
1762 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001763 XMLPrinter printer3(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001764 acceptResult = doc.Accept(&printer3);
1765 XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001766 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001767
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001768 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001769 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001770 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1771 two = doc.RootElement()->FirstChildElement("two");
1772 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001773 XMLPrinter printer4(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001774 acceptResult = doc.Accept(&printer4);
1775 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001776 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001777 }
1778
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001779 {
1780 const char* xml = "<svg width = \"128\" height = \"128\">"
1781 " <text> </text>"
1782 "</svg>";
1783 XMLDocument doc;
1784 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001785 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001786 doc.Print();
1787 }
1788
Lee Thomason92e521b2014-11-15 17:45:51 -08001789 {
1790 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001791 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1792 XMLDocument doc;
1793 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001794 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001795 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001796 }
1797
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001798#if 1
1799 // the question being explored is what kind of print to use:
1800 // https://github.com/leethomason/tinyxml2/issues/63
1801 {
1802 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1803 const char* xml = "<element/>";
1804 XMLDocument doc;
1805 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001806 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001807 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1808 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1809 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1810 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1811 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1812 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1813
1814 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1815 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1816 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1817 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1818 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1819 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1820
1821 doc.Print();
1822
1823 /* The result of this test is platform, compiler, and library version dependent. :("
1824 XMLPrinter printer;
1825 doc.Print( &printer );
1826 XMLTest( "Float and double formatting.",
1827 "<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",
1828 printer.CStr(),
1829 true );
1830 */
1831 }
1832#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001833
1834 {
1835 // Issue #184
1836 // If it doesn't assert, it passes. Caused by objects
1837 // getting created during parsing which are then
1838 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001839 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001840 {
1841 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001842 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001843 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001844 }
1845 {
1846 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001847 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001848 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001849 doc.Clear();
1850 }
1851 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001852
1853 {
1854 // If this doesn't assert in DEBUG, all is well.
1855 tinyxml2::XMLDocument doc;
1856 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1857 doc.DeleteNode(pRoot);
1858 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001859
Dmitry-Mee5790db2017-07-28 17:54:38 +03001860 {
1861 XMLDocument doc;
1862 XMLElement* root = doc.NewElement( "Root" );
1863 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1864 doc.InsertEndChild( root );
1865 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1866 }
1867
1868 {
1869 // If this doesn't assert in DEBUG, all is well.
1870 XMLDocument doc;
1871 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1872 XMLElement* linkedRoot = doc.NewElement( "Root" );
1873 doc.InsertFirstChild( linkedRoot );
1874 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1875 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1876 }
1877
Dmitry-Me8b67d742014-12-22 11:35:12 +03001878 {
1879 // Should not assert in DEBUG
1880 XMLPrinter printer;
1881 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001882
Dmitry-Me6f51c802015-03-14 13:25:03 +03001883 {
1884 // Issue 291. Should not crash
1885 const char* xml = "&#0</a>";
1886 XMLDocument doc;
1887 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001888 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001889
1890 XMLPrinter printer;
1891 doc.Print( &printer );
1892 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001893 {
1894 // Issue 299. Can print elements that are not linked in.
1895 // Will crash if issue not fixed.
1896 XMLDocument doc;
1897 XMLElement* newElement = doc.NewElement( "printme" );
1898 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001899 bool acceptResult = newElement->Accept( &printer );
1900 XMLTest( "printme - Accept()", true, acceptResult );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001901 // Delete the node to avoid possible memory leak report in debug output
1902 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001903 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001904 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001905 // Issue 302. Clear errors from LoadFile/SaveFile
1906 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001907 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001908 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001909 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001910 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001911 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001912 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001913
Dmitry-Med9852a52015-03-25 10:17:49 +03001914 {
1915 // If a document fails to load then subsequent
1916 // successful loads should clear the error
1917 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001918 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001919 doc.LoadFile( "resources/no-such-file.xml" );
1920 XMLTest( "No such file - should fail", true, doc.Error() );
1921
1922 doc.LoadFile( "resources/dream.xml" );
1923 XMLTest( "Error should be cleared", false, doc.Error() );
1924 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301925
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301926 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001927 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001928 const char* xml0 = "<?xml version=\"1.0\" ?>"
1929 " <!-- xml version=\"1.1\" -->"
1930 "<first />";
1931 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001932 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001933 "<first />";
1934 const char* xml2 = "<first />"
1935 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001936 const char* xml3 = "<first></first>"
1937 "<?xml version=\"1.0\" ?>";
1938
1939 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1940
Lee Thomason85492022015-05-22 11:07:45 -07001941 XMLDocument doc;
1942 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001943 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001944 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001945 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001946 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001947 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001948 doc.Parse(xml3);
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(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001951 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301952 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001953
Lee Thomason85492022015-05-22 11:07:45 -07001954 {
1955 // No matter - before or after successfully parsing a text -
Dmitry-Me26043362017-08-30 17:40:15 +03001956 // calling XMLDocument::Value() used to cause an assert in debug.
1957 // Null must be retured.
Lee Thomason85492022015-05-22 11:07:45 -07001958 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1959 "<first />"
1960 "<second />";
1961 XMLDocument* doc = new XMLDocument();
1962 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1963 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001964 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001965 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1966 delete doc;
1967 }
1968
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001969 {
1970 XMLDocument doc;
1971 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
Dmitry-Med3f6c632017-08-30 17:43:14 +03001972 const XMLError error = static_cast<XMLError>(i);
Lee Thomasonf49b9652017-10-11 10:57:49 -07001973 const char* name = XMLDocument::ErrorIDToName(error);
1974 XMLTest( "ErrorName() after ClearError()", true, name != 0 );
1975 XMLTest( "ErrorName() after ClearError()", true, strlen(name) > 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001976 }
1977 }
1978
Lee Thomason816d3fa2017-06-05 14:35:55 -07001979 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001980 // Evil memory leaks.
1981 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1982 // and NOT added to the XMLDocument, what happens?
1983 //
1984 // Previously (buggy):
1985 // The memory would be free'd when the XMLDocument is
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001986 // destructed. But the XMLElement destructor wasn't called, so
1987 // memory allocated for the XMLElement text would not be free'd.
1988 // In practice this meant strings allocated for the XMLElement
1989 // text would be leaked. An edge case, but annoying.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001990 // Now:
Dmitry-Mea9e75d12017-09-08 19:05:23 +03001991 // The XMLElement destructor is called. But the unlinked nodes
1992 // have to be tracked using a list. This has a minor performance
1993 // impact that can become significant if you have a lot of
1994 // unlinked nodes. (But why would you do that?)
1995 // The only way to see this bug was in a Visual C++ runtime debug heap
1996 // leak tracker. This is compiled in by default on Windows Debug and
1997 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
Lee Thomason816d3fa2017-06-05 14:35:55 -07001998 {
1999 XMLDocument doc;
2000 doc.NewElement("LEAK 1");
2001 }
2002 {
2003 XMLDocument doc;
2004 XMLElement* ele = doc.NewElement("LEAK 2");
2005 doc.DeleteNode(ele);
2006 }
2007 }
2008
Lee Thomason224ef772017-06-16 09:45:26 -07002009 {
2010 // Crashing reported via email.
2011 const char* xml =
2012 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07002013 "<property name='track_name'>voice</property>"
2014 "<property name='audio_track'>1</property>"
2015 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2016 "<blank length = '1' />"
2017 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2018 "<blank length = '2' />"
2019 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2020 "<blank length = '1' />"
2021 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07002022 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07002023
Lee Thomason224ef772017-06-16 09:45:26 -07002024 // It's not a good idea to delete elements as you walk the
2025 // list. I'm not sure this technically should work; but it's
2026 // an interesting test case.
2027 XMLDocument doc;
2028 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002029 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03002030
2031 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07002032 XMLTest("Crash bug parsing", true, playlist != 0);
2033
Dmitry-Meb41e24a2017-09-27 18:51:01 +03002034 {
2035 const char* elementName = "entry";
2036 XMLElement* entry = playlist->FirstChildElement(elementName);
2037 XMLTest("Crash bug parsing", true, entry != 0);
2038 while (entry) {
2039 XMLElement* todelete = entry;
2040 entry = entry->NextSiblingElement(elementName);
2041 playlist->DeleteChild(todelete);
2042 }
2043 entry = playlist->FirstChildElement(elementName);
2044 XMLTest("Crash bug parsing", true, entry == 0);
2045 }
2046 {
2047 const char* elementName = "blank";
2048 XMLElement* blank = playlist->FirstChildElement(elementName);
2049 XMLTest("Crash bug parsing", true, blank != 0);
2050 while (blank) {
2051 XMLElement* todelete = blank;
2052 blank = blank->NextSiblingElement(elementName);
2053 playlist->DeleteChild(todelete);
2054 }
2055 XMLTest("Crash bug parsing", true, blank == 0);
2056 }
Lee Thomason224ef772017-06-16 09:45:26 -07002057
2058 tinyxml2::XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002059 const bool acceptResult = playlist->Accept(&printer);
2060 XMLTest("Crash bug parsing - Accept()", true, acceptResult);
Lee Thomason224ef772017-06-16 09:45:26 -07002061 printf("%s\n", printer.CStr());
2062
Lee Thomason82bb0742017-06-16 09:48:20 -07002063 // No test; it only need to not crash.
2064 // Still, wrap it up with a sanity check
2065 int nProperty = 0;
2066 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2067 nProperty++;
2068 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002069 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07002070 }
2071
kezenatorec694152016-11-26 17:21:43 +10002072 // ----------- Line Number Tracking --------------
2073 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002074 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002075 {
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002076 TestUtil() : str() {}
2077
kezenatorec694152016-11-26 17:21:43 +10002078 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2079 {
2080 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002081 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002082
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002083 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002084 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002085 XMLTest(testString, expected_error, parseError);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002086 XMLTest(testString, expectedLine, doc.ErrorLineNum());
kezenatorec694152016-11-26 17:21:43 +10002087 };
2088
2089 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2090 {
2091 XMLDocument doc;
2092 doc.Parse(docStr);
2093 XMLTest(testString, false, doc.Error());
2094 TestDocLines(testString, doc, expectedLines);
2095 }
2096
2097 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2098 {
2099 XMLDocument doc;
2100 doc.LoadFile(file_name);
2101 XMLTest(testString, false, doc.Error());
2102 TestDocLines(testString, doc, expectedLines);
2103 }
2104
2105 private:
2106 DynArray<char, 10> str;
2107
2108 void Push(char type, int lineNum)
2109 {
2110 str.Push(type);
2111 str.Push(char('0' + (lineNum / 10)));
2112 str.Push(char('0' + (lineNum % 10)));
2113 }
2114
2115 bool VisitEnter(const XMLDocument& doc)
2116 {
kezenator19d8ea82016-11-29 19:50:27 +10002117 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002118 return true;
2119 }
2120 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2121 {
kezenator19d8ea82016-11-29 19:50:27 +10002122 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002123 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002124 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002125 return true;
2126 }
2127 bool Visit(const XMLDeclaration& declaration)
2128 {
kezenator19d8ea82016-11-29 19:50:27 +10002129 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002130 return true;
2131 }
2132 bool Visit(const XMLText& text)
2133 {
kezenator19d8ea82016-11-29 19:50:27 +10002134 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002135 return true;
2136 }
2137 bool Visit(const XMLComment& comment)
2138 {
kezenator19d8ea82016-11-29 19:50:27 +10002139 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002140 return true;
2141 }
2142 bool Visit(const XMLUnknown& unknown)
2143 {
kezenator19d8ea82016-11-29 19:50:27 +10002144 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002145 return true;
2146 }
2147
2148 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2149 {
2150 str.Clear();
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002151 const bool acceptResult = doc.Accept(this);
2152 XMLTest(testString, true, acceptResult);
kezenatorec694152016-11-26 17:21:43 +10002153 str.Push(0);
2154 XMLTest(testString, expectedLines, str.Mem());
2155 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002156 } tester;
kezenatorec694152016-11-26 17:21:43 +10002157
Lee Thomasone90e9012016-12-24 07:34:39 -08002158 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2159 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2160 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2161 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2162 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2163 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2164 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2165 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2166 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2167 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2168 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002169
Lee Thomasone90e9012016-12-24 07:34:39 -08002170 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002171 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002172
2173 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2174 "<root a='b' \n" // 2 Element Attribute
2175 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2176 "newline in text \n" // 4 Text
2177 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2178 " cdata test ]]><!-- comment -->\n" // 6 Comment
2179 "<! unknown></root>", // 7 Unknown
2180
kezenatorec694152016-11-26 17:21:43 +10002181 "D01L01E02A02A03T03E03T04E05T05C06U07");
2182
Lee Thomasone90e9012016-12-24 07:34:39 -08002183 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002184 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002185
2186 "\r\n" // 1 Doc (arguably should be line 2)
2187 "<?xml version=\"1.0\"?>\n" // 2 DecL
2188 "<root>\r\n" // 3 Element
2189 "\n" // 4
2190 "text contining new line \n" // 5 Text
2191 " and also containing crlf \r\n" // 6
2192 "<sub><![CDATA[\n" // 7 Element Text
2193 "cdata containing new line \n" // 8
2194 " and also containing cflr\r\n" // 9
2195 "]]></sub><sub2/></root>", // 10 Element
2196
kezenatorec694152016-11-26 17:21:43 +10002197 "D01L02E03T05E07T07E10");
2198
Lee Thomasone90e9012016-12-24 07:34:39 -08002199 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002200 "LineNumbers-File",
2201 "resources/utf8test.xml",
2202 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2203 }
2204
Lee Thomasonf49b9652017-10-11 10:57:49 -07002205 {
2206 const char* xml = "<Hello>Text</Error>";
2207 XMLDocument doc;
2208 doc.Parse(xml);
2209 XMLTest("Test mismatched elements.", true, doc.Error());
2210 XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2211 // For now just make sure calls work & doesn't crash.
2212 // May solidify the error output in the future.
2213 printf("%s\n", doc.ErrorStr());
2214 doc.PrintError();
2215 }
2216
Lee Thomason85492022015-05-22 11:07:45 -07002217 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002218 {
2219#if defined( _MSC_VER )
2220 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002221 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002222#endif
2223
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002224 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002225 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002226 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002227 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002228 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002229
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002230 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002231 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002232 size_t bytesRead = fread(mem, 1, size, perfFP);
2233 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002234 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002235 mem[size] = 0;
2236
2237#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002238 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002239#else
2240 clock_t cstart = clock();
2241#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002242 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002243 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002244 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002245 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002246 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002247 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002248 }
2249#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002250 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002251#else
2252 clock_t cend = clock();
2253#endif
Dmitry-Me1ab85872017-08-10 17:28:10 +03002254 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002255
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002256 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002257
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002258 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002259#ifdef DEBUG
2260 "DEBUG";
2261#else
2262 "Release";
2263#endif
2264
2265#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002266 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002267#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002268 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002269#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002270 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002271 }
2272
Dmitry-Mede381df2017-07-26 18:05:25 +03002273#if defined( _MSC_VER ) && defined( DEBUG )
2274 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002275 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002276
2277 _CrtMemState diffMemState;
2278 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2279 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002280
2281 {
2282 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2283 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2284 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002285 }
2286#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002287
2288 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002289
2290 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002291}