blob: 7931b7254af10420cf3a32915a939164431e99a2 [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 {
389 static const char* test = "<element>Text before.</element>";
390 XMLDocument doc;
391 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300392 XMLTest( "Element text before", false, doc.Error() );
Lee Thomason2c85a712012-01-31 08:24:24 -0800393 XMLElement* root = doc.FirstChildElement();
394 XMLElement* newElement = doc.NewElement( "Subelement" );
395 root->InsertEndChild( newElement );
396 doc.Print();
397 }
Lee Thomasond1983222012-02-06 08:41:24 -0800398 {
399 XMLDocument* doc = new XMLDocument();
400 static const char* test = "<element><sub/></element>";
401 doc->Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300402 XMLTest( "Element with sub element", false, doc->Error() );
Lee Thomasond1983222012-02-06 08:41:24 -0800403 delete doc;
404 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800405 {
Dmitry-Me8e063702017-08-01 17:40:40 +0300406 // Test: Programmatic DOM nodes insertion return values
407 XMLDocument doc;
408
409 XMLNode* first = doc.NewElement( "firstElement" );
410 XMLTest( "New element", true, first != 0 );
411 XMLNode* firstAfterInsertion = doc.InsertFirstChild( first );
412 XMLTest( "New element inserted first", true, firstAfterInsertion == first );
413
414 XMLNode* last = doc.NewElement( "lastElement" );
415 XMLTest( "New element", true, last != 0 );
416 XMLNode* lastAfterInsertion = doc.InsertEndChild( last );
417 XMLTest( "New element inserted last", true, lastAfterInsertion == last );
418
419 XMLNode* middle = doc.NewElement( "middleElement" );
420 XMLTest( "New element", true, middle != 0 );
421 XMLNode* middleAfterInsertion = doc.InsertAfterChild( first, middle );
422 XMLTest( "New element inserted middle", true, middleAfterInsertion == middle );
423 }
424 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800425 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800426 // Build:
427 // <element>
428 // <!--comment-->
429 // <sub attrib="1" />
430 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800431 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800432 // <element>
433
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800434 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800435 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
436
437 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
438 for( int i=0; i<3; ++i ) {
439 sub[i]->SetAttribute( "attrib", i );
440 }
441 element->InsertEndChild( sub[2] );
442 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700443 comment->SetUserData((void*)2);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800444 element->InsertAfterChild( comment, sub[0] );
445 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800446 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800447 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800448 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
449 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
450 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700451 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800452 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Lee Thomasonc9445462016-07-17 22:53:48 -0700453 XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800454
455 // And now deletion:
456 element->DeleteChild( sub[2] );
457 doc->DeleteNode( comment );
458
459 element->FirstChildElement()->SetAttribute( "attrib", true );
460 element->LastChildElement()->DeleteAttribute( "attrib" );
461
462 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300463 const int defaultIntValue = 10;
464 const int replacementIntValue = 20;
465 int value1 = defaultIntValue;
466 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300467 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
468 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300469 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
470 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800471
472 doc->Print();
473
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700474 {
475 XMLPrinter streamer;
476 doc->Print( &streamer );
477 printf( "%s", streamer.CStr() );
478 }
479 {
480 XMLPrinter streamer( 0, true );
481 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200482 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700483 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700484 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300485 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700486 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300487 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800488 delete doc;
489 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800490 {
491 // Test: Dream
492 // XML1 : 1,187,569 bytes in 31,209 allocations
493 // XML2 : 469,073 bytes in 323 allocations
494 //int newStart = gNew;
495 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300496 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300497 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800498
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400499 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300500 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800501 doc.PrintError();
502
503 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400504 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800505 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
506 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
507 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
508 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400509 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800510 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400511 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800512
513 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400514 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300515 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800516 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400517 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800518 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
519 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
520 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
521 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400522 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800523
524 //gNewTotal = gNew - newStart;
525 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800526
527
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800528 {
529 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
530 "<passages count=\"006\" formatversion=\"20020620\">\n"
531 " <wrong error>\n"
532 "</passages>";
533
534 XMLDocument doc;
535 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300536 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800537 }
538
539 {
540 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
541
542 XMLDocument doc;
543 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300544 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800545
546 XMLElement* ele = doc.FirstChildElement();
547
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300548 int iVal;
549 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550 double dVal;
551
552 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300553 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
554 XMLTest( "Query attribute: int as double", 1, (int)dVal );
555 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700556
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800557 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300558 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
559 XMLTest( "Query attribute: double as double", 2.0, dVal );
560 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700561
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800562 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300563 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
564 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700565
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800566 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300567 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
568 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700569
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800570 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300571 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
572 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800573 }
574
575 {
576 const char* str = "<doc/>";
577
578 XMLDocument doc;
579 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300580 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800581
582 XMLElement* ele = doc.FirstChildElement();
583
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800584 int iVal, iVal2;
585 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800586
587 ele->SetAttribute( "str", "strValue" );
588 ele->SetAttribute( "int", 1 );
589 ele->SetAttribute( "double", -1.0 );
590
591 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300592 {
593 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
594 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
595 }
596 {
597 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
598 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
599 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800600
Dmitry-Me2087a272017-07-10 18:13:07 +0300601 {
602 int queryResult = ele->QueryAttribute( "int", &iVal2 );
603 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
604 }
605 {
606 int queryResult = ele->QueryAttribute( "double", &dVal2 );
607 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
608 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800609
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300610 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800611 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
612 XMLTest( "Attribute round trip. int.", 1, iVal );
613 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800614 XMLTest( "Alternate query", true, iVal == iVal2 );
615 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700616 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
617 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800618 }
619
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800620 {
621 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300622 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300623 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800624
625 // Get the attribute "value" from the "Russian" element and check it.
626 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700627 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800628 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
629
630 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
631
632 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
633 0xd1U, 0x81U, 0xd1U, 0x81U,
634 0xd0U, 0xbaU, 0xd0U, 0xb8U,
635 0xd0U, 0xb9U, 0 };
636 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
637
638 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
639 XMLTest( "UTF-8: Browsing russian element name.",
640 russianText,
641 text->Value() );
642
643 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400644 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300645 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800646
647 // Check the round trip.
Dmitry-Me520009e2017-08-10 17:50:03 +0300648 bool roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800649
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200650 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300651 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
652
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300653 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300654 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800655
656 if ( saved && verify )
657 {
Dmitry-Me520009e2017-08-10 17:50:03 +0300658 roundTripOkay = true;
PKEuSc28ba3a2012-07-16 03:08:47 -0700659 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800660 while ( fgets( verifyBuf, 256, verify ) )
661 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700662 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800663 fgets( savedBuf, 256, saved );
664 NullLineEndings( verifyBuf );
665 NullLineEndings( savedBuf );
666
667 if ( strcmp( verifyBuf, savedBuf ) )
668 {
669 printf( "verify:%s<\n", verifyBuf );
670 printf( "saved :%s<\n", savedBuf );
Dmitry-Me520009e2017-08-10 17:50:03 +0300671 roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800672 break;
673 }
674 }
675 }
676 if ( saved )
677 fclose( saved );
678 if ( verify )
679 fclose( verify );
Dmitry-Me520009e2017-08-10 17:50:03 +0300680 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800681 }
682
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800683 // --------GetText()-----------
684 {
685 const char* str = "<foo>This is text</foo>";
686 XMLDocument doc;
687 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300688 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800689 const XMLElement* element = doc.RootElement();
690
691 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
692
693 str = "<foo><b>This is text</b></foo>";
694 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300695 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800696 element = doc.RootElement();
697
698 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
699 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800700
Lee Thomasond6277762012-02-22 16:00:12 -0800701
Uli Kusterer321072e2014-01-21 01:57:38 +0100702 // --------SetText()-----------
703 {
704 const char* str = "<foo></foo>";
705 XMLDocument doc;
706 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300707 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100708 XMLElement* element = doc.RootElement();
709
Lee Thomason9c0678a2014-01-24 10:18:27 -0800710 element->SetText("darkness.");
711 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100712
Lee Thomason9c0678a2014-01-24 10:18:27 -0800713 element->SetText("blue flame.");
714 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100715
716 str = "<foo/>";
717 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300718 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100719 element = doc.RootElement();
720
Lee Thomason9c0678a2014-01-24 10:18:27 -0800721 element->SetText("The driver");
722 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100723
Lee Thomason9c0678a2014-01-24 10:18:27 -0800724 element->SetText("<b>horses</b>");
725 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
726 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100727
728 str = "<foo><bar>Text in nested element</bar></foo>";
729 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300730 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100731 element = doc.RootElement();
732
Lee Thomason9c0678a2014-01-24 10:18:27 -0800733 element->SetText("wolves");
734 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800735
736 str = "<foo/>";
737 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300738 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800739 element = doc.RootElement();
740
741 element->SetText( "str" );
742 XMLTest( "SetText types", "str", element->GetText() );
743
744 element->SetText( 1 );
745 XMLTest( "SetText types", "1", element->GetText() );
746
747 element->SetText( 1U );
748 XMLTest( "SetText types", "1", element->GetText() );
749
750 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200751 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800752
753 element->SetText( 1.5f );
754 XMLTest( "SetText types", "1.5", element->GetText() );
755
756 element->SetText( 1.5 );
757 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100758 }
759
Lee Thomason51c12712016-06-04 20:18:49 -0700760 // ---------- Attributes ---------
761 {
762 static const int64_t BIG = -123456789012345678;
763 XMLDocument doc;
764 XMLElement* element = doc.NewElement("element");
765 doc.InsertFirstChild(element);
766
767 {
768 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300769 {
770 int v = 0;
771 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
772 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
773 XMLTest("Attribute: int", -100, v, true);
774 }
775 {
776 int v = 0;
777 int queryResult = element->QueryAttribute("attrib", &v);
778 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
779 XMLTest("Attribute: int", -100, v, true);
780 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700781 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700782 }
783 {
784 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300785 {
786 unsigned v = 0;
787 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
788 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
789 XMLTest("Attribute: unsigned", unsigned(100), v, true);
790 }
791 {
792 unsigned v = 0;
793 int queryResult = element->QueryAttribute("attrib", &v);
794 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
795 XMLTest("Attribute: unsigned", unsigned(100), v, true);
796 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700797 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700798 }
799 {
800 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300801 {
802 int64_t v = 0;
803 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
804 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
805 XMLTest("Attribute: int64_t", BIG, v, true);
806 }
807 {
808 int64_t v = 0;
809 int queryResult = element->QueryAttribute("attrib", &v);
810 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
811 XMLTest("Attribute: int64_t", BIG, v, true);
812 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700813 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700814 }
815 {
816 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300817 {
818 bool v = false;
819 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
820 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
821 XMLTest("Attribute: bool", true, v, true);
822 }
823 {
824 bool v = false;
825 int queryResult = element->QueryAttribute("attrib", &v);
826 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
827 XMLTest("Attribute: bool", true, v, true);
828 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700829 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700830 }
831 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800832 element->SetAttribute("attrib", true);
833 const char* result = element->Attribute("attrib");
834 XMLTest("Bool true is 'true'", "true", result);
835
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800836 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800837 element->SetAttribute("attrib", true);
838 result = element->Attribute("attrib");
839 XMLTest("Bool true is '1'", "1", result);
840
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800841 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800842 }
843 {
Lee Thomason51c12712016-06-04 20:18:49 -0700844 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300845 {
846 double v = 0;
847 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
848 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
849 XMLTest("Attribute: double", 100.0, v, true);
850 }
851 {
852 double v = 0;
853 int queryResult = element->QueryAttribute("attrib", &v);
854 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
855 XMLTest("Attribute: double", 100.0, v, true);
856 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700857 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700858 }
859 {
860 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300861 {
862 float v = 0;
863 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
864 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
865 XMLTest("Attribute: float", 100.0f, v, true);
866 }
867 {
868 float v = 0;
869 int queryResult = element->QueryAttribute("attrib", &v);
870 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
871 XMLTest("Attribute: float", 100.0f, v, true);
872 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700873 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700874 }
875 {
876 element->SetText(BIG);
877 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300878 XMLError queryResult = element->QueryInt64Text(&v);
879 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700880 XMLTest("Element: int64_t", BIG, v, true);
881 }
882 }
883
884 // ---------- XMLPrinter stream mode ------
885 {
886 {
Dmitry-Mec0fad292017-08-09 19:05:42 +0300887 FILE* printerfp = fopen("resources/out/printer.xml", "w");
888 XMLTest("Open printer.xml", true, printerfp != 0);
Lee Thomason51c12712016-06-04 20:18:49 -0700889 XMLPrinter printer(printerfp);
890 printer.OpenElement("foo");
891 printer.PushAttribute("attrib-text", "text");
892 printer.PushAttribute("attrib-int", int(1));
893 printer.PushAttribute("attrib-unsigned", unsigned(2));
894 printer.PushAttribute("attrib-int64", int64_t(3));
895 printer.PushAttribute("attrib-bool", true);
896 printer.PushAttribute("attrib-double", 4.0);
897 printer.CloseElement();
898 fclose(printerfp);
899 }
900 {
901 XMLDocument doc;
Dmitry-Mec0fad292017-08-09 19:05:42 +0300902 doc.LoadFile("resources/out/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300903 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700904
905 const XMLDocument& cdoc = doc;
906
907 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
908 XMLTest("attrib-text", "text", attrib->Value(), true);
909 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
910 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
911 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
912 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
913 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
914 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
915 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
916 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
917 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
918 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
919 }
920
921 }
922
Uli Kusterer321072e2014-01-21 01:57:38 +0100923
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800924 // ---------- CDATA ---------------
925 {
926 const char* str = "<xmlElement>"
927 "<![CDATA["
928 "I am > the rules!\n"
929 "...since I make symbolic puns"
930 "]]>"
931 "</xmlElement>";
932 XMLDocument doc;
933 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300934 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800935 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800936
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300937 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
938 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800939 false );
940 }
941
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800942 // ----------- CDATA -------------
943 {
944 const char* str = "<xmlElement>"
945 "<![CDATA["
946 "<b>I am > the rules!</b>\n"
947 "...since I make symbolic puns"
948 "]]>"
949 "</xmlElement>";
950 XMLDocument doc;
951 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300952 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800953 doc.Print();
954
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300955 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800956 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300957 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800958 false );
959 }
960
961 // InsertAfterChild causes crash.
962 {
963 // InsertBeforeChild and InsertAfterChild causes crash.
964 XMLDocument doc;
965 XMLElement* parent = doc.NewElement( "Parent" );
966 doc.InsertFirstChild( parent );
967
968 XMLElement* childText0 = doc.NewElement( "childText0" );
969 XMLElement* childText1 = doc.NewElement( "childText1" );
970
971 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +0300972 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800973 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +0300974 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800975
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300976 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800977 }
Lee Thomasond6277762012-02-22 16:00:12 -0800978
979 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800980 // Entities not being written correctly.
981 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800982
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800983 const char* passages =
984 "<?xml version=\"1.0\" standalone=\"no\" ?>"
985 "<passages count=\"006\" formatversion=\"20020620\">"
986 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
987 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
988 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800989
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800990 XMLDocument doc;
991 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +0300992 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800993 XMLElement* psg = doc.RootElement()->FirstChildElement();
994 const char* context = psg->Attribute( "context" );
995 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 -0800996
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800997 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800998
Dmitry-Me520009e2017-08-10 17:50:03 +0300999 const char* textFilePath = "resources/out/textfile.txt";
1000 FILE* textfile = fopen( textFilePath, "w" );
1001 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001002 if ( textfile )
1003 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001004 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001005 psg->Accept( &streamer );
1006 fclose( textfile );
1007 }
Thomas Roß0922b732012-09-23 16:31:22 +02001008
Dmitry-Me520009e2017-08-10 17:50:03 +03001009 textfile = fopen( textFilePath, "r" );
1010 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001011 if ( textfile )
1012 {
1013 char buf[ 1024 ];
1014 fgets( buf, 1024, textfile );
1015 XMLTest( "Entity transformation: write. ",
1016 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1017 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1018 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001019 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001020 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001021 }
1022
1023 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001024 // Suppress entities.
1025 const char* passages =
1026 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1027 "<passages count=\"006\" formatversion=\"20020620\">"
1028 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1029 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001030
Lee Thomason6f381b72012-03-02 12:59:39 -08001031 XMLDocument doc( false );
1032 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001033 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001034
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001035 XMLTest( "No entity parsing.",
1036 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1037 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1038 XMLTest( "No entity parsing.", "Crazy &ttk;",
1039 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001040 doc.Print();
1041 }
1042
1043 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001044 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001045
1046 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001047 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001048 XMLTest( "dot in names", false, doc.Error() );
1049 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1050 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001051 }
1052
1053 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001054 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001055
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001056 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001057 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001058 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001059
1060 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1061 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001062 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001063 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001064 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001065
1066 {
1067 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001068 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001069 const char* doctype =
1070 "<?xml version=\"1.0\" ?>"
1071 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1072 "<!ELEMENT title (#PCDATA)>"
1073 "<!ELEMENT books (title,authors)>"
1074 "<element />";
1075
1076 XMLDocument doc;
1077 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001078 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001079 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001080 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001081 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001082 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001083 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001084 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001085
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001086 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1087 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1088
1089 }
1090
1091 {
1092 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001093 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001094 "<!-- Somewhat<evil> -->";
1095 XMLDocument doc;
1096 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001097 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001098
1099 XMLComment* comment = doc.FirstChild()->ToComment();
1100
1101 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1102 }
1103 {
1104 // Double attributes
1105 const char* doctype = "<element attr='red' attr='blue' />";
1106
1107 XMLDocument doc;
1108 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001109
Lee Thomason2fa81722012-11-09 12:37:46 -08001110 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 -08001111 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001112 }
1113
1114 {
1115 // Embedded null in stream.
1116 const char* doctype = "<element att\0r='red' attr='blue' />";
1117
1118 XMLDocument doc;
1119 doc.Parse( doctype );
1120 XMLTest( "Embedded null throws error.", true, doc.Error() );
1121 }
1122
1123 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001124 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001125 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001126 XMLDocument doc;
1127 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001128 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001129 }
1130
1131 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001132 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1133 const char* str = " ";
1134 XMLDocument doc;
1135 doc.Parse( str );
1136 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1137 }
1138
1139 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001140 // Low entities
1141 XMLDocument doc;
1142 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001143 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001144 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001145 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001146 doc.Print();
1147 }
1148
1149 {
1150 // Attribute values with trailing quotes not handled correctly
1151 XMLDocument doc;
1152 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001153 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001154 }
1155
1156 {
1157 // [ 1663758 ] Failure to report error on bad XML
1158 XMLDocument xml;
1159 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001160 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001161 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001162 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001163 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001164 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001165 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001166
1167
1168 {
1169 // [ 1475201 ] TinyXML parses entities in comments
1170 XMLDocument xml;
1171 xml.Parse("<!-- declarations for <head> & <body> -->"
1172 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001173 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001174
1175 XMLNode* e0 = xml.FirstChild();
1176 XMLNode* e1 = e0->NextSibling();
1177 XMLComment* c0 = e0->ToComment();
1178 XMLComment* c1 = e1->ToComment();
1179
1180 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1181 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1182 }
1183
1184 {
1185 XMLDocument xml;
1186 xml.Parse( "<Parent>"
1187 "<child1 att=''/>"
1188 "<!-- With this comment, child2 will not be parsed! -->"
1189 "<child2 att=''/>"
1190 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001191 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001192 xml.Print();
1193
1194 int count = 0;
1195
1196 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1197 ele;
1198 ele = ele->NextSibling() )
1199 {
1200 ++count;
1201 }
1202
1203 XMLTest( "Comments iterate correctly.", 3, count );
1204 }
1205
1206 {
1207 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1208 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1209 buf[60] = 239;
1210 buf[61] = 0;
1211
1212 XMLDocument doc;
1213 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001214 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001215 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001216
1217
1218 {
1219 // bug 1827248 Error while parsing a little bit malformed file
1220 // Actually not malformed - should work.
1221 XMLDocument xml;
1222 xml.Parse( "<attributelist> </attributelist >" );
1223 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1224 }
1225
1226 {
1227 // This one must not result in an infinite loop
1228 XMLDocument xml;
1229 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001230 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001231 XMLTest( "Infinite loop test.", true, true );
1232 }
1233#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001234 {
1235 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1236 XMLDocument doc;
1237 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001238 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001239
1240 XMLDocument clone;
1241 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1242 XMLNode* copy = node->ShallowClone( &clone );
1243 clone.InsertEndChild( copy );
1244 }
1245
1246 clone.Print();
1247
1248 int count=0;
1249 const XMLNode* a=clone.FirstChild();
1250 const XMLNode* b=doc.FirstChild();
1251 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1252 ++count;
1253 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1254 }
1255 XMLTest( "Clone and Equal", 4, count );
1256 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001257
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001258 {
Lee Thomason7085f002017-06-01 18:09:43 -07001259 // Deep Cloning of root element.
1260 XMLDocument doc2;
1261 XMLPrinter printer1;
1262 {
1263 // Make sure doc1 is deleted before we test doc2
1264 const char* xml =
1265 "<root>"
1266 " <child1 foo='bar'/>"
1267 " <!-- comment thing -->"
1268 " <child2 val='1'>Text</child2>"
1269 "</root>";
1270 XMLDocument doc;
1271 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001272 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001273
1274 doc.Print(&printer1);
1275 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1276 doc2.InsertFirstChild(root);
1277 }
1278 XMLPrinter printer2;
1279 doc2.Print(&printer2);
1280
1281 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1282 }
1283
1284 {
1285 // Deep Cloning of sub element.
1286 XMLDocument doc2;
1287 XMLPrinter printer1;
1288 {
1289 // Make sure doc1 is deleted before we test doc2
1290 const char* xml =
1291 "<?xml version ='1.0'?>"
1292 "<root>"
1293 " <child1 foo='bar'/>"
1294 " <!-- comment thing -->"
1295 " <child2 val='1'>Text</child2>"
1296 "</root>";
1297 XMLDocument doc;
1298 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001299 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001300
1301 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1302 subElement->Accept(&printer1);
1303
1304 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1305 doc2.InsertFirstChild(clonedSubElement);
1306 }
1307 XMLPrinter printer2;
1308 doc2.Print(&printer2);
1309
1310 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1311 }
1312
1313 {
1314 // Deep cloning of document.
1315 XMLDocument doc2;
1316 XMLPrinter printer1;
1317 {
1318 // Make sure doc1 is deleted before we test doc2
1319 const char* xml =
1320 "<?xml version ='1.0'?>"
1321 "<!-- Top level comment. -->"
1322 "<root>"
1323 " <child1 foo='bar'/>"
1324 " <!-- comment thing -->"
1325 " <child2 val='1'>Text</child2>"
1326 "</root>";
1327 XMLDocument doc;
1328 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001329 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001330 doc.Print(&printer1);
1331
1332 doc.DeepCopy(&doc2);
1333 }
1334 XMLPrinter printer2;
1335 doc2.Print(&printer2);
1336
1337 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1338 }
1339
1340
1341 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001342 // This shouldn't crash.
1343 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001344 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001345 {
1346 doc.PrintError();
1347 }
1348 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1349 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001350
Lee Thomason5e3803c2012-04-16 08:57:05 -07001351 {
1352 // Attribute ordering.
1353 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1354 XMLDocument doc;
1355 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001356 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001357 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001358
Lee Thomason5e3803c2012-04-16 08:57:05 -07001359 const XMLAttribute* a = ele->FirstAttribute();
1360 XMLTest( "Attribute order", "1", a->Value() );
1361 a = a->Next();
1362 XMLTest( "Attribute order", "2", a->Value() );
1363 a = a->Next();
1364 XMLTest( "Attribute order", "3", a->Value() );
1365 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001366
Lee Thomason5e3803c2012-04-16 08:57:05 -07001367 ele->DeleteAttribute( "attrib2" );
1368 a = ele->FirstAttribute();
1369 XMLTest( "Attribute order", "1", a->Value() );
1370 a = a->Next();
1371 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001372
Lee Thomason5e3803c2012-04-16 08:57:05 -07001373 ele->DeleteAttribute( "attrib1" );
1374 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001375 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001376 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001377
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001378 {
1379 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001380 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1381 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1382 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1383 XMLDocument doc0;
1384 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001385 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001386 XMLDocument doc1;
1387 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001388 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001389 XMLDocument doc2;
1390 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001391 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001392
Lee Thomason78a773d2012-07-02 10:10:19 -07001393 XMLElement* ele = 0;
1394 ele = doc0.FirstChildElement();
1395 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1396 ele = doc1.FirstChildElement();
1397 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1398 ele = doc2.FirstChildElement();
1399 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001400 }
1401
1402 {
1403 // Make sure we don't go into an infinite loop.
1404 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1405 XMLDocument doc;
1406 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001407 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001408 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1409 XMLElement* ele1 = ele0->NextSiblingElement();
1410 bool equal = ele0->ShallowEqual( ele1 );
1411
1412 XMLTest( "Infinite loop in shallow equal.", true, equal );
1413 }
1414
Lee Thomason5708f812012-03-28 17:46:41 -07001415 // -------- Handles ------------
1416 {
1417 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1418 XMLDocument doc;
1419 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001420 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001421
1422 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001423 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001424
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001425 XMLHandle docH( doc );
1426 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001427 XMLTest( "Handle, dne, mutable", true, ele == 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001428 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001429
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001430 {
1431 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1432 XMLDocument doc;
1433 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001434 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001435 XMLConstHandle docH( doc );
1436
1437 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001438 XMLTest( "Handle, success, const", "sub", ele->Value() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001439
1440 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001441 XMLTest( "Handle, dne, const", true, ele == 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001442 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001443 {
1444 // Default Declaration & BOM
1445 XMLDocument doc;
1446 doc.InsertEndChild( doc.NewDeclaration() );
1447 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001448
Lee Thomasonf68c4382012-04-28 14:37:11 -07001449 XMLPrinter printer;
1450 doc.Print( &printer );
1451
1452 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001453 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1454 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001455 }
Lee Thomason21be8822012-07-15 17:27:22 -07001456 {
1457 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1458 XMLDocument doc;
1459 doc.Parse( xml );
1460 XMLTest( "Ill formed XML", true, doc.Error() );
1461 }
1462
1463 // QueryXYZText
1464 {
1465 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1466 XMLDocument doc;
1467 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001468 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001469
1470 const XMLElement* pointElement = doc.RootElement();
1471
Dmitry-Me43c019d2017-08-02 18:05:23 +03001472 {
1473 int intValue = 0;
1474 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1475 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1476 XMLTest( "QueryIntText", 1, intValue, false );
1477 }
Lee Thomason21be8822012-07-15 17:27:22 -07001478
Dmitry-Me43c019d2017-08-02 18:05:23 +03001479 {
1480 unsigned unsignedValue = 0;
1481 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1482 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1483 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1484 }
Lee Thomason21be8822012-07-15 17:27:22 -07001485
Dmitry-Me43c019d2017-08-02 18:05:23 +03001486 {
1487 float floatValue = 0;
1488 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1489 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1490 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1491 }
Lee Thomason21be8822012-07-15 17:27:22 -07001492
Dmitry-Me43c019d2017-08-02 18:05:23 +03001493 {
1494 double doubleValue = 0;
1495 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1496 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1497 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1498 }
1499
1500 {
1501 bool boolValue = false;
1502 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1503 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1504 XMLTest( "QueryBoolText", true, boolValue, false );
1505 }
Lee Thomason21be8822012-07-15 17:27:22 -07001506 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001507
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001508 {
1509 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1510 XMLDocument doc;
1511 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001512 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001513 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001514
1515 {
1516 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1517 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001518 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001519 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001520 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001521
1522 {
1523 const char* xml = "<3lement></3lement>";
1524 XMLDocument doc;
1525 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001526 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001527 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001528
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001529 {
1530 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1531 XMLDocument doc;
1532 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001533 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001534 }
1535
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001536 {
1537 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001538 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001539 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001540 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001541 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001542 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001543 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001544 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001545 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001546 }
1547
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001548 // ----------- Whitespace ------------
1549 {
1550 const char* xml = "<element>"
1551 "<a> This \nis &apos; text &apos; </a>"
1552 "<b> This is &apos; text &apos; \n</b>"
1553 "<c>This is &apos; \n\n text &apos;</c>"
1554 "</element>";
1555 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1556 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001557 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001558
1559 const XMLElement* element = doc.FirstChildElement();
1560 for( const XMLElement* parent = element->FirstChildElement();
1561 parent;
1562 parent = parent->NextSiblingElement() )
1563 {
1564 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1565 }
1566 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001567
Lee Thomasonae9ab072012-10-24 10:17:53 -07001568#if 0
1569 {
1570 // Passes if assert doesn't fire.
1571 XMLDocument xmlDoc;
1572
1573 xmlDoc.NewDeclaration();
1574 xmlDoc.NewComment("Configuration file");
1575
1576 XMLElement *root = xmlDoc.NewElement("settings");
1577 root->SetAttribute("version", 2);
1578 }
1579#endif
1580
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001581 {
1582 const char* xml = "<element> </element>";
1583 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1584 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001585 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001586 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1587 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001588
Lee Thomason5b0a6772012-11-19 13:54:42 -08001589 {
1590 // An assert should not fire.
1591 const char* xml = "<element/>";
1592 XMLDocument doc;
1593 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001594 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001595 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1596 XMLTest( "Tracking unused elements", true, ele != 0, false );
1597 }
1598
Lee Thomasona6412ac2012-12-13 15:39:11 -08001599
1600 {
1601 const char* xml = "<parent><child>abc</child></parent>";
1602 XMLDocument doc;
1603 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001604 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001605 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1606
1607 XMLPrinter printer;
1608 ele->Accept( &printer );
1609 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1610 }
1611
1612
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001613 {
1614 XMLDocument doc;
1615 XMLError error = doc.LoadFile( "resources/empty.xml" );
1616 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001617 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001618 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001619 }
1620
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001621 {
1622 // BOM preservation
1623 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1624 {
1625 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001626 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001627 XMLPrinter printer;
1628 doc.Print( &printer );
1629
1630 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1631 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001632 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001633 }
1634 {
1635 XMLDocument doc;
1636 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001637 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001638 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1639
1640 XMLPrinter printer;
1641 doc.Print( &printer );
1642 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1643 }
1644 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001645
Michael Daumlinged523282013-10-23 07:47:29 +02001646 {
1647 // Insertion with Removal
1648 const char* xml = "<?xml version=\"1.0\" ?>"
1649 "<root>"
1650 "<one>"
1651 "<subtree>"
1652 "<elem>element 1</elem>text<!-- comment -->"
1653 "</subtree>"
1654 "</one>"
1655 "<two/>"
1656 "</root>";
1657 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1658 "<root>"
1659 "<one/>"
1660 "<two>"
1661 "<subtree>"
1662 "<elem>element 1</elem>text<!-- comment -->"
1663 "</subtree>"
1664 "</two>"
1665 "</root>";
1666 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1667 "<root>"
1668 "<one/>"
1669 "<subtree>"
1670 "<elem>element 1</elem>text<!-- comment -->"
1671 "</subtree>"
1672 "<two/>"
1673 "</root>";
1674 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1675 "<root>"
1676 "<one/>"
1677 "<two/>"
1678 "<subtree>"
1679 "<elem>element 1</elem>text<!-- comment -->"
1680 "</subtree>"
1681 "</root>";
1682
1683 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001684 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001685 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001686 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1687 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1688 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001689 XMLPrinter printer1(0, true);
1690 doc.Accept(&printer1);
1691 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001692
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001693 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001694 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001695 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1696 two = doc.RootElement()->FirstChildElement("two");
1697 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001698 XMLPrinter printer2(0, true);
1699 doc.Accept(&printer2);
1700 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001701
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001702 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001703 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001704 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1705 subtree = one->FirstChildElement("subtree");
1706 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001707 XMLPrinter printer3(0, true);
1708 doc.Accept(&printer3);
1709 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001710
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001711 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001712 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001713 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1714 two = doc.RootElement()->FirstChildElement("two");
1715 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001716 XMLPrinter printer4(0, true);
1717 doc.Accept(&printer4);
1718 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001719 }
1720
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001721 {
1722 const char* xml = "<svg width = \"128\" height = \"128\">"
1723 " <text> </text>"
1724 "</svg>";
1725 XMLDocument doc;
1726 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001727 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001728 doc.Print();
1729 }
1730
Lee Thomason92e521b2014-11-15 17:45:51 -08001731 {
1732 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001733 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1734 XMLDocument doc;
1735 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001736 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001737 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001738 }
1739
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001740#if 1
1741 // the question being explored is what kind of print to use:
1742 // https://github.com/leethomason/tinyxml2/issues/63
1743 {
1744 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1745 const char* xml = "<element/>";
1746 XMLDocument doc;
1747 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001748 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001749 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1750 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1751 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1752 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1753 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1754 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1755
1756 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1757 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1758 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1759 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1760 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1761 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1762
1763 doc.Print();
1764
1765 /* The result of this test is platform, compiler, and library version dependent. :("
1766 XMLPrinter printer;
1767 doc.Print( &printer );
1768 XMLTest( "Float and double formatting.",
1769 "<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",
1770 printer.CStr(),
1771 true );
1772 */
1773 }
1774#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001775
1776 {
1777 // Issue #184
1778 // If it doesn't assert, it passes. Caused by objects
1779 // getting created during parsing which are then
1780 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001781 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001782 {
1783 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001784 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001785 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001786 }
1787 {
1788 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001789 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001790 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001791 doc.Clear();
1792 }
1793 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001794
1795 {
1796 // If this doesn't assert in DEBUG, all is well.
1797 tinyxml2::XMLDocument doc;
1798 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1799 doc.DeleteNode(pRoot);
1800 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001801
Dmitry-Mee5790db2017-07-28 17:54:38 +03001802 {
1803 XMLDocument doc;
1804 XMLElement* root = doc.NewElement( "Root" );
1805 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1806 doc.InsertEndChild( root );
1807 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1808 }
1809
1810 {
1811 // If this doesn't assert in DEBUG, all is well.
1812 XMLDocument doc;
1813 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1814 XMLElement* linkedRoot = doc.NewElement( "Root" );
1815 doc.InsertFirstChild( linkedRoot );
1816 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1817 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1818 }
1819
Dmitry-Me8b67d742014-12-22 11:35:12 +03001820 {
1821 // Should not assert in DEBUG
1822 XMLPrinter printer;
1823 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001824
Dmitry-Me6f51c802015-03-14 13:25:03 +03001825 {
1826 // Issue 291. Should not crash
1827 const char* xml = "&#0</a>";
1828 XMLDocument doc;
1829 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001830 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001831
1832 XMLPrinter printer;
1833 doc.Print( &printer );
1834 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001835 {
1836 // Issue 299. Can print elements that are not linked in.
1837 // Will crash if issue not fixed.
1838 XMLDocument doc;
1839 XMLElement* newElement = doc.NewElement( "printme" );
1840 XMLPrinter printer;
1841 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001842 // Delete the node to avoid possible memory leak report in debug output
1843 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001844 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001845 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001846 // Issue 302. Clear errors from LoadFile/SaveFile
1847 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001848 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001849 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001850 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001851 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001852 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001853 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001854
Dmitry-Med9852a52015-03-25 10:17:49 +03001855 {
1856 // If a document fails to load then subsequent
1857 // successful loads should clear the error
1858 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001859 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001860 doc.LoadFile( "resources/no-such-file.xml" );
1861 XMLTest( "No such file - should fail", true, doc.Error() );
1862
1863 doc.LoadFile( "resources/dream.xml" );
1864 XMLTest( "Error should be cleared", false, doc.Error() );
1865 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301866
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301867 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001868 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001869 const char* xml0 = "<?xml version=\"1.0\" ?>"
1870 " <!-- xml version=\"1.1\" -->"
1871 "<first />";
1872 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001873 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001874 "<first />";
1875 const char* xml2 = "<first />"
1876 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001877 const char* xml3 = "<first></first>"
1878 "<?xml version=\"1.0\" ?>";
1879
1880 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1881
Lee Thomason85492022015-05-22 11:07:45 -07001882 XMLDocument doc;
1883 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001884 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001885 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001886 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001887 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001888 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001889 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001890 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001891 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001892 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301893 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001894
Lee Thomason85492022015-05-22 11:07:45 -07001895 {
1896 // No matter - before or after successfully parsing a text -
1897 // calling XMLDocument::Value() causes an assert in debug.
1898 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1899 "<first />"
1900 "<second />";
1901 XMLDocument* doc = new XMLDocument();
1902 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1903 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001904 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001905 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1906 delete doc;
1907 }
1908
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001909 {
1910 XMLDocument doc;
1911 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001912 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001913 doc.ErrorName();
1914 }
1915 }
1916
Lee Thomason816d3fa2017-06-05 14:35:55 -07001917 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001918 // Evil memory leaks.
1919 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1920 // and NOT added to the XMLDocument, what happens?
1921 //
1922 // Previously (buggy):
1923 // The memory would be free'd when the XMLDocument is
1924 // destructed. But the destructor wasn't called, so that
1925 // memory allocated by the XMLElement would not be free'd.
1926 // In practice this meant strings allocated by the XMLElement
1927 // would leak. An edge case, but annoying.
1928 // Now:
1929 // The destructor is called. But the list of unlinked nodes
1930 // has to be tracked. This has a minor performance impact
1931 // that can become significant if you have a lot. (But why
1932 // would you do that?)
1933 // The only way to see this bug is in a leak tracker. This
1934 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001935 {
1936 XMLDocument doc;
1937 doc.NewElement("LEAK 1");
1938 }
1939 {
1940 XMLDocument doc;
1941 XMLElement* ele = doc.NewElement("LEAK 2");
1942 doc.DeleteNode(ele);
1943 }
1944 }
1945
Lee Thomason224ef772017-06-16 09:45:26 -07001946 {
1947 // Crashing reported via email.
1948 const char* xml =
1949 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001950 "<property name='track_name'>voice</property>"
1951 "<property name='audio_track'>1</property>"
1952 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1953 "<blank length = '1' />"
1954 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1955 "<blank length = '2' />"
1956 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1957 "<blank length = '1' />"
1958 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001959 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001960
Lee Thomason224ef772017-06-16 09:45:26 -07001961 // It's not a good idea to delete elements as you walk the
1962 // list. I'm not sure this technically should work; but it's
1963 // an interesting test case.
1964 XMLDocument doc;
1965 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001966 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03001967
1968 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001969 XMLTest("Crash bug parsing", true, playlist != 0);
1970
1971 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1972 XMLTest("Crash bug parsing", true, entry != 0);
1973 while (entry) {
1974 tinyxml2::XMLElement* todelete = entry;
1975 entry = entry->NextSiblingElement("entry");
1976 playlist->DeleteChild(todelete);
1977 };
1978 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1979 while (blank) {
1980 tinyxml2::XMLElement* todelete = blank;
1981 blank = blank->NextSiblingElement("blank");
1982 playlist->DeleteChild(todelete);
1983 };
1984
1985 tinyxml2::XMLPrinter printer;
1986 playlist->Accept(&printer);
1987 printf("%s\n", printer.CStr());
1988
Lee Thomason82bb0742017-06-16 09:48:20 -07001989 // No test; it only need to not crash.
1990 // Still, wrap it up with a sanity check
1991 int nProperty = 0;
1992 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1993 nProperty++;
1994 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001995 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07001996 }
1997
kezenatorec694152016-11-26 17:21:43 +10001998 // ----------- Line Number Tracking --------------
1999 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002000 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002001 {
2002 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2003 {
2004 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002005 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002006
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002007 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002008 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002009 XMLTest(testString, expected_error, parseError);
kezenatorec694152016-11-26 17:21:43 +10002010 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
2011 };
2012
2013 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2014 {
2015 XMLDocument doc;
2016 doc.Parse(docStr);
2017 XMLTest(testString, false, doc.Error());
2018 TestDocLines(testString, doc, expectedLines);
2019 }
2020
2021 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2022 {
2023 XMLDocument doc;
2024 doc.LoadFile(file_name);
2025 XMLTest(testString, false, doc.Error());
2026 TestDocLines(testString, doc, expectedLines);
2027 }
2028
2029 private:
2030 DynArray<char, 10> str;
2031
2032 void Push(char type, int lineNum)
2033 {
2034 str.Push(type);
2035 str.Push(char('0' + (lineNum / 10)));
2036 str.Push(char('0' + (lineNum % 10)));
2037 }
2038
2039 bool VisitEnter(const XMLDocument& doc)
2040 {
kezenator19d8ea82016-11-29 19:50:27 +10002041 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002042 return true;
2043 }
2044 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2045 {
kezenator19d8ea82016-11-29 19:50:27 +10002046 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002047 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002048 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002049 return true;
2050 }
2051 bool Visit(const XMLDeclaration& declaration)
2052 {
kezenator19d8ea82016-11-29 19:50:27 +10002053 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002054 return true;
2055 }
2056 bool Visit(const XMLText& text)
2057 {
kezenator19d8ea82016-11-29 19:50:27 +10002058 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002059 return true;
2060 }
2061 bool Visit(const XMLComment& comment)
2062 {
kezenator19d8ea82016-11-29 19:50:27 +10002063 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002064 return true;
2065 }
2066 bool Visit(const XMLUnknown& unknown)
2067 {
kezenator19d8ea82016-11-29 19:50:27 +10002068 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002069 return true;
2070 }
2071
2072 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2073 {
2074 str.Clear();
2075 doc.Accept(this);
2076 str.Push(0);
2077 XMLTest(testString, expectedLines, str.Mem());
2078 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002079 } tester;
kezenatorec694152016-11-26 17:21:43 +10002080
Lee Thomasone90e9012016-12-24 07:34:39 -08002081 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2082 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2083 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2084 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2085 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2086 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2087 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2088 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2089 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2090 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2091 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002092
Lee Thomasone90e9012016-12-24 07:34:39 -08002093 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002094 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002095
2096 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2097 "<root a='b' \n" // 2 Element Attribute
2098 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2099 "newline in text \n" // 4 Text
2100 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2101 " cdata test ]]><!-- comment -->\n" // 6 Comment
2102 "<! unknown></root>", // 7 Unknown
2103
kezenatorec694152016-11-26 17:21:43 +10002104 "D01L01E02A02A03T03E03T04E05T05C06U07");
2105
Lee Thomasone90e9012016-12-24 07:34:39 -08002106 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002107 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002108
2109 "\r\n" // 1 Doc (arguably should be line 2)
2110 "<?xml version=\"1.0\"?>\n" // 2 DecL
2111 "<root>\r\n" // 3 Element
2112 "\n" // 4
2113 "text contining new line \n" // 5 Text
2114 " and also containing crlf \r\n" // 6
2115 "<sub><![CDATA[\n" // 7 Element Text
2116 "cdata containing new line \n" // 8
2117 " and also containing cflr\r\n" // 9
2118 "]]></sub><sub2/></root>", // 10 Element
2119
kezenatorec694152016-11-26 17:21:43 +10002120 "D01L02E03T05E07T07E10");
2121
Lee Thomasone90e9012016-12-24 07:34:39 -08002122 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002123 "LineNumbers-File",
2124 "resources/utf8test.xml",
2125 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2126 }
2127
Lee Thomason85492022015-05-22 11:07:45 -07002128 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002129 {
2130#if defined( _MSC_VER )
2131 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002132 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002133#endif
2134
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002135 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002136 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002137 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002138 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002139 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002140
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002141 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002142 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002143 size_t bytesRead = fread(mem, 1, size, perfFP);
2144 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002145 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002146 mem[size] = 0;
2147
2148#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002149 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002150#else
2151 clock_t cstart = clock();
2152#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002153 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002154 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002155 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002156 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002157 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002158 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002159 }
Dmitry-Me68578f42017-07-03 18:21:23 +03002160 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002161#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002162 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002163#else
2164 clock_t cend = clock();
2165#endif
2166
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002167 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002168
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002169 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002170#ifdef DEBUG
2171 "DEBUG";
2172#else
2173 "Release";
2174#endif
2175
2176#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002177 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002178#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002179 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002180#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002181 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002182 }
2183
Dmitry-Mede381df2017-07-26 18:05:25 +03002184#if defined( _MSC_VER ) && defined( DEBUG )
2185 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002186 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002187
2188 _CrtMemState diffMemState;
2189 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2190 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002191
2192 {
2193 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2194 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2195 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002196 }
2197#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002198
2199 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002200
2201 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002202}