blob: 1df0c44efd45d6bc8e528af5191b873beab8987f [file] [log] [blame]
Lee Thomason5b0a6772012-11-19 13:54:42 -08001#if defined( _MSC_VER )
2 #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
3#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08004
Lee Thomason5b0a6772012-11-19 13:54:42 -08005#include "tinyxml2.h"
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07006#include <cstdlib>
7#include <cstring>
8#include <ctime>
U-Lama\Leee13c3e62011-12-28 14:36:55 -08009
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080010#if defined( _MSC_VER )
Lee Thomasone9699e62012-07-25 12:24:23 -070011 #include <direct.h> // _mkdir
Lee Thomason1ff38e02012-02-14 18:18:16 -080012 #include <crtdbg.h>
Lee Thomason6f381b72012-03-02 12:59:39 -080013 #define WIN32_LEAN_AND_MEAN
14 #include <windows.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080015 _CrtMemState startMemState;
16 _CrtMemState endMemState;
Martinsh Shaiters39ddc262013-01-15 21:53:08 +020017#elif defined(MINGW32) || defined(__MINGW32__)
18 #include <io.h> // mkdir
Lee Thomasone9699e62012-07-25 12:24:23 -070019#else
20 #include <sys/stat.h> // mkdir
Lee Thomason1ff38e02012-02-14 18:18:16 -080021#endif
Lee Thomasone9ecdab2012-02-13 18:11:20 -080022
U-Lama\Leee13c3e62011-12-28 14:36:55 -080023using namespace tinyxml2;
Bruno Dias721b42d2013-07-31 11:50:44 -030024int gTests = 0;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080025int gPass = 0;
26int gFail = 0;
27
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080028
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070029bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080030{
31 bool pass = !strcmp( expected, found );
32 if ( pass )
33 printf ("[pass]");
34 else
35 printf ("[fail]");
36
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070037 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080038 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070039 }
40 else {
41 if ( extraNL ) {
42 printf( " %s\n", testString );
43 printf( "%s\n", expected );
44 printf( "%s\n", found );
45 }
46 else {
47 printf (" %s [%s][%s]\n", testString, expected, found);
48 }
49 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080050
Bruno Dias721b42d2013-07-31 11:50:44 -030051 ++gTests;
52
Lee Thomason1ff38e02012-02-14 18:18:16 -080053 if ( pass )
54 ++gPass;
55 else
56 ++gFail;
57 return pass;
58}
59
60
Lee Thomason21be8822012-07-15 17:27:22 -070061template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080062{
63 bool pass = ( expected == found );
64 if ( pass )
65 printf ("[pass]");
66 else
67 printf ("[fail]");
68
U-Stream\Lee09a11c52012-02-17 08:31:16 -080069 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080070 printf (" %s\n", testString);
71 else
Lee Thomasonc8312792012-07-16 12:44:41 -070072 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080073
Bruno Dias721b42d2013-07-31 11:50:44 -030074 ++gTests;
75
Lee Thomason1ff38e02012-02-14 18:18:16 -080076 if ( pass )
77 ++gPass;
78 else
79 ++gFail;
80 return pass;
81}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080082
U-Lama\Leee13c3e62011-12-28 14:36:55 -080083
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080084void NullLineEndings( char* p )
85{
86 while( p && *p ) {
87 if ( *p == '\n' || *p == '\r' ) {
88 *p = 0;
89 return;
90 }
91 ++p;
92 }
93}
94
95
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070096int example_1()
97{
98 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -030099 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700100
101 return doc.ErrorID();
102}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200103/** @page Example-1 Load an XML File
104 * @dontinclude ./xmltest.cpp
105 * Basic XML file loading.
106 * The basic syntax to load an XML file from
107 * disk and check for an error. (ErrorID()
108 * will return 0 for no error.)
109 * @skip example_1()
110 * @until }
111 */
112
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700113
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700114int example_2()
115{
116 static const char* xml = "<element/>";
117 XMLDocument doc;
118 doc.Parse( xml );
119
120 return doc.ErrorID();
121}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200122/** @page Example-2 Parse an XML from char buffer
123 * @dontinclude ./xmltest.cpp
124 * Basic XML string parsing.
125 * The basic syntax to parse an XML for
126 * a char* and check for an error. (ErrorID()
127 * will return 0 for no error.)
128 * @skip example_2()
129 * @until }
130 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700131
132
133int example_3()
134{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700135 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700136 "<?xml version=\"1.0\"?>"
137 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
138 "<PLAY>"
139 "<TITLE>A Midsummer Night's Dream</TITLE>"
140 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700141
142 XMLDocument doc;
143 doc.Parse( xml );
144
145 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
146 const char* title = titleElement->GetText();
147 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700148
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700149 XMLText* textNode = titleElement->FirstChild()->ToText();
150 title = textNode->Value();
151 printf( "Name of play (2): %s\n", title );
152
153 return doc.ErrorID();
154}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200155/** @page Example-3 Get information out of XML
156 @dontinclude ./xmltest.cpp
157 In this example, we navigate a simple XML
158 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700159 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200160 checking; working code should check for null
161 pointers when walking an XML tree, or use
162 XMLHandle.
163
164 (The XML is an excerpt from "dream.xml").
165
166 @skip example_3()
167 @until </PLAY>";
168
169 The structure of the XML file is:
170
171 <ul>
172 <li>(declaration)</li>
173 <li>(dtd stuff)</li>
174 <li>Element "PLAY"</li>
175 <ul>
176 <li>Element "TITLE"</li>
177 <ul>
178 <li>Text "A Midsummer Night's Dream"</li>
179 </ul>
180 </ul>
181 </ul>
182
183 For this example, we want to print out the
184 title of the play. The text of the title (what
185 we want) is child of the "TITLE" element which
186 is a child of the "PLAY" element.
187
188 We want to skip the declaration and dtd, so the
189 method FirstChildElement() is a good choice. The
190 FirstChildElement() of the Document is the "PLAY"
191 Element, the FirstChildElement() of the "PLAY" Element
192 is the "TITLE" Element.
193
194 @until ( "TITLE" );
195
196 We can then use the convenience function GetText()
197 to get the title of the play.
198
199 @until title );
200
201 Text is just another Node in the XML DOM. And in
202 fact you should be a little cautious with it, as
203 text nodes can contain elements.
204
205 @verbatim
206 Consider: A Midsummer Night's <b>Dream</b>
207 @endverbatim
208
209 It is more correct to actually query the Text Node
210 if in doubt:
211
212 @until title );
213
214 Noting that here we use FirstChild() since we are
215 looking for XMLText, not an element, and ToText()
216 is a cast from a Node to a XMLText.
217*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700218
219
Lee Thomason21be8822012-07-15 17:27:22 -0700220bool example_4()
221{
222 static const char* xml =
223 "<information>"
224 " <attributeApproach v='2' />"
225 " <textApproach>"
226 " <v>2</v>"
227 " </textApproach>"
228 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700229
Lee Thomason21be8822012-07-15 17:27:22 -0700230 XMLDocument doc;
231 doc.Parse( xml );
232
233 int v0 = 0;
234 int v1 = 0;
235
236 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
237 attributeApproachElement->QueryIntAttribute( "v", &v0 );
238
239 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
240 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
241
242 printf( "Both values are the same: %d and %d\n", v0, v1 );
243
244 return !doc.Error() && ( v0 == v1 );
245}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200246/** @page Example-4 Read attributes and text information.
247 @dontinclude ./xmltest.cpp
248
249 There are fundamentally 2 ways of writing a key-value
250 pair into an XML file. (Something that's always annoyed
251 me about XML.) Either by using attributes, or by writing
252 the key name into an element and the value into
253 the text node wrapped by the element. Both approaches
254 are illustrated in this example, which shows two ways
255 to encode the value "2" into the key "v":
256
257 @skip example_4()
258 @until "</information>";
259
260 TinyXML-2 has accessors for both approaches.
261
262 When using an attribute, you navigate to the XMLElement
263 with that attribute and use the QueryIntAttribute()
264 group of methods. (Also QueryFloatAttribute(), etc.)
265
266 @skip XMLElement* attributeApproachElement
267 @until &v0 );
268
269 When using the text approach, you need to navigate
270 down one more step to the XMLElement that contains
271 the text. Note the extra FirstChildElement( "v" )
272 in the code below. The value of the text can then
273 be safely queried with the QueryIntText() group
274 of methods. (Also QueryFloatText(), etc.)
275
276 @skip XMLElement* textApproachElement
277 @until &v1 );
278*/
Lee Thomason21be8822012-07-15 17:27:22 -0700279
280
Lee Thomason178e4cc2013-01-25 16:19:05 -0800281int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800282{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800283 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800284 _CrtMemCheckpoint( &startMemState );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700285 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800286
Martinsh Shaiters39ddc262013-01-15 21:53:08 +0200287 #if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__)
ddiproiettoa8ae1f62013-05-05 18:42:52 +0300288 #if defined __MINGW64_VERSION_MAJOR && defined __MINGW64_VERSION_MINOR
289 //MINGW64: both 32 and 64-bit
290 mkdir( "resources/out/" );
291 #else
292 _mkdir( "resources/out/" );
293 #endif
Lee Thomasone9699e62012-07-25 12:24:23 -0700294 #else
295 mkdir( "resources/out/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
296 #endif
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400297
Lee Thomason178e4cc2013-01-25 16:19:05 -0800298 if ( argc > 1 ) {
299 XMLDocument* doc = new XMLDocument();
300 clock_t startTime = clock();
301 doc->LoadFile( argv[1] );
302 clock_t loadTime = clock();
303 int errorID = doc->ErrorID();
304 delete doc; doc = 0;
305 clock_t deleteTime = clock();
306
307 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
308 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700309 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
310 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
311 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800312 }
313 exit(0);
314 }
315
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300316 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700317 if ( !fp ) {
318 printf( "Error opening test file 'dream.xml'.\n"
319 "Is your working directory the same as where \n"
320 "the xmltest.cpp and dream.xml file are?\n\n"
321 #if defined( _MSC_VER )
322 "In windows Visual Studio you may need to set\n"
323 "Properties->Debugging->Working Directory to '..'\n"
324 #endif
325 );
326 exit( 1 );
327 }
328 fclose( fp );
329
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700330 XMLTest( "Example-1", 0, example_1() );
331 XMLTest( "Example-2", 0, example_2() );
332 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700333 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700334
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700335 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700336
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800337 {
Lee Thomason43f59302012-02-06 18:18:11 -0800338 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400339 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800340 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400341 "<element><subelement></subelement></element>",
342 "<element><subelement><subsub/></subelement></element>",
343 "<!--comment beside elements--><element><subelement></subelement></element>",
344 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
345 "<element attrib1='foo' attrib2=\"bar\" ></element>",
346 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800347 "<element>Text inside element.</element>",
348 "<element><b></b></element>",
349 "<element>Text inside and <b>bolded</b> in the element.</element>",
350 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800351 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800352 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800353 0
354 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800355 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800356 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800357 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800358 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800359 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800360 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800361 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800362#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800363 {
364 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400365 " line 2\r"
366 " line 3\r\n"
367 " line 4\n\r"
368 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800369
370 XMLDocument doc;
371 doc.Parse( test );
372 doc.Print();
373 }
374
Lee Thomason2c85a712012-01-31 08:24:24 -0800375 {
376 static const char* test = "<element>Text before.</element>";
377 XMLDocument doc;
378 doc.Parse( test );
379 XMLElement* root = doc.FirstChildElement();
380 XMLElement* newElement = doc.NewElement( "Subelement" );
381 root->InsertEndChild( newElement );
382 doc.Print();
383 }
Lee Thomasond1983222012-02-06 08:41:24 -0800384 {
385 XMLDocument* doc = new XMLDocument();
386 static const char* test = "<element><sub/></element>";
387 doc->Parse( test );
388 delete doc;
389 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800390 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800391 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800392 // Build:
393 // <element>
394 // <!--comment-->
395 // <sub attrib="1" />
396 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800397 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800398 // <element>
399
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800400 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800401 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
402
403 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
404 for( int i=0; i<3; ++i ) {
405 sub[i]->SetAttribute( "attrib", i );
406 }
407 element->InsertEndChild( sub[2] );
408 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
409 element->InsertAfterChild( comment, sub[0] );
410 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800411 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800412 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800413 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
414 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
415 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700416 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800417 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800418
419 // And now deletion:
420 element->DeleteChild( sub[2] );
421 doc->DeleteNode( comment );
422
423 element->FirstChildElement()->SetAttribute( "attrib", true );
424 element->LastChildElement()->DeleteAttribute( "attrib" );
425
426 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
427 int value = 10;
428 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );
Lee Thomason21be8822012-07-15 17:27:22 -0700429 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800430 XMLTest( "Programmatic DOM", value, 10 );
431
432 doc->Print();
433
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700434 {
435 XMLPrinter streamer;
436 doc->Print( &streamer );
437 printf( "%s", streamer.CStr() );
438 }
439 {
440 XMLPrinter streamer( 0, true );
441 doc->Print( &streamer );
442 XMLTest( "Compact mode", "<element><sub attrib=\"1\"/><sub/></element>", streamer.CStr(), false );
443 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700444 doc->SaveFile( "./resources/out/pretty.xml" );
445 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800446 delete doc;
447 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800448 {
449 // Test: Dream
450 // XML1 : 1,187,569 bytes in 31,209 allocations
451 // XML2 : 469,073 bytes in 323 allocations
452 //int newStart = gNew;
453 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300454 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800455
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400456 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800457 doc.PrintError();
458
459 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400460 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800461 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
462 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
463 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
464 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400465 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800466 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400467 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800468
469 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400470 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800471 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400472 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800473 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
474 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
475 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
476 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400477 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800478
479 //gNewTotal = gNew - newStart;
480 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800481
482
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800483 {
484 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
485 "<passages count=\"006\" formatversion=\"20020620\">\n"
486 " <wrong error>\n"
487 "</passages>";
488
489 XMLDocument doc;
490 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800491 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800492 }
493
494 {
495 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
496
497 XMLDocument doc;
498 doc.Parse( str );
499
500 XMLElement* ele = doc.FirstChildElement();
501
502 int iVal, result;
503 double dVal;
504
505 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700506 XMLTest( "Query attribute: int as double", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800507 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
508 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Thomas Roßa5221862013-05-11 10:22:12 +0200509 XMLTest( "Query attribute: double as double", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800510 XMLTest( "Query attribute: double as double", (int)dVal, 2 );
511 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700512 XMLTest( "Query attribute: double as int", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800513 XMLTest( "Query attribute: double as int", iVal, 2 );
514 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700515 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800516 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700517 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800518 }
519
520 {
521 const char* str = "<doc/>";
522
523 XMLDocument doc;
524 doc.Parse( str );
525
526 XMLElement* ele = doc.FirstChildElement();
527
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800528 int iVal, iVal2;
529 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800530
531 ele->SetAttribute( "str", "strValue" );
532 ele->SetAttribute( "int", 1 );
533 ele->SetAttribute( "double", -1.0 );
534
535 const char* cStr = ele->Attribute( "str" );
536 ele->QueryIntAttribute( "int", &iVal );
537 ele->QueryDoubleAttribute( "double", &dVal );
538
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800539 ele->QueryAttribute( "int", &iVal2 );
540 ele->QueryAttribute( "double", &dVal2 );
541
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700542 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800543 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
544 XMLTest( "Attribute round trip. int.", 1, iVal );
545 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800546 XMLTest( "Alternate query", true, iVal == iVal2 );
547 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800548 }
549
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550 {
551 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300552 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800553
554 // Get the attribute "value" from the "Russian" element and check it.
555 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700556 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800557 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
558
559 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
560
561 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
562 0xd1U, 0x81U, 0xd1U, 0x81U,
563 0xd0U, 0xbaU, 0xd0U, 0xb8U,
564 0xd0U, 0xb9U, 0 };
565 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
566
567 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
568 XMLTest( "UTF-8: Browsing russian element name.",
569 russianText,
570 text->Value() );
571
572 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400573 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800574
575 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800576 int okay = 0;
577
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200578 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300579 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800580
581 if ( saved && verify )
582 {
583 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700584 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800585 while ( fgets( verifyBuf, 256, verify ) )
586 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700587 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800588 fgets( savedBuf, 256, saved );
589 NullLineEndings( verifyBuf );
590 NullLineEndings( savedBuf );
591
592 if ( strcmp( verifyBuf, savedBuf ) )
593 {
594 printf( "verify:%s<\n", verifyBuf );
595 printf( "saved :%s<\n", savedBuf );
596 okay = 0;
597 break;
598 }
599 }
600 }
601 if ( saved )
602 fclose( saved );
603 if ( verify )
604 fclose( verify );
605 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
606 }
607
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800608 // --------GetText()-----------
609 {
610 const char* str = "<foo>This is text</foo>";
611 XMLDocument doc;
612 doc.Parse( str );
613 const XMLElement* element = doc.RootElement();
614
615 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
616
617 str = "<foo><b>This is text</b></foo>";
618 doc.Parse( str );
619 element = doc.RootElement();
620
621 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
622 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800623
Lee Thomasond6277762012-02-22 16:00:12 -0800624
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800625 // ---------- CDATA ---------------
626 {
627 const char* str = "<xmlElement>"
628 "<![CDATA["
629 "I am > the rules!\n"
630 "...since I make symbolic puns"
631 "]]>"
632 "</xmlElement>";
633 XMLDocument doc;
634 doc.Parse( str );
635 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800636
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700637 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800638 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800639 false );
640 }
641
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800642 // ----------- CDATA -------------
643 {
644 const char* str = "<xmlElement>"
645 "<![CDATA["
646 "<b>I am > the rules!</b>\n"
647 "...since I make symbolic puns"
648 "]]>"
649 "</xmlElement>";
650 XMLDocument doc;
651 doc.Parse( str );
652 doc.Print();
653
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700654 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800655 "<b>I am > the rules!</b>\n...since I make symbolic puns",
656 false );
657 }
658
659 // InsertAfterChild causes crash.
660 {
661 // InsertBeforeChild and InsertAfterChild causes crash.
662 XMLDocument doc;
663 XMLElement* parent = doc.NewElement( "Parent" );
664 doc.InsertFirstChild( parent );
665
666 XMLElement* childText0 = doc.NewElement( "childText0" );
667 XMLElement* childText1 = doc.NewElement( "childText1" );
668
669 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
670 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
671
672 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
673 }
Lee Thomasond6277762012-02-22 16:00:12 -0800674
675 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800676 // Entities not being written correctly.
677 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800678
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800679 const char* passages =
680 "<?xml version=\"1.0\" standalone=\"no\" ?>"
681 "<passages count=\"006\" formatversion=\"20020620\">"
682 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
683 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
684 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800685
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800686 XMLDocument doc;
687 doc.Parse( passages );
688 XMLElement* psg = doc.RootElement()->FirstChildElement();
689 const char* context = psg->Attribute( "context" );
690 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 -0800691
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800692 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800693
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400694 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800695 if ( textfile )
696 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800697 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800698 psg->Accept( &streamer );
699 fclose( textfile );
700 }
Thomas Roß0922b732012-09-23 16:31:22 +0200701
702 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800703 TIXMLASSERT( textfile );
704 if ( textfile )
705 {
706 char buf[ 1024 ];
707 fgets( buf, 1024, textfile );
708 XMLTest( "Entity transformation: write. ",
709 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
710 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
711 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700712 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800713 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800714 }
715
716 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800717 // Suppress entities.
718 const char* passages =
719 "<?xml version=\"1.0\" standalone=\"no\" ?>"
720 "<passages count=\"006\" formatversion=\"20020620\">"
721 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
722 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700723
Lee Thomason6f381b72012-03-02 12:59:39 -0800724 XMLDocument doc( false );
725 doc.Parse( passages );
726
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700727 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800728 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
729 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
730 "Crazy &ttk;" );
731 doc.Print();
732 }
733
734 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400735 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800736
737 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400738 doc.Parse( test );
739 XMLTest( "dot in names", doc.Error(), false );
740 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
741 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800742 }
743
744 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400745 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800746
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400747 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800748 doc.Parse( test );
749
750 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
751 XMLTest( "Entity with one digit.",
752 text->Value(), "1.1 Start easy ignore fin thickness\n",
753 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400754 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800755
756 {
757 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700758 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800759 const char* doctype =
760 "<?xml version=\"1.0\" ?>"
761 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
762 "<!ELEMENT title (#PCDATA)>"
763 "<!ELEMENT books (title,authors)>"
764 "<element />";
765
766 XMLDocument doc;
767 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400768 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800769 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400770 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800771 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700772
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800773 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
774 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
775
776 }
777
778 {
779 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700780 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800781 "<!-- Somewhat<evil> -->";
782 XMLDocument doc;
783 doc.Parse( doctype );
784
785 XMLComment* comment = doc.FirstChild()->ToComment();
786
787 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
788 }
789 {
790 // Double attributes
791 const char* doctype = "<element attr='red' attr='blue' />";
792
793 XMLDocument doc;
794 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700795
Lee Thomason2fa81722012-11-09 12:37:46 -0800796 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 -0800797 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800798 }
799
800 {
801 // Embedded null in stream.
802 const char* doctype = "<element att\0r='red' attr='blue' />";
803
804 XMLDocument doc;
805 doc.Parse( doctype );
806 XMLTest( "Embedded null throws error.", true, doc.Error() );
807 }
808
809 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700810 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800811 const char* str = " ";
812 XMLDocument doc;
813 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -0800814 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800815 }
816
817 {
818 // Low entities
819 XMLDocument doc;
820 doc.Parse( "<test>&#x0e;</test>" );
821 const char result[] = { 0x0e, 0 };
822 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
823 doc.Print();
824 }
825
826 {
827 // Attribute values with trailing quotes not handled correctly
828 XMLDocument doc;
829 doc.Parse( "<foo attribute=bar\" />" );
830 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
831 }
832
833 {
834 // [ 1663758 ] Failure to report error on bad XML
835 XMLDocument xml;
836 xml.Parse("<x>");
837 XMLTest("Missing end tag at end of input", xml.Error(), true);
838 xml.Parse("<x> ");
839 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
840 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -0800841 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700842 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800843
844
845 {
846 // [ 1475201 ] TinyXML parses entities in comments
847 XMLDocument xml;
848 xml.Parse("<!-- declarations for <head> & <body> -->"
849 "<!-- far &amp; away -->" );
850
851 XMLNode* e0 = xml.FirstChild();
852 XMLNode* e1 = e0->NextSibling();
853 XMLComment* c0 = e0->ToComment();
854 XMLComment* c1 = e1->ToComment();
855
856 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
857 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
858 }
859
860 {
861 XMLDocument xml;
862 xml.Parse( "<Parent>"
863 "<child1 att=''/>"
864 "<!-- With this comment, child2 will not be parsed! -->"
865 "<child2 att=''/>"
866 "</Parent>" );
867 xml.Print();
868
869 int count = 0;
870
871 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
872 ele;
873 ele = ele->NextSibling() )
874 {
875 ++count;
876 }
877
878 XMLTest( "Comments iterate correctly.", 3, count );
879 }
880
881 {
882 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
883 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
884 buf[60] = 239;
885 buf[61] = 0;
886
887 XMLDocument doc;
888 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700889 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800890
891
892 {
893 // bug 1827248 Error while parsing a little bit malformed file
894 // Actually not malformed - should work.
895 XMLDocument xml;
896 xml.Parse( "<attributelist> </attributelist >" );
897 XMLTest( "Handle end tag whitespace", false, xml.Error() );
898 }
899
900 {
901 // This one must not result in an infinite loop
902 XMLDocument xml;
903 xml.Parse( "<infinite>loop" );
904 XMLTest( "Infinite loop test.", true, true );
905 }
906#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800907 {
908 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
909 XMLDocument doc;
910 doc.Parse( pub );
911
912 XMLDocument clone;
913 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
914 XMLNode* copy = node->ShallowClone( &clone );
915 clone.InsertEndChild( copy );
916 }
917
918 clone.Print();
919
920 int count=0;
921 const XMLNode* a=clone.FirstChild();
922 const XMLNode* b=doc.FirstChild();
923 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
924 ++count;
925 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
926 }
927 XMLTest( "Clone and Equal", 4, count );
928 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800929
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700930 {
931 // This shouldn't crash.
932 XMLDocument doc;
933 if(XML_NO_ERROR != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
934 {
935 doc.PrintError();
936 }
937 XMLTest( "Error in snprinf handling.", true, doc.Error() );
938 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700939
Lee Thomason5e3803c2012-04-16 08:57:05 -0700940 {
941 // Attribute ordering.
942 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
943 XMLDocument doc;
944 doc.Parse( xml );
945 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700946
Lee Thomason5e3803c2012-04-16 08:57:05 -0700947 const XMLAttribute* a = ele->FirstAttribute();
948 XMLTest( "Attribute order", "1", a->Value() );
949 a = a->Next();
950 XMLTest( "Attribute order", "2", a->Value() );
951 a = a->Next();
952 XMLTest( "Attribute order", "3", a->Value() );
953 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700954
Lee Thomason5e3803c2012-04-16 08:57:05 -0700955 ele->DeleteAttribute( "attrib2" );
956 a = ele->FirstAttribute();
957 XMLTest( "Attribute order", "1", a->Value() );
958 a = a->Next();
959 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700960
Lee Thomason5e3803c2012-04-16 08:57:05 -0700961 ele->DeleteAttribute( "attrib1" );
962 ele->DeleteAttribute( "attrib3" );
963 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
964 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700965
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700966 {
967 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -0700968 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
969 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
970 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
971 XMLDocument doc0;
972 doc0.Parse( xml0 );
973 XMLDocument doc1;
974 doc1.Parse( xml1 );
975 XMLDocument doc2;
976 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700977
Lee Thomason78a773d2012-07-02 10:10:19 -0700978 XMLElement* ele = 0;
979 ele = doc0.FirstChildElement();
980 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
981 ele = doc1.FirstChildElement();
982 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
983 ele = doc2.FirstChildElement();
984 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700985 }
986
987 {
988 // Make sure we don't go into an infinite loop.
989 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
990 XMLDocument doc;
991 doc.Parse( xml );
992 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
993 XMLElement* ele1 = ele0->NextSiblingElement();
994 bool equal = ele0->ShallowEqual( ele1 );
995
996 XMLTest( "Infinite loop in shallow equal.", true, equal );
997 }
998
Lee Thomason5708f812012-03-28 17:46:41 -0700999 // -------- Handles ------------
1000 {
1001 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1002 XMLDocument doc;
1003 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -07001004
1005 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1006 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
1007
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001008 XMLHandle docH( doc );
1009 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001010 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001011 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001012
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001013 {
1014 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1015 XMLDocument doc;
1016 doc.Parse( xml );
1017 XMLConstHandle docH( doc );
1018
1019 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1020 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1021
1022 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001023 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001024 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001025 {
1026 // Default Declaration & BOM
1027 XMLDocument doc;
1028 doc.InsertEndChild( doc.NewDeclaration() );
1029 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001030
Lee Thomasonf68c4382012-04-28 14:37:11 -07001031 XMLPrinter printer;
1032 doc.Print( &printer );
1033
1034 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1035 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001036 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001037 }
Lee Thomason21be8822012-07-15 17:27:22 -07001038 {
1039 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1040 XMLDocument doc;
1041 doc.Parse( xml );
1042 XMLTest( "Ill formed XML", true, doc.Error() );
1043 }
1044
1045 // QueryXYZText
1046 {
1047 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1048 XMLDocument doc;
1049 doc.Parse( xml );
1050
1051 const XMLElement* pointElement = doc.RootElement();
1052
1053 int intValue = 0;
1054 unsigned unsignedValue = 0;
1055 float floatValue = 0;
1056 double doubleValue = 0;
1057 bool boolValue = false;
1058
1059 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1060 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1061 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1062 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1063 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1064
1065
1066 XMLTest( "QueryIntText", intValue, 1, false );
1067 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1068 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1069 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1070 XMLTest( "QueryBoolText", boolValue, true, false );
1071 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001072
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001073 {
1074 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1075 XMLDocument doc;
1076 doc.Parse( xml );
1077 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1078 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001079
1080 {
1081 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1082 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001083 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001084 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1085 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001086
1087 {
1088 const char* xml = "<3lement></3lement>";
1089 XMLDocument doc;
1090 doc.Parse( xml );
1091 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1092 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001093
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001094 {
1095 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1096 XMLDocument doc;
1097 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001098 XMLTest( "Set length of incoming data", doc.Error(), false );
1099 }
1100
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001101 {
1102 XMLDocument doc;
1103 doc.LoadFile( "resources/dream.xml" );
1104 doc.Clear();
1105 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1106 }
1107
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001108 // ----------- Whitespace ------------
1109 {
1110 const char* xml = "<element>"
1111 "<a> This \nis &apos; text &apos; </a>"
1112 "<b> This is &apos; text &apos; \n</b>"
1113 "<c>This is &apos; \n\n text &apos;</c>"
1114 "</element>";
1115 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1116 doc.Parse( xml );
1117
1118 const XMLElement* element = doc.FirstChildElement();
1119 for( const XMLElement* parent = element->FirstChildElement();
1120 parent;
1121 parent = parent->NextSiblingElement() )
1122 {
1123 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1124 }
1125 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001126
Lee Thomasonae9ab072012-10-24 10:17:53 -07001127#if 0
1128 {
1129 // Passes if assert doesn't fire.
1130 XMLDocument xmlDoc;
1131
1132 xmlDoc.NewDeclaration();
1133 xmlDoc.NewComment("Configuration file");
1134
1135 XMLElement *root = xmlDoc.NewElement("settings");
1136 root->SetAttribute("version", 2);
1137 }
1138#endif
1139
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001140 {
1141 const char* xml = "<element> </element>";
1142 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1143 doc.Parse( xml );
1144 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1145 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001146
Lee Thomason (grinliz)fc6320e2012-09-23 20:25:50 -07001147#if 0 // the question being explored is what kind of print to use:
1148 // https://github.com/leethomason/tinyxml2/issues/63
1149 {
1150 const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9'/>";
1151 XMLDocument doc;
1152 doc.Parse( xml );
1153 doc.FirstChildElement()->SetAttribute( "attrA", 123456789.123456789 );
1154 doc.FirstChildElement()->SetAttribute( "attrB", 1.001e9 );
1155 doc.Print();
1156 }
1157#endif
1158
Lee Thomason5b0a6772012-11-19 13:54:42 -08001159 {
1160 // An assert should not fire.
1161 const char* xml = "<element/>";
1162 XMLDocument doc;
1163 doc.Parse( xml );
1164 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1165 XMLTest( "Tracking unused elements", true, ele != 0, false );
1166 }
1167
Lee Thomasona6412ac2012-12-13 15:39:11 -08001168
1169 {
1170 const char* xml = "<parent><child>abc</child></parent>";
1171 XMLDocument doc;
1172 doc.Parse( xml );
1173 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1174
1175 XMLPrinter printer;
1176 ele->Accept( &printer );
1177 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1178 }
1179
1180
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001181 {
1182 XMLDocument doc;
1183 XMLError error = doc.LoadFile( "resources/empty.xml" );
1184 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
1185 }
1186
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001187 {
1188 // BOM preservation
1189 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1190 {
1191 XMLDocument doc;
1192 XMLTest( "BOM preservation (parse)", XML_NO_ERROR, doc.Parse( xml_bom_preservation ), false );
1193 XMLPrinter printer;
1194 doc.Print( &printer );
1195
1196 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1197 doc.SaveFile( "resources/bomtest.xml" );
1198 }
1199 {
1200 XMLDocument doc;
1201 doc.LoadFile( "resources/bomtest.xml" );
1202 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1203
1204 XMLPrinter printer;
1205 doc.Print( &printer );
1206 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1207 }
1208 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001209
Lee Thomason6f381b72012-03-02 12:59:39 -08001210 // ----------- Performance tracking --------------
1211 {
1212#if defined( _MSC_VER )
1213 __int64 start, end, freq;
1214 QueryPerformanceFrequency( (LARGE_INTEGER*) &freq );
1215#endif
1216
Bruno Diasa2d4e6e2012-05-07 04:58:11 -03001217 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason6f381b72012-03-02 12:59:39 -08001218 fseek( fp, 0, SEEK_END );
1219 long size = ftell( fp );
1220 fseek( fp, 0, SEEK_SET );
1221
1222 char* mem = new char[size+1];
1223 fread( mem, size, 1, fp );
1224 fclose( fp );
1225 mem[size] = 0;
1226
1227#if defined( _MSC_VER )
1228 QueryPerformanceCounter( (LARGE_INTEGER*) &start );
1229#else
1230 clock_t cstart = clock();
1231#endif
1232 static const int COUNT = 10;
1233 for( int i=0; i<COUNT; ++i ) {
1234 XMLDocument doc;
1235 doc.Parse( mem );
1236 }
1237#if defined( _MSC_VER )
1238 QueryPerformanceCounter( (LARGE_INTEGER*) &end );
1239#else
1240 clock_t cend = clock();
1241#endif
1242
1243 delete [] mem;
1244
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001245 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001246#ifdef DEBUG
1247 "DEBUG";
1248#else
1249 "Release";
1250#endif
1251
1252#if defined( _MSC_VER )
1253 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end-start) / ( (double)freq * (double)COUNT) );
1254#else
1255 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart)/(double)COUNT );
1256#endif
1257 }
1258
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001259 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001260 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001261 //_CrtMemDumpStatistics( &endMemState );
1262
1263 _CrtMemState diffMemState;
1264 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1265 _CrtMemDumpStatistics( &diffMemState );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001266 //printf( "new total=%d\n", gNewTotal );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001267 #endif
1268
1269 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Bruno Dias721b42d2013-07-31 11:50:44 -03001270 return (gTests - gPass);
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001271}