blob: 757ad2946b176e8617351e18a8b49ac0dab3d9fd [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.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800648 int okay = 0;
649
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200650 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300651 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800652
653 if ( saved && verify )
654 {
655 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700656 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800657 while ( fgets( verifyBuf, 256, verify ) )
658 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700659 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800660 fgets( savedBuf, 256, saved );
661 NullLineEndings( verifyBuf );
662 NullLineEndings( savedBuf );
663
664 if ( strcmp( verifyBuf, savedBuf ) )
665 {
666 printf( "verify:%s<\n", verifyBuf );
667 printf( "saved :%s<\n", savedBuf );
668 okay = 0;
669 break;
670 }
671 }
672 }
673 if ( saved )
674 fclose( saved );
675 if ( verify )
676 fclose( verify );
677 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
678 }
679
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800680 // --------GetText()-----------
681 {
682 const char* str = "<foo>This is text</foo>";
683 XMLDocument doc;
684 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300685 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800686 const XMLElement* element = doc.RootElement();
687
688 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
689
690 str = "<foo><b>This is text</b></foo>";
691 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300692 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800693 element = doc.RootElement();
694
695 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
696 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800697
Lee Thomasond6277762012-02-22 16:00:12 -0800698
Uli Kusterer321072e2014-01-21 01:57:38 +0100699 // --------SetText()-----------
700 {
701 const char* str = "<foo></foo>";
702 XMLDocument doc;
703 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300704 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100705 XMLElement* element = doc.RootElement();
706
Lee Thomason9c0678a2014-01-24 10:18:27 -0800707 element->SetText("darkness.");
708 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100709
Lee Thomason9c0678a2014-01-24 10:18:27 -0800710 element->SetText("blue flame.");
711 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100712
713 str = "<foo/>";
714 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300715 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100716 element = doc.RootElement();
717
Lee Thomason9c0678a2014-01-24 10:18:27 -0800718 element->SetText("The driver");
719 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100720
Lee Thomason9c0678a2014-01-24 10:18:27 -0800721 element->SetText("<b>horses</b>");
722 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
723 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100724
725 str = "<foo><bar>Text in nested element</bar></foo>";
726 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300727 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100728 element = doc.RootElement();
729
Lee Thomason9c0678a2014-01-24 10:18:27 -0800730 element->SetText("wolves");
731 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800732
733 str = "<foo/>";
734 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300735 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800736 element = doc.RootElement();
737
738 element->SetText( "str" );
739 XMLTest( "SetText types", "str", element->GetText() );
740
741 element->SetText( 1 );
742 XMLTest( "SetText types", "1", element->GetText() );
743
744 element->SetText( 1U );
745 XMLTest( "SetText types", "1", element->GetText() );
746
747 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200748 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800749
750 element->SetText( 1.5f );
751 XMLTest( "SetText types", "1.5", element->GetText() );
752
753 element->SetText( 1.5 );
754 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100755 }
756
Lee Thomason51c12712016-06-04 20:18:49 -0700757 // ---------- Attributes ---------
758 {
759 static const int64_t BIG = -123456789012345678;
760 XMLDocument doc;
761 XMLElement* element = doc.NewElement("element");
762 doc.InsertFirstChild(element);
763
764 {
765 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300766 {
767 int v = 0;
768 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
769 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
770 XMLTest("Attribute: int", -100, v, true);
771 }
772 {
773 int v = 0;
774 int queryResult = element->QueryAttribute("attrib", &v);
775 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
776 XMLTest("Attribute: int", -100, v, true);
777 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700778 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700779 }
780 {
781 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300782 {
783 unsigned v = 0;
784 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
785 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
786 XMLTest("Attribute: unsigned", unsigned(100), v, true);
787 }
788 {
789 unsigned v = 0;
790 int queryResult = element->QueryAttribute("attrib", &v);
791 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
792 XMLTest("Attribute: unsigned", unsigned(100), v, true);
793 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700794 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700795 }
796 {
797 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300798 {
799 int64_t v = 0;
800 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
801 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
802 XMLTest("Attribute: int64_t", BIG, v, true);
803 }
804 {
805 int64_t v = 0;
806 int queryResult = element->QueryAttribute("attrib", &v);
807 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
808 XMLTest("Attribute: int64_t", BIG, v, true);
809 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700810 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700811 }
812 {
813 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300814 {
815 bool v = false;
816 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
817 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
818 XMLTest("Attribute: bool", true, v, true);
819 }
820 {
821 bool v = false;
822 int queryResult = element->QueryAttribute("attrib", &v);
823 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
824 XMLTest("Attribute: bool", true, v, true);
825 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700826 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700827 }
828 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800829 element->SetAttribute("attrib", true);
830 const char* result = element->Attribute("attrib");
831 XMLTest("Bool true is 'true'", "true", result);
832
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800833 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800834 element->SetAttribute("attrib", true);
835 result = element->Attribute("attrib");
836 XMLTest("Bool true is '1'", "1", result);
837
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800838 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800839 }
840 {
Lee Thomason51c12712016-06-04 20:18:49 -0700841 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300842 {
843 double v = 0;
844 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
845 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
846 XMLTest("Attribute: double", 100.0, v, true);
847 }
848 {
849 double v = 0;
850 int queryResult = element->QueryAttribute("attrib", &v);
851 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
852 XMLTest("Attribute: double", 100.0, v, true);
853 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700854 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700855 }
856 {
857 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300858 {
859 float v = 0;
860 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
861 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
862 XMLTest("Attribute: float", 100.0f, v, true);
863 }
864 {
865 float v = 0;
866 int queryResult = element->QueryAttribute("attrib", &v);
867 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
868 XMLTest("Attribute: float", 100.0f, v, true);
869 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700870 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700871 }
872 {
873 element->SetText(BIG);
874 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300875 XMLError queryResult = element->QueryInt64Text(&v);
876 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700877 XMLTest("Element: int64_t", BIG, v, true);
878 }
879 }
880
881 // ---------- XMLPrinter stream mode ------
882 {
883 {
Dmitry-Mec0fad292017-08-09 19:05:42 +0300884 FILE* printerfp = fopen("resources/out/printer.xml", "w");
885 XMLTest("Open printer.xml", true, printerfp != 0);
Lee Thomason51c12712016-06-04 20:18:49 -0700886 XMLPrinter printer(printerfp);
887 printer.OpenElement("foo");
888 printer.PushAttribute("attrib-text", "text");
889 printer.PushAttribute("attrib-int", int(1));
890 printer.PushAttribute("attrib-unsigned", unsigned(2));
891 printer.PushAttribute("attrib-int64", int64_t(3));
892 printer.PushAttribute("attrib-bool", true);
893 printer.PushAttribute("attrib-double", 4.0);
894 printer.CloseElement();
895 fclose(printerfp);
896 }
897 {
898 XMLDocument doc;
Dmitry-Mec0fad292017-08-09 19:05:42 +0300899 doc.LoadFile("resources/out/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300900 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700901
902 const XMLDocument& cdoc = doc;
903
904 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
905 XMLTest("attrib-text", "text", attrib->Value(), true);
906 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
907 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
908 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
909 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
910 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
911 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
912 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
913 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
914 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
915 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
916 }
917
918 }
919
Uli Kusterer321072e2014-01-21 01:57:38 +0100920
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800921 // ---------- CDATA ---------------
922 {
923 const char* str = "<xmlElement>"
924 "<![CDATA["
925 "I am > the rules!\n"
926 "...since I make symbolic puns"
927 "]]>"
928 "</xmlElement>";
929 XMLDocument doc;
930 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300931 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800932 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800933
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300934 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
935 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800936 false );
937 }
938
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800939 // ----------- CDATA -------------
940 {
941 const char* str = "<xmlElement>"
942 "<![CDATA["
943 "<b>I am > the rules!</b>\n"
944 "...since I make symbolic puns"
945 "]]>"
946 "</xmlElement>";
947 XMLDocument doc;
948 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300949 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800950 doc.Print();
951
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300952 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800953 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300954 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800955 false );
956 }
957
958 // InsertAfterChild causes crash.
959 {
960 // InsertBeforeChild and InsertAfterChild causes crash.
961 XMLDocument doc;
962 XMLElement* parent = doc.NewElement( "Parent" );
963 doc.InsertFirstChild( parent );
964
965 XMLElement* childText0 = doc.NewElement( "childText0" );
966 XMLElement* childText1 = doc.NewElement( "childText1" );
967
968 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +0300969 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800970 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +0300971 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800972
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300973 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800974 }
Lee Thomasond6277762012-02-22 16:00:12 -0800975
976 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800977 // Entities not being written correctly.
978 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800979
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800980 const char* passages =
981 "<?xml version=\"1.0\" standalone=\"no\" ?>"
982 "<passages count=\"006\" formatversion=\"20020620\">"
983 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
984 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
985 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800986
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800987 XMLDocument doc;
988 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +0300989 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800990 XMLElement* psg = doc.RootElement()->FirstChildElement();
991 const char* context = psg->Attribute( "context" );
992 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 -0800993
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800994 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800995
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400996 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800997 if ( textfile )
998 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800999 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001000 psg->Accept( &streamer );
1001 fclose( textfile );
1002 }
Thomas Roß0922b732012-09-23 16:31:22 +02001003
1004 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001005 TIXMLASSERT( textfile );
1006 if ( textfile )
1007 {
1008 char buf[ 1024 ];
1009 fgets( buf, 1024, textfile );
1010 XMLTest( "Entity transformation: write. ",
1011 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1012 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1013 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001014 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001015 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001016 }
1017
1018 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001019 // Suppress entities.
1020 const char* passages =
1021 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1022 "<passages count=\"006\" formatversion=\"20020620\">"
1023 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1024 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001025
Lee Thomason6f381b72012-03-02 12:59:39 -08001026 XMLDocument doc( false );
1027 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001028 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001029
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001030 XMLTest( "No entity parsing.",
1031 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1032 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1033 XMLTest( "No entity parsing.", "Crazy &ttk;",
1034 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001035 doc.Print();
1036 }
1037
1038 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001039 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001040
1041 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001042 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001043 XMLTest( "dot in names", false, doc.Error() );
1044 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1045 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001046 }
1047
1048 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001049 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001050
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001051 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001052 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001053 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001054
1055 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1056 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001057 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001058 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001059 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001060
1061 {
1062 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001063 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001064 const char* doctype =
1065 "<?xml version=\"1.0\" ?>"
1066 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1067 "<!ELEMENT title (#PCDATA)>"
1068 "<!ELEMENT books (title,authors)>"
1069 "<element />";
1070
1071 XMLDocument doc;
1072 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001073 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001074 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001075 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001076 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001077 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001078 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001079 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001080
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001081 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1082 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1083
1084 }
1085
1086 {
1087 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001088 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001089 "<!-- Somewhat<evil> -->";
1090 XMLDocument doc;
1091 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001092 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001093
1094 XMLComment* comment = doc.FirstChild()->ToComment();
1095
1096 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1097 }
1098 {
1099 // Double attributes
1100 const char* doctype = "<element attr='red' attr='blue' />";
1101
1102 XMLDocument doc;
1103 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001104
Lee Thomason2fa81722012-11-09 12:37:46 -08001105 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 -08001106 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001107 }
1108
1109 {
1110 // Embedded null in stream.
1111 const char* doctype = "<element att\0r='red' attr='blue' />";
1112
1113 XMLDocument doc;
1114 doc.Parse( doctype );
1115 XMLTest( "Embedded null throws error.", true, doc.Error() );
1116 }
1117
1118 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001119 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001120 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001121 XMLDocument doc;
1122 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001123 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001124 }
1125
1126 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001127 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1128 const char* str = " ";
1129 XMLDocument doc;
1130 doc.Parse( str );
1131 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1132 }
1133
1134 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001135 // Low entities
1136 XMLDocument doc;
1137 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001138 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001139 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001140 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001141 doc.Print();
1142 }
1143
1144 {
1145 // Attribute values with trailing quotes not handled correctly
1146 XMLDocument doc;
1147 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001148 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001149 }
1150
1151 {
1152 // [ 1663758 ] Failure to report error on bad XML
1153 XMLDocument xml;
1154 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001155 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001156 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001157 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001158 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001159 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001160 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001161
1162
1163 {
1164 // [ 1475201 ] TinyXML parses entities in comments
1165 XMLDocument xml;
1166 xml.Parse("<!-- declarations for <head> & <body> -->"
1167 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001168 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001169
1170 XMLNode* e0 = xml.FirstChild();
1171 XMLNode* e1 = e0->NextSibling();
1172 XMLComment* c0 = e0->ToComment();
1173 XMLComment* c1 = e1->ToComment();
1174
1175 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1176 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1177 }
1178
1179 {
1180 XMLDocument xml;
1181 xml.Parse( "<Parent>"
1182 "<child1 att=''/>"
1183 "<!-- With this comment, child2 will not be parsed! -->"
1184 "<child2 att=''/>"
1185 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001186 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001187 xml.Print();
1188
1189 int count = 0;
1190
1191 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1192 ele;
1193 ele = ele->NextSibling() )
1194 {
1195 ++count;
1196 }
1197
1198 XMLTest( "Comments iterate correctly.", 3, count );
1199 }
1200
1201 {
1202 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1203 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1204 buf[60] = 239;
1205 buf[61] = 0;
1206
1207 XMLDocument doc;
1208 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001209 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001210 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001211
1212
1213 {
1214 // bug 1827248 Error while parsing a little bit malformed file
1215 // Actually not malformed - should work.
1216 XMLDocument xml;
1217 xml.Parse( "<attributelist> </attributelist >" );
1218 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1219 }
1220
1221 {
1222 // This one must not result in an infinite loop
1223 XMLDocument xml;
1224 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001225 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001226 XMLTest( "Infinite loop test.", true, true );
1227 }
1228#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001229 {
1230 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1231 XMLDocument doc;
1232 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001233 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001234
1235 XMLDocument clone;
1236 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1237 XMLNode* copy = node->ShallowClone( &clone );
1238 clone.InsertEndChild( copy );
1239 }
1240
1241 clone.Print();
1242
1243 int count=0;
1244 const XMLNode* a=clone.FirstChild();
1245 const XMLNode* b=doc.FirstChild();
1246 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1247 ++count;
1248 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1249 }
1250 XMLTest( "Clone and Equal", 4, count );
1251 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001252
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001253 {
Lee Thomason7085f002017-06-01 18:09:43 -07001254 // Deep Cloning of root element.
1255 XMLDocument doc2;
1256 XMLPrinter printer1;
1257 {
1258 // Make sure doc1 is deleted before we test doc2
1259 const char* xml =
1260 "<root>"
1261 " <child1 foo='bar'/>"
1262 " <!-- comment thing -->"
1263 " <child2 val='1'>Text</child2>"
1264 "</root>";
1265 XMLDocument doc;
1266 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001267 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001268
1269 doc.Print(&printer1);
1270 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1271 doc2.InsertFirstChild(root);
1272 }
1273 XMLPrinter printer2;
1274 doc2.Print(&printer2);
1275
1276 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1277 }
1278
1279 {
1280 // Deep Cloning of sub element.
1281 XMLDocument doc2;
1282 XMLPrinter printer1;
1283 {
1284 // Make sure doc1 is deleted before we test doc2
1285 const char* xml =
1286 "<?xml version ='1.0'?>"
1287 "<root>"
1288 " <child1 foo='bar'/>"
1289 " <!-- comment thing -->"
1290 " <child2 val='1'>Text</child2>"
1291 "</root>";
1292 XMLDocument doc;
1293 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001294 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001295
1296 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1297 subElement->Accept(&printer1);
1298
1299 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1300 doc2.InsertFirstChild(clonedSubElement);
1301 }
1302 XMLPrinter printer2;
1303 doc2.Print(&printer2);
1304
1305 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1306 }
1307
1308 {
1309 // Deep cloning of document.
1310 XMLDocument doc2;
1311 XMLPrinter printer1;
1312 {
1313 // Make sure doc1 is deleted before we test doc2
1314 const char* xml =
1315 "<?xml version ='1.0'?>"
1316 "<!-- Top level comment. -->"
1317 "<root>"
1318 " <child1 foo='bar'/>"
1319 " <!-- comment thing -->"
1320 " <child2 val='1'>Text</child2>"
1321 "</root>";
1322 XMLDocument doc;
1323 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001324 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001325 doc.Print(&printer1);
1326
1327 doc.DeepCopy(&doc2);
1328 }
1329 XMLPrinter printer2;
1330 doc2.Print(&printer2);
1331
1332 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1333 }
1334
1335
1336 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001337 // This shouldn't crash.
1338 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001339 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001340 {
1341 doc.PrintError();
1342 }
1343 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1344 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001345
Lee Thomason5e3803c2012-04-16 08:57:05 -07001346 {
1347 // Attribute ordering.
1348 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1349 XMLDocument doc;
1350 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001351 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001352 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001353
Lee Thomason5e3803c2012-04-16 08:57:05 -07001354 const XMLAttribute* a = ele->FirstAttribute();
1355 XMLTest( "Attribute order", "1", a->Value() );
1356 a = a->Next();
1357 XMLTest( "Attribute order", "2", a->Value() );
1358 a = a->Next();
1359 XMLTest( "Attribute order", "3", a->Value() );
1360 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001361
Lee Thomason5e3803c2012-04-16 08:57:05 -07001362 ele->DeleteAttribute( "attrib2" );
1363 a = ele->FirstAttribute();
1364 XMLTest( "Attribute order", "1", a->Value() );
1365 a = a->Next();
1366 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001367
Lee Thomason5e3803c2012-04-16 08:57:05 -07001368 ele->DeleteAttribute( "attrib1" );
1369 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001370 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001371 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001372
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001373 {
1374 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001375 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1376 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1377 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1378 XMLDocument doc0;
1379 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001380 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001381 XMLDocument doc1;
1382 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001383 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001384 XMLDocument doc2;
1385 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001386 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001387
Lee Thomason78a773d2012-07-02 10:10:19 -07001388 XMLElement* ele = 0;
1389 ele = doc0.FirstChildElement();
1390 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1391 ele = doc1.FirstChildElement();
1392 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1393 ele = doc2.FirstChildElement();
1394 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001395 }
1396
1397 {
1398 // Make sure we don't go into an infinite loop.
1399 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1400 XMLDocument doc;
1401 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001402 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001403 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1404 XMLElement* ele1 = ele0->NextSiblingElement();
1405 bool equal = ele0->ShallowEqual( ele1 );
1406
1407 XMLTest( "Infinite loop in shallow equal.", true, equal );
1408 }
1409
Lee Thomason5708f812012-03-28 17:46:41 -07001410 // -------- Handles ------------
1411 {
1412 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1413 XMLDocument doc;
1414 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001415 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001416
1417 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001418 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001419
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001420 XMLHandle docH( doc );
1421 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001422 XMLTest( "Handle, dne, mutable", true, ele == 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001423 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001424
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001425 {
1426 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1427 XMLDocument doc;
1428 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001429 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001430 XMLConstHandle docH( doc );
1431
1432 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001433 XMLTest( "Handle, success, const", "sub", ele->Value() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001434
1435 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001436 XMLTest( "Handle, dne, const", true, ele == 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001437 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001438 {
1439 // Default Declaration & BOM
1440 XMLDocument doc;
1441 doc.InsertEndChild( doc.NewDeclaration() );
1442 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001443
Lee Thomasonf68c4382012-04-28 14:37:11 -07001444 XMLPrinter printer;
1445 doc.Print( &printer );
1446
1447 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001448 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1449 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001450 }
Lee Thomason21be8822012-07-15 17:27:22 -07001451 {
1452 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1453 XMLDocument doc;
1454 doc.Parse( xml );
1455 XMLTest( "Ill formed XML", true, doc.Error() );
1456 }
1457
1458 // QueryXYZText
1459 {
1460 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1461 XMLDocument doc;
1462 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001463 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001464
1465 const XMLElement* pointElement = doc.RootElement();
1466
Dmitry-Me43c019d2017-08-02 18:05:23 +03001467 {
1468 int intValue = 0;
1469 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1470 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1471 XMLTest( "QueryIntText", 1, intValue, false );
1472 }
Lee Thomason21be8822012-07-15 17:27:22 -07001473
Dmitry-Me43c019d2017-08-02 18:05:23 +03001474 {
1475 unsigned unsignedValue = 0;
1476 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1477 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1478 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1479 }
Lee Thomason21be8822012-07-15 17:27:22 -07001480
Dmitry-Me43c019d2017-08-02 18:05:23 +03001481 {
1482 float floatValue = 0;
1483 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1484 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1485 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1486 }
Lee Thomason21be8822012-07-15 17:27:22 -07001487
Dmitry-Me43c019d2017-08-02 18:05:23 +03001488 {
1489 double doubleValue = 0;
1490 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1491 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1492 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1493 }
1494
1495 {
1496 bool boolValue = false;
1497 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1498 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1499 XMLTest( "QueryBoolText", true, boolValue, false );
1500 }
Lee Thomason21be8822012-07-15 17:27:22 -07001501 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001502
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001503 {
1504 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1505 XMLDocument doc;
1506 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001507 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001508 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001509
1510 {
1511 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1512 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001513 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001514 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001515 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001516
1517 {
1518 const char* xml = "<3lement></3lement>";
1519 XMLDocument doc;
1520 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001521 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001522 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001523
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001524 {
1525 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1526 XMLDocument doc;
1527 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001528 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001529 }
1530
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001531 {
1532 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001533 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001534 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001535 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001536 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001537 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001538 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001539 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001540 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001541 }
1542
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001543 // ----------- Whitespace ------------
1544 {
1545 const char* xml = "<element>"
1546 "<a> This \nis &apos; text &apos; </a>"
1547 "<b> This is &apos; text &apos; \n</b>"
1548 "<c>This is &apos; \n\n text &apos;</c>"
1549 "</element>";
1550 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1551 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001552 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001553
1554 const XMLElement* element = doc.FirstChildElement();
1555 for( const XMLElement* parent = element->FirstChildElement();
1556 parent;
1557 parent = parent->NextSiblingElement() )
1558 {
1559 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1560 }
1561 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001562
Lee Thomasonae9ab072012-10-24 10:17:53 -07001563#if 0
1564 {
1565 // Passes if assert doesn't fire.
1566 XMLDocument xmlDoc;
1567
1568 xmlDoc.NewDeclaration();
1569 xmlDoc.NewComment("Configuration file");
1570
1571 XMLElement *root = xmlDoc.NewElement("settings");
1572 root->SetAttribute("version", 2);
1573 }
1574#endif
1575
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001576 {
1577 const char* xml = "<element> </element>";
1578 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1579 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001580 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001581 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1582 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001583
Lee Thomason5b0a6772012-11-19 13:54:42 -08001584 {
1585 // An assert should not fire.
1586 const char* xml = "<element/>";
1587 XMLDocument doc;
1588 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001589 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001590 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1591 XMLTest( "Tracking unused elements", true, ele != 0, false );
1592 }
1593
Lee Thomasona6412ac2012-12-13 15:39:11 -08001594
1595 {
1596 const char* xml = "<parent><child>abc</child></parent>";
1597 XMLDocument doc;
1598 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001599 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001600 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1601
1602 XMLPrinter printer;
1603 ele->Accept( &printer );
1604 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1605 }
1606
1607
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001608 {
1609 XMLDocument doc;
1610 XMLError error = doc.LoadFile( "resources/empty.xml" );
1611 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001612 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001613 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001614 }
1615
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001616 {
1617 // BOM preservation
1618 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1619 {
1620 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001621 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001622 XMLPrinter printer;
1623 doc.Print( &printer );
1624
1625 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1626 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001627 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001628 }
1629 {
1630 XMLDocument doc;
1631 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001632 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001633 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1634
1635 XMLPrinter printer;
1636 doc.Print( &printer );
1637 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1638 }
1639 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001640
Michael Daumlinged523282013-10-23 07:47:29 +02001641 {
1642 // Insertion with Removal
1643 const char* xml = "<?xml version=\"1.0\" ?>"
1644 "<root>"
1645 "<one>"
1646 "<subtree>"
1647 "<elem>element 1</elem>text<!-- comment -->"
1648 "</subtree>"
1649 "</one>"
1650 "<two/>"
1651 "</root>";
1652 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1653 "<root>"
1654 "<one/>"
1655 "<two>"
1656 "<subtree>"
1657 "<elem>element 1</elem>text<!-- comment -->"
1658 "</subtree>"
1659 "</two>"
1660 "</root>";
1661 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1662 "<root>"
1663 "<one/>"
1664 "<subtree>"
1665 "<elem>element 1</elem>text<!-- comment -->"
1666 "</subtree>"
1667 "<two/>"
1668 "</root>";
1669 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1670 "<root>"
1671 "<one/>"
1672 "<two/>"
1673 "<subtree>"
1674 "<elem>element 1</elem>text<!-- comment -->"
1675 "</subtree>"
1676 "</root>";
1677
1678 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001679 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001680 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001681 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1682 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1683 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001684 XMLPrinter printer1(0, true);
1685 doc.Accept(&printer1);
1686 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001687
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001688 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001689 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001690 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1691 two = doc.RootElement()->FirstChildElement("two");
1692 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001693 XMLPrinter printer2(0, true);
1694 doc.Accept(&printer2);
1695 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001696
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001697 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001698 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001699 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1700 subtree = one->FirstChildElement("subtree");
1701 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001702 XMLPrinter printer3(0, true);
1703 doc.Accept(&printer3);
1704 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001705
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001706 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001707 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001708 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1709 two = doc.RootElement()->FirstChildElement("two");
1710 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001711 XMLPrinter printer4(0, true);
1712 doc.Accept(&printer4);
1713 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001714 }
1715
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001716 {
1717 const char* xml = "<svg width = \"128\" height = \"128\">"
1718 " <text> </text>"
1719 "</svg>";
1720 XMLDocument doc;
1721 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001722 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001723 doc.Print();
1724 }
1725
Lee Thomason92e521b2014-11-15 17:45:51 -08001726 {
1727 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001728 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1729 XMLDocument doc;
1730 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001731 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001732 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001733 }
1734
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001735#if 1
1736 // the question being explored is what kind of print to use:
1737 // https://github.com/leethomason/tinyxml2/issues/63
1738 {
1739 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1740 const char* xml = "<element/>";
1741 XMLDocument doc;
1742 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001743 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001744 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1745 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1746 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1747 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1748 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1749 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1750
1751 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1752 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1753 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1754 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1755 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1756 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1757
1758 doc.Print();
1759
1760 /* The result of this test is platform, compiler, and library version dependent. :("
1761 XMLPrinter printer;
1762 doc.Print( &printer );
1763 XMLTest( "Float and double formatting.",
1764 "<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",
1765 printer.CStr(),
1766 true );
1767 */
1768 }
1769#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001770
1771 {
1772 // Issue #184
1773 // If it doesn't assert, it passes. Caused by objects
1774 // getting created during parsing which are then
1775 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001776 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001777 {
1778 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001779 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001780 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001781 }
1782 {
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 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001786 doc.Clear();
1787 }
1788 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001789
1790 {
1791 // If this doesn't assert in DEBUG, all is well.
1792 tinyxml2::XMLDocument doc;
1793 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1794 doc.DeleteNode(pRoot);
1795 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001796
Dmitry-Mee5790db2017-07-28 17:54:38 +03001797 {
1798 XMLDocument doc;
1799 XMLElement* root = doc.NewElement( "Root" );
1800 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1801 doc.InsertEndChild( root );
1802 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1803 }
1804
1805 {
1806 // If this doesn't assert in DEBUG, all is well.
1807 XMLDocument doc;
1808 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1809 XMLElement* linkedRoot = doc.NewElement( "Root" );
1810 doc.InsertFirstChild( linkedRoot );
1811 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1812 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1813 }
1814
Dmitry-Me8b67d742014-12-22 11:35:12 +03001815 {
1816 // Should not assert in DEBUG
1817 XMLPrinter printer;
1818 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001819
Dmitry-Me6f51c802015-03-14 13:25:03 +03001820 {
1821 // Issue 291. Should not crash
1822 const char* xml = "&#0</a>";
1823 XMLDocument doc;
1824 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001825 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001826
1827 XMLPrinter printer;
1828 doc.Print( &printer );
1829 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001830 {
1831 // Issue 299. Can print elements that are not linked in.
1832 // Will crash if issue not fixed.
1833 XMLDocument doc;
1834 XMLElement* newElement = doc.NewElement( "printme" );
1835 XMLPrinter printer;
1836 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001837 // Delete the node to avoid possible memory leak report in debug output
1838 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001839 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001840 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001841 // Issue 302. Clear errors from LoadFile/SaveFile
1842 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001843 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001844 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001845 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001846 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001847 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001848 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001849
Dmitry-Med9852a52015-03-25 10:17:49 +03001850 {
1851 // If a document fails to load then subsequent
1852 // successful loads should clear the error
1853 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001854 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001855 doc.LoadFile( "resources/no-such-file.xml" );
1856 XMLTest( "No such file - should fail", true, doc.Error() );
1857
1858 doc.LoadFile( "resources/dream.xml" );
1859 XMLTest( "Error should be cleared", false, doc.Error() );
1860 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301861
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301862 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001863 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001864 const char* xml0 = "<?xml version=\"1.0\" ?>"
1865 " <!-- xml version=\"1.1\" -->"
1866 "<first />";
1867 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001868 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001869 "<first />";
1870 const char* xml2 = "<first />"
1871 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001872 const char* xml3 = "<first></first>"
1873 "<?xml version=\"1.0\" ?>";
1874
1875 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1876
Lee Thomason85492022015-05-22 11:07:45 -07001877 XMLDocument doc;
1878 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001879 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001880 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001881 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001882 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001883 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001884 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001885 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001886 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001887 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301888 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001889
Lee Thomason85492022015-05-22 11:07:45 -07001890 {
1891 // No matter - before or after successfully parsing a text -
1892 // calling XMLDocument::Value() causes an assert in debug.
1893 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1894 "<first />"
1895 "<second />";
1896 XMLDocument* doc = new XMLDocument();
1897 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1898 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001899 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001900 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1901 delete doc;
1902 }
1903
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001904 {
1905 XMLDocument doc;
1906 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001907 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001908 doc.ErrorName();
1909 }
1910 }
1911
Lee Thomason816d3fa2017-06-05 14:35:55 -07001912 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001913 // Evil memory leaks.
1914 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1915 // and NOT added to the XMLDocument, what happens?
1916 //
1917 // Previously (buggy):
1918 // The memory would be free'd when the XMLDocument is
1919 // destructed. But the destructor wasn't called, so that
1920 // memory allocated by the XMLElement would not be free'd.
1921 // In practice this meant strings allocated by the XMLElement
1922 // would leak. An edge case, but annoying.
1923 // Now:
1924 // The destructor is called. But the list of unlinked nodes
1925 // has to be tracked. This has a minor performance impact
1926 // that can become significant if you have a lot. (But why
1927 // would you do that?)
1928 // The only way to see this bug is in a leak tracker. This
1929 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001930 {
1931 XMLDocument doc;
1932 doc.NewElement("LEAK 1");
1933 }
1934 {
1935 XMLDocument doc;
1936 XMLElement* ele = doc.NewElement("LEAK 2");
1937 doc.DeleteNode(ele);
1938 }
1939 }
1940
Lee Thomason224ef772017-06-16 09:45:26 -07001941 {
1942 // Crashing reported via email.
1943 const char* xml =
1944 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001945 "<property name='track_name'>voice</property>"
1946 "<property name='audio_track'>1</property>"
1947 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1948 "<blank length = '1' />"
1949 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1950 "<blank length = '2' />"
1951 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1952 "<blank length = '1' />"
1953 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001954 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001955
Lee Thomason224ef772017-06-16 09:45:26 -07001956 // It's not a good idea to delete elements as you walk the
1957 // list. I'm not sure this technically should work; but it's
1958 // an interesting test case.
1959 XMLDocument doc;
1960 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001961 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03001962
1963 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001964 XMLTest("Crash bug parsing", true, playlist != 0);
1965
1966 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1967 XMLTest("Crash bug parsing", true, entry != 0);
1968 while (entry) {
1969 tinyxml2::XMLElement* todelete = entry;
1970 entry = entry->NextSiblingElement("entry");
1971 playlist->DeleteChild(todelete);
1972 };
1973 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1974 while (blank) {
1975 tinyxml2::XMLElement* todelete = blank;
1976 blank = blank->NextSiblingElement("blank");
1977 playlist->DeleteChild(todelete);
1978 };
1979
1980 tinyxml2::XMLPrinter printer;
1981 playlist->Accept(&printer);
1982 printf("%s\n", printer.CStr());
1983
Lee Thomason82bb0742017-06-16 09:48:20 -07001984 // No test; it only need to not crash.
1985 // Still, wrap it up with a sanity check
1986 int nProperty = 0;
1987 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1988 nProperty++;
1989 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001990 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07001991 }
1992
kezenatorec694152016-11-26 17:21:43 +10001993 // ----------- Line Number Tracking --------------
1994 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001995 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001996 {
1997 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1998 {
1999 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002000 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002001
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002002 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002003 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002004 XMLTest(testString, expected_error, parseError);
kezenatorec694152016-11-26 17:21:43 +10002005 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
2006 };
2007
2008 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2009 {
2010 XMLDocument doc;
2011 doc.Parse(docStr);
2012 XMLTest(testString, false, doc.Error());
2013 TestDocLines(testString, doc, expectedLines);
2014 }
2015
2016 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2017 {
2018 XMLDocument doc;
2019 doc.LoadFile(file_name);
2020 XMLTest(testString, false, doc.Error());
2021 TestDocLines(testString, doc, expectedLines);
2022 }
2023
2024 private:
2025 DynArray<char, 10> str;
2026
2027 void Push(char type, int lineNum)
2028 {
2029 str.Push(type);
2030 str.Push(char('0' + (lineNum / 10)));
2031 str.Push(char('0' + (lineNum % 10)));
2032 }
2033
2034 bool VisitEnter(const XMLDocument& doc)
2035 {
kezenator19d8ea82016-11-29 19:50:27 +10002036 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002037 return true;
2038 }
2039 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2040 {
kezenator19d8ea82016-11-29 19:50:27 +10002041 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002042 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002043 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002044 return true;
2045 }
2046 bool Visit(const XMLDeclaration& declaration)
2047 {
kezenator19d8ea82016-11-29 19:50:27 +10002048 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002049 return true;
2050 }
2051 bool Visit(const XMLText& text)
2052 {
kezenator19d8ea82016-11-29 19:50:27 +10002053 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002054 return true;
2055 }
2056 bool Visit(const XMLComment& comment)
2057 {
kezenator19d8ea82016-11-29 19:50:27 +10002058 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002059 return true;
2060 }
2061 bool Visit(const XMLUnknown& unknown)
2062 {
kezenator19d8ea82016-11-29 19:50:27 +10002063 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002064 return true;
2065 }
2066
2067 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2068 {
2069 str.Clear();
2070 doc.Accept(this);
2071 str.Push(0);
2072 XMLTest(testString, expectedLines, str.Mem());
2073 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002074 } tester;
kezenatorec694152016-11-26 17:21:43 +10002075
Lee Thomasone90e9012016-12-24 07:34:39 -08002076 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2077 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2078 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2079 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2080 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2081 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2082 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2083 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2084 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2085 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2086 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002087
Lee Thomasone90e9012016-12-24 07:34:39 -08002088 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002089 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002090
2091 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2092 "<root a='b' \n" // 2 Element Attribute
2093 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2094 "newline in text \n" // 4 Text
2095 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2096 " cdata test ]]><!-- comment -->\n" // 6 Comment
2097 "<! unknown></root>", // 7 Unknown
2098
kezenatorec694152016-11-26 17:21:43 +10002099 "D01L01E02A02A03T03E03T04E05T05C06U07");
2100
Lee Thomasone90e9012016-12-24 07:34:39 -08002101 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002102 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002103
2104 "\r\n" // 1 Doc (arguably should be line 2)
2105 "<?xml version=\"1.0\"?>\n" // 2 DecL
2106 "<root>\r\n" // 3 Element
2107 "\n" // 4
2108 "text contining new line \n" // 5 Text
2109 " and also containing crlf \r\n" // 6
2110 "<sub><![CDATA[\n" // 7 Element Text
2111 "cdata containing new line \n" // 8
2112 " and also containing cflr\r\n" // 9
2113 "]]></sub><sub2/></root>", // 10 Element
2114
kezenatorec694152016-11-26 17:21:43 +10002115 "D01L02E03T05E07T07E10");
2116
Lee Thomasone90e9012016-12-24 07:34:39 -08002117 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002118 "LineNumbers-File",
2119 "resources/utf8test.xml",
2120 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2121 }
2122
Lee Thomason85492022015-05-22 11:07:45 -07002123 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002124 {
2125#if defined( _MSC_VER )
2126 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002127 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002128#endif
2129
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002130 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002131 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002132 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002133 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002134 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002135
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002136 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002137 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002138 size_t bytesRead = fread(mem, 1, size, perfFP);
2139 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002140 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002141 mem[size] = 0;
2142
2143#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002144 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002145#else
2146 clock_t cstart = clock();
2147#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002148 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002149 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002150 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002151 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002152 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002153 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002154 }
Dmitry-Me68578f42017-07-03 18:21:23 +03002155 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002156#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002157 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002158#else
2159 clock_t cend = clock();
2160#endif
2161
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002162 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002163
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002164 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002165#ifdef DEBUG
2166 "DEBUG";
2167#else
2168 "Release";
2169#endif
2170
2171#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002172 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002173#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002174 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002175#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002176 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002177 }
2178
Dmitry-Mede381df2017-07-26 18:05:25 +03002179#if defined( _MSC_VER ) && defined( DEBUG )
2180 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002181 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002182
2183 _CrtMemState diffMemState;
2184 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2185 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002186
2187 {
2188 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2189 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2190 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002191 }
2192#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002193
2194 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002195
2196 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002197}