blob: 9ef52ce41a85ae1002c84ccd9adb1aaa44ac40fe [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] );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300423
424 const int dummyInitialValue = 1000;
425 int dummyValue = dummyInitialValue;
426
Lee Thomason1ff38e02012-02-14 18:18:16 -0800427 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300428 comment->SetUserData(&dummyValue);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800429 element->InsertAfterChild( comment, sub[0] );
430 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800431 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800432 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800433 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
434 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
435 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700436 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800437 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300438 XMLTest("User data", true, &dummyValue == comment->GetUserData(), false);
439 XMLTest("User data", dummyInitialValue, dummyValue, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800440
441 // And now deletion:
442 element->DeleteChild( sub[2] );
443 doc->DeleteNode( comment );
444
445 element->FirstChildElement()->SetAttribute( "attrib", true );
446 element->LastChildElement()->DeleteAttribute( "attrib" );
447
448 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300449 const int defaultIntValue = 10;
450 const int replacementIntValue = 20;
451 int value1 = defaultIntValue;
452 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300453 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
454 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300455 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
456 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800457
458 doc->Print();
459
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700460 {
461 XMLPrinter streamer;
462 doc->Print( &streamer );
463 printf( "%s", streamer.CStr() );
464 }
465 {
466 XMLPrinter streamer( 0, true );
467 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200468 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700469 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700470 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300471 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700472 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300473 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800474 delete doc;
475 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800476 {
477 // Test: Dream
478 // XML1 : 1,187,569 bytes in 31,209 allocations
479 // XML2 : 469,073 bytes in 323 allocations
480 //int newStart = gNew;
481 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300482 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300483 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800484
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400485 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300486 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800487 doc.PrintError();
488
489 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400490 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800491 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
492 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
493 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
494 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400495 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800496 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400497 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800498
499 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400500 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300501 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800502 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400503 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800504 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
505 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
506 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
507 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400508 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800509
510 //gNewTotal = gNew - newStart;
511 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800512
513
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800514 {
515 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
516 "<passages count=\"006\" formatversion=\"20020620\">\n"
517 " <wrong error>\n"
518 "</passages>";
519
520 XMLDocument doc;
521 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300522 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800523 }
524
525 {
526 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
527
528 XMLDocument doc;
529 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300530 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800531
532 XMLElement* ele = doc.FirstChildElement();
533
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300534 int iVal;
535 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800536 double dVal;
537
538 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300539 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
540 XMLTest( "Query attribute: int as double", 1, (int)dVal );
541 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700542
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800543 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300544 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
545 XMLTest( "Query attribute: double as double", 2.0, dVal );
546 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700547
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800548 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300549 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
550 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700551
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800552 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300553 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
554 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700555
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800556 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300557 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
558 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800559 }
560
561 {
562 const char* str = "<doc/>";
563
564 XMLDocument doc;
565 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300566 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800567
568 XMLElement* ele = doc.FirstChildElement();
569
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800570 int iVal, iVal2;
571 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800572
573 ele->SetAttribute( "str", "strValue" );
574 ele->SetAttribute( "int", 1 );
575 ele->SetAttribute( "double", -1.0 );
576
577 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300578 {
579 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
580 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
581 }
582 {
583 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
584 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
585 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800586
Dmitry-Me2087a272017-07-10 18:13:07 +0300587 {
588 int queryResult = ele->QueryAttribute( "int", &iVal2 );
589 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
590 }
591 {
592 int queryResult = ele->QueryAttribute( "double", &dVal2 );
593 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
594 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800595
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300596 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800597 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
598 XMLTest( "Attribute round trip. int.", 1, iVal );
599 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800600 XMLTest( "Alternate query", true, iVal == iVal2 );
601 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700602 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
603 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800604 }
605
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800606 {
607 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300608 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300609 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800610
611 // Get the attribute "value" from the "Russian" element and check it.
612 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700613 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800614 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
615
616 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
617
618 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
619 0xd1U, 0x81U, 0xd1U, 0x81U,
620 0xd0U, 0xbaU, 0xd0U, 0xb8U,
621 0xd0U, 0xb9U, 0 };
622 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
623
624 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
625 XMLTest( "UTF-8: Browsing russian element name.",
626 russianText,
627 text->Value() );
628
629 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400630 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300631 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800632
633 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800634 int okay = 0;
635
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200636 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300637 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800638
639 if ( saved && verify )
640 {
641 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700642 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800643 while ( fgets( verifyBuf, 256, verify ) )
644 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700645 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800646 fgets( savedBuf, 256, saved );
647 NullLineEndings( verifyBuf );
648 NullLineEndings( savedBuf );
649
650 if ( strcmp( verifyBuf, savedBuf ) )
651 {
652 printf( "verify:%s<\n", verifyBuf );
653 printf( "saved :%s<\n", savedBuf );
654 okay = 0;
655 break;
656 }
657 }
658 }
659 if ( saved )
660 fclose( saved );
661 if ( verify )
662 fclose( verify );
663 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
664 }
665
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800666 // --------GetText()-----------
667 {
668 const char* str = "<foo>This is text</foo>";
669 XMLDocument doc;
670 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300671 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800672 const XMLElement* element = doc.RootElement();
673
674 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
675
676 str = "<foo><b>This is text</b></foo>";
677 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300678 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800679 element = doc.RootElement();
680
681 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
682 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800683
Lee Thomasond6277762012-02-22 16:00:12 -0800684
Uli Kusterer321072e2014-01-21 01:57:38 +0100685 // --------SetText()-----------
686 {
687 const char* str = "<foo></foo>";
688 XMLDocument doc;
689 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300690 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100691 XMLElement* element = doc.RootElement();
692
Lee Thomason9c0678a2014-01-24 10:18:27 -0800693 element->SetText("darkness.");
694 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100695
Lee Thomason9c0678a2014-01-24 10:18:27 -0800696 element->SetText("blue flame.");
697 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100698
699 str = "<foo/>";
700 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300701 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100702 element = doc.RootElement();
703
Lee Thomason9c0678a2014-01-24 10:18:27 -0800704 element->SetText("The driver");
705 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100706
Lee Thomason9c0678a2014-01-24 10:18:27 -0800707 element->SetText("<b>horses</b>");
708 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
709 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100710
711 str = "<foo><bar>Text in nested element</bar></foo>";
712 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300713 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100714 element = doc.RootElement();
715
Lee Thomason9c0678a2014-01-24 10:18:27 -0800716 element->SetText("wolves");
717 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800718
719 str = "<foo/>";
720 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300721 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800722 element = doc.RootElement();
723
724 element->SetText( "str" );
725 XMLTest( "SetText types", "str", element->GetText() );
726
727 element->SetText( 1 );
728 XMLTest( "SetText types", "1", element->GetText() );
729
730 element->SetText( 1U );
731 XMLTest( "SetText types", "1", element->GetText() );
732
733 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200734 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800735
736 element->SetText( 1.5f );
737 XMLTest( "SetText types", "1.5", element->GetText() );
738
739 element->SetText( 1.5 );
740 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100741 }
742
Lee Thomason51c12712016-06-04 20:18:49 -0700743 // ---------- Attributes ---------
744 {
745 static const int64_t BIG = -123456789012345678;
746 XMLDocument doc;
747 XMLElement* element = doc.NewElement("element");
748 doc.InsertFirstChild(element);
749
750 {
751 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300752 {
753 int v = 0;
754 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
755 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
756 XMLTest("Attribute: int", -100, v, true);
757 }
758 {
759 int v = 0;
760 int queryResult = element->QueryAttribute("attrib", &v);
761 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
762 XMLTest("Attribute: int", -100, v, true);
763 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700764 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700765 }
766 {
767 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300768 {
769 unsigned v = 0;
770 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
771 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
772 XMLTest("Attribute: unsigned", unsigned(100), v, true);
773 }
774 {
775 unsigned v = 0;
776 int queryResult = element->QueryAttribute("attrib", &v);
777 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
778 XMLTest("Attribute: unsigned", unsigned(100), v, true);
779 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700780 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700781 }
782 {
783 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300784 {
785 int64_t v = 0;
786 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
787 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
788 XMLTest("Attribute: int64_t", BIG, v, true);
789 }
790 {
791 int64_t v = 0;
792 int queryResult = element->QueryAttribute("attrib", &v);
793 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
794 XMLTest("Attribute: int64_t", BIG, v, true);
795 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700796 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700797 }
798 {
799 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300800 {
801 bool v = false;
802 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
803 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
804 XMLTest("Attribute: bool", true, v, true);
805 }
806 {
807 bool v = false;
808 int queryResult = element->QueryAttribute("attrib", &v);
809 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
810 XMLTest("Attribute: bool", true, v, true);
811 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700812 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700813 }
814 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800815 element->SetAttribute("attrib", true);
816 const char* result = element->Attribute("attrib");
817 XMLTest("Bool true is 'true'", "true", result);
818
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800819 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800820 element->SetAttribute("attrib", true);
821 result = element->Attribute("attrib");
822 XMLTest("Bool true is '1'", "1", result);
823
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800824 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800825 }
826 {
Lee Thomason51c12712016-06-04 20:18:49 -0700827 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300828 {
829 double v = 0;
830 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
831 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
832 XMLTest("Attribute: double", 100.0, v, true);
833 }
834 {
835 double v = 0;
836 int queryResult = element->QueryAttribute("attrib", &v);
837 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
838 XMLTest("Attribute: double", 100.0, v, true);
839 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700840 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700841 }
842 {
843 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300844 {
845 float v = 0;
846 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
847 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
848 XMLTest("Attribute: float", 100.0f, v, true);
849 }
850 {
851 float v = 0;
852 int queryResult = element->QueryAttribute("attrib", &v);
853 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
854 XMLTest("Attribute: float", 100.0f, v, true);
855 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700856 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700857 }
858 {
859 element->SetText(BIG);
860 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300861 XMLError queryResult = element->QueryInt64Text(&v);
862 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700863 XMLTest("Element: int64_t", BIG, v, true);
864 }
865 }
866
867 // ---------- XMLPrinter stream mode ------
868 {
869 {
870 FILE* printerfp = fopen("resources/printer.xml", "w");
871 XMLPrinter printer(printerfp);
872 printer.OpenElement("foo");
873 printer.PushAttribute("attrib-text", "text");
874 printer.PushAttribute("attrib-int", int(1));
875 printer.PushAttribute("attrib-unsigned", unsigned(2));
876 printer.PushAttribute("attrib-int64", int64_t(3));
877 printer.PushAttribute("attrib-bool", true);
878 printer.PushAttribute("attrib-double", 4.0);
879 printer.CloseElement();
880 fclose(printerfp);
881 }
882 {
883 XMLDocument doc;
884 doc.LoadFile("resources/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300885 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700886
887 const XMLDocument& cdoc = doc;
888
889 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
890 XMLTest("attrib-text", "text", attrib->Value(), true);
891 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
892 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
893 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
894 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
895 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
896 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
897 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
898 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
899 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
900 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
901 }
902
903 }
904
Uli Kusterer321072e2014-01-21 01:57:38 +0100905
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800906 // ---------- CDATA ---------------
907 {
908 const char* str = "<xmlElement>"
909 "<![CDATA["
910 "I am > the rules!\n"
911 "...since I make symbolic puns"
912 "]]>"
913 "</xmlElement>";
914 XMLDocument doc;
915 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300916 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800917 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800918
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300919 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
920 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800921 false );
922 }
923
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800924 // ----------- CDATA -------------
925 {
926 const char* str = "<xmlElement>"
927 "<![CDATA["
928 "<b>I am > the rules!</b>\n"
929 "...since I make symbolic puns"
930 "]]>"
931 "</xmlElement>";
932 XMLDocument doc;
933 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300934 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800935 doc.Print();
936
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300937 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800938 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300939 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800940 false );
941 }
942
943 // InsertAfterChild causes crash.
944 {
945 // InsertBeforeChild and InsertAfterChild causes crash.
946 XMLDocument doc;
947 XMLElement* parent = doc.NewElement( "Parent" );
948 doc.InsertFirstChild( parent );
949
950 XMLElement* childText0 = doc.NewElement( "childText0" );
951 XMLElement* childText1 = doc.NewElement( "childText1" );
952
953 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
954 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
955
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300956 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800957 }
Lee Thomasond6277762012-02-22 16:00:12 -0800958
959 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800960 // Entities not being written correctly.
961 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800962
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800963 const char* passages =
964 "<?xml version=\"1.0\" standalone=\"no\" ?>"
965 "<passages count=\"006\" formatversion=\"20020620\">"
966 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
967 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
968 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800969
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800970 XMLDocument doc;
971 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +0300972 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800973 XMLElement* psg = doc.RootElement()->FirstChildElement();
974 const char* context = psg->Attribute( "context" );
975 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 -0800976
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800977 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800978
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400979 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800980 if ( textfile )
981 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800982 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800983 psg->Accept( &streamer );
984 fclose( textfile );
985 }
Thomas Roß0922b732012-09-23 16:31:22 +0200986
987 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800988 TIXMLASSERT( textfile );
989 if ( textfile )
990 {
991 char buf[ 1024 ];
992 fgets( buf, 1024, textfile );
993 XMLTest( "Entity transformation: write. ",
994 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
995 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
996 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700997 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800998 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800999 }
1000
1001 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001002 // Suppress entities.
1003 const char* passages =
1004 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1005 "<passages count=\"006\" formatversion=\"20020620\">"
1006 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1007 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001008
Lee Thomason6f381b72012-03-02 12:59:39 -08001009 XMLDocument doc( false );
1010 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001011 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001012
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001013 XMLTest( "No entity parsing.",
1014 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1015 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1016 XMLTest( "No entity parsing.", "Crazy &ttk;",
1017 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001018 doc.Print();
1019 }
1020
1021 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001022 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001023
1024 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001025 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001026 XMLTest( "dot in names", false, doc.Error() );
1027 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1028 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001029 }
1030
1031 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001032 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001033
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001034 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001035 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001036 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001037
1038 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1039 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001040 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001041 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001042 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001043
1044 {
1045 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001046 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001047 const char* doctype =
1048 "<?xml version=\"1.0\" ?>"
1049 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1050 "<!ELEMENT title (#PCDATA)>"
1051 "<!ELEMENT books (title,authors)>"
1052 "<element />";
1053
1054 XMLDocument doc;
1055 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001056 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001057 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001058 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001059 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001060 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001061 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001062 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001063
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001064 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1065 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1066
1067 }
1068
1069 {
1070 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001071 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001072 "<!-- Somewhat<evil> -->";
1073 XMLDocument doc;
1074 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001075 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001076
1077 XMLComment* comment = doc.FirstChild()->ToComment();
1078
1079 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1080 }
1081 {
1082 // Double attributes
1083 const char* doctype = "<element attr='red' attr='blue' />";
1084
1085 XMLDocument doc;
1086 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001087
Lee Thomason2fa81722012-11-09 12:37:46 -08001088 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 -08001089 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001090 }
1091
1092 {
1093 // Embedded null in stream.
1094 const char* doctype = "<element att\0r='red' attr='blue' />";
1095
1096 XMLDocument doc;
1097 doc.Parse( doctype );
1098 XMLTest( "Embedded null throws error.", true, doc.Error() );
1099 }
1100
1101 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001102 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001103 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001104 XMLDocument doc;
1105 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001106 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001107 }
1108
1109 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001110 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1111 const char* str = " ";
1112 XMLDocument doc;
1113 doc.Parse( str );
1114 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1115 }
1116
1117 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001118 // Low entities
1119 XMLDocument doc;
1120 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001121 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001122 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001123 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001124 doc.Print();
1125 }
1126
1127 {
1128 // Attribute values with trailing quotes not handled correctly
1129 XMLDocument doc;
1130 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001131 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001132 }
1133
1134 {
1135 // [ 1663758 ] Failure to report error on bad XML
1136 XMLDocument xml;
1137 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001138 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001139 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001140 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001141 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001142 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001143 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001144
1145
1146 {
1147 // [ 1475201 ] TinyXML parses entities in comments
1148 XMLDocument xml;
1149 xml.Parse("<!-- declarations for <head> & <body> -->"
1150 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001151 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001152
1153 XMLNode* e0 = xml.FirstChild();
1154 XMLNode* e1 = e0->NextSibling();
1155 XMLComment* c0 = e0->ToComment();
1156 XMLComment* c1 = e1->ToComment();
1157
1158 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1159 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1160 }
1161
1162 {
1163 XMLDocument xml;
1164 xml.Parse( "<Parent>"
1165 "<child1 att=''/>"
1166 "<!-- With this comment, child2 will not be parsed! -->"
1167 "<child2 att=''/>"
1168 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001169 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001170 xml.Print();
1171
1172 int count = 0;
1173
1174 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1175 ele;
1176 ele = ele->NextSibling() )
1177 {
1178 ++count;
1179 }
1180
1181 XMLTest( "Comments iterate correctly.", 3, count );
1182 }
1183
1184 {
1185 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1186 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1187 buf[60] = 239;
1188 buf[61] = 0;
1189
1190 XMLDocument doc;
1191 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001192 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001193 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001194
1195
1196 {
1197 // bug 1827248 Error while parsing a little bit malformed file
1198 // Actually not malformed - should work.
1199 XMLDocument xml;
1200 xml.Parse( "<attributelist> </attributelist >" );
1201 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1202 }
1203
1204 {
1205 // This one must not result in an infinite loop
1206 XMLDocument xml;
1207 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001208 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001209 XMLTest( "Infinite loop test.", true, true );
1210 }
1211#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001212 {
1213 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1214 XMLDocument doc;
1215 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001216 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001217
1218 XMLDocument clone;
1219 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1220 XMLNode* copy = node->ShallowClone( &clone );
1221 clone.InsertEndChild( copy );
1222 }
1223
1224 clone.Print();
1225
1226 int count=0;
1227 const XMLNode* a=clone.FirstChild();
1228 const XMLNode* b=doc.FirstChild();
1229 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1230 ++count;
1231 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1232 }
1233 XMLTest( "Clone and Equal", 4, count );
1234 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001235
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001236 {
Lee Thomason7085f002017-06-01 18:09:43 -07001237 // Deep Cloning of root element.
1238 XMLDocument doc2;
1239 XMLPrinter printer1;
1240 {
1241 // Make sure doc1 is deleted before we test doc2
1242 const char* xml =
1243 "<root>"
1244 " <child1 foo='bar'/>"
1245 " <!-- comment thing -->"
1246 " <child2 val='1'>Text</child2>"
1247 "</root>";
1248 XMLDocument doc;
1249 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001250 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001251
1252 doc.Print(&printer1);
1253 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1254 doc2.InsertFirstChild(root);
1255 }
1256 XMLPrinter printer2;
1257 doc2.Print(&printer2);
1258
1259 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1260 }
1261
1262 {
1263 // Deep Cloning of sub element.
1264 XMLDocument doc2;
1265 XMLPrinter printer1;
1266 {
1267 // Make sure doc1 is deleted before we test doc2
1268 const char* xml =
1269 "<?xml version ='1.0'?>"
1270 "<root>"
1271 " <child1 foo='bar'/>"
1272 " <!-- comment thing -->"
1273 " <child2 val='1'>Text</child2>"
1274 "</root>";
1275 XMLDocument doc;
1276 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001277 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001278
1279 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1280 subElement->Accept(&printer1);
1281
1282 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1283 doc2.InsertFirstChild(clonedSubElement);
1284 }
1285 XMLPrinter printer2;
1286 doc2.Print(&printer2);
1287
1288 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1289 }
1290
1291 {
1292 // Deep cloning of document.
1293 XMLDocument doc2;
1294 XMLPrinter printer1;
1295 {
1296 // Make sure doc1 is deleted before we test doc2
1297 const char* xml =
1298 "<?xml version ='1.0'?>"
1299 "<!-- Top level comment. -->"
1300 "<root>"
1301 " <child1 foo='bar'/>"
1302 " <!-- comment thing -->"
1303 " <child2 val='1'>Text</child2>"
1304 "</root>";
1305 XMLDocument doc;
1306 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001307 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001308 doc.Print(&printer1);
1309
1310 doc.DeepCopy(&doc2);
1311 }
1312 XMLPrinter printer2;
1313 doc2.Print(&printer2);
1314
1315 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1316 }
1317
1318
1319 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001320 // This shouldn't crash.
1321 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001322 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001323 {
1324 doc.PrintError();
1325 }
1326 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1327 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001328
Lee Thomason5e3803c2012-04-16 08:57:05 -07001329 {
1330 // Attribute ordering.
1331 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1332 XMLDocument doc;
1333 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001334 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001335 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001336
Lee Thomason5e3803c2012-04-16 08:57:05 -07001337 const XMLAttribute* a = ele->FirstAttribute();
1338 XMLTest( "Attribute order", "1", a->Value() );
1339 a = a->Next();
1340 XMLTest( "Attribute order", "2", a->Value() );
1341 a = a->Next();
1342 XMLTest( "Attribute order", "3", a->Value() );
1343 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001344
Lee Thomason5e3803c2012-04-16 08:57:05 -07001345 ele->DeleteAttribute( "attrib2" );
1346 a = ele->FirstAttribute();
1347 XMLTest( "Attribute order", "1", a->Value() );
1348 a = a->Next();
1349 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001350
Lee Thomason5e3803c2012-04-16 08:57:05 -07001351 ele->DeleteAttribute( "attrib1" );
1352 ele->DeleteAttribute( "attrib3" );
1353 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1354 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001355
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001356 {
1357 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001358 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1359 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1360 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1361 XMLDocument doc0;
1362 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001363 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001364 XMLDocument doc1;
1365 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001366 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001367 XMLDocument doc2;
1368 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001369 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001370
Lee Thomason78a773d2012-07-02 10:10:19 -07001371 XMLElement* ele = 0;
1372 ele = doc0.FirstChildElement();
1373 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1374 ele = doc1.FirstChildElement();
1375 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1376 ele = doc2.FirstChildElement();
1377 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001378 }
1379
1380 {
1381 // Make sure we don't go into an infinite loop.
1382 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1383 XMLDocument doc;
1384 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001385 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001386 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1387 XMLElement* ele1 = ele0->NextSiblingElement();
1388 bool equal = ele0->ShallowEqual( ele1 );
1389
1390 XMLTest( "Infinite loop in shallow equal.", true, equal );
1391 }
1392
Lee Thomason5708f812012-03-28 17:46:41 -07001393 // -------- Handles ------------
1394 {
1395 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1396 XMLDocument doc;
1397 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001398 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001399
1400 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001401 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001402
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001403 XMLHandle docH( doc );
1404 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001405 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001406 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001407
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001408 {
1409 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1410 XMLDocument doc;
1411 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001412 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001413 XMLConstHandle docH( doc );
1414
1415 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1416 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1417
1418 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001419 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001420 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001421 {
1422 // Default Declaration & BOM
1423 XMLDocument doc;
1424 doc.InsertEndChild( doc.NewDeclaration() );
1425 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001426
Lee Thomasonf68c4382012-04-28 14:37:11 -07001427 XMLPrinter printer;
1428 doc.Print( &printer );
1429
1430 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001431 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1432 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001433 }
Lee Thomason21be8822012-07-15 17:27:22 -07001434 {
1435 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1436 XMLDocument doc;
1437 doc.Parse( xml );
1438 XMLTest( "Ill formed XML", true, doc.Error() );
1439 }
1440
1441 // QueryXYZText
1442 {
1443 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1444 XMLDocument doc;
1445 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001446 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001447
1448 const XMLElement* pointElement = doc.RootElement();
1449
1450 int intValue = 0;
1451 unsigned unsignedValue = 0;
1452 float floatValue = 0;
1453 double doubleValue = 0;
1454 bool boolValue = false;
1455
1456 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1457 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1458 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1459 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1460 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1461
1462
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001463 XMLTest( "QueryIntText", 1, intValue, false );
1464 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1465 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1466 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1467 XMLTest( "QueryBoolText", true, boolValue, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001468 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001469
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001470 {
1471 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1472 XMLDocument doc;
1473 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001474 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001475 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001476
1477 {
1478 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1479 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001480 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001481 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001482 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001483
1484 {
1485 const char* xml = "<3lement></3lement>";
1486 XMLDocument doc;
1487 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001488 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001489 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001490
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001491 {
1492 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1493 XMLDocument doc;
1494 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001495 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001496 }
1497
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001498 {
1499 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001500 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001501 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001502 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001503 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001504 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001505 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001506 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001507 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001508 }
1509
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001510 // ----------- Whitespace ------------
1511 {
1512 const char* xml = "<element>"
1513 "<a> This \nis &apos; text &apos; </a>"
1514 "<b> This is &apos; text &apos; \n</b>"
1515 "<c>This is &apos; \n\n text &apos;</c>"
1516 "</element>";
1517 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1518 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001519 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001520
1521 const XMLElement* element = doc.FirstChildElement();
1522 for( const XMLElement* parent = element->FirstChildElement();
1523 parent;
1524 parent = parent->NextSiblingElement() )
1525 {
1526 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1527 }
1528 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001529
Lee Thomasonae9ab072012-10-24 10:17:53 -07001530#if 0
1531 {
1532 // Passes if assert doesn't fire.
1533 XMLDocument xmlDoc;
1534
1535 xmlDoc.NewDeclaration();
1536 xmlDoc.NewComment("Configuration file");
1537
1538 XMLElement *root = xmlDoc.NewElement("settings");
1539 root->SetAttribute("version", 2);
1540 }
1541#endif
1542
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001543 {
1544 const char* xml = "<element> </element>";
1545 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1546 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001547 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001548 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1549 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001550
Lee Thomason5b0a6772012-11-19 13:54:42 -08001551 {
1552 // An assert should not fire.
1553 const char* xml = "<element/>";
1554 XMLDocument doc;
1555 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001556 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001557 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1558 XMLTest( "Tracking unused elements", true, ele != 0, false );
1559 }
1560
Lee Thomasona6412ac2012-12-13 15:39:11 -08001561
1562 {
1563 const char* xml = "<parent><child>abc</child></parent>";
1564 XMLDocument doc;
1565 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001566 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001567 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1568
1569 XMLPrinter printer;
1570 ele->Accept( &printer );
1571 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1572 }
1573
1574
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001575 {
1576 XMLDocument doc;
1577 XMLError error = doc.LoadFile( "resources/empty.xml" );
1578 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001579 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001580 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001581 }
1582
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001583 {
1584 // BOM preservation
1585 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1586 {
1587 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001588 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001589 XMLPrinter printer;
1590 doc.Print( &printer );
1591
1592 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1593 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001594 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001595 }
1596 {
1597 XMLDocument doc;
1598 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001599 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001600 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1601
1602 XMLPrinter printer;
1603 doc.Print( &printer );
1604 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1605 }
1606 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001607
Michael Daumlinged523282013-10-23 07:47:29 +02001608 {
1609 // Insertion with Removal
1610 const char* xml = "<?xml version=\"1.0\" ?>"
1611 "<root>"
1612 "<one>"
1613 "<subtree>"
1614 "<elem>element 1</elem>text<!-- comment -->"
1615 "</subtree>"
1616 "</one>"
1617 "<two/>"
1618 "</root>";
1619 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1620 "<root>"
1621 "<one/>"
1622 "<two>"
1623 "<subtree>"
1624 "<elem>element 1</elem>text<!-- comment -->"
1625 "</subtree>"
1626 "</two>"
1627 "</root>";
1628 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1629 "<root>"
1630 "<one/>"
1631 "<subtree>"
1632 "<elem>element 1</elem>text<!-- comment -->"
1633 "</subtree>"
1634 "<two/>"
1635 "</root>";
1636 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1637 "<root>"
1638 "<one/>"
1639 "<two/>"
1640 "<subtree>"
1641 "<elem>element 1</elem>text<!-- comment -->"
1642 "</subtree>"
1643 "</root>";
1644
1645 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001646 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001647 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001648 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1649 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1650 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001651 XMLPrinter printer1(0, true);
1652 doc.Accept(&printer1);
1653 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001654
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001655 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001656 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001657 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1658 two = doc.RootElement()->FirstChildElement("two");
1659 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001660 XMLPrinter printer2(0, true);
1661 doc.Accept(&printer2);
1662 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001663
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001664 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001665 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001666 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1667 subtree = one->FirstChildElement("subtree");
1668 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001669 XMLPrinter printer3(0, true);
1670 doc.Accept(&printer3);
1671 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001672
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001673 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001674 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001675 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1676 two = doc.RootElement()->FirstChildElement("two");
1677 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001678 XMLPrinter printer4(0, true);
1679 doc.Accept(&printer4);
1680 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001681 }
1682
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001683 {
1684 const char* xml = "<svg width = \"128\" height = \"128\">"
1685 " <text> </text>"
1686 "</svg>";
1687 XMLDocument doc;
1688 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001689 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001690 doc.Print();
1691 }
1692
Lee Thomason92e521b2014-11-15 17:45:51 -08001693 {
1694 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001695 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1696 XMLDocument doc;
1697 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001698 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001699 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001700 }
1701
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001702#if 1
1703 // the question being explored is what kind of print to use:
1704 // https://github.com/leethomason/tinyxml2/issues/63
1705 {
1706 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1707 const char* xml = "<element/>";
1708 XMLDocument doc;
1709 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001710 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001711 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1712 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1713 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1714 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1715 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1716 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1717
1718 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1719 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1720 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1721 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1722 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1723 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1724
1725 doc.Print();
1726
1727 /* The result of this test is platform, compiler, and library version dependent. :("
1728 XMLPrinter printer;
1729 doc.Print( &printer );
1730 XMLTest( "Float and double formatting.",
1731 "<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",
1732 printer.CStr(),
1733 true );
1734 */
1735 }
1736#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001737
1738 {
1739 // Issue #184
1740 // If it doesn't assert, it passes. Caused by objects
1741 // getting created during parsing which are then
1742 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001743 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001744 {
1745 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001746 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001747 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001748 }
1749 {
1750 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001751 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001752 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001753 doc.Clear();
1754 }
1755 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001756
1757 {
1758 // If this doesn't assert in DEBUG, all is well.
1759 tinyxml2::XMLDocument doc;
1760 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1761 doc.DeleteNode(pRoot);
1762 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001763
Dmitry-Mee5790db2017-07-28 17:54:38 +03001764 {
1765 XMLDocument doc;
1766 XMLElement* root = doc.NewElement( "Root" );
1767 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1768 doc.InsertEndChild( root );
1769 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1770 }
1771
1772 {
1773 // If this doesn't assert in DEBUG, all is well.
1774 XMLDocument doc;
1775 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1776 XMLElement* linkedRoot = doc.NewElement( "Root" );
1777 doc.InsertFirstChild( linkedRoot );
1778 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1779 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1780 }
1781
Dmitry-Me8b67d742014-12-22 11:35:12 +03001782 {
1783 // Should not assert in DEBUG
1784 XMLPrinter printer;
1785 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001786
Dmitry-Me6f51c802015-03-14 13:25:03 +03001787 {
1788 // Issue 291. Should not crash
1789 const char* xml = "&#0</a>";
1790 XMLDocument doc;
1791 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001792 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001793
1794 XMLPrinter printer;
1795 doc.Print( &printer );
1796 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001797 {
1798 // Issue 299. Can print elements that are not linked in.
1799 // Will crash if issue not fixed.
1800 XMLDocument doc;
1801 XMLElement* newElement = doc.NewElement( "printme" );
1802 XMLPrinter printer;
1803 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001804 // Delete the node to avoid possible memory leak report in debug output
1805 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001806 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001807 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001808 // Issue 302. Clear errors from LoadFile/SaveFile
1809 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001810 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001811 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001812 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001813 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001814 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001815 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001816
Dmitry-Med9852a52015-03-25 10:17:49 +03001817 {
1818 // If a document fails to load then subsequent
1819 // successful loads should clear the error
1820 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001821 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001822 doc.LoadFile( "resources/no-such-file.xml" );
1823 XMLTest( "No such file - should fail", true, doc.Error() );
1824
1825 doc.LoadFile( "resources/dream.xml" );
1826 XMLTest( "Error should be cleared", false, doc.Error() );
1827 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301828
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301829 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001830 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001831 const char* xml0 = "<?xml version=\"1.0\" ?>"
1832 " <!-- xml version=\"1.1\" -->"
1833 "<first />";
1834 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001835 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001836 "<first />";
1837 const char* xml2 = "<first />"
1838 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001839 const char* xml3 = "<first></first>"
1840 "<?xml version=\"1.0\" ?>";
1841
1842 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1843
Lee Thomason85492022015-05-22 11:07:45 -07001844 XMLDocument doc;
1845 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001846 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001847 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001848 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001849 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001850 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001851 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001852 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001853 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001854 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301855 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001856
Lee Thomason85492022015-05-22 11:07:45 -07001857 {
1858 // No matter - before or after successfully parsing a text -
1859 // calling XMLDocument::Value() causes an assert in debug.
1860 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1861 "<first />"
1862 "<second />";
1863 XMLDocument* doc = new XMLDocument();
1864 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1865 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001866 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001867 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1868 delete doc;
1869 }
1870
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001871 {
1872 XMLDocument doc;
1873 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001874 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001875 doc.ErrorName();
1876 }
1877 }
1878
Lee Thomason816d3fa2017-06-05 14:35:55 -07001879 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001880 // Evil memory leaks.
1881 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1882 // and NOT added to the XMLDocument, what happens?
1883 //
1884 // Previously (buggy):
1885 // The memory would be free'd when the XMLDocument is
1886 // destructed. But the destructor wasn't called, so that
1887 // memory allocated by the XMLElement would not be free'd.
1888 // In practice this meant strings allocated by the XMLElement
1889 // would leak. An edge case, but annoying.
1890 // Now:
1891 // The destructor is called. But the list of unlinked nodes
1892 // has to be tracked. This has a minor performance impact
1893 // that can become significant if you have a lot. (But why
1894 // would you do that?)
1895 // The only way to see this bug is in a leak tracker. This
1896 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001897 {
1898 XMLDocument doc;
1899 doc.NewElement("LEAK 1");
1900 }
1901 {
1902 XMLDocument doc;
1903 XMLElement* ele = doc.NewElement("LEAK 2");
1904 doc.DeleteNode(ele);
1905 }
1906 }
1907
Lee Thomason224ef772017-06-16 09:45:26 -07001908 {
1909 // Crashing reported via email.
1910 const char* xml =
1911 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001912 "<property name='track_name'>voice</property>"
1913 "<property name='audio_track'>1</property>"
1914 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1915 "<blank length = '1' />"
1916 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1917 "<blank length = '2' />"
1918 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1919 "<blank length = '1' />"
1920 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001921 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001922
Lee Thomason224ef772017-06-16 09:45:26 -07001923 // It's not a good idea to delete elements as you walk the
1924 // list. I'm not sure this technically should work; but it's
1925 // an interesting test case.
1926 XMLDocument doc;
1927 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001928 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03001929
1930 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001931 XMLTest("Crash bug parsing", true, playlist != 0);
1932
1933 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1934 XMLTest("Crash bug parsing", true, entry != 0);
1935 while (entry) {
1936 tinyxml2::XMLElement* todelete = entry;
1937 entry = entry->NextSiblingElement("entry");
1938 playlist->DeleteChild(todelete);
1939 };
1940 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1941 while (blank) {
1942 tinyxml2::XMLElement* todelete = blank;
1943 blank = blank->NextSiblingElement("blank");
1944 playlist->DeleteChild(todelete);
1945 };
1946
1947 tinyxml2::XMLPrinter printer;
1948 playlist->Accept(&printer);
1949 printf("%s\n", printer.CStr());
1950
Lee Thomason82bb0742017-06-16 09:48:20 -07001951 // No test; it only need to not crash.
1952 // Still, wrap it up with a sanity check
1953 int nProperty = 0;
1954 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1955 nProperty++;
1956 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001957 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07001958 }
1959
kezenatorec694152016-11-26 17:21:43 +10001960 // ----------- Line Number Tracking --------------
1961 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001962 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001963 {
1964 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1965 {
1966 XMLDocument doc;
1967 XMLError err = doc.Parse(docStr);
1968
1969 XMLTest(testString, true, doc.Error());
1970 XMLTest(testString, expected_error, err);
1971 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1972 };
1973
1974 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1975 {
1976 XMLDocument doc;
1977 doc.Parse(docStr);
1978 XMLTest(testString, false, doc.Error());
1979 TestDocLines(testString, doc, expectedLines);
1980 }
1981
1982 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1983 {
1984 XMLDocument doc;
1985 doc.LoadFile(file_name);
1986 XMLTest(testString, false, doc.Error());
1987 TestDocLines(testString, doc, expectedLines);
1988 }
1989
1990 private:
1991 DynArray<char, 10> str;
1992
1993 void Push(char type, int lineNum)
1994 {
1995 str.Push(type);
1996 str.Push(char('0' + (lineNum / 10)));
1997 str.Push(char('0' + (lineNum % 10)));
1998 }
1999
2000 bool VisitEnter(const XMLDocument& doc)
2001 {
kezenator19d8ea82016-11-29 19:50:27 +10002002 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002003 return true;
2004 }
2005 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2006 {
kezenator19d8ea82016-11-29 19:50:27 +10002007 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002008 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002009 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002010 return true;
2011 }
2012 bool Visit(const XMLDeclaration& declaration)
2013 {
kezenator19d8ea82016-11-29 19:50:27 +10002014 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002015 return true;
2016 }
2017 bool Visit(const XMLText& text)
2018 {
kezenator19d8ea82016-11-29 19:50:27 +10002019 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002020 return true;
2021 }
2022 bool Visit(const XMLComment& comment)
2023 {
kezenator19d8ea82016-11-29 19:50:27 +10002024 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002025 return true;
2026 }
2027 bool Visit(const XMLUnknown& unknown)
2028 {
kezenator19d8ea82016-11-29 19:50:27 +10002029 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002030 return true;
2031 }
2032
2033 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2034 {
2035 str.Clear();
2036 doc.Accept(this);
2037 str.Push(0);
2038 XMLTest(testString, expectedLines, str.Mem());
2039 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002040 } tester;
kezenatorec694152016-11-26 17:21:43 +10002041
Lee Thomasone90e9012016-12-24 07:34:39 -08002042 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2043 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2044 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2045 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2046 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2047 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2048 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2049 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2050 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2051 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2052 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002053
Lee Thomasone90e9012016-12-24 07:34:39 -08002054 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002055 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002056
2057 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2058 "<root a='b' \n" // 2 Element Attribute
2059 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2060 "newline in text \n" // 4 Text
2061 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2062 " cdata test ]]><!-- comment -->\n" // 6 Comment
2063 "<! unknown></root>", // 7 Unknown
2064
kezenatorec694152016-11-26 17:21:43 +10002065 "D01L01E02A02A03T03E03T04E05T05C06U07");
2066
Lee Thomasone90e9012016-12-24 07:34:39 -08002067 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002068 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002069
2070 "\r\n" // 1 Doc (arguably should be line 2)
2071 "<?xml version=\"1.0\"?>\n" // 2 DecL
2072 "<root>\r\n" // 3 Element
2073 "\n" // 4
2074 "text contining new line \n" // 5 Text
2075 " and also containing crlf \r\n" // 6
2076 "<sub><![CDATA[\n" // 7 Element Text
2077 "cdata containing new line \n" // 8
2078 " and also containing cflr\r\n" // 9
2079 "]]></sub><sub2/></root>", // 10 Element
2080
kezenatorec694152016-11-26 17:21:43 +10002081 "D01L02E03T05E07T07E10");
2082
Lee Thomasone90e9012016-12-24 07:34:39 -08002083 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002084 "LineNumbers-File",
2085 "resources/utf8test.xml",
2086 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2087 }
2088
Lee Thomason85492022015-05-22 11:07:45 -07002089 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002090 {
2091#if defined( _MSC_VER )
2092 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002093 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002094#endif
2095
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002096 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002097 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002098 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002099 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002100 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002101
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002102 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002103 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002104 size_t bytesRead = fread(mem, 1, size, perfFP);
2105 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002106 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002107 mem[size] = 0;
2108
2109#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002110 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002111#else
2112 clock_t cstart = clock();
2113#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002114 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002115 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002116 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002117 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002118 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002119 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002120 }
Dmitry-Me68578f42017-07-03 18:21:23 +03002121 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002122#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002123 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002124#else
2125 clock_t cend = clock();
2126#endif
2127
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002128 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002129
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002130 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002131#ifdef DEBUG
2132 "DEBUG";
2133#else
2134 "Release";
2135#endif
2136
2137#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002138 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002139#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002140 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002141#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002142 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002143 }
2144
Dmitry-Mede381df2017-07-26 18:05:25 +03002145#if defined( _MSC_VER ) && defined( DEBUG )
2146 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002147 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002148
2149 _CrtMemState diffMemState;
2150 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2151 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002152
2153 {
2154 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2155 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2156 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002157 }
2158#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002159
2160 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002161
2162 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002163}