blob: baeaf1d67c5023df7548e3a91319a0c24e3acebf [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 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800406 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800407 // Build:
408 // <element>
409 // <!--comment-->
410 // <sub attrib="1" />
411 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800412 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800413 // <element>
414
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800415 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800416 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
417
418 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
419 for( int i=0; i<3; ++i ) {
420 sub[i]->SetAttribute( "attrib", i );
421 }
422 element->InsertEndChild( sub[2] );
423 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700424 comment->SetUserData((void*)2);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800425 element->InsertAfterChild( comment, sub[0] );
426 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800427 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800428 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800429 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
430 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
431 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700432 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800433 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Lee Thomasonc9445462016-07-17 22:53:48 -0700434 XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800435
436 // And now deletion:
437 element->DeleteChild( sub[2] );
438 doc->DeleteNode( comment );
439
440 element->FirstChildElement()->SetAttribute( "attrib", true );
441 element->LastChildElement()->DeleteAttribute( "attrib" );
442
443 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300444 const int defaultIntValue = 10;
445 const int replacementIntValue = 20;
446 int value1 = defaultIntValue;
447 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300448 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
449 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300450 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
451 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800452
453 doc->Print();
454
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700455 {
456 XMLPrinter streamer;
457 doc->Print( &streamer );
458 printf( "%s", streamer.CStr() );
459 }
460 {
461 XMLPrinter streamer( 0, true );
462 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200463 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700464 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700465 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300466 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700467 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300468 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800469 delete doc;
470 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800471 {
472 // Test: Dream
473 // XML1 : 1,187,569 bytes in 31,209 allocations
474 // XML2 : 469,073 bytes in 323 allocations
475 //int newStart = gNew;
476 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300477 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300478 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800479
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400480 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300481 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800482 doc.PrintError();
483
484 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400485 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800486 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
487 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
488 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
489 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400490 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800491 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400492 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800493
494 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400495 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300496 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800497 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400498 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800499 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
500 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
501 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
502 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400503 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800504
505 //gNewTotal = gNew - newStart;
506 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800507
508
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800509 {
510 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
511 "<passages count=\"006\" formatversion=\"20020620\">\n"
512 " <wrong error>\n"
513 "</passages>";
514
515 XMLDocument doc;
516 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300517 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800518 }
519
520 {
521 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
522
523 XMLDocument doc;
524 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300525 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800526
527 XMLElement* ele = doc.FirstChildElement();
528
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300529 int iVal;
530 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800531 double dVal;
532
533 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300534 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
535 XMLTest( "Query attribute: int as double", 1, (int)dVal );
536 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700537
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800538 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300539 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
540 XMLTest( "Query attribute: double as double", 2.0, dVal );
541 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700542
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800543 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300544 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
545 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700546
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800547 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300548 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
549 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700550
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800551 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300552 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
553 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800554 }
555
556 {
557 const char* str = "<doc/>";
558
559 XMLDocument doc;
560 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300561 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800562
563 XMLElement* ele = doc.FirstChildElement();
564
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800565 int iVal, iVal2;
566 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800567
568 ele->SetAttribute( "str", "strValue" );
569 ele->SetAttribute( "int", 1 );
570 ele->SetAttribute( "double", -1.0 );
571
572 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300573 {
574 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
575 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
576 }
577 {
578 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
579 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
580 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800581
Dmitry-Me2087a272017-07-10 18:13:07 +0300582 {
583 int queryResult = ele->QueryAttribute( "int", &iVal2 );
584 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
585 }
586 {
587 int queryResult = ele->QueryAttribute( "double", &dVal2 );
588 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
589 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800590
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300591 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800592 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
593 XMLTest( "Attribute round trip. int.", 1, iVal );
594 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800595 XMLTest( "Alternate query", true, iVal == iVal2 );
596 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700597 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
598 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800599 }
600
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800601 {
602 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300603 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300604 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800605
606 // Get the attribute "value" from the "Russian" element and check it.
607 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700608 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800609 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
610
611 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
612
613 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
614 0xd1U, 0x81U, 0xd1U, 0x81U,
615 0xd0U, 0xbaU, 0xd0U, 0xb8U,
616 0xd0U, 0xb9U, 0 };
617 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
618
619 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
620 XMLTest( "UTF-8: Browsing russian element name.",
621 russianText,
622 text->Value() );
623
624 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400625 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300626 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800627
628 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800629 int okay = 0;
630
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200631 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300632 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800633
634 if ( saved && verify )
635 {
636 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700637 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800638 while ( fgets( verifyBuf, 256, verify ) )
639 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700640 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800641 fgets( savedBuf, 256, saved );
642 NullLineEndings( verifyBuf );
643 NullLineEndings( savedBuf );
644
645 if ( strcmp( verifyBuf, savedBuf ) )
646 {
647 printf( "verify:%s<\n", verifyBuf );
648 printf( "saved :%s<\n", savedBuf );
649 okay = 0;
650 break;
651 }
652 }
653 }
654 if ( saved )
655 fclose( saved );
656 if ( verify )
657 fclose( verify );
658 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
659 }
660
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800661 // --------GetText()-----------
662 {
663 const char* str = "<foo>This is text</foo>";
664 XMLDocument doc;
665 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300666 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800667 const XMLElement* element = doc.RootElement();
668
669 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
670
671 str = "<foo><b>This is text</b></foo>";
672 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300673 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800674 element = doc.RootElement();
675
676 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
677 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800678
Lee Thomasond6277762012-02-22 16:00:12 -0800679
Uli Kusterer321072e2014-01-21 01:57:38 +0100680 // --------SetText()-----------
681 {
682 const char* str = "<foo></foo>";
683 XMLDocument doc;
684 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300685 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100686 XMLElement* element = doc.RootElement();
687
Lee Thomason9c0678a2014-01-24 10:18:27 -0800688 element->SetText("darkness.");
689 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100690
Lee Thomason9c0678a2014-01-24 10:18:27 -0800691 element->SetText("blue flame.");
692 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100693
694 str = "<foo/>";
695 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300696 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100697 element = doc.RootElement();
698
Lee Thomason9c0678a2014-01-24 10:18:27 -0800699 element->SetText("The driver");
700 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100701
Lee Thomason9c0678a2014-01-24 10:18:27 -0800702 element->SetText("<b>horses</b>");
703 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
704 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100705
706 str = "<foo><bar>Text in nested element</bar></foo>";
707 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300708 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100709 element = doc.RootElement();
710
Lee Thomason9c0678a2014-01-24 10:18:27 -0800711 element->SetText("wolves");
712 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800713
714 str = "<foo/>";
715 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300716 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800717 element = doc.RootElement();
718
719 element->SetText( "str" );
720 XMLTest( "SetText types", "str", element->GetText() );
721
722 element->SetText( 1 );
723 XMLTest( "SetText types", "1", element->GetText() );
724
725 element->SetText( 1U );
726 XMLTest( "SetText types", "1", element->GetText() );
727
728 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200729 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800730
731 element->SetText( 1.5f );
732 XMLTest( "SetText types", "1.5", element->GetText() );
733
734 element->SetText( 1.5 );
735 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100736 }
737
Lee Thomason51c12712016-06-04 20:18:49 -0700738 // ---------- Attributes ---------
739 {
740 static const int64_t BIG = -123456789012345678;
741 XMLDocument doc;
742 XMLElement* element = doc.NewElement("element");
743 doc.InsertFirstChild(element);
744
745 {
746 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300747 {
748 int v = 0;
749 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
750 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
751 XMLTest("Attribute: int", -100, v, true);
752 }
753 {
754 int v = 0;
755 int queryResult = element->QueryAttribute("attrib", &v);
756 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
757 XMLTest("Attribute: int", -100, v, true);
758 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700759 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700760 }
761 {
762 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300763 {
764 unsigned v = 0;
765 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
766 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
767 XMLTest("Attribute: unsigned", unsigned(100), v, true);
768 }
769 {
770 unsigned v = 0;
771 int queryResult = element->QueryAttribute("attrib", &v);
772 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
773 XMLTest("Attribute: unsigned", unsigned(100), v, true);
774 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700775 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700776 }
777 {
778 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300779 {
780 int64_t v = 0;
781 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
782 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
783 XMLTest("Attribute: int64_t", BIG, v, true);
784 }
785 {
786 int64_t v = 0;
787 int queryResult = element->QueryAttribute("attrib", &v);
788 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
789 XMLTest("Attribute: int64_t", BIG, v, true);
790 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700791 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700792 }
793 {
794 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300795 {
796 bool v = false;
797 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
798 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
799 XMLTest("Attribute: bool", true, v, true);
800 }
801 {
802 bool v = false;
803 int queryResult = element->QueryAttribute("attrib", &v);
804 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
805 XMLTest("Attribute: bool", true, v, true);
806 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700807 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700808 }
809 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800810 element->SetAttribute("attrib", true);
811 const char* result = element->Attribute("attrib");
812 XMLTest("Bool true is 'true'", "true", result);
813
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800814 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800815 element->SetAttribute("attrib", true);
816 result = element->Attribute("attrib");
817 XMLTest("Bool true is '1'", "1", result);
818
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800819 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800820 }
821 {
Lee Thomason51c12712016-06-04 20:18:49 -0700822 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300823 {
824 double v = 0;
825 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
826 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
827 XMLTest("Attribute: double", 100.0, v, true);
828 }
829 {
830 double v = 0;
831 int queryResult = element->QueryAttribute("attrib", &v);
832 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
833 XMLTest("Attribute: double", 100.0, v, true);
834 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700835 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700836 }
837 {
838 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300839 {
840 float v = 0;
841 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
842 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
843 XMLTest("Attribute: float", 100.0f, v, true);
844 }
845 {
846 float v = 0;
847 int queryResult = element->QueryAttribute("attrib", &v);
848 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
849 XMLTest("Attribute: float", 100.0f, v, true);
850 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700851 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700852 }
853 {
854 element->SetText(BIG);
855 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300856 XMLError queryResult = element->QueryInt64Text(&v);
857 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700858 XMLTest("Element: int64_t", BIG, v, true);
859 }
860 }
861
862 // ---------- XMLPrinter stream mode ------
863 {
864 {
865 FILE* printerfp = fopen("resources/printer.xml", "w");
866 XMLPrinter printer(printerfp);
867 printer.OpenElement("foo");
868 printer.PushAttribute("attrib-text", "text");
869 printer.PushAttribute("attrib-int", int(1));
870 printer.PushAttribute("attrib-unsigned", unsigned(2));
871 printer.PushAttribute("attrib-int64", int64_t(3));
872 printer.PushAttribute("attrib-bool", true);
873 printer.PushAttribute("attrib-double", 4.0);
874 printer.CloseElement();
875 fclose(printerfp);
876 }
877 {
878 XMLDocument doc;
879 doc.LoadFile("resources/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300880 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700881
882 const XMLDocument& cdoc = doc;
883
884 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
885 XMLTest("attrib-text", "text", attrib->Value(), true);
886 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
887 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
888 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
889 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
890 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
891 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
892 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
893 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
894 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
895 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
896 }
897
898 }
899
Uli Kusterer321072e2014-01-21 01:57:38 +0100900
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800901 // ---------- CDATA ---------------
902 {
903 const char* str = "<xmlElement>"
904 "<![CDATA["
905 "I am > the rules!\n"
906 "...since I make symbolic puns"
907 "]]>"
908 "</xmlElement>";
909 XMLDocument doc;
910 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300911 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800912 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800913
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300914 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
915 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800916 false );
917 }
918
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800919 // ----------- CDATA -------------
920 {
921 const char* str = "<xmlElement>"
922 "<![CDATA["
923 "<b>I am > the rules!</b>\n"
924 "...since I make symbolic puns"
925 "]]>"
926 "</xmlElement>";
927 XMLDocument doc;
928 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300929 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800930 doc.Print();
931
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300932 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800933 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300934 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800935 false );
936 }
937
938 // InsertAfterChild causes crash.
939 {
940 // InsertBeforeChild and InsertAfterChild causes crash.
941 XMLDocument doc;
942 XMLElement* parent = doc.NewElement( "Parent" );
943 doc.InsertFirstChild( parent );
944
945 XMLElement* childText0 = doc.NewElement( "childText0" );
946 XMLElement* childText1 = doc.NewElement( "childText1" );
947
948 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
949 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
950
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300951 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800952 }
Lee Thomasond6277762012-02-22 16:00:12 -0800953
954 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800955 // Entities not being written correctly.
956 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800957
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800958 const char* passages =
959 "<?xml version=\"1.0\" standalone=\"no\" ?>"
960 "<passages count=\"006\" formatversion=\"20020620\">"
961 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
962 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
963 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800964
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800965 XMLDocument doc;
966 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +0300967 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800968 XMLElement* psg = doc.RootElement()->FirstChildElement();
969 const char* context = psg->Attribute( "context" );
970 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 -0800971
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800972 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800973
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400974 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800975 if ( textfile )
976 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800977 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800978 psg->Accept( &streamer );
979 fclose( textfile );
980 }
Thomas Roß0922b732012-09-23 16:31:22 +0200981
982 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800983 TIXMLASSERT( textfile );
984 if ( textfile )
985 {
986 char buf[ 1024 ];
987 fgets( buf, 1024, textfile );
988 XMLTest( "Entity transformation: write. ",
989 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
990 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
991 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700992 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800993 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800994 }
995
996 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800997 // Suppress entities.
998 const char* passages =
999 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1000 "<passages count=\"006\" formatversion=\"20020620\">"
1001 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1002 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001003
Lee Thomason6f381b72012-03-02 12:59:39 -08001004 XMLDocument doc( false );
1005 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001006 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001007
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001008 XMLTest( "No entity parsing.",
1009 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1010 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1011 XMLTest( "No entity parsing.", "Crazy &ttk;",
1012 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001013 doc.Print();
1014 }
1015
1016 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001017 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001018
1019 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001020 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001021 XMLTest( "dot in names", false, doc.Error() );
1022 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1023 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001024 }
1025
1026 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001027 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001028
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001029 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001030 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001031 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001032
1033 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1034 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001035 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001036 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001037 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001038
1039 {
1040 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001041 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001042 const char* doctype =
1043 "<?xml version=\"1.0\" ?>"
1044 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1045 "<!ELEMENT title (#PCDATA)>"
1046 "<!ELEMENT books (title,authors)>"
1047 "<element />";
1048
1049 XMLDocument doc;
1050 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001051 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001052 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001053 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001054 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001055 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001056 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001057 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001058
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001059 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1060 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1061
1062 }
1063
1064 {
1065 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001066 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001067 "<!-- Somewhat<evil> -->";
1068 XMLDocument doc;
1069 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001070 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001071
1072 XMLComment* comment = doc.FirstChild()->ToComment();
1073
1074 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1075 }
1076 {
1077 // Double attributes
1078 const char* doctype = "<element attr='red' attr='blue' />";
1079
1080 XMLDocument doc;
1081 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001082
Lee Thomason2fa81722012-11-09 12:37:46 -08001083 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 -08001084 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001085 }
1086
1087 {
1088 // Embedded null in stream.
1089 const char* doctype = "<element att\0r='red' attr='blue' />";
1090
1091 XMLDocument doc;
1092 doc.Parse( doctype );
1093 XMLTest( "Embedded null throws error.", true, doc.Error() );
1094 }
1095
1096 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001097 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001098 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001099 XMLDocument doc;
1100 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001101 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001102 }
1103
1104 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001105 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1106 const char* str = " ";
1107 XMLDocument doc;
1108 doc.Parse( str );
1109 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1110 }
1111
1112 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001113 // Low entities
1114 XMLDocument doc;
1115 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001116 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001117 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001118 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001119 doc.Print();
1120 }
1121
1122 {
1123 // Attribute values with trailing quotes not handled correctly
1124 XMLDocument doc;
1125 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001126 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001127 }
1128
1129 {
1130 // [ 1663758 ] Failure to report error on bad XML
1131 XMLDocument xml;
1132 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001133 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001134 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001135 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001136 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001137 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001138 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001139
1140
1141 {
1142 // [ 1475201 ] TinyXML parses entities in comments
1143 XMLDocument xml;
1144 xml.Parse("<!-- declarations for <head> & <body> -->"
1145 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001146 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001147
1148 XMLNode* e0 = xml.FirstChild();
1149 XMLNode* e1 = e0->NextSibling();
1150 XMLComment* c0 = e0->ToComment();
1151 XMLComment* c1 = e1->ToComment();
1152
1153 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1154 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1155 }
1156
1157 {
1158 XMLDocument xml;
1159 xml.Parse( "<Parent>"
1160 "<child1 att=''/>"
1161 "<!-- With this comment, child2 will not be parsed! -->"
1162 "<child2 att=''/>"
1163 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001164 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001165 xml.Print();
1166
1167 int count = 0;
1168
1169 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1170 ele;
1171 ele = ele->NextSibling() )
1172 {
1173 ++count;
1174 }
1175
1176 XMLTest( "Comments iterate correctly.", 3, count );
1177 }
1178
1179 {
1180 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1181 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1182 buf[60] = 239;
1183 buf[61] = 0;
1184
1185 XMLDocument doc;
1186 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001187 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001188 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001189
1190
1191 {
1192 // bug 1827248 Error while parsing a little bit malformed file
1193 // Actually not malformed - should work.
1194 XMLDocument xml;
1195 xml.Parse( "<attributelist> </attributelist >" );
1196 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1197 }
1198
1199 {
1200 // This one must not result in an infinite loop
1201 XMLDocument xml;
1202 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001203 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001204 XMLTest( "Infinite loop test.", true, true );
1205 }
1206#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001207 {
1208 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1209 XMLDocument doc;
1210 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001211 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001212
1213 XMLDocument clone;
1214 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1215 XMLNode* copy = node->ShallowClone( &clone );
1216 clone.InsertEndChild( copy );
1217 }
1218
1219 clone.Print();
1220
1221 int count=0;
1222 const XMLNode* a=clone.FirstChild();
1223 const XMLNode* b=doc.FirstChild();
1224 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1225 ++count;
1226 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1227 }
1228 XMLTest( "Clone and Equal", 4, count );
1229 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001230
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001231 {
Lee Thomason7085f002017-06-01 18:09:43 -07001232 // Deep Cloning of root element.
1233 XMLDocument doc2;
1234 XMLPrinter printer1;
1235 {
1236 // Make sure doc1 is deleted before we test doc2
1237 const char* xml =
1238 "<root>"
1239 " <child1 foo='bar'/>"
1240 " <!-- comment thing -->"
1241 " <child2 val='1'>Text</child2>"
1242 "</root>";
1243 XMLDocument doc;
1244 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001245 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001246
1247 doc.Print(&printer1);
1248 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1249 doc2.InsertFirstChild(root);
1250 }
1251 XMLPrinter printer2;
1252 doc2.Print(&printer2);
1253
1254 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1255 }
1256
1257 {
1258 // Deep Cloning of sub element.
1259 XMLDocument doc2;
1260 XMLPrinter printer1;
1261 {
1262 // Make sure doc1 is deleted before we test doc2
1263 const char* xml =
1264 "<?xml version ='1.0'?>"
1265 "<root>"
1266 " <child1 foo='bar'/>"
1267 " <!-- comment thing -->"
1268 " <child2 val='1'>Text</child2>"
1269 "</root>";
1270 XMLDocument doc;
1271 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001272 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001273
1274 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1275 subElement->Accept(&printer1);
1276
1277 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1278 doc2.InsertFirstChild(clonedSubElement);
1279 }
1280 XMLPrinter printer2;
1281 doc2.Print(&printer2);
1282
1283 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1284 }
1285
1286 {
1287 // Deep cloning of document.
1288 XMLDocument doc2;
1289 XMLPrinter printer1;
1290 {
1291 // Make sure doc1 is deleted before we test doc2
1292 const char* xml =
1293 "<?xml version ='1.0'?>"
1294 "<!-- Top level comment. -->"
1295 "<root>"
1296 " <child1 foo='bar'/>"
1297 " <!-- comment thing -->"
1298 " <child2 val='1'>Text</child2>"
1299 "</root>";
1300 XMLDocument doc;
1301 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001302 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001303 doc.Print(&printer1);
1304
1305 doc.DeepCopy(&doc2);
1306 }
1307 XMLPrinter printer2;
1308 doc2.Print(&printer2);
1309
1310 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1311 }
1312
1313
1314 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001315 // This shouldn't crash.
1316 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001317 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001318 {
1319 doc.PrintError();
1320 }
1321 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1322 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001323
Lee Thomason5e3803c2012-04-16 08:57:05 -07001324 {
1325 // Attribute ordering.
1326 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1327 XMLDocument doc;
1328 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001329 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001330 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001331
Lee Thomason5e3803c2012-04-16 08:57:05 -07001332 const XMLAttribute* a = ele->FirstAttribute();
1333 XMLTest( "Attribute order", "1", a->Value() );
1334 a = a->Next();
1335 XMLTest( "Attribute order", "2", a->Value() );
1336 a = a->Next();
1337 XMLTest( "Attribute order", "3", a->Value() );
1338 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001339
Lee Thomason5e3803c2012-04-16 08:57:05 -07001340 ele->DeleteAttribute( "attrib2" );
1341 a = ele->FirstAttribute();
1342 XMLTest( "Attribute order", "1", a->Value() );
1343 a = a->Next();
1344 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001345
Lee Thomason5e3803c2012-04-16 08:57:05 -07001346 ele->DeleteAttribute( "attrib1" );
1347 ele->DeleteAttribute( "attrib3" );
1348 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1349 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001350
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001351 {
1352 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001353 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1354 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1355 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1356 XMLDocument doc0;
1357 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001358 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001359 XMLDocument doc1;
1360 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001361 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001362 XMLDocument doc2;
1363 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001364 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001365
Lee Thomason78a773d2012-07-02 10:10:19 -07001366 XMLElement* ele = 0;
1367 ele = doc0.FirstChildElement();
1368 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1369 ele = doc1.FirstChildElement();
1370 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1371 ele = doc2.FirstChildElement();
1372 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001373 }
1374
1375 {
1376 // Make sure we don't go into an infinite loop.
1377 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1378 XMLDocument doc;
1379 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001380 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001381 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1382 XMLElement* ele1 = ele0->NextSiblingElement();
1383 bool equal = ele0->ShallowEqual( ele1 );
1384
1385 XMLTest( "Infinite loop in shallow equal.", true, equal );
1386 }
1387
Lee Thomason5708f812012-03-28 17:46:41 -07001388 // -------- Handles ------------
1389 {
1390 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1391 XMLDocument doc;
1392 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001393 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001394
1395 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001396 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001397
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001398 XMLHandle docH( doc );
1399 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001400 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001401 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001402
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001403 {
1404 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1405 XMLDocument doc;
1406 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001407 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001408 XMLConstHandle docH( doc );
1409
1410 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1411 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1412
1413 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001414 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001415 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001416 {
1417 // Default Declaration & BOM
1418 XMLDocument doc;
1419 doc.InsertEndChild( doc.NewDeclaration() );
1420 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001421
Lee Thomasonf68c4382012-04-28 14:37:11 -07001422 XMLPrinter printer;
1423 doc.Print( &printer );
1424
1425 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001426 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1427 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001428 }
Lee Thomason21be8822012-07-15 17:27:22 -07001429 {
1430 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1431 XMLDocument doc;
1432 doc.Parse( xml );
1433 XMLTest( "Ill formed XML", true, doc.Error() );
1434 }
1435
1436 // QueryXYZText
1437 {
1438 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1439 XMLDocument doc;
1440 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001441 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001442
1443 const XMLElement* pointElement = doc.RootElement();
1444
1445 int intValue = 0;
1446 unsigned unsignedValue = 0;
1447 float floatValue = 0;
1448 double doubleValue = 0;
1449 bool boolValue = false;
1450
1451 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1452 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1453 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1454 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1455 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1456
1457
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001458 XMLTest( "QueryIntText", 1, intValue, false );
1459 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1460 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1461 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1462 XMLTest( "QueryBoolText", true, boolValue, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001463 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001464
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001465 {
1466 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1467 XMLDocument doc;
1468 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001469 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001470 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001471
1472 {
1473 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1474 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001475 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001476 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001477 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001478
1479 {
1480 const char* xml = "<3lement></3lement>";
1481 XMLDocument doc;
1482 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001483 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001484 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001485
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001486 {
1487 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1488 XMLDocument doc;
1489 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001490 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001491 }
1492
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001493 {
1494 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001495 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001496 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001497 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001498 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001499 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001500 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001501 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001502 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001503 }
1504
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001505 // ----------- Whitespace ------------
1506 {
1507 const char* xml = "<element>"
1508 "<a> This \nis &apos; text &apos; </a>"
1509 "<b> This is &apos; text &apos; \n</b>"
1510 "<c>This is &apos; \n\n text &apos;</c>"
1511 "</element>";
1512 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1513 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001514 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001515
1516 const XMLElement* element = doc.FirstChildElement();
1517 for( const XMLElement* parent = element->FirstChildElement();
1518 parent;
1519 parent = parent->NextSiblingElement() )
1520 {
1521 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1522 }
1523 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001524
Lee Thomasonae9ab072012-10-24 10:17:53 -07001525#if 0
1526 {
1527 // Passes if assert doesn't fire.
1528 XMLDocument xmlDoc;
1529
1530 xmlDoc.NewDeclaration();
1531 xmlDoc.NewComment("Configuration file");
1532
1533 XMLElement *root = xmlDoc.NewElement("settings");
1534 root->SetAttribute("version", 2);
1535 }
1536#endif
1537
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001538 {
1539 const char* xml = "<element> </element>";
1540 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1541 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001542 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001543 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1544 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001545
Lee Thomason5b0a6772012-11-19 13:54:42 -08001546 {
1547 // An assert should not fire.
1548 const char* xml = "<element/>";
1549 XMLDocument doc;
1550 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001551 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001552 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1553 XMLTest( "Tracking unused elements", true, ele != 0, false );
1554 }
1555
Lee Thomasona6412ac2012-12-13 15:39:11 -08001556
1557 {
1558 const char* xml = "<parent><child>abc</child></parent>";
1559 XMLDocument doc;
1560 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001561 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001562 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1563
1564 XMLPrinter printer;
1565 ele->Accept( &printer );
1566 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1567 }
1568
1569
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001570 {
1571 XMLDocument doc;
1572 XMLError error = doc.LoadFile( "resources/empty.xml" );
1573 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001574 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001575 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001576 }
1577
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001578 {
1579 // BOM preservation
1580 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1581 {
1582 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001583 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001584 XMLPrinter printer;
1585 doc.Print( &printer );
1586
1587 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1588 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001589 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001590 }
1591 {
1592 XMLDocument doc;
1593 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001594 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001595 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1596
1597 XMLPrinter printer;
1598 doc.Print( &printer );
1599 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1600 }
1601 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001602
Michael Daumlinged523282013-10-23 07:47:29 +02001603 {
1604 // Insertion with Removal
1605 const char* xml = "<?xml version=\"1.0\" ?>"
1606 "<root>"
1607 "<one>"
1608 "<subtree>"
1609 "<elem>element 1</elem>text<!-- comment -->"
1610 "</subtree>"
1611 "</one>"
1612 "<two/>"
1613 "</root>";
1614 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1615 "<root>"
1616 "<one/>"
1617 "<two>"
1618 "<subtree>"
1619 "<elem>element 1</elem>text<!-- comment -->"
1620 "</subtree>"
1621 "</two>"
1622 "</root>";
1623 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1624 "<root>"
1625 "<one/>"
1626 "<subtree>"
1627 "<elem>element 1</elem>text<!-- comment -->"
1628 "</subtree>"
1629 "<two/>"
1630 "</root>";
1631 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1632 "<root>"
1633 "<one/>"
1634 "<two/>"
1635 "<subtree>"
1636 "<elem>element 1</elem>text<!-- comment -->"
1637 "</subtree>"
1638 "</root>";
1639
1640 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001641 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001642 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001643 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1644 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1645 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001646 XMLPrinter printer1(0, true);
1647 doc.Accept(&printer1);
1648 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001649
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001650 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001651 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001652 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1653 two = doc.RootElement()->FirstChildElement("two");
1654 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001655 XMLPrinter printer2(0, true);
1656 doc.Accept(&printer2);
1657 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001658
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001659 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001660 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001661 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1662 subtree = one->FirstChildElement("subtree");
1663 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001664 XMLPrinter printer3(0, true);
1665 doc.Accept(&printer3);
1666 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001667
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001668 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001669 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001670 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1671 two = doc.RootElement()->FirstChildElement("two");
1672 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001673 XMLPrinter printer4(0, true);
1674 doc.Accept(&printer4);
1675 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001676 }
1677
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001678 {
1679 const char* xml = "<svg width = \"128\" height = \"128\">"
1680 " <text> </text>"
1681 "</svg>";
1682 XMLDocument doc;
1683 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001684 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001685 doc.Print();
1686 }
1687
Lee Thomason92e521b2014-11-15 17:45:51 -08001688 {
1689 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001690 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1691 XMLDocument doc;
1692 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001693 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001694 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001695 }
1696
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001697#if 1
1698 // the question being explored is what kind of print to use:
1699 // https://github.com/leethomason/tinyxml2/issues/63
1700 {
1701 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1702 const char* xml = "<element/>";
1703 XMLDocument doc;
1704 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001705 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001706 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1707 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1708 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1709 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1710 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1711 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1712
1713 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1714 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1715 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1716 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1717 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1718 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1719
1720 doc.Print();
1721
1722 /* The result of this test is platform, compiler, and library version dependent. :("
1723 XMLPrinter printer;
1724 doc.Print( &printer );
1725 XMLTest( "Float and double formatting.",
1726 "<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",
1727 printer.CStr(),
1728 true );
1729 */
1730 }
1731#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001732
1733 {
1734 // Issue #184
1735 // If it doesn't assert, it passes. Caused by objects
1736 // getting created during parsing which are then
1737 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001738 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001739 {
1740 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001741 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001742 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001743 }
1744 {
1745 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001746 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001747 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001748 doc.Clear();
1749 }
1750 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001751
1752 {
1753 // If this doesn't assert in DEBUG, all is well.
1754 tinyxml2::XMLDocument doc;
1755 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1756 doc.DeleteNode(pRoot);
1757 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001758
Dmitry-Me8b67d742014-12-22 11:35:12 +03001759 {
1760 // Should not assert in DEBUG
1761 XMLPrinter printer;
1762 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001763
Dmitry-Me6f51c802015-03-14 13:25:03 +03001764 {
1765 // Issue 291. Should not crash
1766 const char* xml = "&#0</a>";
1767 XMLDocument doc;
1768 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001769 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001770
1771 XMLPrinter printer;
1772 doc.Print( &printer );
1773 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001774 {
1775 // Issue 299. Can print elements that are not linked in.
1776 // Will crash if issue not fixed.
1777 XMLDocument doc;
1778 XMLElement* newElement = doc.NewElement( "printme" );
1779 XMLPrinter printer;
1780 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001781 // Delete the node to avoid possible memory leak report in debug output
1782 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001783 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001784 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001785 // Issue 302. Clear errors from LoadFile/SaveFile
1786 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001787 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001788 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001789 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001790 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001791 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001792 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001793
Dmitry-Med9852a52015-03-25 10:17:49 +03001794 {
1795 // If a document fails to load then subsequent
1796 // successful loads should clear the error
1797 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001798 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001799 doc.LoadFile( "resources/no-such-file.xml" );
1800 XMLTest( "No such file - should fail", true, doc.Error() );
1801
1802 doc.LoadFile( "resources/dream.xml" );
1803 XMLTest( "Error should be cleared", false, doc.Error() );
1804 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301805
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301806 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001807 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001808 const char* xml0 = "<?xml version=\"1.0\" ?>"
1809 " <!-- xml version=\"1.1\" -->"
1810 "<first />";
1811 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001812 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001813 "<first />";
1814 const char* xml2 = "<first />"
1815 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001816 const char* xml3 = "<first></first>"
1817 "<?xml version=\"1.0\" ?>";
1818
1819 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1820
Lee Thomason85492022015-05-22 11:07:45 -07001821 XMLDocument doc;
1822 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001823 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001824 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001825 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001826 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001827 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001828 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001829 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001830 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001831 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301832 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001833
Lee Thomason85492022015-05-22 11:07:45 -07001834 {
1835 // No matter - before or after successfully parsing a text -
1836 // calling XMLDocument::Value() causes an assert in debug.
1837 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1838 "<first />"
1839 "<second />";
1840 XMLDocument* doc = new XMLDocument();
1841 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1842 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001843 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001844 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1845 delete doc;
1846 }
1847
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001848 {
1849 XMLDocument doc;
1850 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001851 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001852 doc.ErrorName();
1853 }
1854 }
1855
Lee Thomason816d3fa2017-06-05 14:35:55 -07001856 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001857 // Evil memory leaks.
1858 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1859 // and NOT added to the XMLDocument, what happens?
1860 //
1861 // Previously (buggy):
1862 // The memory would be free'd when the XMLDocument is
1863 // destructed. But the destructor wasn't called, so that
1864 // memory allocated by the XMLElement would not be free'd.
1865 // In practice this meant strings allocated by the XMLElement
1866 // would leak. An edge case, but annoying.
1867 // Now:
1868 // The destructor is called. But the list of unlinked nodes
1869 // has to be tracked. This has a minor performance impact
1870 // that can become significant if you have a lot. (But why
1871 // would you do that?)
1872 // The only way to see this bug is in a leak tracker. This
1873 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001874 {
1875 XMLDocument doc;
1876 doc.NewElement("LEAK 1");
1877 }
1878 {
1879 XMLDocument doc;
1880 XMLElement* ele = doc.NewElement("LEAK 2");
1881 doc.DeleteNode(ele);
1882 }
1883 }
1884
Lee Thomason224ef772017-06-16 09:45:26 -07001885 {
1886 // Crashing reported via email.
1887 const char* xml =
1888 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001889 "<property name='track_name'>voice</property>"
1890 "<property name='audio_track'>1</property>"
1891 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1892 "<blank length = '1' />"
1893 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1894 "<blank length = '2' />"
1895 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1896 "<blank length = '1' />"
1897 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001898 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001899
Lee Thomason224ef772017-06-16 09:45:26 -07001900 // It's not a good idea to delete elements as you walk the
1901 // list. I'm not sure this technically should work; but it's
1902 // an interesting test case.
1903 XMLDocument doc;
1904 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001905 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03001906
1907 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001908 XMLTest("Crash bug parsing", true, playlist != 0);
1909
1910 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1911 XMLTest("Crash bug parsing", true, entry != 0);
1912 while (entry) {
1913 tinyxml2::XMLElement* todelete = entry;
1914 entry = entry->NextSiblingElement("entry");
1915 playlist->DeleteChild(todelete);
1916 };
1917 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1918 while (blank) {
1919 tinyxml2::XMLElement* todelete = blank;
1920 blank = blank->NextSiblingElement("blank");
1921 playlist->DeleteChild(todelete);
1922 };
1923
1924 tinyxml2::XMLPrinter printer;
1925 playlist->Accept(&printer);
1926 printf("%s\n", printer.CStr());
1927
Lee Thomason82bb0742017-06-16 09:48:20 -07001928 // No test; it only need to not crash.
1929 // Still, wrap it up with a sanity check
1930 int nProperty = 0;
1931 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1932 nProperty++;
1933 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001934 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07001935 }
1936
kezenatorec694152016-11-26 17:21:43 +10001937 // ----------- Line Number Tracking --------------
1938 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001939 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001940 {
1941 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1942 {
1943 XMLDocument doc;
1944 XMLError err = doc.Parse(docStr);
1945
1946 XMLTest(testString, true, doc.Error());
1947 XMLTest(testString, expected_error, err);
1948 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1949 };
1950
1951 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1952 {
1953 XMLDocument doc;
1954 doc.Parse(docStr);
1955 XMLTest(testString, false, doc.Error());
1956 TestDocLines(testString, doc, expectedLines);
1957 }
1958
1959 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1960 {
1961 XMLDocument doc;
1962 doc.LoadFile(file_name);
1963 XMLTest(testString, false, doc.Error());
1964 TestDocLines(testString, doc, expectedLines);
1965 }
1966
1967 private:
1968 DynArray<char, 10> str;
1969
1970 void Push(char type, int lineNum)
1971 {
1972 str.Push(type);
1973 str.Push(char('0' + (lineNum / 10)));
1974 str.Push(char('0' + (lineNum % 10)));
1975 }
1976
1977 bool VisitEnter(const XMLDocument& doc)
1978 {
kezenator19d8ea82016-11-29 19:50:27 +10001979 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001980 return true;
1981 }
1982 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
1983 {
kezenator19d8ea82016-11-29 19:50:27 +10001984 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001985 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10001986 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001987 return true;
1988 }
1989 bool Visit(const XMLDeclaration& declaration)
1990 {
kezenator19d8ea82016-11-29 19:50:27 +10001991 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001992 return true;
1993 }
1994 bool Visit(const XMLText& text)
1995 {
kezenator19d8ea82016-11-29 19:50:27 +10001996 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001997 return true;
1998 }
1999 bool Visit(const XMLComment& comment)
2000 {
kezenator19d8ea82016-11-29 19:50:27 +10002001 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002002 return true;
2003 }
2004 bool Visit(const XMLUnknown& unknown)
2005 {
kezenator19d8ea82016-11-29 19:50:27 +10002006 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002007 return true;
2008 }
2009
2010 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2011 {
2012 str.Clear();
2013 doc.Accept(this);
2014 str.Push(0);
2015 XMLTest(testString, expectedLines, str.Mem());
2016 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002017 } tester;
kezenatorec694152016-11-26 17:21:43 +10002018
Lee Thomasone90e9012016-12-24 07:34:39 -08002019 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2020 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2021 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2022 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2023 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2024 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2025 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2026 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2027 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2028 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2029 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002030
Lee Thomasone90e9012016-12-24 07:34:39 -08002031 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002032 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002033
2034 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2035 "<root a='b' \n" // 2 Element Attribute
2036 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2037 "newline in text \n" // 4 Text
2038 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2039 " cdata test ]]><!-- comment -->\n" // 6 Comment
2040 "<! unknown></root>", // 7 Unknown
2041
kezenatorec694152016-11-26 17:21:43 +10002042 "D01L01E02A02A03T03E03T04E05T05C06U07");
2043
Lee Thomasone90e9012016-12-24 07:34:39 -08002044 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002045 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002046
2047 "\r\n" // 1 Doc (arguably should be line 2)
2048 "<?xml version=\"1.0\"?>\n" // 2 DecL
2049 "<root>\r\n" // 3 Element
2050 "\n" // 4
2051 "text contining new line \n" // 5 Text
2052 " and also containing crlf \r\n" // 6
2053 "<sub><![CDATA[\n" // 7 Element Text
2054 "cdata containing new line \n" // 8
2055 " and also containing cflr\r\n" // 9
2056 "]]></sub><sub2/></root>", // 10 Element
2057
kezenatorec694152016-11-26 17:21:43 +10002058 "D01L02E03T05E07T07E10");
2059
Lee Thomasone90e9012016-12-24 07:34:39 -08002060 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002061 "LineNumbers-File",
2062 "resources/utf8test.xml",
2063 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2064 }
2065
Lee Thomason85492022015-05-22 11:07:45 -07002066 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002067 {
2068#if defined( _MSC_VER )
2069 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002070 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002071#endif
2072
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002073 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002074 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002075 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002076 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002077 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002078
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002079 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002080 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002081 size_t bytesRead = fread(mem, 1, size, perfFP);
2082 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002083 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002084 mem[size] = 0;
2085
2086#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002087 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002088#else
2089 clock_t cstart = clock();
2090#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002091 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002092 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002093 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002094 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002095 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002096 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002097 }
Dmitry-Me68578f42017-07-03 18:21:23 +03002098 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002099#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002100 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002101#else
2102 clock_t cend = clock();
2103#endif
2104
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002105 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002106
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002107 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002108#ifdef DEBUG
2109 "DEBUG";
2110#else
2111 "Release";
2112#endif
2113
2114#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002115 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002116#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002117 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002118#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002119 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002120 }
2121
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08002122 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002123 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002124
2125 _CrtMemState diffMemState;
2126 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2127 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002128
2129 {
2130 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2131 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2132 }
Lee Thomason1ff38e02012-02-14 18:18:16 -08002133 #endif
2134
2135 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002136
2137 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002138}