blob: 336aeefedf18bd2cc911e634c9383bdb091ed787 [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
kbinny62bf29a152017-06-23 18:15:25 +0000341#if defined WIN32
342 if ( !CreateDirectory( "resources/out", NULL ) && GetLastError() != ERROR_ALREADY_EXISTS ) {
343#else
344 if ( mkdir( "resources/out", 0750 ) == -1 && errno != EEXIST ) {
345#endif
346 printf( "Unable to create directory 'resources/out': %s\n", strerror( errno ) );
347 exit( 1 );
348 }
349
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700350 XMLTest( "Example-1", 0, example_1() );
351 XMLTest( "Example-2", 0, example_2() );
352 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700353 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700354
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700355 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700356
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800357 {
Lee Thomason43f59302012-02-06 18:18:11 -0800358 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400359 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800360 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400361 "<element><subelement></subelement></element>",
362 "<element><subelement><subsub/></subelement></element>",
363 "<!--comment beside elements--><element><subelement></subelement></element>",
364 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
365 "<element attrib1='foo' attrib2=\"bar\" ></element>",
366 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800367 "<element>Text inside element.</element>",
368 "<element><b></b></element>",
369 "<element>Text inside and <b>bolded</b> in the element.</element>",
370 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800371 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800372 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800373 0
374 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800375 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800376 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800377 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800378 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800379 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800380 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800381 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800382#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800383 {
384 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400385 " line 2\r"
386 " line 3\r\n"
387 " line 4\n\r"
388 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800389
390 XMLDocument doc;
391 doc.Parse( test );
392 doc.Print();
393 }
394
Lee Thomason2c85a712012-01-31 08:24:24 -0800395 {
396 static const char* test = "<element>Text before.</element>";
397 XMLDocument doc;
398 doc.Parse( test );
399 XMLElement* root = doc.FirstChildElement();
400 XMLElement* newElement = doc.NewElement( "Subelement" );
401 root->InsertEndChild( newElement );
402 doc.Print();
403 }
Lee Thomasond1983222012-02-06 08:41:24 -0800404 {
405 XMLDocument* doc = new XMLDocument();
406 static const char* test = "<element><sub/></element>";
407 doc->Parse( test );
408 delete doc;
409 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800410 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800411 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800412 // Build:
413 // <element>
414 // <!--comment-->
415 // <sub attrib="1" />
416 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800417 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800418 // <element>
419
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800420 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800421 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
422
423 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
424 for( int i=0; i<3; ++i ) {
425 sub[i]->SetAttribute( "attrib", i );
426 }
427 element->InsertEndChild( sub[2] );
428 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700429 comment->SetUserData((void*)2);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800430 element->InsertAfterChild( comment, sub[0] );
431 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800432 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800433 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800434 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
435 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
436 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700437 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800438 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Lee Thomasonc9445462016-07-17 22:53:48 -0700439 XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800440
441 // And now deletion:
442 element->DeleteChild( sub[2] );
443 doc->DeleteNode( comment );
444
445 element->FirstChildElement()->SetAttribute( "attrib", true );
446 element->LastChildElement()->DeleteAttribute( "attrib" );
447
448 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700449 int value1 = 10;
450 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", 10 );
451 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
Lee Thomason21be8822012-07-15 17:27:22 -0700452 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700453 XMLTest( "Programmatic DOM", value1, 10 );
454 XMLTest( "Programmatic DOM", value2, 10 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800455
456 doc->Print();
457
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700458 {
459 XMLPrinter streamer;
460 doc->Print( &streamer );
461 printf( "%s", streamer.CStr() );
462 }
463 {
464 XMLPrinter streamer( 0, true );
465 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200466 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700467 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700468 doc->SaveFile( "./resources/out/pretty.xml" );
469 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800470 delete doc;
471 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800472 {
473 // Test: Dream
474 // XML1 : 1,187,569 bytes in 31,209 allocations
475 // XML2 : 469,073 bytes in 323 allocations
476 //int newStart = gNew;
477 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300478 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800479
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400480 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800481 doc.PrintError();
482
483 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400484 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800485 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
486 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
487 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
488 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400489 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800490 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400491 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800492
493 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400494 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800495 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400496 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800497 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
498 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
499 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
500 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400501 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800502
503 //gNewTotal = gNew - newStart;
504 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800505
506
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800507 {
508 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
509 "<passages count=\"006\" formatversion=\"20020620\">\n"
510 " <wrong error>\n"
511 "</passages>";
512
513 XMLDocument doc;
514 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800515 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800516 }
517
518 {
519 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
520
521 XMLDocument doc;
522 doc.Parse( str );
523
524 XMLElement* ele = doc.FirstChildElement();
525
526 int iVal, result;
527 double dVal;
528
529 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700530 XMLTest( "Query attribute: int as double", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800531 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700532 XMLTest( "Query attribute: int as double", (int)ele->DoubleAttribute("attr0"), 1);
533
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800534 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700535 XMLTest( "Query attribute: double as double", result, (int)XML_SUCCESS);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700536 XMLTest( "Query attribute: double as double", dVal, 2.0 );
537 XMLTest( "Query attribute: double as double", ele->DoubleAttribute("attr1"), 2.0 );
538
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800539 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason85536252016-06-04 19:10:53 -0700540 XMLTest( "Query attribute: double as int", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800541 XMLTest( "Query attribute: double as int", iVal, 2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700542
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800543 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700544 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700545 XMLTest( "Query attribute: not a number", ele->DoubleAttribute("attr2", 4.0), 4.0 );
546
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800547 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700548 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700549 XMLTest( "Query attribute: does not exist", ele->BoolAttribute("bar", true), true );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550 }
551
552 {
553 const char* str = "<doc/>";
554
555 XMLDocument doc;
556 doc.Parse( str );
557
558 XMLElement* ele = doc.FirstChildElement();
559
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800560 int iVal, iVal2;
561 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800562
563 ele->SetAttribute( "str", "strValue" );
564 ele->SetAttribute( "int", 1 );
565 ele->SetAttribute( "double", -1.0 );
566
567 const char* cStr = ele->Attribute( "str" );
568 ele->QueryIntAttribute( "int", &iVal );
569 ele->QueryDoubleAttribute( "double", &dVal );
570
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800571 ele->QueryAttribute( "int", &iVal2 );
572 ele->QueryAttribute( "double", &dVal2 );
573
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700574 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800575 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
576 XMLTest( "Attribute round trip. int.", 1, iVal );
577 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800578 XMLTest( "Alternate query", true, iVal == iVal2 );
579 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700580 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
581 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800582 }
583
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800584 {
585 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300586 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800587
588 // Get the attribute "value" from the "Russian" element and check it.
589 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700590 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800591 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
592
593 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
594
595 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
596 0xd1U, 0x81U, 0xd1U, 0x81U,
597 0xd0U, 0xbaU, 0xd0U, 0xb8U,
598 0xd0U, 0xb9U, 0 };
599 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
600
601 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
602 XMLTest( "UTF-8: Browsing russian element name.",
603 russianText,
604 text->Value() );
605
606 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400607 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800608
609 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800610 int okay = 0;
611
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200612 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300613 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800614
615 if ( saved && verify )
616 {
617 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700618 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800619 while ( fgets( verifyBuf, 256, verify ) )
620 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700621 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800622 fgets( savedBuf, 256, saved );
623 NullLineEndings( verifyBuf );
624 NullLineEndings( savedBuf );
625
626 if ( strcmp( verifyBuf, savedBuf ) )
627 {
628 printf( "verify:%s<\n", verifyBuf );
629 printf( "saved :%s<\n", savedBuf );
630 okay = 0;
631 break;
632 }
633 }
634 }
635 if ( saved )
636 fclose( saved );
637 if ( verify )
638 fclose( verify );
639 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
640 }
641
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800642 // --------GetText()-----------
643 {
644 const char* str = "<foo>This is text</foo>";
645 XMLDocument doc;
646 doc.Parse( str );
647 const XMLElement* element = doc.RootElement();
648
649 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
650
651 str = "<foo><b>This is text</b></foo>";
652 doc.Parse( str );
653 element = doc.RootElement();
654
655 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
656 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800657
Lee Thomasond6277762012-02-22 16:00:12 -0800658
Uli Kusterer321072e2014-01-21 01:57:38 +0100659 // --------SetText()-----------
660 {
661 const char* str = "<foo></foo>";
662 XMLDocument doc;
663 doc.Parse( str );
664 XMLElement* element = doc.RootElement();
665
Lee Thomason9c0678a2014-01-24 10:18:27 -0800666 element->SetText("darkness.");
667 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100668
Lee Thomason9c0678a2014-01-24 10:18:27 -0800669 element->SetText("blue flame.");
670 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100671
672 str = "<foo/>";
673 doc.Parse( str );
674 element = doc.RootElement();
675
Lee Thomason9c0678a2014-01-24 10:18:27 -0800676 element->SetText("The driver");
677 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100678
Lee Thomason9c0678a2014-01-24 10:18:27 -0800679 element->SetText("<b>horses</b>");
680 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
681 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100682
683 str = "<foo><bar>Text in nested element</bar></foo>";
684 doc.Parse( str );
685 element = doc.RootElement();
686
Lee Thomason9c0678a2014-01-24 10:18:27 -0800687 element->SetText("wolves");
688 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800689
690 str = "<foo/>";
691 doc.Parse( str );
692 element = doc.RootElement();
693
694 element->SetText( "str" );
695 XMLTest( "SetText types", "str", element->GetText() );
696
697 element->SetText( 1 );
698 XMLTest( "SetText types", "1", element->GetText() );
699
700 element->SetText( 1U );
701 XMLTest( "SetText types", "1", element->GetText() );
702
703 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200704 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800705
706 element->SetText( 1.5f );
707 XMLTest( "SetText types", "1.5", element->GetText() );
708
709 element->SetText( 1.5 );
710 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100711 }
712
Lee Thomason51c12712016-06-04 20:18:49 -0700713 // ---------- Attributes ---------
714 {
715 static const int64_t BIG = -123456789012345678;
716 XMLDocument doc;
717 XMLElement* element = doc.NewElement("element");
718 doc.InsertFirstChild(element);
719
720 {
721 element->SetAttribute("attrib", int(-100));
722 int v = 0;
723 element->QueryIntAttribute("attrib", &v);
724 XMLTest("Attribute: int", -100, v, true);
725 element->QueryAttribute("attrib", &v);
726 XMLTest("Attribute: int", -100, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700727 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700728 }
729 {
730 element->SetAttribute("attrib", unsigned(100));
731 unsigned v = 0;
732 element->QueryUnsignedAttribute("attrib", &v);
733 XMLTest("Attribute: unsigned", unsigned(100), v, true);
734 element->QueryAttribute("attrib", &v);
735 XMLTest("Attribute: unsigned", unsigned(100), v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700736 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700737 }
738 {
739 element->SetAttribute("attrib", BIG);
740 int64_t v = 0;
741 element->QueryInt64Attribute("attrib", &v);
742 XMLTest("Attribute: int64_t", BIG, v, true);
743 element->QueryAttribute("attrib", &v);
744 XMLTest("Attribute: int64_t", BIG, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700745 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700746 }
747 {
748 element->SetAttribute("attrib", true);
749 bool v = false;
750 element->QueryBoolAttribute("attrib", &v);
751 XMLTest("Attribute: bool", true, v, true);
752 element->QueryAttribute("attrib", &v);
753 XMLTest("Attribute: bool", true, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700754 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700755 }
756 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800757 element->SetAttribute("attrib", true);
758 const char* result = element->Attribute("attrib");
759 XMLTest("Bool true is 'true'", "true", result);
760
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800761 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800762 element->SetAttribute("attrib", true);
763 result = element->Attribute("attrib");
764 XMLTest("Bool true is '1'", "1", result);
765
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800766 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800767 }
768 {
Lee Thomason51c12712016-06-04 20:18:49 -0700769 element->SetAttribute("attrib", 100.0);
770 double v = 0;
771 element->QueryDoubleAttribute("attrib", &v);
772 XMLTest("Attribute: double", 100.0, v, true);
773 element->QueryAttribute("attrib", &v);
774 XMLTest("Attribute: double", 100.0, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700775 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700776 }
777 {
778 element->SetAttribute("attrib", 100.0f);
779 float v = 0;
780 element->QueryFloatAttribute("attrib", &v);
781 XMLTest("Attribute: float", 100.0f, v, true);
782 element->QueryAttribute("attrib", &v);
783 XMLTest("Attribute: float", 100.0f, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700784 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700785 }
786 {
787 element->SetText(BIG);
788 int64_t v = 0;
789 element->QueryInt64Text(&v);
790 XMLTest("Element: int64_t", BIG, v, true);
791 }
792 }
793
794 // ---------- XMLPrinter stream mode ------
795 {
796 {
797 FILE* printerfp = fopen("resources/printer.xml", "w");
798 XMLPrinter printer(printerfp);
799 printer.OpenElement("foo");
800 printer.PushAttribute("attrib-text", "text");
801 printer.PushAttribute("attrib-int", int(1));
802 printer.PushAttribute("attrib-unsigned", unsigned(2));
803 printer.PushAttribute("attrib-int64", int64_t(3));
804 printer.PushAttribute("attrib-bool", true);
805 printer.PushAttribute("attrib-double", 4.0);
806 printer.CloseElement();
807 fclose(printerfp);
808 }
809 {
810 XMLDocument doc;
811 doc.LoadFile("resources/printer.xml");
812 XMLTest("XMLPrinter Stream mode: load", doc.ErrorID(), XML_SUCCESS, true);
813
814 const XMLDocument& cdoc = doc;
815
816 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
817 XMLTest("attrib-text", "text", attrib->Value(), true);
818 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
819 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
820 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
821 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
822 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
823 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
824 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
825 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
826 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
827 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
828 }
829
830 }
831
Uli Kusterer321072e2014-01-21 01:57:38 +0100832
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800833 // ---------- CDATA ---------------
834 {
835 const char* str = "<xmlElement>"
836 "<![CDATA["
837 "I am > the rules!\n"
838 "...since I make symbolic puns"
839 "]]>"
840 "</xmlElement>";
841 XMLDocument doc;
842 doc.Parse( str );
843 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800844
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700845 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800846 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800847 false );
848 }
849
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800850 // ----------- CDATA -------------
851 {
852 const char* str = "<xmlElement>"
853 "<![CDATA["
854 "<b>I am > the rules!</b>\n"
855 "...since I make symbolic puns"
856 "]]>"
857 "</xmlElement>";
858 XMLDocument doc;
859 doc.Parse( str );
860 doc.Print();
861
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700862 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800863 "<b>I am > the rules!</b>\n...since I make symbolic puns",
864 false );
865 }
866
867 // InsertAfterChild causes crash.
868 {
869 // InsertBeforeChild and InsertAfterChild causes crash.
870 XMLDocument doc;
871 XMLElement* parent = doc.NewElement( "Parent" );
872 doc.InsertFirstChild( parent );
873
874 XMLElement* childText0 = doc.NewElement( "childText0" );
875 XMLElement* childText1 = doc.NewElement( "childText1" );
876
877 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
878 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
879
880 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
881 }
Lee Thomasond6277762012-02-22 16:00:12 -0800882
883 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800884 // Entities not being written correctly.
885 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800886
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800887 const char* passages =
888 "<?xml version=\"1.0\" standalone=\"no\" ?>"
889 "<passages count=\"006\" formatversion=\"20020620\">"
890 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
891 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
892 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800893
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800894 XMLDocument doc;
895 doc.Parse( passages );
896 XMLElement* psg = doc.RootElement()->FirstChildElement();
897 const char* context = psg->Attribute( "context" );
898 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 -0800899
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800900 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800901
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400902 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800903 if ( textfile )
904 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800905 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800906 psg->Accept( &streamer );
907 fclose( textfile );
908 }
Thomas Roß0922b732012-09-23 16:31:22 +0200909
910 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800911 TIXMLASSERT( textfile );
912 if ( textfile )
913 {
914 char buf[ 1024 ];
915 fgets( buf, 1024, textfile );
916 XMLTest( "Entity transformation: write. ",
917 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
918 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
919 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700920 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800921 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800922 }
923
924 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800925 // Suppress entities.
926 const char* passages =
927 "<?xml version=\"1.0\" standalone=\"no\" ?>"
928 "<passages count=\"006\" formatversion=\"20020620\">"
929 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
930 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700931
Lee Thomason6f381b72012-03-02 12:59:39 -0800932 XMLDocument doc( false );
933 doc.Parse( passages );
934
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700935 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800936 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
937 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
938 "Crazy &ttk;" );
939 doc.Print();
940 }
941
942 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400943 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800944
945 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400946 doc.Parse( test );
947 XMLTest( "dot in names", doc.Error(), false );
948 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
949 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800950 }
951
952 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400953 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800954
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400955 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800956 doc.Parse( test );
957
958 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
959 XMLTest( "Entity with one digit.",
960 text->Value(), "1.1 Start easy ignore fin thickness\n",
961 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400962 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800963
964 {
965 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700966 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800967 const char* doctype =
968 "<?xml version=\"1.0\" ?>"
969 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
970 "<!ELEMENT title (#PCDATA)>"
971 "<!ELEMENT books (title,authors)>"
972 "<element />";
973
974 XMLDocument doc;
975 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400976 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800977 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400978 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800979 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700980
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800981 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
982 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
983
984 }
985
986 {
987 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700988 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800989 "<!-- Somewhat<evil> -->";
990 XMLDocument doc;
991 doc.Parse( doctype );
992
993 XMLComment* comment = doc.FirstChild()->ToComment();
994
995 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
996 }
997 {
998 // Double attributes
999 const char* doctype = "<element attr='red' attr='blue' />";
1000
1001 XMLDocument doc;
1002 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001003
Lee Thomason2fa81722012-11-09 12:37:46 -08001004 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 -08001005 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001006 }
1007
1008 {
1009 // Embedded null in stream.
1010 const char* doctype = "<element att\0r='red' attr='blue' />";
1011
1012 XMLDocument doc;
1013 doc.Parse( doctype );
1014 XMLTest( "Embedded null throws error.", true, doc.Error() );
1015 }
1016
1017 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001018 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001019 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001020 XMLDocument doc;
1021 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001022 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001023 }
1024
1025 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001026 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1027 const char* str = " ";
1028 XMLDocument doc;
1029 doc.Parse( str );
1030 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1031 }
1032
1033 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001034 // Low entities
1035 XMLDocument doc;
1036 doc.Parse( "<test>&#x0e;</test>" );
1037 const char result[] = { 0x0e, 0 };
1038 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
1039 doc.Print();
1040 }
1041
1042 {
1043 // Attribute values with trailing quotes not handled correctly
1044 XMLDocument doc;
1045 doc.Parse( "<foo attribute=bar\" />" );
1046 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
1047 }
1048
1049 {
1050 // [ 1663758 ] Failure to report error on bad XML
1051 XMLDocument xml;
1052 xml.Parse("<x>");
1053 XMLTest("Missing end tag at end of input", xml.Error(), true);
1054 xml.Parse("<x> ");
1055 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
1056 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -08001057 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001058 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001059
1060
1061 {
1062 // [ 1475201 ] TinyXML parses entities in comments
1063 XMLDocument xml;
1064 xml.Parse("<!-- declarations for <head> & <body> -->"
1065 "<!-- far &amp; away -->" );
1066
1067 XMLNode* e0 = xml.FirstChild();
1068 XMLNode* e1 = e0->NextSibling();
1069 XMLComment* c0 = e0->ToComment();
1070 XMLComment* c1 = e1->ToComment();
1071
1072 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1073 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1074 }
1075
1076 {
1077 XMLDocument xml;
1078 xml.Parse( "<Parent>"
1079 "<child1 att=''/>"
1080 "<!-- With this comment, child2 will not be parsed! -->"
1081 "<child2 att=''/>"
1082 "</Parent>" );
1083 xml.Print();
1084
1085 int count = 0;
1086
1087 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1088 ele;
1089 ele = ele->NextSibling() )
1090 {
1091 ++count;
1092 }
1093
1094 XMLTest( "Comments iterate correctly.", 3, count );
1095 }
1096
1097 {
1098 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1099 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1100 buf[60] = 239;
1101 buf[61] = 0;
1102
1103 XMLDocument doc;
1104 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001105 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001106
1107
1108 {
1109 // bug 1827248 Error while parsing a little bit malformed file
1110 // Actually not malformed - should work.
1111 XMLDocument xml;
1112 xml.Parse( "<attributelist> </attributelist >" );
1113 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1114 }
1115
1116 {
1117 // This one must not result in an infinite loop
1118 XMLDocument xml;
1119 xml.Parse( "<infinite>loop" );
1120 XMLTest( "Infinite loop test.", true, true );
1121 }
1122#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001123 {
1124 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1125 XMLDocument doc;
1126 doc.Parse( pub );
1127
1128 XMLDocument clone;
1129 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1130 XMLNode* copy = node->ShallowClone( &clone );
1131 clone.InsertEndChild( copy );
1132 }
1133
1134 clone.Print();
1135
1136 int count=0;
1137 const XMLNode* a=clone.FirstChild();
1138 const XMLNode* b=doc.FirstChild();
1139 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1140 ++count;
1141 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1142 }
1143 XMLTest( "Clone and Equal", 4, count );
1144 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001145
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001146 {
Lee Thomason7085f002017-06-01 18:09:43 -07001147 // Deep Cloning of root element.
1148 XMLDocument doc2;
1149 XMLPrinter printer1;
1150 {
1151 // Make sure doc1 is deleted before we test doc2
1152 const char* xml =
1153 "<root>"
1154 " <child1 foo='bar'/>"
1155 " <!-- comment thing -->"
1156 " <child2 val='1'>Text</child2>"
1157 "</root>";
1158 XMLDocument doc;
1159 doc.Parse(xml);
1160
1161 doc.Print(&printer1);
1162 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1163 doc2.InsertFirstChild(root);
1164 }
1165 XMLPrinter printer2;
1166 doc2.Print(&printer2);
1167
1168 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1169 }
1170
1171 {
1172 // Deep Cloning of sub element.
1173 XMLDocument doc2;
1174 XMLPrinter printer1;
1175 {
1176 // Make sure doc1 is deleted before we test doc2
1177 const char* xml =
1178 "<?xml version ='1.0'?>"
1179 "<root>"
1180 " <child1 foo='bar'/>"
1181 " <!-- comment thing -->"
1182 " <child2 val='1'>Text</child2>"
1183 "</root>";
1184 XMLDocument doc;
1185 doc.Parse(xml);
1186
1187 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1188 subElement->Accept(&printer1);
1189
1190 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1191 doc2.InsertFirstChild(clonedSubElement);
1192 }
1193 XMLPrinter printer2;
1194 doc2.Print(&printer2);
1195
1196 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1197 }
1198
1199 {
1200 // Deep cloning of document.
1201 XMLDocument doc2;
1202 XMLPrinter printer1;
1203 {
1204 // Make sure doc1 is deleted before we test doc2
1205 const char* xml =
1206 "<?xml version ='1.0'?>"
1207 "<!-- Top level comment. -->"
1208 "<root>"
1209 " <child1 foo='bar'/>"
1210 " <!-- comment thing -->"
1211 " <child2 val='1'>Text</child2>"
1212 "</root>";
1213 XMLDocument doc;
1214 doc.Parse(xml);
1215 doc.Print(&printer1);
1216
1217 doc.DeepCopy(&doc2);
1218 }
1219 XMLPrinter printer2;
1220 doc2.Print(&printer2);
1221
1222 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1223 }
1224
1225
1226 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001227 // This shouldn't crash.
1228 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001229 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001230 {
1231 doc.PrintError();
1232 }
1233 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1234 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001235
Lee Thomason5e3803c2012-04-16 08:57:05 -07001236 {
1237 // Attribute ordering.
1238 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1239 XMLDocument doc;
1240 doc.Parse( xml );
1241 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001242
Lee Thomason5e3803c2012-04-16 08:57:05 -07001243 const XMLAttribute* a = ele->FirstAttribute();
1244 XMLTest( "Attribute order", "1", a->Value() );
1245 a = a->Next();
1246 XMLTest( "Attribute order", "2", a->Value() );
1247 a = a->Next();
1248 XMLTest( "Attribute order", "3", a->Value() );
1249 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001250
Lee Thomason5e3803c2012-04-16 08:57:05 -07001251 ele->DeleteAttribute( "attrib2" );
1252 a = ele->FirstAttribute();
1253 XMLTest( "Attribute order", "1", a->Value() );
1254 a = a->Next();
1255 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001256
Lee Thomason5e3803c2012-04-16 08:57:05 -07001257 ele->DeleteAttribute( "attrib1" );
1258 ele->DeleteAttribute( "attrib3" );
1259 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1260 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001261
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001262 {
1263 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001264 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1265 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1266 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1267 XMLDocument doc0;
1268 doc0.Parse( xml0 );
1269 XMLDocument doc1;
1270 doc1.Parse( xml1 );
1271 XMLDocument doc2;
1272 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001273
Lee Thomason78a773d2012-07-02 10:10:19 -07001274 XMLElement* ele = 0;
1275 ele = doc0.FirstChildElement();
1276 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1277 ele = doc1.FirstChildElement();
1278 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1279 ele = doc2.FirstChildElement();
1280 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001281 }
1282
1283 {
1284 // Make sure we don't go into an infinite loop.
1285 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1286 XMLDocument doc;
1287 doc.Parse( xml );
1288 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1289 XMLElement* ele1 = ele0->NextSiblingElement();
1290 bool equal = ele0->ShallowEqual( ele1 );
1291
1292 XMLTest( "Infinite loop in shallow equal.", true, equal );
1293 }
1294
Lee Thomason5708f812012-03-28 17:46:41 -07001295 // -------- Handles ------------
1296 {
1297 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1298 XMLDocument doc;
1299 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -07001300
1301 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1302 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
1303
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001304 XMLHandle docH( doc );
1305 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001306 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001307 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001308
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001309 {
1310 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1311 XMLDocument doc;
1312 doc.Parse( xml );
1313 XMLConstHandle docH( doc );
1314
1315 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1316 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1317
1318 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001319 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001320 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001321 {
1322 // Default Declaration & BOM
1323 XMLDocument doc;
1324 doc.InsertEndChild( doc.NewDeclaration() );
1325 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001326
Lee Thomasonf68c4382012-04-28 14:37:11 -07001327 XMLPrinter printer;
1328 doc.Print( &printer );
1329
1330 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1331 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001332 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001333 }
Lee Thomason21be8822012-07-15 17:27:22 -07001334 {
1335 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1336 XMLDocument doc;
1337 doc.Parse( xml );
1338 XMLTest( "Ill formed XML", true, doc.Error() );
1339 }
1340
1341 // QueryXYZText
1342 {
1343 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1344 XMLDocument doc;
1345 doc.Parse( xml );
1346
1347 const XMLElement* pointElement = doc.RootElement();
1348
1349 int intValue = 0;
1350 unsigned unsignedValue = 0;
1351 float floatValue = 0;
1352 double doubleValue = 0;
1353 bool boolValue = false;
1354
1355 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1356 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1357 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1358 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1359 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1360
1361
1362 XMLTest( "QueryIntText", intValue, 1, false );
1363 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1364 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1365 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1366 XMLTest( "QueryBoolText", boolValue, true, false );
1367 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001368
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001369 {
1370 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1371 XMLDocument doc;
1372 doc.Parse( xml );
1373 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1374 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001375
1376 {
1377 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1378 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001379 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001380 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1381 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001382
1383 {
1384 const char* xml = "<3lement></3lement>";
1385 XMLDocument doc;
1386 doc.Parse( xml );
1387 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1388 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001389
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001390 {
1391 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1392 XMLDocument doc;
1393 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001394 XMLTest( "Set length of incoming data", doc.Error(), false );
1395 }
1396
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001397 {
1398 XMLDocument doc;
Dmitry-Me48b5df02015-04-06 18:20:25 +03001399 XMLTest( "Document is initially empty", doc.NoChildren(), true );
1400 doc.Clear();
1401 XMLTest( "Empty is empty after Clear()", doc.NoChildren(), true );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001402 doc.LoadFile( "resources/dream.xml" );
Dmitry-Meaaa4cea2015-02-06 16:00:46 +03001403 XMLTest( "Document has something to Clear()", doc.NoChildren(), false );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001404 doc.Clear();
1405 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1406 }
1407
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001408 // ----------- Whitespace ------------
1409 {
1410 const char* xml = "<element>"
1411 "<a> This \nis &apos; text &apos; </a>"
1412 "<b> This is &apos; text &apos; \n</b>"
1413 "<c>This is &apos; \n\n text &apos;</c>"
1414 "</element>";
1415 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1416 doc.Parse( xml );
1417
1418 const XMLElement* element = doc.FirstChildElement();
1419 for( const XMLElement* parent = element->FirstChildElement();
1420 parent;
1421 parent = parent->NextSiblingElement() )
1422 {
1423 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1424 }
1425 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001426
Lee Thomasonae9ab072012-10-24 10:17:53 -07001427#if 0
1428 {
1429 // Passes if assert doesn't fire.
1430 XMLDocument xmlDoc;
1431
1432 xmlDoc.NewDeclaration();
1433 xmlDoc.NewComment("Configuration file");
1434
1435 XMLElement *root = xmlDoc.NewElement("settings");
1436 root->SetAttribute("version", 2);
1437 }
1438#endif
1439
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001440 {
1441 const char* xml = "<element> </element>";
1442 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1443 doc.Parse( xml );
1444 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1445 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001446
Lee Thomason5b0a6772012-11-19 13:54:42 -08001447 {
1448 // An assert should not fire.
1449 const char* xml = "<element/>";
1450 XMLDocument doc;
1451 doc.Parse( xml );
1452 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1453 XMLTest( "Tracking unused elements", true, ele != 0, false );
1454 }
1455
Lee Thomasona6412ac2012-12-13 15:39:11 -08001456
1457 {
1458 const char* xml = "<parent><child>abc</child></parent>";
1459 XMLDocument doc;
1460 doc.Parse( xml );
1461 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1462
1463 XMLPrinter printer;
1464 ele->Accept( &printer );
1465 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1466 }
1467
1468
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001469 {
1470 XMLDocument doc;
1471 XMLError error = doc.LoadFile( "resources/empty.xml" );
1472 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001473 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001474 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001475 }
1476
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001477 {
1478 // BOM preservation
1479 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1480 {
1481 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001482 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001483 XMLPrinter printer;
1484 doc.Print( &printer );
1485
1486 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1487 doc.SaveFile( "resources/bomtest.xml" );
1488 }
1489 {
1490 XMLDocument doc;
1491 doc.LoadFile( "resources/bomtest.xml" );
1492 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1493
1494 XMLPrinter printer;
1495 doc.Print( &printer );
1496 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1497 }
1498 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001499
Michael Daumlinged523282013-10-23 07:47:29 +02001500 {
1501 // Insertion with Removal
1502 const char* xml = "<?xml version=\"1.0\" ?>"
1503 "<root>"
1504 "<one>"
1505 "<subtree>"
1506 "<elem>element 1</elem>text<!-- comment -->"
1507 "</subtree>"
1508 "</one>"
1509 "<two/>"
1510 "</root>";
1511 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1512 "<root>"
1513 "<one/>"
1514 "<two>"
1515 "<subtree>"
1516 "<elem>element 1</elem>text<!-- comment -->"
1517 "</subtree>"
1518 "</two>"
1519 "</root>";
1520 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1521 "<root>"
1522 "<one/>"
1523 "<subtree>"
1524 "<elem>element 1</elem>text<!-- comment -->"
1525 "</subtree>"
1526 "<two/>"
1527 "</root>";
1528 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1529 "<root>"
1530 "<one/>"
1531 "<two/>"
1532 "<subtree>"
1533 "<elem>element 1</elem>text<!-- comment -->"
1534 "</subtree>"
1535 "</root>";
1536
1537 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001538 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001539 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1540 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1541 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001542 XMLPrinter printer1(0, true);
1543 doc.Accept(&printer1);
1544 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001545
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001546 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001547 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1548 two = doc.RootElement()->FirstChildElement("two");
1549 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001550 XMLPrinter printer2(0, true);
1551 doc.Accept(&printer2);
1552 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001553
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001554 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001555 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1556 subtree = one->FirstChildElement("subtree");
1557 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001558 XMLPrinter printer3(0, true);
1559 doc.Accept(&printer3);
1560 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001561
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001562 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001563 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1564 two = doc.RootElement()->FirstChildElement("two");
1565 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001566 XMLPrinter printer4(0, true);
1567 doc.Accept(&printer4);
1568 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001569 }
1570
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001571 {
1572 const char* xml = "<svg width = \"128\" height = \"128\">"
1573 " <text> </text>"
1574 "</svg>";
1575 XMLDocument doc;
1576 doc.Parse(xml);
1577 doc.Print();
1578 }
1579
Lee Thomason92e521b2014-11-15 17:45:51 -08001580 {
1581 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001582 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1583 XMLDocument doc;
1584 doc.Parse(xml);
1585 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001586 }
1587
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001588#if 1
1589 // the question being explored is what kind of print to use:
1590 // https://github.com/leethomason/tinyxml2/issues/63
1591 {
1592 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1593 const char* xml = "<element/>";
1594 XMLDocument doc;
1595 doc.Parse( xml );
1596 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1597 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1598 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1599 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1600 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1601 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1602
1603 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1604 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1605 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1606 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1607 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1608 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1609
1610 doc.Print();
1611
1612 /* The result of this test is platform, compiler, and library version dependent. :("
1613 XMLPrinter printer;
1614 doc.Print( &printer );
1615 XMLTest( "Float and double formatting.",
1616 "<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",
1617 printer.CStr(),
1618 true );
1619 */
1620 }
1621#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001622
1623 {
1624 // Issue #184
1625 // If it doesn't assert, it passes. Caused by objects
1626 // getting created during parsing which are then
1627 // inaccessible in the memory pools.
1628 {
1629 XMLDocument doc;
1630 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1631 }
1632 {
1633 XMLDocument doc;
1634 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1635 doc.Clear();
1636 }
1637 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001638
1639 {
1640 // If this doesn't assert in DEBUG, all is well.
1641 tinyxml2::XMLDocument doc;
1642 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1643 doc.DeleteNode(pRoot);
1644 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001645
Dmitry-Me8b67d742014-12-22 11:35:12 +03001646 {
1647 // Should not assert in DEBUG
1648 XMLPrinter printer;
1649 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001650
Dmitry-Me6f51c802015-03-14 13:25:03 +03001651 {
1652 // Issue 291. Should not crash
1653 const char* xml = "&#0</a>";
1654 XMLDocument doc;
1655 doc.Parse( xml );
1656
1657 XMLPrinter printer;
1658 doc.Print( &printer );
1659 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001660 {
1661 // Issue 299. Can print elements that are not linked in.
1662 // Will crash if issue not fixed.
1663 XMLDocument doc;
1664 XMLElement* newElement = doc.NewElement( "printme" );
1665 XMLPrinter printer;
1666 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001667 // Delete the node to avoid possible memory leak report in debug output
1668 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001669 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001670 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001671 // Issue 302. Clear errors from LoadFile/SaveFile
1672 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001673 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001674 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001675 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001676 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001677 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001678 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001679
Dmitry-Med9852a52015-03-25 10:17:49 +03001680 {
1681 // If a document fails to load then subsequent
1682 // successful loads should clear the error
1683 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001684 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001685 doc.LoadFile( "resources/no-such-file.xml" );
1686 XMLTest( "No such file - should fail", true, doc.Error() );
1687
1688 doc.LoadFile( "resources/dream.xml" );
1689 XMLTest( "Error should be cleared", false, doc.Error() );
1690 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301691
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301692 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001693 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001694 const char* xml0 = "<?xml version=\"1.0\" ?>"
1695 " <!-- xml version=\"1.1\" -->"
1696 "<first />";
1697 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001698 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001699 "<first />";
1700 const char* xml2 = "<first />"
1701 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001702 const char* xml3 = "<first></first>"
1703 "<?xml version=\"1.0\" ?>";
1704
1705 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1706
Lee Thomason85492022015-05-22 11:07:45 -07001707 XMLDocument doc;
1708 doc.Parse(xml0);
1709 XMLTest("Test that the code changes do not affect normal parsing", doc.Error(), false);
1710 doc.Parse(xml1);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001711 XMLTest("Test that the second declaration is allowed", doc.Error(), false);
Lee Thomason85492022015-05-22 11:07:45 -07001712 doc.Parse(xml2);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001713 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1714 doc.Parse(xml3);
1715 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1716 doc.Parse(xml4);
1717 XMLTest("Test that declaration inside a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301718 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001719
Lee Thomason85492022015-05-22 11:07:45 -07001720 {
1721 // No matter - before or after successfully parsing a text -
1722 // calling XMLDocument::Value() causes an assert in debug.
1723 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1724 "<first />"
1725 "<second />";
1726 XMLDocument* doc = new XMLDocument();
1727 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1728 doc->Parse( validXml );
1729 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1730 delete doc;
1731 }
1732
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001733 {
1734 XMLDocument doc;
1735 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001736 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001737 doc.ErrorName();
1738 }
1739 }
1740
Lee Thomason816d3fa2017-06-05 14:35:55 -07001741 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001742 // Evil memory leaks.
1743 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1744 // and NOT added to the XMLDocument, what happens?
1745 //
1746 // Previously (buggy):
1747 // The memory would be free'd when the XMLDocument is
1748 // destructed. But the destructor wasn't called, so that
1749 // memory allocated by the XMLElement would not be free'd.
1750 // In practice this meant strings allocated by the XMLElement
1751 // would leak. An edge case, but annoying.
1752 // Now:
1753 // The destructor is called. But the list of unlinked nodes
1754 // has to be tracked. This has a minor performance impact
1755 // that can become significant if you have a lot. (But why
1756 // would you do that?)
1757 // The only way to see this bug is in a leak tracker. This
1758 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001759 {
1760 XMLDocument doc;
1761 doc.NewElement("LEAK 1");
1762 }
1763 {
1764 XMLDocument doc;
1765 XMLElement* ele = doc.NewElement("LEAK 2");
1766 doc.DeleteNode(ele);
1767 }
1768 }
1769
Lee Thomason224ef772017-06-16 09:45:26 -07001770 {
1771 // Crashing reported via email.
1772 const char* xml =
1773 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001774 "<property name='track_name'>voice</property>"
1775 "<property name='audio_track'>1</property>"
1776 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1777 "<blank length = '1' />"
1778 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1779 "<blank length = '2' />"
1780 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1781 "<blank length = '1' />"
1782 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001783 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001784
Lee Thomason224ef772017-06-16 09:45:26 -07001785 // It's not a good idea to delete elements as you walk the
1786 // list. I'm not sure this technically should work; but it's
1787 // an interesting test case.
1788 XMLDocument doc;
1789 XMLError err = doc.Parse(xml);
Lee Thomason9e2d29b2017-06-16 09:51:11 -07001790 XMLTest("Crash bug parsing", err, XML_SUCCESS);
Dmitry-Meaea64c42017-06-20 18:20:15 +03001791
1792 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001793 XMLTest("Crash bug parsing", true, playlist != 0);
1794
1795 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1796 XMLTest("Crash bug parsing", true, entry != 0);
1797 while (entry) {
1798 tinyxml2::XMLElement* todelete = entry;
1799 entry = entry->NextSiblingElement("entry");
1800 playlist->DeleteChild(todelete);
1801 };
1802 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1803 while (blank) {
1804 tinyxml2::XMLElement* todelete = blank;
1805 blank = blank->NextSiblingElement("blank");
1806 playlist->DeleteChild(todelete);
1807 };
1808
1809 tinyxml2::XMLPrinter printer;
1810 playlist->Accept(&printer);
1811 printf("%s\n", printer.CStr());
1812
Lee Thomason82bb0742017-06-16 09:48:20 -07001813 // No test; it only need to not crash.
1814 // Still, wrap it up with a sanity check
1815 int nProperty = 0;
1816 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1817 nProperty++;
1818 }
1819 XMLTest("Crash bug parsing", nProperty, 2);
Lee Thomason224ef772017-06-16 09:45:26 -07001820 }
1821
kezenatorec694152016-11-26 17:21:43 +10001822 // ----------- Line Number Tracking --------------
1823 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001824 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001825 {
1826 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1827 {
1828 XMLDocument doc;
1829 XMLError err = doc.Parse(docStr);
1830
1831 XMLTest(testString, true, doc.Error());
1832 XMLTest(testString, expected_error, err);
1833 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1834 };
1835
1836 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1837 {
1838 XMLDocument doc;
1839 doc.Parse(docStr);
1840 XMLTest(testString, false, doc.Error());
1841 TestDocLines(testString, doc, expectedLines);
1842 }
1843
1844 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1845 {
1846 XMLDocument doc;
1847 doc.LoadFile(file_name);
1848 XMLTest(testString, false, doc.Error());
1849 TestDocLines(testString, doc, expectedLines);
1850 }
1851
1852 private:
1853 DynArray<char, 10> str;
1854
1855 void Push(char type, int lineNum)
1856 {
1857 str.Push(type);
1858 str.Push(char('0' + (lineNum / 10)));
1859 str.Push(char('0' + (lineNum % 10)));
1860 }
1861
1862 bool VisitEnter(const XMLDocument& doc)
1863 {
kezenator19d8ea82016-11-29 19:50:27 +10001864 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001865 return true;
1866 }
1867 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
1868 {
kezenator19d8ea82016-11-29 19:50:27 +10001869 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001870 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10001871 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001872 return true;
1873 }
1874 bool Visit(const XMLDeclaration& declaration)
1875 {
kezenator19d8ea82016-11-29 19:50:27 +10001876 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001877 return true;
1878 }
1879 bool Visit(const XMLText& text)
1880 {
kezenator19d8ea82016-11-29 19:50:27 +10001881 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001882 return true;
1883 }
1884 bool Visit(const XMLComment& comment)
1885 {
kezenator19d8ea82016-11-29 19:50:27 +10001886 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001887 return true;
1888 }
1889 bool Visit(const XMLUnknown& unknown)
1890 {
kezenator19d8ea82016-11-29 19:50:27 +10001891 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001892 return true;
1893 }
1894
1895 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
1896 {
1897 str.Clear();
1898 doc.Accept(this);
1899 str.Push(0);
1900 XMLTest(testString, expectedLines, str.Mem());
1901 }
Lee Thomasone90e9012016-12-24 07:34:39 -08001902 } tester;
kezenatorec694152016-11-26 17:21:43 +10001903
Lee Thomasone90e9012016-12-24 07:34:39 -08001904 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
1905 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
1906 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
1907 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
1908 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
1909 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
1910 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
1911 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
1912 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
1913 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
1914 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10001915
Lee Thomasone90e9012016-12-24 07:34:39 -08001916 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001917 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08001918
1919 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
1920 "<root a='b' \n" // 2 Element Attribute
1921 "c='d'> d <blah/> \n" // 3 Attribute Text Element
1922 "newline in text \n" // 4 Text
1923 "and second <zxcv/><![CDATA[\n" // 5 Element Text
1924 " cdata test ]]><!-- comment -->\n" // 6 Comment
1925 "<! unknown></root>", // 7 Unknown
1926
kezenatorec694152016-11-26 17:21:43 +10001927 "D01L01E02A02A03T03E03T04E05T05C06U07");
1928
Lee Thomasone90e9012016-12-24 07:34:39 -08001929 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001930 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08001931
1932 "\r\n" // 1 Doc (arguably should be line 2)
1933 "<?xml version=\"1.0\"?>\n" // 2 DecL
1934 "<root>\r\n" // 3 Element
1935 "\n" // 4
1936 "text contining new line \n" // 5 Text
1937 " and also containing crlf \r\n" // 6
1938 "<sub><![CDATA[\n" // 7 Element Text
1939 "cdata containing new line \n" // 8
1940 " and also containing cflr\r\n" // 9
1941 "]]></sub><sub2/></root>", // 10 Element
1942
kezenatorec694152016-11-26 17:21:43 +10001943 "D01L02E03T05E07T07E10");
1944
Lee Thomasone90e9012016-12-24 07:34:39 -08001945 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10001946 "LineNumbers-File",
1947 "resources/utf8test.xml",
1948 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
1949 }
1950
Lee Thomason85492022015-05-22 11:07:45 -07001951 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08001952 {
1953#if defined( _MSC_VER )
1954 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001955 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08001956#endif
1957
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001958 FILE* perfFP = fopen("resources/dream.xml", "r");
1959 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02001960 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001961 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08001962
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001963 char* mem = new char[size + 1];
1964 fread(mem, size, 1, perfFP);
1965 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08001966 mem[size] = 0;
1967
1968#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001969 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08001970#else
1971 clock_t cstart = clock();
1972#endif
1973 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001974 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001975 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001976 doc.Parse(mem);
Lee Thomason6f381b72012-03-02 12:59:39 -08001977 }
1978#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001979 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08001980#else
1981 clock_t cend = clock();
1982#endif
1983
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001984 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08001985
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001986 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001987#ifdef DEBUG
1988 "DEBUG";
1989#else
1990 "Release";
1991#endif
1992
1993#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001994 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT));
Lee Thomason6f381b72012-03-02 12:59:39 -08001995#else
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001996 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08001997#endif
1998 }
1999
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08002000 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002001 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002002
2003 _CrtMemState diffMemState;
2004 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2005 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002006
2007 {
2008 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2009 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2010 }
Lee Thomason1ff38e02012-02-14 18:18:16 -08002011 #endif
2012
2013 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002014
2015 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002016}