blob: 7c11389d8b751e17f47d0e160b5b57cc0dcfcbe2 [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 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800756 element->SetAttribute("attrib", true);
757 const char* result = element->Attribute("attrib");
758 XMLTest("Bool true is 'true'", "true", result);
759
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800760 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800761 element->SetAttribute("attrib", true);
762 result = element->Attribute("attrib");
763 XMLTest("Bool true is '1'", "1", result);
764
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800765 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800766 }
767 {
Lee Thomason51c12712016-06-04 20:18:49 -0700768 element->SetAttribute("attrib", 100.0);
769 double v = 0;
770 element->QueryDoubleAttribute("attrib", &v);
771 XMLTest("Attribute: double", 100.0, v, true);
772 element->QueryAttribute("attrib", &v);
773 XMLTest("Attribute: double", 100.0, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700774 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700775 }
776 {
777 element->SetAttribute("attrib", 100.0f);
778 float v = 0;
779 element->QueryFloatAttribute("attrib", &v);
780 XMLTest("Attribute: float", 100.0f, v, true);
781 element->QueryAttribute("attrib", &v);
782 XMLTest("Attribute: float", 100.0f, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700783 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700784 }
785 {
786 element->SetText(BIG);
787 int64_t v = 0;
788 element->QueryInt64Text(&v);
789 XMLTest("Element: int64_t", BIG, v, true);
790 }
791 }
792
793 // ---------- XMLPrinter stream mode ------
794 {
795 {
796 FILE* printerfp = fopen("resources/printer.xml", "w");
797 XMLPrinter printer(printerfp);
798 printer.OpenElement("foo");
799 printer.PushAttribute("attrib-text", "text");
800 printer.PushAttribute("attrib-int", int(1));
801 printer.PushAttribute("attrib-unsigned", unsigned(2));
802 printer.PushAttribute("attrib-int64", int64_t(3));
803 printer.PushAttribute("attrib-bool", true);
804 printer.PushAttribute("attrib-double", 4.0);
805 printer.CloseElement();
806 fclose(printerfp);
807 }
808 {
809 XMLDocument doc;
810 doc.LoadFile("resources/printer.xml");
811 XMLTest("XMLPrinter Stream mode: load", doc.ErrorID(), XML_SUCCESS, true);
812
813 const XMLDocument& cdoc = doc;
814
815 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
816 XMLTest("attrib-text", "text", attrib->Value(), true);
817 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
818 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
819 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
820 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
821 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
822 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
823 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
824 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
825 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
826 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
827 }
828
829 }
830
Uli Kusterer321072e2014-01-21 01:57:38 +0100831
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800832 // ---------- CDATA ---------------
833 {
834 const char* str = "<xmlElement>"
835 "<![CDATA["
836 "I am > the rules!\n"
837 "...since I make symbolic puns"
838 "]]>"
839 "</xmlElement>";
840 XMLDocument doc;
841 doc.Parse( str );
842 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800843
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700844 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800845 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800846 false );
847 }
848
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800849 // ----------- CDATA -------------
850 {
851 const char* str = "<xmlElement>"
852 "<![CDATA["
853 "<b>I am > the rules!</b>\n"
854 "...since I make symbolic puns"
855 "]]>"
856 "</xmlElement>";
857 XMLDocument doc;
858 doc.Parse( str );
859 doc.Print();
860
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700861 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800862 "<b>I am > the rules!</b>\n...since I make symbolic puns",
863 false );
864 }
865
866 // InsertAfterChild causes crash.
867 {
868 // InsertBeforeChild and InsertAfterChild causes crash.
869 XMLDocument doc;
870 XMLElement* parent = doc.NewElement( "Parent" );
871 doc.InsertFirstChild( parent );
872
873 XMLElement* childText0 = doc.NewElement( "childText0" );
874 XMLElement* childText1 = doc.NewElement( "childText1" );
875
876 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
877 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
878
879 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
880 }
Lee Thomasond6277762012-02-22 16:00:12 -0800881
882 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800883 // Entities not being written correctly.
884 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800885
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800886 const char* passages =
887 "<?xml version=\"1.0\" standalone=\"no\" ?>"
888 "<passages count=\"006\" formatversion=\"20020620\">"
889 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
890 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
891 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800892
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800893 XMLDocument doc;
894 doc.Parse( passages );
895 XMLElement* psg = doc.RootElement()->FirstChildElement();
896 const char* context = psg->Attribute( "context" );
897 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 -0800898
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800899 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800900
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400901 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800902 if ( textfile )
903 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800904 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800905 psg->Accept( &streamer );
906 fclose( textfile );
907 }
Thomas Roß0922b732012-09-23 16:31:22 +0200908
909 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800910 TIXMLASSERT( textfile );
911 if ( textfile )
912 {
913 char buf[ 1024 ];
914 fgets( buf, 1024, textfile );
915 XMLTest( "Entity transformation: write. ",
916 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
917 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
918 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700919 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800920 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800921 }
922
923 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800924 // Suppress entities.
925 const char* passages =
926 "<?xml version=\"1.0\" standalone=\"no\" ?>"
927 "<passages count=\"006\" formatversion=\"20020620\">"
928 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
929 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700930
Lee Thomason6f381b72012-03-02 12:59:39 -0800931 XMLDocument doc( false );
932 doc.Parse( passages );
933
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700934 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800935 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
936 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
937 "Crazy &ttk;" );
938 doc.Print();
939 }
940
941 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400942 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800943
944 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400945 doc.Parse( test );
946 XMLTest( "dot in names", doc.Error(), false );
947 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
948 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800949 }
950
951 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400952 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800953
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400954 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800955 doc.Parse( test );
956
957 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
958 XMLTest( "Entity with one digit.",
959 text->Value(), "1.1 Start easy ignore fin thickness\n",
960 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400961 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800962
963 {
964 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700965 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800966 const char* doctype =
967 "<?xml version=\"1.0\" ?>"
968 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
969 "<!ELEMENT title (#PCDATA)>"
970 "<!ELEMENT books (title,authors)>"
971 "<element />";
972
973 XMLDocument doc;
974 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400975 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400977 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800978 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700979
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800980 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
981 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
982
983 }
984
985 {
986 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700987 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800988 "<!-- Somewhat<evil> -->";
989 XMLDocument doc;
990 doc.Parse( doctype );
991
992 XMLComment* comment = doc.FirstChild()->ToComment();
993
994 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
995 }
996 {
997 // Double attributes
998 const char* doctype = "<element attr='red' attr='blue' />";
999
1000 XMLDocument doc;
1001 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001002
Lee Thomason2fa81722012-11-09 12:37:46 -08001003 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 -08001004 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001005 }
1006
1007 {
1008 // Embedded null in stream.
1009 const char* doctype = "<element att\0r='red' attr='blue' />";
1010
1011 XMLDocument doc;
1012 doc.Parse( doctype );
1013 XMLTest( "Embedded null throws error.", true, doc.Error() );
1014 }
1015
1016 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001017 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001018 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001019 XMLDocument doc;
1020 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001021 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001022 }
1023
1024 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001025 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1026 const char* str = " ";
1027 XMLDocument doc;
1028 doc.Parse( str );
1029 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1030 }
1031
1032 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001033 // Low entities
1034 XMLDocument doc;
1035 doc.Parse( "<test>&#x0e;</test>" );
1036 const char result[] = { 0x0e, 0 };
1037 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
1038 doc.Print();
1039 }
1040
1041 {
1042 // Attribute values with trailing quotes not handled correctly
1043 XMLDocument doc;
1044 doc.Parse( "<foo attribute=bar\" />" );
1045 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
1046 }
1047
1048 {
1049 // [ 1663758 ] Failure to report error on bad XML
1050 XMLDocument xml;
1051 xml.Parse("<x>");
1052 XMLTest("Missing end tag at end of input", xml.Error(), true);
1053 xml.Parse("<x> ");
1054 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
1055 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -08001056 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001057 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001058
1059
1060 {
1061 // [ 1475201 ] TinyXML parses entities in comments
1062 XMLDocument xml;
1063 xml.Parse("<!-- declarations for <head> & <body> -->"
1064 "<!-- far &amp; away -->" );
1065
1066 XMLNode* e0 = xml.FirstChild();
1067 XMLNode* e1 = e0->NextSibling();
1068 XMLComment* c0 = e0->ToComment();
1069 XMLComment* c1 = e1->ToComment();
1070
1071 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1072 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1073 }
1074
1075 {
1076 XMLDocument xml;
1077 xml.Parse( "<Parent>"
1078 "<child1 att=''/>"
1079 "<!-- With this comment, child2 will not be parsed! -->"
1080 "<child2 att=''/>"
1081 "</Parent>" );
1082 xml.Print();
1083
1084 int count = 0;
1085
1086 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1087 ele;
1088 ele = ele->NextSibling() )
1089 {
1090 ++count;
1091 }
1092
1093 XMLTest( "Comments iterate correctly.", 3, count );
1094 }
1095
1096 {
1097 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1098 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1099 buf[60] = 239;
1100 buf[61] = 0;
1101
1102 XMLDocument doc;
1103 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001104 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001105
1106
1107 {
1108 // bug 1827248 Error while parsing a little bit malformed file
1109 // Actually not malformed - should work.
1110 XMLDocument xml;
1111 xml.Parse( "<attributelist> </attributelist >" );
1112 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1113 }
1114
1115 {
1116 // This one must not result in an infinite loop
1117 XMLDocument xml;
1118 xml.Parse( "<infinite>loop" );
1119 XMLTest( "Infinite loop test.", true, true );
1120 }
1121#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001122 {
1123 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1124 XMLDocument doc;
1125 doc.Parse( pub );
1126
1127 XMLDocument clone;
1128 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1129 XMLNode* copy = node->ShallowClone( &clone );
1130 clone.InsertEndChild( copy );
1131 }
1132
1133 clone.Print();
1134
1135 int count=0;
1136 const XMLNode* a=clone.FirstChild();
1137 const XMLNode* b=doc.FirstChild();
1138 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1139 ++count;
1140 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1141 }
1142 XMLTest( "Clone and Equal", 4, count );
1143 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001144
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001145 {
1146 // This shouldn't crash.
1147 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001148 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001149 {
1150 doc.PrintError();
1151 }
1152 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1153 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001154
Lee Thomason5e3803c2012-04-16 08:57:05 -07001155 {
1156 // Attribute ordering.
1157 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1158 XMLDocument doc;
1159 doc.Parse( xml );
1160 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001161
Lee Thomason5e3803c2012-04-16 08:57:05 -07001162 const XMLAttribute* a = ele->FirstAttribute();
1163 XMLTest( "Attribute order", "1", a->Value() );
1164 a = a->Next();
1165 XMLTest( "Attribute order", "2", a->Value() );
1166 a = a->Next();
1167 XMLTest( "Attribute order", "3", a->Value() );
1168 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001169
Lee Thomason5e3803c2012-04-16 08:57:05 -07001170 ele->DeleteAttribute( "attrib2" );
1171 a = ele->FirstAttribute();
1172 XMLTest( "Attribute order", "1", a->Value() );
1173 a = a->Next();
1174 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001175
Lee Thomason5e3803c2012-04-16 08:57:05 -07001176 ele->DeleteAttribute( "attrib1" );
1177 ele->DeleteAttribute( "attrib3" );
1178 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1179 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001180
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001181 {
1182 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001183 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1184 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1185 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1186 XMLDocument doc0;
1187 doc0.Parse( xml0 );
1188 XMLDocument doc1;
1189 doc1.Parse( xml1 );
1190 XMLDocument doc2;
1191 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001192
Lee Thomason78a773d2012-07-02 10:10:19 -07001193 XMLElement* ele = 0;
1194 ele = doc0.FirstChildElement();
1195 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1196 ele = doc1.FirstChildElement();
1197 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1198 ele = doc2.FirstChildElement();
1199 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001200 }
1201
1202 {
1203 // Make sure we don't go into an infinite loop.
1204 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1205 XMLDocument doc;
1206 doc.Parse( xml );
1207 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1208 XMLElement* ele1 = ele0->NextSiblingElement();
1209 bool equal = ele0->ShallowEqual( ele1 );
1210
1211 XMLTest( "Infinite loop in shallow equal.", true, equal );
1212 }
1213
Lee Thomason5708f812012-03-28 17:46:41 -07001214 // -------- Handles ------------
1215 {
1216 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1217 XMLDocument doc;
1218 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -07001219
1220 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1221 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
1222
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001223 XMLHandle docH( doc );
1224 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001225 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001226 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001227
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001228 {
1229 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1230 XMLDocument doc;
1231 doc.Parse( xml );
1232 XMLConstHandle docH( doc );
1233
1234 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1235 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1236
1237 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001238 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001239 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001240 {
1241 // Default Declaration & BOM
1242 XMLDocument doc;
1243 doc.InsertEndChild( doc.NewDeclaration() );
1244 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001245
Lee Thomasonf68c4382012-04-28 14:37:11 -07001246 XMLPrinter printer;
1247 doc.Print( &printer );
1248
1249 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1250 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001251 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001252 }
Lee Thomason21be8822012-07-15 17:27:22 -07001253 {
1254 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1255 XMLDocument doc;
1256 doc.Parse( xml );
1257 XMLTest( "Ill formed XML", true, doc.Error() );
1258 }
1259
1260 // QueryXYZText
1261 {
1262 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1263 XMLDocument doc;
1264 doc.Parse( xml );
1265
1266 const XMLElement* pointElement = doc.RootElement();
1267
1268 int intValue = 0;
1269 unsigned unsignedValue = 0;
1270 float floatValue = 0;
1271 double doubleValue = 0;
1272 bool boolValue = false;
1273
1274 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1275 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1276 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1277 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1278 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1279
1280
1281 XMLTest( "QueryIntText", intValue, 1, false );
1282 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1283 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1284 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1285 XMLTest( "QueryBoolText", boolValue, true, false );
1286 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001287
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001288 {
1289 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1290 XMLDocument doc;
1291 doc.Parse( xml );
1292 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1293 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001294
1295 {
1296 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1297 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001298 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001299 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1300 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001301
1302 {
1303 const char* xml = "<3lement></3lement>";
1304 XMLDocument doc;
1305 doc.Parse( xml );
1306 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1307 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001308
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001309 {
1310 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1311 XMLDocument doc;
1312 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001313 XMLTest( "Set length of incoming data", doc.Error(), false );
1314 }
1315
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001316 {
1317 XMLDocument doc;
Dmitry-Me48b5df02015-04-06 18:20:25 +03001318 XMLTest( "Document is initially empty", doc.NoChildren(), true );
1319 doc.Clear();
1320 XMLTest( "Empty is empty after Clear()", doc.NoChildren(), true );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001321 doc.LoadFile( "resources/dream.xml" );
Dmitry-Meaaa4cea2015-02-06 16:00:46 +03001322 XMLTest( "Document has something to Clear()", doc.NoChildren(), false );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001323 doc.Clear();
1324 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1325 }
1326
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001327 // ----------- Whitespace ------------
1328 {
1329 const char* xml = "<element>"
1330 "<a> This \nis &apos; text &apos; </a>"
1331 "<b> This is &apos; text &apos; \n</b>"
1332 "<c>This is &apos; \n\n text &apos;</c>"
1333 "</element>";
1334 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1335 doc.Parse( xml );
1336
1337 const XMLElement* element = doc.FirstChildElement();
1338 for( const XMLElement* parent = element->FirstChildElement();
1339 parent;
1340 parent = parent->NextSiblingElement() )
1341 {
1342 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1343 }
1344 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001345
Lee Thomasonae9ab072012-10-24 10:17:53 -07001346#if 0
1347 {
1348 // Passes if assert doesn't fire.
1349 XMLDocument xmlDoc;
1350
1351 xmlDoc.NewDeclaration();
1352 xmlDoc.NewComment("Configuration file");
1353
1354 XMLElement *root = xmlDoc.NewElement("settings");
1355 root->SetAttribute("version", 2);
1356 }
1357#endif
1358
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001359 {
1360 const char* xml = "<element> </element>";
1361 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1362 doc.Parse( xml );
1363 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1364 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001365
Lee Thomason5b0a6772012-11-19 13:54:42 -08001366 {
1367 // An assert should not fire.
1368 const char* xml = "<element/>";
1369 XMLDocument doc;
1370 doc.Parse( xml );
1371 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1372 XMLTest( "Tracking unused elements", true, ele != 0, false );
1373 }
1374
Lee Thomasona6412ac2012-12-13 15:39:11 -08001375
1376 {
1377 const char* xml = "<parent><child>abc</child></parent>";
1378 XMLDocument doc;
1379 doc.Parse( xml );
1380 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1381
1382 XMLPrinter printer;
1383 ele->Accept( &printer );
1384 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1385 }
1386
1387
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001388 {
1389 XMLDocument doc;
1390 XMLError error = doc.LoadFile( "resources/empty.xml" );
1391 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001392 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001393 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001394 }
1395
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001396 {
1397 // BOM preservation
1398 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1399 {
1400 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001401 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001402 XMLPrinter printer;
1403 doc.Print( &printer );
1404
1405 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1406 doc.SaveFile( "resources/bomtest.xml" );
1407 }
1408 {
1409 XMLDocument doc;
1410 doc.LoadFile( "resources/bomtest.xml" );
1411 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1412
1413 XMLPrinter printer;
1414 doc.Print( &printer );
1415 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1416 }
1417 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001418
Michael Daumlinged523282013-10-23 07:47:29 +02001419 {
1420 // Insertion with Removal
1421 const char* xml = "<?xml version=\"1.0\" ?>"
1422 "<root>"
1423 "<one>"
1424 "<subtree>"
1425 "<elem>element 1</elem>text<!-- comment -->"
1426 "</subtree>"
1427 "</one>"
1428 "<two/>"
1429 "</root>";
1430 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1431 "<root>"
1432 "<one/>"
1433 "<two>"
1434 "<subtree>"
1435 "<elem>element 1</elem>text<!-- comment -->"
1436 "</subtree>"
1437 "</two>"
1438 "</root>";
1439 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1440 "<root>"
1441 "<one/>"
1442 "<subtree>"
1443 "<elem>element 1</elem>text<!-- comment -->"
1444 "</subtree>"
1445 "<two/>"
1446 "</root>";
1447 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1448 "<root>"
1449 "<one/>"
1450 "<two/>"
1451 "<subtree>"
1452 "<elem>element 1</elem>text<!-- comment -->"
1453 "</subtree>"
1454 "</root>";
1455
1456 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001457 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001458 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1459 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1460 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001461 XMLPrinter printer1(0, true);
1462 doc.Accept(&printer1);
1463 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001464
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001465 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001466 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1467 two = doc.RootElement()->FirstChildElement("two");
1468 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001469 XMLPrinter printer2(0, true);
1470 doc.Accept(&printer2);
1471 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001472
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001473 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001474 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1475 subtree = one->FirstChildElement("subtree");
1476 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001477 XMLPrinter printer3(0, true);
1478 doc.Accept(&printer3);
1479 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001480
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001481 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001482 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1483 two = doc.RootElement()->FirstChildElement("two");
1484 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001485 XMLPrinter printer4(0, true);
1486 doc.Accept(&printer4);
1487 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001488 }
1489
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001490 {
1491 const char* xml = "<svg width = \"128\" height = \"128\">"
1492 " <text> </text>"
1493 "</svg>";
1494 XMLDocument doc;
1495 doc.Parse(xml);
1496 doc.Print();
1497 }
1498
Lee Thomason92e521b2014-11-15 17:45:51 -08001499 {
1500 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001501 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1502 XMLDocument doc;
1503 doc.Parse(xml);
1504 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001505 }
1506
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001507#if 1
1508 // the question being explored is what kind of print to use:
1509 // https://github.com/leethomason/tinyxml2/issues/63
1510 {
1511 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1512 const char* xml = "<element/>";
1513 XMLDocument doc;
1514 doc.Parse( xml );
1515 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1516 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1517 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1518 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1519 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1520 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1521
1522 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1523 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1524 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1525 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1526 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1527 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1528
1529 doc.Print();
1530
1531 /* The result of this test is platform, compiler, and library version dependent. :("
1532 XMLPrinter printer;
1533 doc.Print( &printer );
1534 XMLTest( "Float and double formatting.",
1535 "<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",
1536 printer.CStr(),
1537 true );
1538 */
1539 }
1540#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001541
1542 {
1543 // Issue #184
1544 // If it doesn't assert, it passes. Caused by objects
1545 // getting created during parsing which are then
1546 // inaccessible in the memory pools.
1547 {
1548 XMLDocument doc;
1549 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1550 }
1551 {
1552 XMLDocument doc;
1553 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1554 doc.Clear();
1555 }
1556 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001557
1558 {
1559 // If this doesn't assert in DEBUG, all is well.
1560 tinyxml2::XMLDocument doc;
1561 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1562 doc.DeleteNode(pRoot);
1563 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001564
Dmitry-Me8b67d742014-12-22 11:35:12 +03001565 {
1566 // Should not assert in DEBUG
1567 XMLPrinter printer;
1568 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001569
Dmitry-Me6f51c802015-03-14 13:25:03 +03001570 {
1571 // Issue 291. Should not crash
1572 const char* xml = "&#0</a>";
1573 XMLDocument doc;
1574 doc.Parse( xml );
1575
1576 XMLPrinter printer;
1577 doc.Print( &printer );
1578 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001579 {
1580 // Issue 299. Can print elements that are not linked in.
1581 // Will crash if issue not fixed.
1582 XMLDocument doc;
1583 XMLElement* newElement = doc.NewElement( "printme" );
1584 XMLPrinter printer;
1585 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001586 // Delete the node to avoid possible memory leak report in debug output
1587 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001588 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001589 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001590 // Issue 302. Clear errors from LoadFile/SaveFile
1591 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001592 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001593 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001594 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001595 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001596 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001597 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001598
Dmitry-Med9852a52015-03-25 10:17:49 +03001599 {
1600 // If a document fails to load then subsequent
1601 // successful loads should clear the error
1602 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001603 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001604 doc.LoadFile( "resources/no-such-file.xml" );
1605 XMLTest( "No such file - should fail", true, doc.Error() );
1606
1607 doc.LoadFile( "resources/dream.xml" );
1608 XMLTest( "Error should be cleared", false, doc.Error() );
1609 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301610
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301611 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001612 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001613 const char* xml0 = "<?xml version=\"1.0\" ?>"
1614 " <!-- xml version=\"1.1\" -->"
1615 "<first />";
1616 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001617 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001618 "<first />";
1619 const char* xml2 = "<first />"
1620 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001621 const char* xml3 = "<first></first>"
1622 "<?xml version=\"1.0\" ?>";
1623
1624 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1625
Lee Thomason85492022015-05-22 11:07:45 -07001626 XMLDocument doc;
1627 doc.Parse(xml0);
1628 XMLTest("Test that the code changes do not affect normal parsing", doc.Error(), false);
1629 doc.Parse(xml1);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001630 XMLTest("Test that the second declaration is allowed", doc.Error(), false);
Lee Thomason85492022015-05-22 11:07:45 -07001631 doc.Parse(xml2);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001632 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1633 doc.Parse(xml3);
1634 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1635 doc.Parse(xml4);
1636 XMLTest("Test that declaration inside a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301637 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001638
Lee Thomason85492022015-05-22 11:07:45 -07001639 {
1640 // No matter - before or after successfully parsing a text -
1641 // calling XMLDocument::Value() causes an assert in debug.
1642 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1643 "<first />"
1644 "<second />";
1645 XMLDocument* doc = new XMLDocument();
1646 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1647 doc->Parse( validXml );
1648 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1649 delete doc;
1650 }
1651
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001652 {
1653 XMLDocument doc;
1654 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001655 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001656 doc.ErrorName();
1657 }
1658 }
1659
kezenatorec694152016-11-26 17:21:43 +10001660 // ----------- Line Number Tracking --------------
1661 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001662 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001663 {
1664 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1665 {
1666 XMLDocument doc;
1667 XMLError err = doc.Parse(docStr);
1668
1669 XMLTest(testString, true, doc.Error());
1670 XMLTest(testString, expected_error, err);
1671 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1672 };
1673
1674 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1675 {
1676 XMLDocument doc;
1677 doc.Parse(docStr);
1678 XMLTest(testString, false, doc.Error());
1679 TestDocLines(testString, doc, expectedLines);
1680 }
1681
1682 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1683 {
1684 XMLDocument doc;
1685 doc.LoadFile(file_name);
1686 XMLTest(testString, false, doc.Error());
1687 TestDocLines(testString, doc, expectedLines);
1688 }
1689
1690 private:
1691 DynArray<char, 10> str;
1692
1693 void Push(char type, int lineNum)
1694 {
1695 str.Push(type);
1696 str.Push(char('0' + (lineNum / 10)));
1697 str.Push(char('0' + (lineNum % 10)));
1698 }
1699
1700 bool VisitEnter(const XMLDocument& doc)
1701 {
kezenator19d8ea82016-11-29 19:50:27 +10001702 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001703 return true;
1704 }
1705 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
1706 {
kezenator19d8ea82016-11-29 19:50:27 +10001707 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001708 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10001709 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001710 return true;
1711 }
1712 bool Visit(const XMLDeclaration& declaration)
1713 {
kezenator19d8ea82016-11-29 19:50:27 +10001714 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001715 return true;
1716 }
1717 bool Visit(const XMLText& text)
1718 {
kezenator19d8ea82016-11-29 19:50:27 +10001719 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001720 return true;
1721 }
1722 bool Visit(const XMLComment& comment)
1723 {
kezenator19d8ea82016-11-29 19:50:27 +10001724 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001725 return true;
1726 }
1727 bool Visit(const XMLUnknown& unknown)
1728 {
kezenator19d8ea82016-11-29 19:50:27 +10001729 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001730 return true;
1731 }
1732
1733 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
1734 {
1735 str.Clear();
1736 doc.Accept(this);
1737 str.Push(0);
1738 XMLTest(testString, expectedLines, str.Mem());
1739 }
Lee Thomasone90e9012016-12-24 07:34:39 -08001740 } tester;
kezenatorec694152016-11-26 17:21:43 +10001741
Lee Thomasone90e9012016-12-24 07:34:39 -08001742 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
1743 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
1744 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
1745 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
1746 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
1747 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
1748 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
1749 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
1750 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
1751 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
1752 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10001753
Lee Thomasone90e9012016-12-24 07:34:39 -08001754 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001755 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08001756
1757 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
1758 "<root a='b' \n" // 2 Element Attribute
1759 "c='d'> d <blah/> \n" // 3 Attribute Text Element
1760 "newline in text \n" // 4 Text
1761 "and second <zxcv/><![CDATA[\n" // 5 Element Text
1762 " cdata test ]]><!-- comment -->\n" // 6 Comment
1763 "<! unknown></root>", // 7 Unknown
1764
kezenatorec694152016-11-26 17:21:43 +10001765 "D01L01E02A02A03T03E03T04E05T05C06U07");
1766
Lee Thomasone90e9012016-12-24 07:34:39 -08001767 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001768 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08001769
1770 "\r\n" // 1 Doc (arguably should be line 2)
1771 "<?xml version=\"1.0\"?>\n" // 2 DecL
1772 "<root>\r\n" // 3 Element
1773 "\n" // 4
1774 "text contining new line \n" // 5 Text
1775 " and also containing crlf \r\n" // 6
1776 "<sub><![CDATA[\n" // 7 Element Text
1777 "cdata containing new line \n" // 8
1778 " and also containing cflr\r\n" // 9
1779 "]]></sub><sub2/></root>", // 10 Element
1780
kezenatorec694152016-11-26 17:21:43 +10001781 "D01L02E03T05E07T07E10");
1782
Lee Thomasone90e9012016-12-24 07:34:39 -08001783 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10001784 "LineNumbers-File",
1785 "resources/utf8test.xml",
1786 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
1787 }
1788
Lee Thomason85492022015-05-22 11:07:45 -07001789 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08001790 {
1791#if defined( _MSC_VER )
1792 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001793 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08001794#endif
1795
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001796 FILE* perfFP = fopen("resources/dream.xml", "r");
1797 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02001798 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001799 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08001800
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001801 char* mem = new char[size + 1];
1802 fread(mem, size, 1, perfFP);
1803 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08001804 mem[size] = 0;
1805
1806#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001807 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08001808#else
1809 clock_t cstart = clock();
1810#endif
1811 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001812 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001813 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001814 doc.Parse(mem);
Lee Thomason6f381b72012-03-02 12:59:39 -08001815 }
1816#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001817 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08001818#else
1819 clock_t cend = clock();
1820#endif
1821
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001822 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08001823
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001824 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001825#ifdef DEBUG
1826 "DEBUG";
1827#else
1828 "Release";
1829#endif
1830
1831#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001832 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 -08001833#else
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001834 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08001835#endif
1836 }
1837
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001838 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001839 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001840
1841 _CrtMemState diffMemState;
1842 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1843 _CrtMemDumpStatistics( &diffMemState );
1844 #endif
1845
1846 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07001847
1848 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001849}