blob: af0fd7c945faf4d70e3430c7436dda194ba92e83 [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 {
884 FILE* printerfp = fopen("resources/printer.xml", "w");
885 XMLPrinter printer(printerfp);
886 printer.OpenElement("foo");
887 printer.PushAttribute("attrib-text", "text");
888 printer.PushAttribute("attrib-int", int(1));
889 printer.PushAttribute("attrib-unsigned", unsigned(2));
890 printer.PushAttribute("attrib-int64", int64_t(3));
891 printer.PushAttribute("attrib-bool", true);
892 printer.PushAttribute("attrib-double", 4.0);
893 printer.CloseElement();
894 fclose(printerfp);
895 }
896 {
897 XMLDocument doc;
898 doc.LoadFile("resources/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300899 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700900
901 const XMLDocument& cdoc = doc;
902
903 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
904 XMLTest("attrib-text", "text", attrib->Value(), true);
905 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
906 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
907 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
908 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
909 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
910 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
911 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
912 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
913 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
914 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
915 }
916
917 }
918
Uli Kusterer321072e2014-01-21 01:57:38 +0100919
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800920 // ---------- CDATA ---------------
921 {
922 const char* str = "<xmlElement>"
923 "<![CDATA["
924 "I am > the rules!\n"
925 "...since I make symbolic puns"
926 "]]>"
927 "</xmlElement>";
928 XMLDocument doc;
929 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300930 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800931 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800932
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300933 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
934 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800935 false );
936 }
937
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800938 // ----------- CDATA -------------
939 {
940 const char* str = "<xmlElement>"
941 "<![CDATA["
942 "<b>I am > the rules!</b>\n"
943 "...since I make symbolic puns"
944 "]]>"
945 "</xmlElement>";
946 XMLDocument doc;
947 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300948 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800949 doc.Print();
950
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300951 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800952 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300953 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800954 false );
955 }
956
957 // InsertAfterChild causes crash.
958 {
959 // InsertBeforeChild and InsertAfterChild causes crash.
960 XMLDocument doc;
961 XMLElement* parent = doc.NewElement( "Parent" );
962 doc.InsertFirstChild( parent );
963
964 XMLElement* childText0 = doc.NewElement( "childText0" );
965 XMLElement* childText1 = doc.NewElement( "childText1" );
966
967 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +0300968 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800969 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +0300970 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800971
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300972 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800973 }
Lee Thomasond6277762012-02-22 16:00:12 -0800974
975 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976 // Entities not being written correctly.
977 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800978
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800979 const char* passages =
980 "<?xml version=\"1.0\" standalone=\"no\" ?>"
981 "<passages count=\"006\" formatversion=\"20020620\">"
982 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
983 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
984 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800985
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800986 XMLDocument doc;
987 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +0300988 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800989 XMLElement* psg = doc.RootElement()->FirstChildElement();
990 const char* context = psg->Attribute( "context" );
991 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 -0800992
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800993 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800994
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400995 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800996 if ( textfile )
997 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800998 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800999 psg->Accept( &streamer );
1000 fclose( textfile );
1001 }
Thomas Roß0922b732012-09-23 16:31:22 +02001002
1003 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001004 TIXMLASSERT( textfile );
1005 if ( textfile )
1006 {
1007 char buf[ 1024 ];
1008 fgets( buf, 1024, textfile );
1009 XMLTest( "Entity transformation: write. ",
1010 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1011 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1012 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001013 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001014 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001015 }
1016
1017 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001018 // Suppress entities.
1019 const char* passages =
1020 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1021 "<passages count=\"006\" formatversion=\"20020620\">"
1022 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1023 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001024
Lee Thomason6f381b72012-03-02 12:59:39 -08001025 XMLDocument doc( false );
1026 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001027 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001028
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001029 XMLTest( "No entity parsing.",
1030 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1031 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1032 XMLTest( "No entity parsing.", "Crazy &ttk;",
1033 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001034 doc.Print();
1035 }
1036
1037 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001038 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001039
1040 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001041 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001042 XMLTest( "dot in names", false, doc.Error() );
1043 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1044 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001045 }
1046
1047 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001048 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001049
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001050 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001051 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001052 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001053
1054 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1055 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001056 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001057 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001058 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001059
1060 {
1061 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001062 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001063 const char* doctype =
1064 "<?xml version=\"1.0\" ?>"
1065 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1066 "<!ELEMENT title (#PCDATA)>"
1067 "<!ELEMENT books (title,authors)>"
1068 "<element />";
1069
1070 XMLDocument doc;
1071 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001072 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001073 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001074 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001075 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001076 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001077 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001078 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001079
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001080 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1081 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1082
1083 }
1084
1085 {
1086 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001087 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001088 "<!-- Somewhat<evil> -->";
1089 XMLDocument doc;
1090 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001091 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001092
1093 XMLComment* comment = doc.FirstChild()->ToComment();
1094
1095 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1096 }
1097 {
1098 // Double attributes
1099 const char* doctype = "<element attr='red' attr='blue' />";
1100
1101 XMLDocument doc;
1102 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001103
Lee Thomason2fa81722012-11-09 12:37:46 -08001104 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 -08001105 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001106 }
1107
1108 {
1109 // Embedded null in stream.
1110 const char* doctype = "<element att\0r='red' attr='blue' />";
1111
1112 XMLDocument doc;
1113 doc.Parse( doctype );
1114 XMLTest( "Embedded null throws error.", true, doc.Error() );
1115 }
1116
1117 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001118 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001119 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001120 XMLDocument doc;
1121 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001122 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001123 }
1124
1125 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001126 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1127 const char* str = " ";
1128 XMLDocument doc;
1129 doc.Parse( str );
1130 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1131 }
1132
1133 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001134 // Low entities
1135 XMLDocument doc;
1136 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001137 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001138 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001139 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001140 doc.Print();
1141 }
1142
1143 {
1144 // Attribute values with trailing quotes not handled correctly
1145 XMLDocument doc;
1146 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001147 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001148 }
1149
1150 {
1151 // [ 1663758 ] Failure to report error on bad XML
1152 XMLDocument xml;
1153 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001154 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001155 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001156 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001157 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001158 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001159 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001160
1161
1162 {
1163 // [ 1475201 ] TinyXML parses entities in comments
1164 XMLDocument xml;
1165 xml.Parse("<!-- declarations for <head> & <body> -->"
1166 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001167 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001168
1169 XMLNode* e0 = xml.FirstChild();
1170 XMLNode* e1 = e0->NextSibling();
1171 XMLComment* c0 = e0->ToComment();
1172 XMLComment* c1 = e1->ToComment();
1173
1174 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1175 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1176 }
1177
1178 {
1179 XMLDocument xml;
1180 xml.Parse( "<Parent>"
1181 "<child1 att=''/>"
1182 "<!-- With this comment, child2 will not be parsed! -->"
1183 "<child2 att=''/>"
1184 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001185 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001186 xml.Print();
1187
1188 int count = 0;
1189
1190 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1191 ele;
1192 ele = ele->NextSibling() )
1193 {
1194 ++count;
1195 }
1196
1197 XMLTest( "Comments iterate correctly.", 3, count );
1198 }
1199
1200 {
1201 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1202 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1203 buf[60] = 239;
1204 buf[61] = 0;
1205
1206 XMLDocument doc;
1207 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001208 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001209 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001210
1211
1212 {
1213 // bug 1827248 Error while parsing a little bit malformed file
1214 // Actually not malformed - should work.
1215 XMLDocument xml;
1216 xml.Parse( "<attributelist> </attributelist >" );
1217 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1218 }
1219
1220 {
1221 // This one must not result in an infinite loop
1222 XMLDocument xml;
1223 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001224 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001225 XMLTest( "Infinite loop test.", true, true );
1226 }
1227#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001228 {
1229 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1230 XMLDocument doc;
1231 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001232 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001233
1234 XMLDocument clone;
1235 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1236 XMLNode* copy = node->ShallowClone( &clone );
1237 clone.InsertEndChild( copy );
1238 }
1239
1240 clone.Print();
1241
1242 int count=0;
1243 const XMLNode* a=clone.FirstChild();
1244 const XMLNode* b=doc.FirstChild();
1245 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1246 ++count;
1247 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1248 }
1249 XMLTest( "Clone and Equal", 4, count );
1250 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001251
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001252 {
Lee Thomason7085f002017-06-01 18:09:43 -07001253 // Deep Cloning of root element.
1254 XMLDocument doc2;
1255 XMLPrinter printer1;
1256 {
1257 // Make sure doc1 is deleted before we test doc2
1258 const char* xml =
1259 "<root>"
1260 " <child1 foo='bar'/>"
1261 " <!-- comment thing -->"
1262 " <child2 val='1'>Text</child2>"
1263 "</root>";
1264 XMLDocument doc;
1265 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001266 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001267
1268 doc.Print(&printer1);
1269 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1270 doc2.InsertFirstChild(root);
1271 }
1272 XMLPrinter printer2;
1273 doc2.Print(&printer2);
1274
1275 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1276 }
1277
1278 {
1279 // Deep Cloning of sub element.
1280 XMLDocument doc2;
1281 XMLPrinter printer1;
1282 {
1283 // Make sure doc1 is deleted before we test doc2
1284 const char* xml =
1285 "<?xml version ='1.0'?>"
1286 "<root>"
1287 " <child1 foo='bar'/>"
1288 " <!-- comment thing -->"
1289 " <child2 val='1'>Text</child2>"
1290 "</root>";
1291 XMLDocument doc;
1292 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001293 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001294
1295 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1296 subElement->Accept(&printer1);
1297
1298 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1299 doc2.InsertFirstChild(clonedSubElement);
1300 }
1301 XMLPrinter printer2;
1302 doc2.Print(&printer2);
1303
1304 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1305 }
1306
1307 {
1308 // Deep cloning of document.
1309 XMLDocument doc2;
1310 XMLPrinter printer1;
1311 {
1312 // Make sure doc1 is deleted before we test doc2
1313 const char* xml =
1314 "<?xml version ='1.0'?>"
1315 "<!-- Top level comment. -->"
1316 "<root>"
1317 " <child1 foo='bar'/>"
1318 " <!-- comment thing -->"
1319 " <child2 val='1'>Text</child2>"
1320 "</root>";
1321 XMLDocument doc;
1322 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001323 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001324 doc.Print(&printer1);
1325
1326 doc.DeepCopy(&doc2);
1327 }
1328 XMLPrinter printer2;
1329 doc2.Print(&printer2);
1330
1331 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1332 }
1333
1334
1335 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001336 // This shouldn't crash.
1337 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001338 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001339 {
1340 doc.PrintError();
1341 }
1342 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1343 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001344
Lee Thomason5e3803c2012-04-16 08:57:05 -07001345 {
1346 // Attribute ordering.
1347 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1348 XMLDocument doc;
1349 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001350 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001351 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001352
Lee Thomason5e3803c2012-04-16 08:57:05 -07001353 const XMLAttribute* a = ele->FirstAttribute();
1354 XMLTest( "Attribute order", "1", a->Value() );
1355 a = a->Next();
1356 XMLTest( "Attribute order", "2", a->Value() );
1357 a = a->Next();
1358 XMLTest( "Attribute order", "3", a->Value() );
1359 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001360
Lee Thomason5e3803c2012-04-16 08:57:05 -07001361 ele->DeleteAttribute( "attrib2" );
1362 a = ele->FirstAttribute();
1363 XMLTest( "Attribute order", "1", a->Value() );
1364 a = a->Next();
1365 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001366
Lee Thomason5e3803c2012-04-16 08:57:05 -07001367 ele->DeleteAttribute( "attrib1" );
1368 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001369 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001370 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001371
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001372 {
1373 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001374 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1375 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1376 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1377 XMLDocument doc0;
1378 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001379 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001380 XMLDocument doc1;
1381 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001382 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001383 XMLDocument doc2;
1384 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001385 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001386
Lee Thomason78a773d2012-07-02 10:10:19 -07001387 XMLElement* ele = 0;
1388 ele = doc0.FirstChildElement();
1389 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1390 ele = doc1.FirstChildElement();
1391 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1392 ele = doc2.FirstChildElement();
1393 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001394 }
1395
1396 {
1397 // Make sure we don't go into an infinite loop.
1398 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1399 XMLDocument doc;
1400 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001401 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001402 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1403 XMLElement* ele1 = ele0->NextSiblingElement();
1404 bool equal = ele0->ShallowEqual( ele1 );
1405
1406 XMLTest( "Infinite loop in shallow equal.", true, equal );
1407 }
1408
Lee Thomason5708f812012-03-28 17:46:41 -07001409 // -------- Handles ------------
1410 {
1411 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1412 XMLDocument doc;
1413 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001414 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001415
1416 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001417 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001418
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001419 XMLHandle docH( doc );
1420 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001421 XMLTest( "Handle, dne, mutable", true, ele == 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001422 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001423
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001424 {
1425 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1426 XMLDocument doc;
1427 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001428 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001429 XMLConstHandle docH( doc );
1430
1431 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001432 XMLTest( "Handle, success, const", "sub", ele->Value() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001433
1434 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001435 XMLTest( "Handle, dne, const", true, ele == 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001436 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001437 {
1438 // Default Declaration & BOM
1439 XMLDocument doc;
1440 doc.InsertEndChild( doc.NewDeclaration() );
1441 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001442
Lee Thomasonf68c4382012-04-28 14:37:11 -07001443 XMLPrinter printer;
1444 doc.Print( &printer );
1445
1446 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001447 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1448 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001449 }
Lee Thomason21be8822012-07-15 17:27:22 -07001450 {
1451 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1452 XMLDocument doc;
1453 doc.Parse( xml );
1454 XMLTest( "Ill formed XML", true, doc.Error() );
1455 }
1456
1457 // QueryXYZText
1458 {
1459 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1460 XMLDocument doc;
1461 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001462 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001463
1464 const XMLElement* pointElement = doc.RootElement();
1465
Dmitry-Me43c019d2017-08-02 18:05:23 +03001466 {
1467 int intValue = 0;
1468 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1469 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1470 XMLTest( "QueryIntText", 1, intValue, false );
1471 }
Lee Thomason21be8822012-07-15 17:27:22 -07001472
Dmitry-Me43c019d2017-08-02 18:05:23 +03001473 {
1474 unsigned unsignedValue = 0;
1475 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1476 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1477 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1478 }
Lee Thomason21be8822012-07-15 17:27:22 -07001479
Dmitry-Me43c019d2017-08-02 18:05:23 +03001480 {
1481 float floatValue = 0;
1482 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1483 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1484 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1485 }
Lee Thomason21be8822012-07-15 17:27:22 -07001486
Dmitry-Me43c019d2017-08-02 18:05:23 +03001487 {
1488 double doubleValue = 0;
1489 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1490 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1491 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1492 }
1493
1494 {
1495 bool boolValue = false;
1496 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1497 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1498 XMLTest( "QueryBoolText", true, boolValue, false );
1499 }
Lee Thomason21be8822012-07-15 17:27:22 -07001500 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001501
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001502 {
1503 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1504 XMLDocument doc;
1505 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001506 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001507 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001508
1509 {
1510 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1511 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001512 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001513 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001514 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001515
1516 {
1517 const char* xml = "<3lement></3lement>";
1518 XMLDocument doc;
1519 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001520 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001521 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001522
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001523 {
1524 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1525 XMLDocument doc;
1526 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001527 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001528 }
1529
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001530 {
1531 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001532 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001533 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001534 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001535 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001536 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001537 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001538 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001539 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001540 }
1541
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001542 // ----------- Whitespace ------------
1543 {
1544 const char* xml = "<element>"
1545 "<a> This \nis &apos; text &apos; </a>"
1546 "<b> This is &apos; text &apos; \n</b>"
1547 "<c>This is &apos; \n\n text &apos;</c>"
1548 "</element>";
1549 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1550 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001551 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001552
1553 const XMLElement* element = doc.FirstChildElement();
1554 for( const XMLElement* parent = element->FirstChildElement();
1555 parent;
1556 parent = parent->NextSiblingElement() )
1557 {
1558 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1559 }
1560 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001561
Lee Thomasonae9ab072012-10-24 10:17:53 -07001562#if 0
1563 {
1564 // Passes if assert doesn't fire.
1565 XMLDocument xmlDoc;
1566
1567 xmlDoc.NewDeclaration();
1568 xmlDoc.NewComment("Configuration file");
1569
1570 XMLElement *root = xmlDoc.NewElement("settings");
1571 root->SetAttribute("version", 2);
1572 }
1573#endif
1574
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001575 {
1576 const char* xml = "<element> </element>";
1577 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1578 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001579 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001580 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1581 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001582
Lee Thomason5b0a6772012-11-19 13:54:42 -08001583 {
1584 // An assert should not fire.
1585 const char* xml = "<element/>";
1586 XMLDocument doc;
1587 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001588 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001589 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1590 XMLTest( "Tracking unused elements", true, ele != 0, false );
1591 }
1592
Lee Thomasona6412ac2012-12-13 15:39:11 -08001593
1594 {
1595 const char* xml = "<parent><child>abc</child></parent>";
1596 XMLDocument doc;
1597 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001598 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001599 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1600
1601 XMLPrinter printer;
1602 ele->Accept( &printer );
1603 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1604 }
1605
1606
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001607 {
1608 XMLDocument doc;
1609 XMLError error = doc.LoadFile( "resources/empty.xml" );
1610 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001611 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001612 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001613 }
1614
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001615 {
1616 // BOM preservation
1617 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1618 {
1619 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001620 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001621 XMLPrinter printer;
1622 doc.Print( &printer );
1623
1624 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1625 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001626 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001627 }
1628 {
1629 XMLDocument doc;
1630 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001631 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001632 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1633
1634 XMLPrinter printer;
1635 doc.Print( &printer );
1636 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1637 }
1638 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001639
Michael Daumlinged523282013-10-23 07:47:29 +02001640 {
1641 // Insertion with Removal
1642 const char* xml = "<?xml version=\"1.0\" ?>"
1643 "<root>"
1644 "<one>"
1645 "<subtree>"
1646 "<elem>element 1</elem>text<!-- comment -->"
1647 "</subtree>"
1648 "</one>"
1649 "<two/>"
1650 "</root>";
1651 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1652 "<root>"
1653 "<one/>"
1654 "<two>"
1655 "<subtree>"
1656 "<elem>element 1</elem>text<!-- comment -->"
1657 "</subtree>"
1658 "</two>"
1659 "</root>";
1660 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1661 "<root>"
1662 "<one/>"
1663 "<subtree>"
1664 "<elem>element 1</elem>text<!-- comment -->"
1665 "</subtree>"
1666 "<two/>"
1667 "</root>";
1668 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1669 "<root>"
1670 "<one/>"
1671 "<two/>"
1672 "<subtree>"
1673 "<elem>element 1</elem>text<!-- comment -->"
1674 "</subtree>"
1675 "</root>";
1676
1677 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001678 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001679 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001680 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1681 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1682 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001683 XMLPrinter printer1(0, true);
1684 doc.Accept(&printer1);
1685 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001686
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001687 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001688 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001689 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1690 two = doc.RootElement()->FirstChildElement("two");
1691 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001692 XMLPrinter printer2(0, true);
1693 doc.Accept(&printer2);
1694 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001695
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001696 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001697 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001698 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1699 subtree = one->FirstChildElement("subtree");
1700 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001701 XMLPrinter printer3(0, true);
1702 doc.Accept(&printer3);
1703 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001704
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001705 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001706 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001707 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1708 two = doc.RootElement()->FirstChildElement("two");
1709 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001710 XMLPrinter printer4(0, true);
1711 doc.Accept(&printer4);
1712 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001713 }
1714
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001715 {
1716 const char* xml = "<svg width = \"128\" height = \"128\">"
1717 " <text> </text>"
1718 "</svg>";
1719 XMLDocument doc;
1720 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001721 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001722 doc.Print();
1723 }
1724
Lee Thomason92e521b2014-11-15 17:45:51 -08001725 {
1726 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001727 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1728 XMLDocument doc;
1729 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001730 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001731 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001732 }
1733
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001734#if 1
1735 // the question being explored is what kind of print to use:
1736 // https://github.com/leethomason/tinyxml2/issues/63
1737 {
1738 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1739 const char* xml = "<element/>";
1740 XMLDocument doc;
1741 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001742 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001743 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1744 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1745 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1746 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1747 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1748 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1749
1750 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1751 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1752 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1753 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1754 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1755 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1756
1757 doc.Print();
1758
1759 /* The result of this test is platform, compiler, and library version dependent. :("
1760 XMLPrinter printer;
1761 doc.Print( &printer );
1762 XMLTest( "Float and double formatting.",
1763 "<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",
1764 printer.CStr(),
1765 true );
1766 */
1767 }
1768#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001769
1770 {
1771 // Issue #184
1772 // If it doesn't assert, it passes. Caused by objects
1773 // getting created during parsing which are then
1774 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001775 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001776 {
1777 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001778 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001779 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001780 }
1781 {
1782 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001783 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001784 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001785 doc.Clear();
1786 }
1787 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001788
1789 {
1790 // If this doesn't assert in DEBUG, all is well.
1791 tinyxml2::XMLDocument doc;
1792 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1793 doc.DeleteNode(pRoot);
1794 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001795
Dmitry-Mee5790db2017-07-28 17:54:38 +03001796 {
1797 XMLDocument doc;
1798 XMLElement* root = doc.NewElement( "Root" );
1799 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1800 doc.InsertEndChild( root );
1801 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1802 }
1803
1804 {
1805 // If this doesn't assert in DEBUG, all is well.
1806 XMLDocument doc;
1807 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1808 XMLElement* linkedRoot = doc.NewElement( "Root" );
1809 doc.InsertFirstChild( linkedRoot );
1810 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1811 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1812 }
1813
Dmitry-Me8b67d742014-12-22 11:35:12 +03001814 {
1815 // Should not assert in DEBUG
1816 XMLPrinter printer;
1817 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001818
Dmitry-Me6f51c802015-03-14 13:25:03 +03001819 {
1820 // Issue 291. Should not crash
1821 const char* xml = "&#0</a>";
1822 XMLDocument doc;
1823 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001824 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001825
1826 XMLPrinter printer;
1827 doc.Print( &printer );
1828 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001829 {
1830 // Issue 299. Can print elements that are not linked in.
1831 // Will crash if issue not fixed.
1832 XMLDocument doc;
1833 XMLElement* newElement = doc.NewElement( "printme" );
1834 XMLPrinter printer;
1835 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001836 // Delete the node to avoid possible memory leak report in debug output
1837 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001838 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001839 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001840 // Issue 302. Clear errors from LoadFile/SaveFile
1841 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001842 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001843 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001844 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001845 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001846 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001847 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001848
Dmitry-Med9852a52015-03-25 10:17:49 +03001849 {
1850 // If a document fails to load then subsequent
1851 // successful loads should clear the error
1852 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001853 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001854 doc.LoadFile( "resources/no-such-file.xml" );
1855 XMLTest( "No such file - should fail", true, doc.Error() );
1856
1857 doc.LoadFile( "resources/dream.xml" );
1858 XMLTest( "Error should be cleared", false, doc.Error() );
1859 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301860
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301861 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001862 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001863 const char* xml0 = "<?xml version=\"1.0\" ?>"
1864 " <!-- xml version=\"1.1\" -->"
1865 "<first />";
1866 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001867 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001868 "<first />";
1869 const char* xml2 = "<first />"
1870 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001871 const char* xml3 = "<first></first>"
1872 "<?xml version=\"1.0\" ?>";
1873
1874 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1875
Lee Thomason85492022015-05-22 11:07:45 -07001876 XMLDocument doc;
1877 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001878 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001879 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001880 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001881 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001882 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001883 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001884 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001885 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001886 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301887 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001888
Lee Thomason85492022015-05-22 11:07:45 -07001889 {
1890 // No matter - before or after successfully parsing a text -
1891 // calling XMLDocument::Value() causes an assert in debug.
1892 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1893 "<first />"
1894 "<second />";
1895 XMLDocument* doc = new XMLDocument();
1896 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1897 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001898 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001899 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1900 delete doc;
1901 }
1902
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001903 {
1904 XMLDocument doc;
1905 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001906 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001907 doc.ErrorName();
1908 }
1909 }
1910
Lee Thomason816d3fa2017-06-05 14:35:55 -07001911 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001912 // Evil memory leaks.
1913 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1914 // and NOT added to the XMLDocument, what happens?
1915 //
1916 // Previously (buggy):
1917 // The memory would be free'd when the XMLDocument is
1918 // destructed. But the destructor wasn't called, so that
1919 // memory allocated by the XMLElement would not be free'd.
1920 // In practice this meant strings allocated by the XMLElement
1921 // would leak. An edge case, but annoying.
1922 // Now:
1923 // The destructor is called. But the list of unlinked nodes
1924 // has to be tracked. This has a minor performance impact
1925 // that can become significant if you have a lot. (But why
1926 // would you do that?)
1927 // The only way to see this bug is in a leak tracker. This
1928 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001929 {
1930 XMLDocument doc;
1931 doc.NewElement("LEAK 1");
1932 }
1933 {
1934 XMLDocument doc;
1935 XMLElement* ele = doc.NewElement("LEAK 2");
1936 doc.DeleteNode(ele);
1937 }
1938 }
1939
Lee Thomason224ef772017-06-16 09:45:26 -07001940 {
1941 // Crashing reported via email.
1942 const char* xml =
1943 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001944 "<property name='track_name'>voice</property>"
1945 "<property name='audio_track'>1</property>"
1946 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1947 "<blank length = '1' />"
1948 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1949 "<blank length = '2' />"
1950 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1951 "<blank length = '1' />"
1952 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001953 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001954
Lee Thomason224ef772017-06-16 09:45:26 -07001955 // It's not a good idea to delete elements as you walk the
1956 // list. I'm not sure this technically should work; but it's
1957 // an interesting test case.
1958 XMLDocument doc;
1959 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001960 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03001961
1962 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001963 XMLTest("Crash bug parsing", true, playlist != 0);
1964
1965 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1966 XMLTest("Crash bug parsing", true, entry != 0);
1967 while (entry) {
1968 tinyxml2::XMLElement* todelete = entry;
1969 entry = entry->NextSiblingElement("entry");
1970 playlist->DeleteChild(todelete);
1971 };
1972 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1973 while (blank) {
1974 tinyxml2::XMLElement* todelete = blank;
1975 blank = blank->NextSiblingElement("blank");
1976 playlist->DeleteChild(todelete);
1977 };
1978
1979 tinyxml2::XMLPrinter printer;
1980 playlist->Accept(&printer);
1981 printf("%s\n", printer.CStr());
1982
Lee Thomason82bb0742017-06-16 09:48:20 -07001983 // No test; it only need to not crash.
1984 // Still, wrap it up with a sanity check
1985 int nProperty = 0;
1986 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1987 nProperty++;
1988 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001989 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07001990 }
1991
kezenatorec694152016-11-26 17:21:43 +10001992 // ----------- Line Number Tracking --------------
1993 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001994 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001995 {
1996 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1997 {
1998 XMLDocument doc;
1999 XMLError err = doc.Parse(docStr);
2000
2001 XMLTest(testString, true, doc.Error());
2002 XMLTest(testString, expected_error, err);
2003 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
2004 };
2005
2006 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2007 {
2008 XMLDocument doc;
2009 doc.Parse(docStr);
2010 XMLTest(testString, false, doc.Error());
2011 TestDocLines(testString, doc, expectedLines);
2012 }
2013
2014 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2015 {
2016 XMLDocument doc;
2017 doc.LoadFile(file_name);
2018 XMLTest(testString, false, doc.Error());
2019 TestDocLines(testString, doc, expectedLines);
2020 }
2021
2022 private:
2023 DynArray<char, 10> str;
2024
2025 void Push(char type, int lineNum)
2026 {
2027 str.Push(type);
2028 str.Push(char('0' + (lineNum / 10)));
2029 str.Push(char('0' + (lineNum % 10)));
2030 }
2031
2032 bool VisitEnter(const XMLDocument& doc)
2033 {
kezenator19d8ea82016-11-29 19:50:27 +10002034 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002035 return true;
2036 }
2037 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2038 {
kezenator19d8ea82016-11-29 19:50:27 +10002039 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002040 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002041 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002042 return true;
2043 }
2044 bool Visit(const XMLDeclaration& declaration)
2045 {
kezenator19d8ea82016-11-29 19:50:27 +10002046 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002047 return true;
2048 }
2049 bool Visit(const XMLText& text)
2050 {
kezenator19d8ea82016-11-29 19:50:27 +10002051 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002052 return true;
2053 }
2054 bool Visit(const XMLComment& comment)
2055 {
kezenator19d8ea82016-11-29 19:50:27 +10002056 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002057 return true;
2058 }
2059 bool Visit(const XMLUnknown& unknown)
2060 {
kezenator19d8ea82016-11-29 19:50:27 +10002061 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002062 return true;
2063 }
2064
2065 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2066 {
2067 str.Clear();
2068 doc.Accept(this);
2069 str.Push(0);
2070 XMLTest(testString, expectedLines, str.Mem());
2071 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002072 } tester;
kezenatorec694152016-11-26 17:21:43 +10002073
Lee Thomasone90e9012016-12-24 07:34:39 -08002074 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2075 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2076 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2077 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2078 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2079 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2080 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2081 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2082 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2083 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2084 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002085
Lee Thomasone90e9012016-12-24 07:34:39 -08002086 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002087 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002088
2089 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2090 "<root a='b' \n" // 2 Element Attribute
2091 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2092 "newline in text \n" // 4 Text
2093 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2094 " cdata test ]]><!-- comment -->\n" // 6 Comment
2095 "<! unknown></root>", // 7 Unknown
2096
kezenatorec694152016-11-26 17:21:43 +10002097 "D01L01E02A02A03T03E03T04E05T05C06U07");
2098
Lee Thomasone90e9012016-12-24 07:34:39 -08002099 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002100 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002101
2102 "\r\n" // 1 Doc (arguably should be line 2)
2103 "<?xml version=\"1.0\"?>\n" // 2 DecL
2104 "<root>\r\n" // 3 Element
2105 "\n" // 4
2106 "text contining new line \n" // 5 Text
2107 " and also containing crlf \r\n" // 6
2108 "<sub><![CDATA[\n" // 7 Element Text
2109 "cdata containing new line \n" // 8
2110 " and also containing cflr\r\n" // 9
2111 "]]></sub><sub2/></root>", // 10 Element
2112
kezenatorec694152016-11-26 17:21:43 +10002113 "D01L02E03T05E07T07E10");
2114
Lee Thomasone90e9012016-12-24 07:34:39 -08002115 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002116 "LineNumbers-File",
2117 "resources/utf8test.xml",
2118 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2119 }
2120
Lee Thomason85492022015-05-22 11:07:45 -07002121 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002122 {
2123#if defined( _MSC_VER )
2124 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002125 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002126#endif
2127
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002128 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002129 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002130 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002131 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002132 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002133
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002134 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002135 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002136 size_t bytesRead = fread(mem, 1, size, perfFP);
2137 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002138 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002139 mem[size] = 0;
2140
2141#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002142 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002143#else
2144 clock_t cstart = clock();
2145#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002146 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002147 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002148 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002149 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002150 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002151 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002152 }
Dmitry-Me68578f42017-07-03 18:21:23 +03002153 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002154#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002155 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002156#else
2157 clock_t cend = clock();
2158#endif
2159
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002160 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002161
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002162 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002163#ifdef DEBUG
2164 "DEBUG";
2165#else
2166 "Release";
2167#endif
2168
2169#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002170 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002171#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002172 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002173#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002174 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002175 }
2176
Dmitry-Mede381df2017-07-26 18:05:25 +03002177#if defined( _MSC_VER ) && defined( DEBUG )
2178 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002179 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002180
2181 _CrtMemState diffMemState;
2182 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2183 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002184
2185 {
2186 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2187 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2188 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002189 }
2190#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002191
2192 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002193
2194 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002195}