blob: 499d62678b126045fc76356007b1a3c7ff9f9f4c [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"
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07008#include <cstdlib>
9#include <cstring>
10#include <ctime>
U-Lama\Leee13c3e62011-12-28 14:36:55 -080011
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080012#if defined( _MSC_VER )
Lee Thomasone9699e62012-07-25 12:24:23 -070013 #include <direct.h> // _mkdir
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;
18 _CrtMemState endMemState;
Martinsh Shaiters39ddc262013-01-15 21:53:08 +020019#elif defined(MINGW32) || defined(__MINGW32__)
20 #include <io.h> // mkdir
Lee Thomasone9699e62012-07-25 12:24:23 -070021#else
22 #include <sys/stat.h> // mkdir
Lee Thomason1ff38e02012-02-14 18:18:16 -080023#endif
Lee Thomasone9ecdab2012-02-13 18:11:20 -080024
U-Lama\Leee13c3e62011-12-28 14:36:55 -080025using namespace tinyxml2;
Anton Indrawan8a0006c2014-11-20 18:27:07 +010026using namespace std;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080027int gPass = 0;
28int gFail = 0;
29
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080030
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070031bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080032{
Sarat Addepalli13b2d732015-05-19 12:44:57 +053033 bool pass;
34 if ( !expected && !found )
35 pass = true;
36 else if ( !expected || !found )
37 pass = false;
Sarat Addepallid608c562015-05-20 10:19:00 +053038 else
39 pass = !strcmp( expected, found );
Lee Thomason1ff38e02012-02-14 18:18:16 -080040 if ( pass )
41 printf ("[pass]");
42 else
43 printf ("[fail]");
44
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070045 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080046 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070047 }
48 else {
49 if ( extraNL ) {
50 printf( " %s\n", testString );
51 printf( "%s\n", expected );
52 printf( "%s\n", found );
53 }
54 else {
55 printf (" %s [%s][%s]\n", testString, expected, found);
56 }
57 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080058
59 if ( pass )
60 ++gPass;
61 else
62 ++gFail;
63 return pass;
64}
65
kezenator5a700712016-11-26 13:54:42 +100066bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
67{
Lee Thomasone90e9012016-12-24 07:34:39 -080068 return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
kezenator5a700712016-11-26 13:54:42 +100069}
70
71bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
72{
73 return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
74}
Lee Thomason1ff38e02012-02-14 18:18:16 -080075
Lee Thomason21be8822012-07-15 17:27:22 -070076template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080077{
78 bool pass = ( expected == found );
79 if ( pass )
80 printf ("[pass]");
81 else
82 printf ("[fail]");
83
U-Stream\Lee09a11c52012-02-17 08:31:16 -080084 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080085 printf (" %s\n", testString);
86 else
Lee Thomasonc8312792012-07-16 12:44:41 -070087 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080088
89 if ( pass )
90 ++gPass;
91 else
92 ++gFail;
93 return pass;
94}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080095
U-Lama\Leee13c3e62011-12-28 14:36:55 -080096
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080097void NullLineEndings( char* p )
98{
99 while( p && *p ) {
100 if ( *p == '\n' || *p == '\r' ) {
101 *p = 0;
102 return;
103 }
104 ++p;
105 }
106}
107
108
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700109int example_1()
110{
111 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300112 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700113
114 return doc.ErrorID();
115}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200116/** @page Example-1 Load an XML File
117 * @dontinclude ./xmltest.cpp
118 * Basic XML file loading.
119 * The basic syntax to load an XML file from
120 * disk and check for an error. (ErrorID()
121 * will return 0 for no error.)
122 * @skip example_1()
123 * @until }
124 */
125
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700126
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700127int example_2()
128{
129 static const char* xml = "<element/>";
130 XMLDocument doc;
131 doc.Parse( xml );
132
133 return doc.ErrorID();
134}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200135/** @page Example-2 Parse an XML from char buffer
136 * @dontinclude ./xmltest.cpp
137 * Basic XML string parsing.
138 * The basic syntax to parse an XML for
139 * a char* and check for an error. (ErrorID()
140 * will return 0 for no error.)
141 * @skip example_2()
142 * @until }
143 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700144
145
146int example_3()
147{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700148 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700149 "<?xml version=\"1.0\"?>"
150 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
151 "<PLAY>"
152 "<TITLE>A Midsummer Night's Dream</TITLE>"
153 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700154
155 XMLDocument doc;
156 doc.Parse( xml );
157
158 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
159 const char* title = titleElement->GetText();
160 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700161
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700162 XMLText* textNode = titleElement->FirstChild()->ToText();
163 title = textNode->Value();
164 printf( "Name of play (2): %s\n", title );
165
166 return doc.ErrorID();
167}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200168/** @page Example-3 Get information out of XML
169 @dontinclude ./xmltest.cpp
170 In this example, we navigate a simple XML
171 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700172 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200173 checking; working code should check for null
174 pointers when walking an XML tree, or use
175 XMLHandle.
176
177 (The XML is an excerpt from "dream.xml").
178
179 @skip example_3()
180 @until </PLAY>";
181
182 The structure of the XML file is:
183
184 <ul>
185 <li>(declaration)</li>
186 <li>(dtd stuff)</li>
187 <li>Element "PLAY"</li>
188 <ul>
189 <li>Element "TITLE"</li>
190 <ul>
191 <li>Text "A Midsummer Night's Dream"</li>
192 </ul>
193 </ul>
194 </ul>
195
196 For this example, we want to print out the
197 title of the play. The text of the title (what
198 we want) is child of the "TITLE" element which
199 is a child of the "PLAY" element.
200
201 We want to skip the declaration and dtd, so the
202 method FirstChildElement() is a good choice. The
203 FirstChildElement() of the Document is the "PLAY"
204 Element, the FirstChildElement() of the "PLAY" Element
205 is the "TITLE" Element.
206
207 @until ( "TITLE" );
208
209 We can then use the convenience function GetText()
210 to get the title of the play.
211
212 @until title );
213
214 Text is just another Node in the XML DOM. And in
215 fact you should be a little cautious with it, as
216 text nodes can contain elements.
217
218 @verbatim
219 Consider: A Midsummer Night's <b>Dream</b>
220 @endverbatim
221
222 It is more correct to actually query the Text Node
223 if in doubt:
224
225 @until title );
226
227 Noting that here we use FirstChild() since we are
228 looking for XMLText, not an element, and ToText()
229 is a cast from a Node to a XMLText.
230*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700231
232
Lee Thomason21be8822012-07-15 17:27:22 -0700233bool example_4()
234{
235 static const char* xml =
236 "<information>"
237 " <attributeApproach v='2' />"
238 " <textApproach>"
239 " <v>2</v>"
240 " </textApproach>"
241 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700242
Lee Thomason21be8822012-07-15 17:27:22 -0700243 XMLDocument doc;
244 doc.Parse( xml );
245
246 int v0 = 0;
247 int v1 = 0;
248
249 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
250 attributeApproachElement->QueryIntAttribute( "v", &v0 );
251
252 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
253 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
254
255 printf( "Both values are the same: %d and %d\n", v0, v1 );
256
257 return !doc.Error() && ( v0 == v1 );
258}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200259/** @page Example-4 Read attributes and text information.
260 @dontinclude ./xmltest.cpp
261
262 There are fundamentally 2 ways of writing a key-value
263 pair into an XML file. (Something that's always annoyed
264 me about XML.) Either by using attributes, or by writing
265 the key name into an element and the value into
266 the text node wrapped by the element. Both approaches
267 are illustrated in this example, which shows two ways
268 to encode the value "2" into the key "v":
269
270 @skip example_4()
271 @until "</information>";
272
273 TinyXML-2 has accessors for both approaches.
274
275 When using an attribute, you navigate to the XMLElement
276 with that attribute and use the QueryIntAttribute()
277 group of methods. (Also QueryFloatAttribute(), etc.)
278
279 @skip XMLElement* attributeApproachElement
280 @until &v0 );
281
282 When using the text approach, you need to navigate
283 down one more step to the XMLElement that contains
284 the text. Note the extra FirstChildElement( "v" )
285 in the code below. The value of the text can then
286 be safely queried with the QueryIntText() group
287 of methods. (Also QueryFloatText(), etc.)
288
289 @skip XMLElement* textApproachElement
290 @until &v1 );
291*/
Lee Thomason21be8822012-07-15 17:27:22 -0700292
293
Lee Thomason178e4cc2013-01-25 16:19:05 -0800294int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800295{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800296 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800297 _CrtMemCheckpoint( &startMemState );
Dmitry-Me99916592014-10-23 11:37:03 +0400298 // Enable MS Visual C++ debug heap memory leaks dump on exit
299 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700300 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800301
Martinsh Shaiters39ddc262013-01-15 21:53:08 +0200302 #if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__)
ddiproiettoa8ae1f62013-05-05 18:42:52 +0300303 #if defined __MINGW64_VERSION_MAJOR && defined __MINGW64_VERSION_MINOR
304 //MINGW64: both 32 and 64-bit
305 mkdir( "resources/out/" );
306 #else
307 _mkdir( "resources/out/" );
308 #endif
Lee Thomasone9699e62012-07-25 12:24:23 -0700309 #else
310 mkdir( "resources/out/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
311 #endif
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400312
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300313 {
314 TIXMLASSERT( true );
315 }
316
Lee Thomason178e4cc2013-01-25 16:19:05 -0800317 if ( argc > 1 ) {
318 XMLDocument* doc = new XMLDocument();
319 clock_t startTime = clock();
320 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100321 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800322 int errorID = doc->ErrorID();
323 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100324 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800325
326 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
327 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700328 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
329 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
330 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800331 }
332 exit(0);
333 }
334
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300335 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700336 if ( !fp ) {
337 printf( "Error opening test file 'dream.xml'.\n"
338 "Is your working directory the same as where \n"
339 "the xmltest.cpp and dream.xml file are?\n\n"
340 #if defined( _MSC_VER )
341 "In windows Visual Studio you may need to set\n"
342 "Properties->Debugging->Working Directory to '..'\n"
343 #endif
344 );
345 exit( 1 );
346 }
347 fclose( fp );
348
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700349 XMLTest( "Example-1", 0, example_1() );
350 XMLTest( "Example-2", 0, example_2() );
351 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700352 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700353
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700354 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700355
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800356 {
Lee Thomason43f59302012-02-06 18:18:11 -0800357 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400358 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800359 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400360 "<element><subelement></subelement></element>",
361 "<element><subelement><subsub/></subelement></element>",
362 "<!--comment beside elements--><element><subelement></subelement></element>",
363 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
364 "<element attrib1='foo' attrib2=\"bar\" ></element>",
365 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800366 "<element>Text inside element.</element>",
367 "<element><b></b></element>",
368 "<element>Text inside and <b>bolded</b> in the element.</element>",
369 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800370 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800371 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800372 0
373 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800374 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800375 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800376 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800377 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800378 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800379 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800380 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800382 {
383 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400384 " line 2\r"
385 " line 3\r\n"
386 " line 4\n\r"
387 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800388
389 XMLDocument doc;
390 doc.Parse( test );
391 doc.Print();
392 }
393
Lee Thomason2c85a712012-01-31 08:24:24 -0800394 {
395 static const char* test = "<element>Text before.</element>";
396 XMLDocument doc;
397 doc.Parse( test );
398 XMLElement* root = doc.FirstChildElement();
399 XMLElement* newElement = doc.NewElement( "Subelement" );
400 root->InsertEndChild( newElement );
401 doc.Print();
402 }
Lee Thomasond1983222012-02-06 08:41:24 -0800403 {
404 XMLDocument* doc = new XMLDocument();
405 static const char* test = "<element><sub/></element>";
406 doc->Parse( test );
407 delete doc;
408 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800409 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800410 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800411 // Build:
412 // <element>
413 // <!--comment-->
414 // <sub attrib="1" />
415 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800416 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800417 // <element>
418
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800419 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800420 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
421
422 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
423 for( int i=0; i<3; ++i ) {
424 sub[i]->SetAttribute( "attrib", i );
425 }
426 element->InsertEndChild( sub[2] );
427 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700428 comment->SetUserData((void*)2);
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() );
Lee Thomasonc9445462016-07-17 22:53:48 -0700438 XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800439
440 // And now deletion:
441 element->DeleteChild( sub[2] );
442 doc->DeleteNode( comment );
443
444 element->FirstChildElement()->SetAttribute( "attrib", true );
445 element->LastChildElement()->DeleteAttribute( "attrib" );
446
447 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700448 int value1 = 10;
449 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", 10 );
450 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
Lee Thomason21be8822012-07-15 17:27:22 -0700451 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700452 XMLTest( "Programmatic DOM", value1, 10 );
453 XMLTest( "Programmatic DOM", value2, 10 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800454
455 doc->Print();
456
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700457 {
458 XMLPrinter streamer;
459 doc->Print( &streamer );
460 printf( "%s", streamer.CStr() );
461 }
462 {
463 XMLPrinter streamer( 0, true );
464 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200465 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700466 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700467 doc->SaveFile( "./resources/out/pretty.xml" );
468 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800469 delete doc;
470 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800471 {
472 // Test: Dream
473 // XML1 : 1,187,569 bytes in 31,209 allocations
474 // XML2 : 469,073 bytes in 323 allocations
475 //int newStart = gNew;
476 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300477 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800478
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400479 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800480 doc.PrintError();
481
482 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400483 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800484 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
485 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
486 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
487 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400488 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800489 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400490 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800491
492 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400493 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800494 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400495 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800496 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
497 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
498 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
499 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400500 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800501
502 //gNewTotal = gNew - newStart;
503 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800504
505
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800506 {
507 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
508 "<passages count=\"006\" formatversion=\"20020620\">\n"
509 " <wrong error>\n"
510 "</passages>";
511
512 XMLDocument doc;
513 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800514 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800515 }
516
517 {
518 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
519
520 XMLDocument doc;
521 doc.Parse( str );
522
523 XMLElement* ele = doc.FirstChildElement();
524
525 int iVal, result;
526 double dVal;
527
528 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700529 XMLTest( "Query attribute: int as double", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800530 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700531 XMLTest( "Query attribute: int as double", (int)ele->DoubleAttribute("attr0"), 1);
532
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800533 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700534 XMLTest( "Query attribute: double as double", result, (int)XML_SUCCESS);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700535 XMLTest( "Query attribute: double as double", dVal, 2.0 );
536 XMLTest( "Query attribute: double as double", ele->DoubleAttribute("attr1"), 2.0 );
537
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800538 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason85536252016-06-04 19:10:53 -0700539 XMLTest( "Query attribute: double as int", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800540 XMLTest( "Query attribute: double as int", iVal, 2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700541
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800542 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700543 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700544 XMLTest( "Query attribute: not a number", ele->DoubleAttribute("attr2", 4.0), 4.0 );
545
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800546 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700547 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700548 XMLTest( "Query attribute: does not exist", ele->BoolAttribute("bar", true), true );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800549 }
550
551 {
552 const char* str = "<doc/>";
553
554 XMLDocument doc;
555 doc.Parse( str );
556
557 XMLElement* ele = doc.FirstChildElement();
558
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800559 int iVal, iVal2;
560 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800561
562 ele->SetAttribute( "str", "strValue" );
563 ele->SetAttribute( "int", 1 );
564 ele->SetAttribute( "double", -1.0 );
565
566 const char* cStr = ele->Attribute( "str" );
567 ele->QueryIntAttribute( "int", &iVal );
568 ele->QueryDoubleAttribute( "double", &dVal );
569
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800570 ele->QueryAttribute( "int", &iVal2 );
571 ele->QueryAttribute( "double", &dVal2 );
572
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700573 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800574 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
575 XMLTest( "Attribute round trip. int.", 1, iVal );
576 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800577 XMLTest( "Alternate query", true, iVal == iVal2 );
578 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700579 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
580 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800581 }
582
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800583 {
584 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300585 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800586
587 // Get the attribute "value" from the "Russian" element and check it.
588 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700589 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800590 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
591
592 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
593
594 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
595 0xd1U, 0x81U, 0xd1U, 0x81U,
596 0xd0U, 0xbaU, 0xd0U, 0xb8U,
597 0xd0U, 0xb9U, 0 };
598 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
599
600 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
601 XMLTest( "UTF-8: Browsing russian element name.",
602 russianText,
603 text->Value() );
604
605 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400606 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800607
608 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800609 int okay = 0;
610
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200611 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300612 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800613
614 if ( saved && verify )
615 {
616 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700617 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800618 while ( fgets( verifyBuf, 256, verify ) )
619 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700620 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800621 fgets( savedBuf, 256, saved );
622 NullLineEndings( verifyBuf );
623 NullLineEndings( savedBuf );
624
625 if ( strcmp( verifyBuf, savedBuf ) )
626 {
627 printf( "verify:%s<\n", verifyBuf );
628 printf( "saved :%s<\n", savedBuf );
629 okay = 0;
630 break;
631 }
632 }
633 }
634 if ( saved )
635 fclose( saved );
636 if ( verify )
637 fclose( verify );
638 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
639 }
640
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800641 // --------GetText()-----------
642 {
643 const char* str = "<foo>This is text</foo>";
644 XMLDocument doc;
645 doc.Parse( str );
646 const XMLElement* element = doc.RootElement();
647
648 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
649
650 str = "<foo><b>This is text</b></foo>";
651 doc.Parse( str );
652 element = doc.RootElement();
653
654 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
655 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800656
Lee Thomasond6277762012-02-22 16:00:12 -0800657
Uli Kusterer321072e2014-01-21 01:57:38 +0100658 // --------SetText()-----------
659 {
660 const char* str = "<foo></foo>";
661 XMLDocument doc;
662 doc.Parse( str );
663 XMLElement* element = doc.RootElement();
664
Lee Thomason9c0678a2014-01-24 10:18:27 -0800665 element->SetText("darkness.");
666 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100667
Lee Thomason9c0678a2014-01-24 10:18:27 -0800668 element->SetText("blue flame.");
669 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100670
671 str = "<foo/>";
672 doc.Parse( str );
673 element = doc.RootElement();
674
Lee Thomason9c0678a2014-01-24 10:18:27 -0800675 element->SetText("The driver");
676 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100677
Lee Thomason9c0678a2014-01-24 10:18:27 -0800678 element->SetText("<b>horses</b>");
679 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
680 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100681
682 str = "<foo><bar>Text in nested element</bar></foo>";
683 doc.Parse( str );
684 element = doc.RootElement();
685
Lee Thomason9c0678a2014-01-24 10:18:27 -0800686 element->SetText("wolves");
687 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800688
689 str = "<foo/>";
690 doc.Parse( str );
691 element = doc.RootElement();
692
693 element->SetText( "str" );
694 XMLTest( "SetText types", "str", element->GetText() );
695
696 element->SetText( 1 );
697 XMLTest( "SetText types", "1", element->GetText() );
698
699 element->SetText( 1U );
700 XMLTest( "SetText types", "1", element->GetText() );
701
702 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200703 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800704
705 element->SetText( 1.5f );
706 XMLTest( "SetText types", "1.5", element->GetText() );
707
708 element->SetText( 1.5 );
709 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100710 }
711
Lee Thomason51c12712016-06-04 20:18:49 -0700712 // ---------- Attributes ---------
713 {
714 static const int64_t BIG = -123456789012345678;
715 XMLDocument doc;
716 XMLElement* element = doc.NewElement("element");
717 doc.InsertFirstChild(element);
718
719 {
720 element->SetAttribute("attrib", int(-100));
721 int v = 0;
722 element->QueryIntAttribute("attrib", &v);
723 XMLTest("Attribute: int", -100, v, true);
724 element->QueryAttribute("attrib", &v);
725 XMLTest("Attribute: int", -100, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700726 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700727 }
728 {
729 element->SetAttribute("attrib", unsigned(100));
730 unsigned v = 0;
731 element->QueryUnsignedAttribute("attrib", &v);
732 XMLTest("Attribute: unsigned", unsigned(100), v, true);
733 element->QueryAttribute("attrib", &v);
734 XMLTest("Attribute: unsigned", unsigned(100), v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700735 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700736 }
737 {
738 element->SetAttribute("attrib", BIG);
739 int64_t v = 0;
740 element->QueryInt64Attribute("attrib", &v);
741 XMLTest("Attribute: int64_t", BIG, v, true);
742 element->QueryAttribute("attrib", &v);
743 XMLTest("Attribute: int64_t", BIG, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700744 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700745 }
746 {
747 element->SetAttribute("attrib", true);
748 bool v = false;
749 element->QueryBoolAttribute("attrib", &v);
750 XMLTest("Attribute: bool", true, v, true);
751 element->QueryAttribute("attrib", &v);
752 XMLTest("Attribute: bool", true, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700753 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700754 }
755 {
756 element->SetAttribute("attrib", 100.0);
757 double v = 0;
758 element->QueryDoubleAttribute("attrib", &v);
759 XMLTest("Attribute: double", 100.0, v, true);
760 element->QueryAttribute("attrib", &v);
761 XMLTest("Attribute: double", 100.0, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700762 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700763 }
764 {
765 element->SetAttribute("attrib", 100.0f);
766 float v = 0;
767 element->QueryFloatAttribute("attrib", &v);
768 XMLTest("Attribute: float", 100.0f, v, true);
769 element->QueryAttribute("attrib", &v);
770 XMLTest("Attribute: float", 100.0f, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700771 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700772 }
773 {
774 element->SetText(BIG);
775 int64_t v = 0;
776 element->QueryInt64Text(&v);
777 XMLTest("Element: int64_t", BIG, v, true);
778 }
779 }
780
781 // ---------- XMLPrinter stream mode ------
782 {
783 {
784 FILE* printerfp = fopen("resources/printer.xml", "w");
785 XMLPrinter printer(printerfp);
786 printer.OpenElement("foo");
787 printer.PushAttribute("attrib-text", "text");
788 printer.PushAttribute("attrib-int", int(1));
789 printer.PushAttribute("attrib-unsigned", unsigned(2));
790 printer.PushAttribute("attrib-int64", int64_t(3));
791 printer.PushAttribute("attrib-bool", true);
792 printer.PushAttribute("attrib-double", 4.0);
793 printer.CloseElement();
794 fclose(printerfp);
795 }
796 {
797 XMLDocument doc;
798 doc.LoadFile("resources/printer.xml");
799 XMLTest("XMLPrinter Stream mode: load", doc.ErrorID(), XML_SUCCESS, true);
800
801 const XMLDocument& cdoc = doc;
802
803 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
804 XMLTest("attrib-text", "text", attrib->Value(), true);
805 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
806 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
807 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
808 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
809 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
810 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
811 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
812 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
813 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
814 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
815 }
816
817 }
818
Uli Kusterer321072e2014-01-21 01:57:38 +0100819
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800820 // ---------- CDATA ---------------
821 {
822 const char* str = "<xmlElement>"
823 "<![CDATA["
824 "I am > the rules!\n"
825 "...since I make symbolic puns"
826 "]]>"
827 "</xmlElement>";
828 XMLDocument doc;
829 doc.Parse( str );
830 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800831
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700832 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800833 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800834 false );
835 }
836
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800837 // ----------- CDATA -------------
838 {
839 const char* str = "<xmlElement>"
840 "<![CDATA["
841 "<b>I am > the rules!</b>\n"
842 "...since I make symbolic puns"
843 "]]>"
844 "</xmlElement>";
845 XMLDocument doc;
846 doc.Parse( str );
847 doc.Print();
848
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700849 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800850 "<b>I am > the rules!</b>\n...since I make symbolic puns",
851 false );
852 }
853
854 // InsertAfterChild causes crash.
855 {
856 // InsertBeforeChild and InsertAfterChild causes crash.
857 XMLDocument doc;
858 XMLElement* parent = doc.NewElement( "Parent" );
859 doc.InsertFirstChild( parent );
860
861 XMLElement* childText0 = doc.NewElement( "childText0" );
862 XMLElement* childText1 = doc.NewElement( "childText1" );
863
864 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
865 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
866
867 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
868 }
Lee Thomasond6277762012-02-22 16:00:12 -0800869
870 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800871 // Entities not being written correctly.
872 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800873
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800874 const char* passages =
875 "<?xml version=\"1.0\" standalone=\"no\" ?>"
876 "<passages count=\"006\" formatversion=\"20020620\">"
877 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
878 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
879 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800880
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800881 XMLDocument doc;
882 doc.Parse( passages );
883 XMLElement* psg = doc.RootElement()->FirstChildElement();
884 const char* context = psg->Attribute( "context" );
885 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 -0800886
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800887 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800888
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400889 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800890 if ( textfile )
891 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800892 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800893 psg->Accept( &streamer );
894 fclose( textfile );
895 }
Thomas Roß0922b732012-09-23 16:31:22 +0200896
897 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800898 TIXMLASSERT( textfile );
899 if ( textfile )
900 {
901 char buf[ 1024 ];
902 fgets( buf, 1024, textfile );
903 XMLTest( "Entity transformation: write. ",
904 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
905 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
906 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700907 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800908 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800909 }
910
911 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800912 // Suppress entities.
913 const char* passages =
914 "<?xml version=\"1.0\" standalone=\"no\" ?>"
915 "<passages count=\"006\" formatversion=\"20020620\">"
916 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
917 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700918
Lee Thomason6f381b72012-03-02 12:59:39 -0800919 XMLDocument doc( false );
920 doc.Parse( passages );
921
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700922 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800923 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
924 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
925 "Crazy &ttk;" );
926 doc.Print();
927 }
928
929 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400930 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800931
932 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400933 doc.Parse( test );
934 XMLTest( "dot in names", doc.Error(), false );
935 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
936 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800937 }
938
939 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400940 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800941
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400942 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800943 doc.Parse( test );
944
945 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
946 XMLTest( "Entity with one digit.",
947 text->Value(), "1.1 Start easy ignore fin thickness\n",
948 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400949 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800950
951 {
952 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700953 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800954 const char* doctype =
955 "<?xml version=\"1.0\" ?>"
956 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
957 "<!ELEMENT title (#PCDATA)>"
958 "<!ELEMENT books (title,authors)>"
959 "<element />";
960
961 XMLDocument doc;
962 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400963 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800964 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400965 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800966 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700967
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800968 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
969 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
970
971 }
972
973 {
974 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700975 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976 "<!-- Somewhat<evil> -->";
977 XMLDocument doc;
978 doc.Parse( doctype );
979
980 XMLComment* comment = doc.FirstChild()->ToComment();
981
982 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
983 }
984 {
985 // Double attributes
986 const char* doctype = "<element attr='red' attr='blue' />";
987
988 XMLDocument doc;
989 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700990
Lee Thomason2fa81722012-11-09 12:37:46 -0800991 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 -0800992 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800993 }
994
995 {
996 // Embedded null in stream.
997 const char* doctype = "<element att\0r='red' attr='blue' />";
998
999 XMLDocument doc;
1000 doc.Parse( doctype );
1001 XMLTest( "Embedded null throws error.", true, doc.Error() );
1002 }
1003
1004 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001005 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001006 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001007 XMLDocument doc;
1008 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001009 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001010 }
1011
1012 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001013 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1014 const char* str = " ";
1015 XMLDocument doc;
1016 doc.Parse( str );
1017 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1018 }
1019
1020 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001021 // Low entities
1022 XMLDocument doc;
1023 doc.Parse( "<test>&#x0e;</test>" );
1024 const char result[] = { 0x0e, 0 };
1025 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
1026 doc.Print();
1027 }
1028
1029 {
1030 // Attribute values with trailing quotes not handled correctly
1031 XMLDocument doc;
1032 doc.Parse( "<foo attribute=bar\" />" );
1033 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
1034 }
1035
1036 {
1037 // [ 1663758 ] Failure to report error on bad XML
1038 XMLDocument xml;
1039 xml.Parse("<x>");
1040 XMLTest("Missing end tag at end of input", xml.Error(), true);
1041 xml.Parse("<x> ");
1042 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
1043 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -08001044 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001045 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001046
1047
1048 {
1049 // [ 1475201 ] TinyXML parses entities in comments
1050 XMLDocument xml;
1051 xml.Parse("<!-- declarations for <head> & <body> -->"
1052 "<!-- far &amp; away -->" );
1053
1054 XMLNode* e0 = xml.FirstChild();
1055 XMLNode* e1 = e0->NextSibling();
1056 XMLComment* c0 = e0->ToComment();
1057 XMLComment* c1 = e1->ToComment();
1058
1059 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1060 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1061 }
1062
1063 {
1064 XMLDocument xml;
1065 xml.Parse( "<Parent>"
1066 "<child1 att=''/>"
1067 "<!-- With this comment, child2 will not be parsed! -->"
1068 "<child2 att=''/>"
1069 "</Parent>" );
1070 xml.Print();
1071
1072 int count = 0;
1073
1074 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1075 ele;
1076 ele = ele->NextSibling() )
1077 {
1078 ++count;
1079 }
1080
1081 XMLTest( "Comments iterate correctly.", 3, count );
1082 }
1083
1084 {
1085 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1086 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1087 buf[60] = 239;
1088 buf[61] = 0;
1089
1090 XMLDocument doc;
1091 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001092 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001093
1094
1095 {
1096 // bug 1827248 Error while parsing a little bit malformed file
1097 // Actually not malformed - should work.
1098 XMLDocument xml;
1099 xml.Parse( "<attributelist> </attributelist >" );
1100 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1101 }
1102
1103 {
1104 // This one must not result in an infinite loop
1105 XMLDocument xml;
1106 xml.Parse( "<infinite>loop" );
1107 XMLTest( "Infinite loop test.", true, true );
1108 }
1109#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001110 {
1111 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1112 XMLDocument doc;
1113 doc.Parse( pub );
1114
1115 XMLDocument clone;
1116 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1117 XMLNode* copy = node->ShallowClone( &clone );
1118 clone.InsertEndChild( copy );
1119 }
1120
1121 clone.Print();
1122
1123 int count=0;
1124 const XMLNode* a=clone.FirstChild();
1125 const XMLNode* b=doc.FirstChild();
1126 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1127 ++count;
1128 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1129 }
1130 XMLTest( "Clone and Equal", 4, count );
1131 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001132
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001133 {
Lee Thomason7085f002017-06-01 18:09:43 -07001134 // Deep Cloning of root element.
1135 XMLDocument doc2;
1136 XMLPrinter printer1;
1137 {
1138 // Make sure doc1 is deleted before we test doc2
1139 const char* xml =
1140 "<root>"
1141 " <child1 foo='bar'/>"
1142 " <!-- comment thing -->"
1143 " <child2 val='1'>Text</child2>"
1144 "</root>";
1145 XMLDocument doc;
1146 doc.Parse(xml);
1147
1148 doc.Print(&printer1);
1149 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1150 doc2.InsertFirstChild(root);
1151 }
1152 XMLPrinter printer2;
1153 doc2.Print(&printer2);
1154
1155 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1156 }
1157
1158 {
1159 // Deep Cloning of sub element.
1160 XMLDocument doc2;
1161 XMLPrinter printer1;
1162 {
1163 // Make sure doc1 is deleted before we test doc2
1164 const char* xml =
1165 "<?xml version ='1.0'?>"
1166 "<root>"
1167 " <child1 foo='bar'/>"
1168 " <!-- comment thing -->"
1169 " <child2 val='1'>Text</child2>"
1170 "</root>";
1171 XMLDocument doc;
1172 doc.Parse(xml);
1173
1174 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1175 subElement->Accept(&printer1);
1176
1177 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1178 doc2.InsertFirstChild(clonedSubElement);
1179 }
1180 XMLPrinter printer2;
1181 doc2.Print(&printer2);
1182
1183 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1184 }
1185
1186 {
1187 // Deep cloning of document.
1188 XMLDocument doc2;
1189 XMLPrinter printer1;
1190 {
1191 // Make sure doc1 is deleted before we test doc2
1192 const char* xml =
1193 "<?xml version ='1.0'?>"
1194 "<!-- Top level comment. -->"
1195 "<root>"
1196 " <child1 foo='bar'/>"
1197 " <!-- comment thing -->"
1198 " <child2 val='1'>Text</child2>"
1199 "</root>";
1200 XMLDocument doc;
1201 doc.Parse(xml);
1202 doc.Print(&printer1);
1203
1204 doc.DeepCopy(&doc2);
1205 }
1206 XMLPrinter printer2;
1207 doc2.Print(&printer2);
1208
1209 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1210 }
1211
1212
1213 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001214 // This shouldn't crash.
1215 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001216 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001217 {
1218 doc.PrintError();
1219 }
1220 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1221 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001222
Lee Thomason5e3803c2012-04-16 08:57:05 -07001223 {
1224 // Attribute ordering.
1225 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1226 XMLDocument doc;
1227 doc.Parse( xml );
1228 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001229
Lee Thomason5e3803c2012-04-16 08:57:05 -07001230 const XMLAttribute* a = ele->FirstAttribute();
1231 XMLTest( "Attribute order", "1", a->Value() );
1232 a = a->Next();
1233 XMLTest( "Attribute order", "2", a->Value() );
1234 a = a->Next();
1235 XMLTest( "Attribute order", "3", a->Value() );
1236 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001237
Lee Thomason5e3803c2012-04-16 08:57:05 -07001238 ele->DeleteAttribute( "attrib2" );
1239 a = ele->FirstAttribute();
1240 XMLTest( "Attribute order", "1", a->Value() );
1241 a = a->Next();
1242 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001243
Lee Thomason5e3803c2012-04-16 08:57:05 -07001244 ele->DeleteAttribute( "attrib1" );
1245 ele->DeleteAttribute( "attrib3" );
1246 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1247 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001248
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001249 {
1250 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001251 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1252 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1253 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1254 XMLDocument doc0;
1255 doc0.Parse( xml0 );
1256 XMLDocument doc1;
1257 doc1.Parse( xml1 );
1258 XMLDocument doc2;
1259 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001260
Lee Thomason78a773d2012-07-02 10:10:19 -07001261 XMLElement* ele = 0;
1262 ele = doc0.FirstChildElement();
1263 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1264 ele = doc1.FirstChildElement();
1265 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1266 ele = doc2.FirstChildElement();
1267 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001268 }
1269
1270 {
1271 // Make sure we don't go into an infinite loop.
1272 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1273 XMLDocument doc;
1274 doc.Parse( xml );
1275 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1276 XMLElement* ele1 = ele0->NextSiblingElement();
1277 bool equal = ele0->ShallowEqual( ele1 );
1278
1279 XMLTest( "Infinite loop in shallow equal.", true, equal );
1280 }
1281
Lee Thomason5708f812012-03-28 17:46:41 -07001282 // -------- Handles ------------
1283 {
1284 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1285 XMLDocument doc;
1286 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -07001287
1288 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1289 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
1290
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001291 XMLHandle docH( doc );
1292 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001293 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001294 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001295
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001296 {
1297 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1298 XMLDocument doc;
1299 doc.Parse( xml );
1300 XMLConstHandle docH( doc );
1301
1302 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1303 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1304
1305 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001306 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001307 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001308 {
1309 // Default Declaration & BOM
1310 XMLDocument doc;
1311 doc.InsertEndChild( doc.NewDeclaration() );
1312 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001313
Lee Thomasonf68c4382012-04-28 14:37:11 -07001314 XMLPrinter printer;
1315 doc.Print( &printer );
1316
1317 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1318 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001319 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001320 }
Lee Thomason21be8822012-07-15 17:27:22 -07001321 {
1322 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1323 XMLDocument doc;
1324 doc.Parse( xml );
1325 XMLTest( "Ill formed XML", true, doc.Error() );
1326 }
1327
1328 // QueryXYZText
1329 {
1330 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1331 XMLDocument doc;
1332 doc.Parse( xml );
1333
1334 const XMLElement* pointElement = doc.RootElement();
1335
1336 int intValue = 0;
1337 unsigned unsignedValue = 0;
1338 float floatValue = 0;
1339 double doubleValue = 0;
1340 bool boolValue = false;
1341
1342 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1343 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1344 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1345 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1346 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1347
1348
1349 XMLTest( "QueryIntText", intValue, 1, false );
1350 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1351 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1352 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1353 XMLTest( "QueryBoolText", boolValue, true, false );
1354 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001355
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001356 {
1357 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1358 XMLDocument doc;
1359 doc.Parse( xml );
1360 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1361 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001362
1363 {
1364 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1365 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001366 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001367 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1368 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001369
1370 {
1371 const char* xml = "<3lement></3lement>";
1372 XMLDocument doc;
1373 doc.Parse( xml );
1374 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1375 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001376
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001377 {
1378 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1379 XMLDocument doc;
1380 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001381 XMLTest( "Set length of incoming data", doc.Error(), false );
1382 }
1383
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001384 {
1385 XMLDocument doc;
Dmitry-Me48b5df02015-04-06 18:20:25 +03001386 XMLTest( "Document is initially empty", doc.NoChildren(), true );
1387 doc.Clear();
1388 XMLTest( "Empty is empty after Clear()", doc.NoChildren(), true );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001389 doc.LoadFile( "resources/dream.xml" );
Dmitry-Meaaa4cea2015-02-06 16:00:46 +03001390 XMLTest( "Document has something to Clear()", doc.NoChildren(), false );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001391 doc.Clear();
1392 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1393 }
1394
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001395 // ----------- Whitespace ------------
1396 {
1397 const char* xml = "<element>"
1398 "<a> This \nis &apos; text &apos; </a>"
1399 "<b> This is &apos; text &apos; \n</b>"
1400 "<c>This is &apos; \n\n text &apos;</c>"
1401 "</element>";
1402 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1403 doc.Parse( xml );
1404
1405 const XMLElement* element = doc.FirstChildElement();
1406 for( const XMLElement* parent = element->FirstChildElement();
1407 parent;
1408 parent = parent->NextSiblingElement() )
1409 {
1410 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1411 }
1412 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001413
Lee Thomasonae9ab072012-10-24 10:17:53 -07001414#if 0
1415 {
1416 // Passes if assert doesn't fire.
1417 XMLDocument xmlDoc;
1418
1419 xmlDoc.NewDeclaration();
1420 xmlDoc.NewComment("Configuration file");
1421
1422 XMLElement *root = xmlDoc.NewElement("settings");
1423 root->SetAttribute("version", 2);
1424 }
1425#endif
1426
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001427 {
1428 const char* xml = "<element> </element>";
1429 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1430 doc.Parse( xml );
1431 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1432 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001433
Lee Thomason5b0a6772012-11-19 13:54:42 -08001434 {
1435 // An assert should not fire.
1436 const char* xml = "<element/>";
1437 XMLDocument doc;
1438 doc.Parse( xml );
1439 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1440 XMLTest( "Tracking unused elements", true, ele != 0, false );
1441 }
1442
Lee Thomasona6412ac2012-12-13 15:39:11 -08001443
1444 {
1445 const char* xml = "<parent><child>abc</child></parent>";
1446 XMLDocument doc;
1447 doc.Parse( xml );
1448 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1449
1450 XMLPrinter printer;
1451 ele->Accept( &printer );
1452 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1453 }
1454
1455
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001456 {
1457 XMLDocument doc;
1458 XMLError error = doc.LoadFile( "resources/empty.xml" );
1459 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001460 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001461 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001462 }
1463
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001464 {
1465 // BOM preservation
1466 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1467 {
1468 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001469 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001470 XMLPrinter printer;
1471 doc.Print( &printer );
1472
1473 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1474 doc.SaveFile( "resources/bomtest.xml" );
1475 }
1476 {
1477 XMLDocument doc;
1478 doc.LoadFile( "resources/bomtest.xml" );
1479 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1480
1481 XMLPrinter printer;
1482 doc.Print( &printer );
1483 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1484 }
1485 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001486
Michael Daumlinged523282013-10-23 07:47:29 +02001487 {
1488 // Insertion with Removal
1489 const char* xml = "<?xml version=\"1.0\" ?>"
1490 "<root>"
1491 "<one>"
1492 "<subtree>"
1493 "<elem>element 1</elem>text<!-- comment -->"
1494 "</subtree>"
1495 "</one>"
1496 "<two/>"
1497 "</root>";
1498 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1499 "<root>"
1500 "<one/>"
1501 "<two>"
1502 "<subtree>"
1503 "<elem>element 1</elem>text<!-- comment -->"
1504 "</subtree>"
1505 "</two>"
1506 "</root>";
1507 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1508 "<root>"
1509 "<one/>"
1510 "<subtree>"
1511 "<elem>element 1</elem>text<!-- comment -->"
1512 "</subtree>"
1513 "<two/>"
1514 "</root>";
1515 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1516 "<root>"
1517 "<one/>"
1518 "<two/>"
1519 "<subtree>"
1520 "<elem>element 1</elem>text<!-- comment -->"
1521 "</subtree>"
1522 "</root>";
1523
1524 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001525 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001526 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1527 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1528 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001529 XMLPrinter printer1(0, true);
1530 doc.Accept(&printer1);
1531 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001532
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001533 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001534 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1535 two = doc.RootElement()->FirstChildElement("two");
1536 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001537 XMLPrinter printer2(0, true);
1538 doc.Accept(&printer2);
1539 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001540
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001541 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001542 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1543 subtree = one->FirstChildElement("subtree");
1544 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001545 XMLPrinter printer3(0, true);
1546 doc.Accept(&printer3);
1547 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001548
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001549 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001550 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1551 two = doc.RootElement()->FirstChildElement("two");
1552 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001553 XMLPrinter printer4(0, true);
1554 doc.Accept(&printer4);
1555 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001556 }
1557
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001558 {
1559 const char* xml = "<svg width = \"128\" height = \"128\">"
1560 " <text> </text>"
1561 "</svg>";
1562 XMLDocument doc;
1563 doc.Parse(xml);
1564 doc.Print();
1565 }
1566
Lee Thomason92e521b2014-11-15 17:45:51 -08001567 {
1568 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001569 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1570 XMLDocument doc;
1571 doc.Parse(xml);
1572 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001573 }
1574
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001575#if 1
1576 // the question being explored is what kind of print to use:
1577 // https://github.com/leethomason/tinyxml2/issues/63
1578 {
1579 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1580 const char* xml = "<element/>";
1581 XMLDocument doc;
1582 doc.Parse( xml );
1583 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1584 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1585 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1586 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1587 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1588 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1589
1590 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1591 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1592 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1593 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1594 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1595 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1596
1597 doc.Print();
1598
1599 /* The result of this test is platform, compiler, and library version dependent. :("
1600 XMLPrinter printer;
1601 doc.Print( &printer );
1602 XMLTest( "Float and double formatting.",
1603 "<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",
1604 printer.CStr(),
1605 true );
1606 */
1607 }
1608#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001609
1610 {
1611 // Issue #184
1612 // If it doesn't assert, it passes. Caused by objects
1613 // getting created during parsing which are then
1614 // inaccessible in the memory pools.
1615 {
1616 XMLDocument doc;
1617 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1618 }
1619 {
1620 XMLDocument doc;
1621 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1622 doc.Clear();
1623 }
1624 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001625
1626 {
1627 // If this doesn't assert in DEBUG, all is well.
1628 tinyxml2::XMLDocument doc;
1629 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1630 doc.DeleteNode(pRoot);
1631 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001632
Dmitry-Me8b67d742014-12-22 11:35:12 +03001633 {
1634 // Should not assert in DEBUG
1635 XMLPrinter printer;
1636 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001637
Dmitry-Me6f51c802015-03-14 13:25:03 +03001638 {
1639 // Issue 291. Should not crash
1640 const char* xml = "&#0</a>";
1641 XMLDocument doc;
1642 doc.Parse( xml );
1643
1644 XMLPrinter printer;
1645 doc.Print( &printer );
1646 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001647 {
1648 // Issue 299. Can print elements that are not linked in.
1649 // Will crash if issue not fixed.
1650 XMLDocument doc;
1651 XMLElement* newElement = doc.NewElement( "printme" );
1652 XMLPrinter printer;
1653 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001654 // Delete the node to avoid possible memory leak report in debug output
1655 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001656 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001657 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001658 // Issue 302. Clear errors from LoadFile/SaveFile
1659 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001660 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001661 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001662 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001663 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001664 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001665 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001666
Dmitry-Med9852a52015-03-25 10:17:49 +03001667 {
1668 // If a document fails to load then subsequent
1669 // successful loads should clear the error
1670 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001671 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001672 doc.LoadFile( "resources/no-such-file.xml" );
1673 XMLTest( "No such file - should fail", true, doc.Error() );
1674
1675 doc.LoadFile( "resources/dream.xml" );
1676 XMLTest( "Error should be cleared", false, doc.Error() );
1677 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301678
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301679 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001680 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001681 const char* xml0 = "<?xml version=\"1.0\" ?>"
1682 " <!-- xml version=\"1.1\" -->"
1683 "<first />";
1684 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001685 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001686 "<first />";
1687 const char* xml2 = "<first />"
1688 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001689 const char* xml3 = "<first></first>"
1690 "<?xml version=\"1.0\" ?>";
1691
1692 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1693
Lee Thomason85492022015-05-22 11:07:45 -07001694 XMLDocument doc;
1695 doc.Parse(xml0);
1696 XMLTest("Test that the code changes do not affect normal parsing", doc.Error(), false);
1697 doc.Parse(xml1);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001698 XMLTest("Test that the second declaration is allowed", doc.Error(), false);
Lee Thomason85492022015-05-22 11:07:45 -07001699 doc.Parse(xml2);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001700 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1701 doc.Parse(xml3);
1702 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1703 doc.Parse(xml4);
1704 XMLTest("Test that declaration inside a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301705 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001706
Lee Thomason85492022015-05-22 11:07:45 -07001707 {
1708 // No matter - before or after successfully parsing a text -
1709 // calling XMLDocument::Value() causes an assert in debug.
1710 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1711 "<first />"
1712 "<second />";
1713 XMLDocument* doc = new XMLDocument();
1714 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1715 doc->Parse( validXml );
1716 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1717 delete doc;
1718 }
1719
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001720 {
1721 XMLDocument doc;
1722 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001723 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001724 doc.ErrorName();
1725 }
1726 }
1727
kezenatorec694152016-11-26 17:21:43 +10001728 // ----------- Line Number Tracking --------------
1729 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001730 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001731 {
1732 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1733 {
1734 XMLDocument doc;
1735 XMLError err = doc.Parse(docStr);
1736
1737 XMLTest(testString, true, doc.Error());
1738 XMLTest(testString, expected_error, err);
1739 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1740 };
1741
1742 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1743 {
1744 XMLDocument doc;
1745 doc.Parse(docStr);
1746 XMLTest(testString, false, doc.Error());
1747 TestDocLines(testString, doc, expectedLines);
1748 }
1749
1750 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1751 {
1752 XMLDocument doc;
1753 doc.LoadFile(file_name);
1754 XMLTest(testString, false, doc.Error());
1755 TestDocLines(testString, doc, expectedLines);
1756 }
1757
1758 private:
1759 DynArray<char, 10> str;
1760
1761 void Push(char type, int lineNum)
1762 {
1763 str.Push(type);
1764 str.Push(char('0' + (lineNum / 10)));
1765 str.Push(char('0' + (lineNum % 10)));
1766 }
1767
1768 bool VisitEnter(const XMLDocument& doc)
1769 {
kezenator19d8ea82016-11-29 19:50:27 +10001770 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001771 return true;
1772 }
1773 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
1774 {
kezenator19d8ea82016-11-29 19:50:27 +10001775 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001776 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10001777 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001778 return true;
1779 }
1780 bool Visit(const XMLDeclaration& declaration)
1781 {
kezenator19d8ea82016-11-29 19:50:27 +10001782 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001783 return true;
1784 }
1785 bool Visit(const XMLText& text)
1786 {
kezenator19d8ea82016-11-29 19:50:27 +10001787 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001788 return true;
1789 }
1790 bool Visit(const XMLComment& comment)
1791 {
kezenator19d8ea82016-11-29 19:50:27 +10001792 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001793 return true;
1794 }
1795 bool Visit(const XMLUnknown& unknown)
1796 {
kezenator19d8ea82016-11-29 19:50:27 +10001797 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001798 return true;
1799 }
1800
1801 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
1802 {
1803 str.Clear();
1804 doc.Accept(this);
1805 str.Push(0);
1806 XMLTest(testString, expectedLines, str.Mem());
1807 }
Lee Thomasone90e9012016-12-24 07:34:39 -08001808 } tester;
kezenatorec694152016-11-26 17:21:43 +10001809
Lee Thomasone90e9012016-12-24 07:34:39 -08001810 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
1811 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
1812 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
1813 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
1814 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
1815 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
1816 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
1817 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
1818 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
1819 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
1820 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10001821
Lee Thomasone90e9012016-12-24 07:34:39 -08001822 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001823 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08001824
1825 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
1826 "<root a='b' \n" // 2 Element Attribute
1827 "c='d'> d <blah/> \n" // 3 Attribute Text Element
1828 "newline in text \n" // 4 Text
1829 "and second <zxcv/><![CDATA[\n" // 5 Element Text
1830 " cdata test ]]><!-- comment -->\n" // 6 Comment
1831 "<! unknown></root>", // 7 Unknown
1832
kezenatorec694152016-11-26 17:21:43 +10001833 "D01L01E02A02A03T03E03T04E05T05C06U07");
1834
Lee Thomasone90e9012016-12-24 07:34:39 -08001835 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001836 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08001837
1838 "\r\n" // 1 Doc (arguably should be line 2)
1839 "<?xml version=\"1.0\"?>\n" // 2 DecL
1840 "<root>\r\n" // 3 Element
1841 "\n" // 4
1842 "text contining new line \n" // 5 Text
1843 " and also containing crlf \r\n" // 6
1844 "<sub><![CDATA[\n" // 7 Element Text
1845 "cdata containing new line \n" // 8
1846 " and also containing cflr\r\n" // 9
1847 "]]></sub><sub2/></root>", // 10 Element
1848
kezenatorec694152016-11-26 17:21:43 +10001849 "D01L02E03T05E07T07E10");
1850
Lee Thomasone90e9012016-12-24 07:34:39 -08001851 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10001852 "LineNumbers-File",
1853 "resources/utf8test.xml",
1854 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
1855 }
1856
Lee Thomason85492022015-05-22 11:07:45 -07001857 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08001858 {
1859#if defined( _MSC_VER )
1860 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001861 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08001862#endif
1863
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001864 FILE* perfFP = fopen("resources/dream.xml", "r");
1865 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02001866 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001867 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08001868
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001869 char* mem = new char[size + 1];
1870 fread(mem, size, 1, perfFP);
1871 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08001872 mem[size] = 0;
1873
1874#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001875 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08001876#else
1877 clock_t cstart = clock();
1878#endif
1879 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001880 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001881 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001882 doc.Parse(mem);
Lee Thomason6f381b72012-03-02 12:59:39 -08001883 }
1884#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001885 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08001886#else
1887 clock_t cend = clock();
1888#endif
1889
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001890 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08001891
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001892 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001893#ifdef DEBUG
1894 "DEBUG";
1895#else
1896 "Release";
1897#endif
1898
1899#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001900 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT));
Lee Thomason6f381b72012-03-02 12:59:39 -08001901#else
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001902 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08001903#endif
1904 }
1905
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001906 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001907 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001908
1909 _CrtMemState diffMemState;
1910 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1911 _CrtMemDumpStatistics( &diffMemState );
1912 #endif
1913
1914 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07001915
1916 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001917}