blob: 6dd3b42da524894795a88f6e397c9476e0b087a6 [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
Dmitry-Me43c019d2017-08-02 18:05:23 +03001445 {
1446 int intValue = 0;
1447 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1448 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1449 XMLTest( "QueryIntText", 1, intValue, false );
1450 }
Lee Thomason21be8822012-07-15 17:27:22 -07001451
Dmitry-Me43c019d2017-08-02 18:05:23 +03001452 {
1453 unsigned unsignedValue = 0;
1454 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1455 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1456 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1457 }
Lee Thomason21be8822012-07-15 17:27:22 -07001458
Dmitry-Me43c019d2017-08-02 18:05:23 +03001459 {
1460 float floatValue = 0;
1461 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1462 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1463 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1464 }
Lee Thomason21be8822012-07-15 17:27:22 -07001465
Dmitry-Me43c019d2017-08-02 18:05:23 +03001466 {
1467 double doubleValue = 0;
1468 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1469 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1470 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1471 }
1472
1473 {
1474 bool boolValue = false;
1475 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1476 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1477 XMLTest( "QueryBoolText", true, boolValue, false );
1478 }
Lee Thomason21be8822012-07-15 17:27:22 -07001479 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001480
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001481 {
1482 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1483 XMLDocument doc;
1484 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001485 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001486 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001487
1488 {
1489 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1490 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001491 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001492 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001493 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001494
1495 {
1496 const char* xml = "<3lement></3lement>";
1497 XMLDocument doc;
1498 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001499 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001500 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001501
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001502 {
1503 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1504 XMLDocument doc;
1505 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001506 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001507 }
1508
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001509 {
1510 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001511 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001512 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001513 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001514 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001515 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001516 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001517 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001518 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001519 }
1520
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001521 // ----------- Whitespace ------------
1522 {
1523 const char* xml = "<element>"
1524 "<a> This \nis &apos; text &apos; </a>"
1525 "<b> This is &apos; text &apos; \n</b>"
1526 "<c>This is &apos; \n\n text &apos;</c>"
1527 "</element>";
1528 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1529 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001530 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001531
1532 const XMLElement* element = doc.FirstChildElement();
1533 for( const XMLElement* parent = element->FirstChildElement();
1534 parent;
1535 parent = parent->NextSiblingElement() )
1536 {
1537 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1538 }
1539 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001540
Lee Thomasonae9ab072012-10-24 10:17:53 -07001541#if 0
1542 {
1543 // Passes if assert doesn't fire.
1544 XMLDocument xmlDoc;
1545
1546 xmlDoc.NewDeclaration();
1547 xmlDoc.NewComment("Configuration file");
1548
1549 XMLElement *root = xmlDoc.NewElement("settings");
1550 root->SetAttribute("version", 2);
1551 }
1552#endif
1553
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001554 {
1555 const char* xml = "<element> </element>";
1556 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1557 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001558 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001559 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1560 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001561
Lee Thomason5b0a6772012-11-19 13:54:42 -08001562 {
1563 // An assert should not fire.
1564 const char* xml = "<element/>";
1565 XMLDocument doc;
1566 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001567 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001568 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1569 XMLTest( "Tracking unused elements", true, ele != 0, false );
1570 }
1571
Lee Thomasona6412ac2012-12-13 15:39:11 -08001572
1573 {
1574 const char* xml = "<parent><child>abc</child></parent>";
1575 XMLDocument doc;
1576 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001577 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001578 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1579
1580 XMLPrinter printer;
1581 ele->Accept( &printer );
1582 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1583 }
1584
1585
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001586 {
1587 XMLDocument doc;
1588 XMLError error = doc.LoadFile( "resources/empty.xml" );
1589 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001590 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001591 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001592 }
1593
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001594 {
1595 // BOM preservation
1596 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1597 {
1598 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001599 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001600 XMLPrinter printer;
1601 doc.Print( &printer );
1602
1603 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1604 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001605 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001606 }
1607 {
1608 XMLDocument doc;
1609 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001610 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001611 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1612
1613 XMLPrinter printer;
1614 doc.Print( &printer );
1615 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1616 }
1617 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001618
Michael Daumlinged523282013-10-23 07:47:29 +02001619 {
1620 // Insertion with Removal
1621 const char* xml = "<?xml version=\"1.0\" ?>"
1622 "<root>"
1623 "<one>"
1624 "<subtree>"
1625 "<elem>element 1</elem>text<!-- comment -->"
1626 "</subtree>"
1627 "</one>"
1628 "<two/>"
1629 "</root>";
1630 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1631 "<root>"
1632 "<one/>"
1633 "<two>"
1634 "<subtree>"
1635 "<elem>element 1</elem>text<!-- comment -->"
1636 "</subtree>"
1637 "</two>"
1638 "</root>";
1639 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1640 "<root>"
1641 "<one/>"
1642 "<subtree>"
1643 "<elem>element 1</elem>text<!-- comment -->"
1644 "</subtree>"
1645 "<two/>"
1646 "</root>";
1647 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1648 "<root>"
1649 "<one/>"
1650 "<two/>"
1651 "<subtree>"
1652 "<elem>element 1</elem>text<!-- comment -->"
1653 "</subtree>"
1654 "</root>";
1655
1656 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001657 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001658 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001659 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1660 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1661 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001662 XMLPrinter printer1(0, true);
1663 doc.Accept(&printer1);
1664 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001665
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001666 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001667 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001668 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1669 two = doc.RootElement()->FirstChildElement("two");
1670 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001671 XMLPrinter printer2(0, true);
1672 doc.Accept(&printer2);
1673 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001674
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001675 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001676 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001677 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1678 subtree = one->FirstChildElement("subtree");
1679 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001680 XMLPrinter printer3(0, true);
1681 doc.Accept(&printer3);
1682 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001683
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001684 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001685 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001686 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1687 two = doc.RootElement()->FirstChildElement("two");
1688 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001689 XMLPrinter printer4(0, true);
1690 doc.Accept(&printer4);
1691 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001692 }
1693
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001694 {
1695 const char* xml = "<svg width = \"128\" height = \"128\">"
1696 " <text> </text>"
1697 "</svg>";
1698 XMLDocument doc;
1699 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001700 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001701 doc.Print();
1702 }
1703
Lee Thomason92e521b2014-11-15 17:45:51 -08001704 {
1705 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001706 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1707 XMLDocument doc;
1708 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001709 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001710 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001711 }
1712
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001713#if 1
1714 // the question being explored is what kind of print to use:
1715 // https://github.com/leethomason/tinyxml2/issues/63
1716 {
1717 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1718 const char* xml = "<element/>";
1719 XMLDocument doc;
1720 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001721 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001722 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1723 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1724 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1725 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1726 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1727 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1728
1729 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1730 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1731 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1732 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1733 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1734 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1735
1736 doc.Print();
1737
1738 /* The result of this test is platform, compiler, and library version dependent. :("
1739 XMLPrinter printer;
1740 doc.Print( &printer );
1741 XMLTest( "Float and double formatting.",
1742 "<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",
1743 printer.CStr(),
1744 true );
1745 */
1746 }
1747#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001748
1749 {
1750 // Issue #184
1751 // If it doesn't assert, it passes. Caused by objects
1752 // getting created during parsing which are then
1753 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001754 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001755 {
1756 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001757 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001758 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001759 }
1760 {
1761 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001762 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001763 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001764 doc.Clear();
1765 }
1766 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001767
1768 {
1769 // If this doesn't assert in DEBUG, all is well.
1770 tinyxml2::XMLDocument doc;
1771 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1772 doc.DeleteNode(pRoot);
1773 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001774
Dmitry-Mee5790db2017-07-28 17:54:38 +03001775 {
1776 XMLDocument doc;
1777 XMLElement* root = doc.NewElement( "Root" );
1778 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1779 doc.InsertEndChild( root );
1780 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1781 }
1782
1783 {
1784 // If this doesn't assert in DEBUG, all is well.
1785 XMLDocument doc;
1786 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1787 XMLElement* linkedRoot = doc.NewElement( "Root" );
1788 doc.InsertFirstChild( linkedRoot );
1789 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1790 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1791 }
1792
Dmitry-Me8b67d742014-12-22 11:35:12 +03001793 {
1794 // Should not assert in DEBUG
1795 XMLPrinter printer;
1796 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001797
Dmitry-Me6f51c802015-03-14 13:25:03 +03001798 {
1799 // Issue 291. Should not crash
1800 const char* xml = "&#0</a>";
1801 XMLDocument doc;
1802 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001803 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001804
1805 XMLPrinter printer;
1806 doc.Print( &printer );
1807 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001808 {
1809 // Issue 299. Can print elements that are not linked in.
1810 // Will crash if issue not fixed.
1811 XMLDocument doc;
1812 XMLElement* newElement = doc.NewElement( "printme" );
1813 XMLPrinter printer;
1814 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001815 // Delete the node to avoid possible memory leak report in debug output
1816 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001817 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001818 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001819 // Issue 302. Clear errors from LoadFile/SaveFile
1820 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001821 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001822 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001823 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001824 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001825 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001826 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001827
Dmitry-Med9852a52015-03-25 10:17:49 +03001828 {
1829 // If a document fails to load then subsequent
1830 // successful loads should clear the error
1831 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001832 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001833 doc.LoadFile( "resources/no-such-file.xml" );
1834 XMLTest( "No such file - should fail", true, doc.Error() );
1835
1836 doc.LoadFile( "resources/dream.xml" );
1837 XMLTest( "Error should be cleared", false, doc.Error() );
1838 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301839
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301840 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001841 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001842 const char* xml0 = "<?xml version=\"1.0\" ?>"
1843 " <!-- xml version=\"1.1\" -->"
1844 "<first />";
1845 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001846 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001847 "<first />";
1848 const char* xml2 = "<first />"
1849 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001850 const char* xml3 = "<first></first>"
1851 "<?xml version=\"1.0\" ?>";
1852
1853 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1854
Lee Thomason85492022015-05-22 11:07:45 -07001855 XMLDocument doc;
1856 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001857 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001858 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001859 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001860 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001861 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001862 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001863 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001864 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001865 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301866 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001867
Lee Thomason85492022015-05-22 11:07:45 -07001868 {
1869 // No matter - before or after successfully parsing a text -
1870 // calling XMLDocument::Value() causes an assert in debug.
1871 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1872 "<first />"
1873 "<second />";
1874 XMLDocument* doc = new XMLDocument();
1875 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1876 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001877 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001878 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1879 delete doc;
1880 }
1881
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001882 {
1883 XMLDocument doc;
1884 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001885 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001886 doc.ErrorName();
1887 }
1888 }
1889
Lee Thomason816d3fa2017-06-05 14:35:55 -07001890 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001891 // Evil memory leaks.
1892 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1893 // and NOT added to the XMLDocument, what happens?
1894 //
1895 // Previously (buggy):
1896 // The memory would be free'd when the XMLDocument is
1897 // destructed. But the destructor wasn't called, so that
1898 // memory allocated by the XMLElement would not be free'd.
1899 // In practice this meant strings allocated by the XMLElement
1900 // would leak. An edge case, but annoying.
1901 // Now:
1902 // The destructor is called. But the list of unlinked nodes
1903 // has to be tracked. This has a minor performance impact
1904 // that can become significant if you have a lot. (But why
1905 // would you do that?)
1906 // The only way to see this bug is in a leak tracker. This
1907 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001908 {
1909 XMLDocument doc;
1910 doc.NewElement("LEAK 1");
1911 }
1912 {
1913 XMLDocument doc;
1914 XMLElement* ele = doc.NewElement("LEAK 2");
1915 doc.DeleteNode(ele);
1916 }
1917 }
1918
Lee Thomason224ef772017-06-16 09:45:26 -07001919 {
1920 // Crashing reported via email.
1921 const char* xml =
1922 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001923 "<property name='track_name'>voice</property>"
1924 "<property name='audio_track'>1</property>"
1925 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1926 "<blank length = '1' />"
1927 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1928 "<blank length = '2' />"
1929 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1930 "<blank length = '1' />"
1931 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001932 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001933
Lee Thomason224ef772017-06-16 09:45:26 -07001934 // It's not a good idea to delete elements as you walk the
1935 // list. I'm not sure this technically should work; but it's
1936 // an interesting test case.
1937 XMLDocument doc;
1938 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001939 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03001940
1941 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001942 XMLTest("Crash bug parsing", true, playlist != 0);
1943
1944 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1945 XMLTest("Crash bug parsing", true, entry != 0);
1946 while (entry) {
1947 tinyxml2::XMLElement* todelete = entry;
1948 entry = entry->NextSiblingElement("entry");
1949 playlist->DeleteChild(todelete);
1950 };
1951 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1952 while (blank) {
1953 tinyxml2::XMLElement* todelete = blank;
1954 blank = blank->NextSiblingElement("blank");
1955 playlist->DeleteChild(todelete);
1956 };
1957
1958 tinyxml2::XMLPrinter printer;
1959 playlist->Accept(&printer);
1960 printf("%s\n", printer.CStr());
1961
Lee Thomason82bb0742017-06-16 09:48:20 -07001962 // No test; it only need to not crash.
1963 // Still, wrap it up with a sanity check
1964 int nProperty = 0;
1965 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1966 nProperty++;
1967 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001968 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07001969 }
1970
kezenatorec694152016-11-26 17:21:43 +10001971 // ----------- Line Number Tracking --------------
1972 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001973 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001974 {
1975 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1976 {
1977 XMLDocument doc;
1978 XMLError err = doc.Parse(docStr);
1979
1980 XMLTest(testString, true, doc.Error());
1981 XMLTest(testString, expected_error, err);
1982 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1983 };
1984
1985 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1986 {
1987 XMLDocument doc;
1988 doc.Parse(docStr);
1989 XMLTest(testString, false, doc.Error());
1990 TestDocLines(testString, doc, expectedLines);
1991 }
1992
1993 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1994 {
1995 XMLDocument doc;
1996 doc.LoadFile(file_name);
1997 XMLTest(testString, false, doc.Error());
1998 TestDocLines(testString, doc, expectedLines);
1999 }
2000
2001 private:
2002 DynArray<char, 10> str;
2003
2004 void Push(char type, int lineNum)
2005 {
2006 str.Push(type);
2007 str.Push(char('0' + (lineNum / 10)));
2008 str.Push(char('0' + (lineNum % 10)));
2009 }
2010
2011 bool VisitEnter(const XMLDocument& doc)
2012 {
kezenator19d8ea82016-11-29 19:50:27 +10002013 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002014 return true;
2015 }
2016 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2017 {
kezenator19d8ea82016-11-29 19:50:27 +10002018 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002019 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002020 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002021 return true;
2022 }
2023 bool Visit(const XMLDeclaration& declaration)
2024 {
kezenator19d8ea82016-11-29 19:50:27 +10002025 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002026 return true;
2027 }
2028 bool Visit(const XMLText& text)
2029 {
kezenator19d8ea82016-11-29 19:50:27 +10002030 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002031 return true;
2032 }
2033 bool Visit(const XMLComment& comment)
2034 {
kezenator19d8ea82016-11-29 19:50:27 +10002035 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002036 return true;
2037 }
2038 bool Visit(const XMLUnknown& unknown)
2039 {
kezenator19d8ea82016-11-29 19:50:27 +10002040 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002041 return true;
2042 }
2043
2044 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2045 {
2046 str.Clear();
2047 doc.Accept(this);
2048 str.Push(0);
2049 XMLTest(testString, expectedLines, str.Mem());
2050 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002051 } tester;
kezenatorec694152016-11-26 17:21:43 +10002052
Lee Thomasone90e9012016-12-24 07:34:39 -08002053 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2054 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2055 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2056 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2057 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2058 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2059 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2060 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2061 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2062 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2063 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002064
Lee Thomasone90e9012016-12-24 07:34:39 -08002065 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002066 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002067
2068 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2069 "<root a='b' \n" // 2 Element Attribute
2070 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2071 "newline in text \n" // 4 Text
2072 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2073 " cdata test ]]><!-- comment -->\n" // 6 Comment
2074 "<! unknown></root>", // 7 Unknown
2075
kezenatorec694152016-11-26 17:21:43 +10002076 "D01L01E02A02A03T03E03T04E05T05C06U07");
2077
Lee Thomasone90e9012016-12-24 07:34:39 -08002078 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002079 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002080
2081 "\r\n" // 1 Doc (arguably should be line 2)
2082 "<?xml version=\"1.0\"?>\n" // 2 DecL
2083 "<root>\r\n" // 3 Element
2084 "\n" // 4
2085 "text contining new line \n" // 5 Text
2086 " and also containing crlf \r\n" // 6
2087 "<sub><![CDATA[\n" // 7 Element Text
2088 "cdata containing new line \n" // 8
2089 " and also containing cflr\r\n" // 9
2090 "]]></sub><sub2/></root>", // 10 Element
2091
kezenatorec694152016-11-26 17:21:43 +10002092 "D01L02E03T05E07T07E10");
2093
Lee Thomasone90e9012016-12-24 07:34:39 -08002094 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002095 "LineNumbers-File",
2096 "resources/utf8test.xml",
2097 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2098 }
2099
Lee Thomason85492022015-05-22 11:07:45 -07002100 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002101 {
2102#if defined( _MSC_VER )
2103 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002104 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002105#endif
2106
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002107 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002108 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002109 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002110 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002111 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002112
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002113 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002114 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002115 size_t bytesRead = fread(mem, 1, size, perfFP);
2116 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002117 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002118 mem[size] = 0;
2119
2120#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002121 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002122#else
2123 clock_t cstart = clock();
2124#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002125 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002126 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002127 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002128 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002129 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002130 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002131 }
Dmitry-Me68578f42017-07-03 18:21:23 +03002132 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002133#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002134 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002135#else
2136 clock_t cend = clock();
2137#endif
2138
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002139 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002140
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002141 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002142#ifdef DEBUG
2143 "DEBUG";
2144#else
2145 "Release";
2146#endif
2147
2148#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002149 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002150#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002151 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002152#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002153 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002154 }
2155
Dmitry-Mede381df2017-07-26 18:05:25 +03002156#if defined( _MSC_VER ) && defined( DEBUG )
2157 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002158 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002159
2160 _CrtMemState diffMemState;
2161 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2162 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002163
2164 {
2165 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2166 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2167 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002168 }
2169#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002170
2171 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002172
2173 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002174}