blob: c8e1b0ba135fde1f9f1cc112cacef79760694a10 [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;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080024int gPass = 0;
25int gFail = 0;
26
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080027
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070028bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080029{
30 bool pass = !strcmp( expected, found );
31 if ( pass )
32 printf ("[pass]");
33 else
34 printf ("[fail]");
35
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070036 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080037 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070038 }
39 else {
40 if ( extraNL ) {
41 printf( " %s\n", testString );
42 printf( "%s\n", expected );
43 printf( "%s\n", found );
44 }
45 else {
46 printf (" %s [%s][%s]\n", testString, expected, found);
47 }
48 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080049
50 if ( pass )
51 ++gPass;
52 else
53 ++gFail;
54 return pass;
55}
56
57
Lee Thomason21be8822012-07-15 17:27:22 -070058template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080059{
60 bool pass = ( expected == found );
61 if ( pass )
62 printf ("[pass]");
63 else
64 printf ("[fail]");
65
U-Stream\Lee09a11c52012-02-17 08:31:16 -080066 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080067 printf (" %s\n", testString);
68 else
Lee Thomasonc8312792012-07-16 12:44:41 -070069 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080070
71 if ( pass )
72 ++gPass;
73 else
74 ++gFail;
75 return pass;
76}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080077
U-Lama\Leee13c3e62011-12-28 14:36:55 -080078
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080079void NullLineEndings( char* p )
80{
81 while( p && *p ) {
82 if ( *p == '\n' || *p == '\r' ) {
83 *p = 0;
84 return;
85 }
86 ++p;
87 }
88}
89
90
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070091int example_1()
92{
93 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -030094 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070095
96 return doc.ErrorID();
97}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +020098/** @page Example-1 Load an XML File
99 * @dontinclude ./xmltest.cpp
100 * Basic XML file loading.
101 * The basic syntax to load an XML file from
102 * disk and check for an error. (ErrorID()
103 * will return 0 for no error.)
104 * @skip example_1()
105 * @until }
106 */
107
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700108
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700109int example_2()
110{
111 static const char* xml = "<element/>";
112 XMLDocument doc;
113 doc.Parse( xml );
114
115 return doc.ErrorID();
116}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200117/** @page Example-2 Parse an XML from char buffer
118 * @dontinclude ./xmltest.cpp
119 * Basic XML string parsing.
120 * The basic syntax to parse an XML for
121 * a char* and check for an error. (ErrorID()
122 * will return 0 for no error.)
123 * @skip example_2()
124 * @until }
125 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700126
127
128int example_3()
129{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700130 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700131 "<?xml version=\"1.0\"?>"
132 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
133 "<PLAY>"
134 "<TITLE>A Midsummer Night's Dream</TITLE>"
135 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700136
137 XMLDocument doc;
138 doc.Parse( xml );
139
140 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
141 const char* title = titleElement->GetText();
142 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700143
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700144 XMLText* textNode = titleElement->FirstChild()->ToText();
145 title = textNode->Value();
146 printf( "Name of play (2): %s\n", title );
147
148 return doc.ErrorID();
149}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200150/** @page Example-3 Get information out of XML
151 @dontinclude ./xmltest.cpp
152 In this example, we navigate a simple XML
153 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700154 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200155 checking; working code should check for null
156 pointers when walking an XML tree, or use
157 XMLHandle.
158
159 (The XML is an excerpt from "dream.xml").
160
161 @skip example_3()
162 @until </PLAY>";
163
164 The structure of the XML file is:
165
166 <ul>
167 <li>(declaration)</li>
168 <li>(dtd stuff)</li>
169 <li>Element "PLAY"</li>
170 <ul>
171 <li>Element "TITLE"</li>
172 <ul>
173 <li>Text "A Midsummer Night's Dream"</li>
174 </ul>
175 </ul>
176 </ul>
177
178 For this example, we want to print out the
179 title of the play. The text of the title (what
180 we want) is child of the "TITLE" element which
181 is a child of the "PLAY" element.
182
183 We want to skip the declaration and dtd, so the
184 method FirstChildElement() is a good choice. The
185 FirstChildElement() of the Document is the "PLAY"
186 Element, the FirstChildElement() of the "PLAY" Element
187 is the "TITLE" Element.
188
189 @until ( "TITLE" );
190
191 We can then use the convenience function GetText()
192 to get the title of the play.
193
194 @until title );
195
196 Text is just another Node in the XML DOM. And in
197 fact you should be a little cautious with it, as
198 text nodes can contain elements.
199
200 @verbatim
201 Consider: A Midsummer Night's <b>Dream</b>
202 @endverbatim
203
204 It is more correct to actually query the Text Node
205 if in doubt:
206
207 @until title );
208
209 Noting that here we use FirstChild() since we are
210 looking for XMLText, not an element, and ToText()
211 is a cast from a Node to a XMLText.
212*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700213
214
Lee Thomason21be8822012-07-15 17:27:22 -0700215bool example_4()
216{
217 static const char* xml =
218 "<information>"
219 " <attributeApproach v='2' />"
220 " <textApproach>"
221 " <v>2</v>"
222 " </textApproach>"
223 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700224
Lee Thomason21be8822012-07-15 17:27:22 -0700225 XMLDocument doc;
226 doc.Parse( xml );
227
228 int v0 = 0;
229 int v1 = 0;
230
231 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
232 attributeApproachElement->QueryIntAttribute( "v", &v0 );
233
234 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
235 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
236
237 printf( "Both values are the same: %d and %d\n", v0, v1 );
238
239 return !doc.Error() && ( v0 == v1 );
240}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200241/** @page Example-4 Read attributes and text information.
242 @dontinclude ./xmltest.cpp
243
244 There are fundamentally 2 ways of writing a key-value
245 pair into an XML file. (Something that's always annoyed
246 me about XML.) Either by using attributes, or by writing
247 the key name into an element and the value into
248 the text node wrapped by the element. Both approaches
249 are illustrated in this example, which shows two ways
250 to encode the value "2" into the key "v":
251
252 @skip example_4()
253 @until "</information>";
254
255 TinyXML-2 has accessors for both approaches.
256
257 When using an attribute, you navigate to the XMLElement
258 with that attribute and use the QueryIntAttribute()
259 group of methods. (Also QueryFloatAttribute(), etc.)
260
261 @skip XMLElement* attributeApproachElement
262 @until &v0 );
263
264 When using the text approach, you need to navigate
265 down one more step to the XMLElement that contains
266 the text. Note the extra FirstChildElement( "v" )
267 in the code below. The value of the text can then
268 be safely queried with the QueryIntText() group
269 of methods. (Also QueryFloatText(), etc.)
270
271 @skip XMLElement* textApproachElement
272 @until &v1 );
273*/
Lee Thomason21be8822012-07-15 17:27:22 -0700274
275
Lee Thomason178e4cc2013-01-25 16:19:05 -0800276int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800277{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800278 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800279 _CrtMemCheckpoint( &startMemState );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700280 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800281
Martinsh Shaiters39ddc262013-01-15 21:53:08 +0200282 #if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__)
Lee Thomasone9699e62012-07-25 12:24:23 -0700283 _mkdir( "resources/out/" );
284 #else
285 mkdir( "resources/out/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
286 #endif
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400287
Lee Thomason178e4cc2013-01-25 16:19:05 -0800288 if ( argc > 1 ) {
289 XMLDocument* doc = new XMLDocument();
290 clock_t startTime = clock();
291 doc->LoadFile( argv[1] );
292 clock_t loadTime = clock();
293 int errorID = doc->ErrorID();
294 delete doc; doc = 0;
295 clock_t deleteTime = clock();
296
297 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
298 if ( !errorID ) {
299 printf( "Load time=%d\n", loadTime - startTime );
300 printf( "Delete time=%d\n", deleteTime - loadTime );
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -0800301 printf( "Total time=%d\n", deleteTime - startTime );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800302 }
303 exit(0);
304 }
305
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300306 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700307 if ( !fp ) {
308 printf( "Error opening test file 'dream.xml'.\n"
309 "Is your working directory the same as where \n"
310 "the xmltest.cpp and dream.xml file are?\n\n"
311 #if defined( _MSC_VER )
312 "In windows Visual Studio you may need to set\n"
313 "Properties->Debugging->Working Directory to '..'\n"
314 #endif
315 );
316 exit( 1 );
317 }
318 fclose( fp );
319
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700320 XMLTest( "Example-1", 0, example_1() );
321 XMLTest( "Example-2", 0, example_2() );
322 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700323 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700324
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700325 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700326
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800327 {
Lee Thomason43f59302012-02-06 18:18:11 -0800328 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400329 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800330 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400331 "<element><subelement></subelement></element>",
332 "<element><subelement><subsub/></subelement></element>",
333 "<!--comment beside elements--><element><subelement></subelement></element>",
334 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
335 "<element attrib1='foo' attrib2=\"bar\" ></element>",
336 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800337 "<element>Text inside element.</element>",
338 "<element><b></b></element>",
339 "<element>Text inside and <b>bolded</b> in the element.</element>",
340 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800341 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800342 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800343 0
344 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800345 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800346 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800347 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800348 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800349 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800350 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800351 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800353 {
354 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400355 " line 2\r"
356 " line 3\r\n"
357 " line 4\n\r"
358 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800359
360 XMLDocument doc;
361 doc.Parse( test );
362 doc.Print();
363 }
364
Lee Thomason2c85a712012-01-31 08:24:24 -0800365 {
366 static const char* test = "<element>Text before.</element>";
367 XMLDocument doc;
368 doc.Parse( test );
369 XMLElement* root = doc.FirstChildElement();
370 XMLElement* newElement = doc.NewElement( "Subelement" );
371 root->InsertEndChild( newElement );
372 doc.Print();
373 }
Lee Thomasond1983222012-02-06 08:41:24 -0800374 {
375 XMLDocument* doc = new XMLDocument();
376 static const char* test = "<element><sub/></element>";
377 doc->Parse( test );
378 delete doc;
379 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800380 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800381 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800382 // Build:
383 // <element>
384 // <!--comment-->
385 // <sub attrib="1" />
386 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800387 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800388 // <element>
389
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800390 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800391 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
392
393 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
394 for( int i=0; i<3; ++i ) {
395 sub[i]->SetAttribute( "attrib", i );
396 }
397 element->InsertEndChild( sub[2] );
398 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
399 element->InsertAfterChild( comment, sub[0] );
400 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800401 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800402 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800403 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
404 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
405 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700406 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800407 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800408
409 // And now deletion:
410 element->DeleteChild( sub[2] );
411 doc->DeleteNode( comment );
412
413 element->FirstChildElement()->SetAttribute( "attrib", true );
414 element->LastChildElement()->DeleteAttribute( "attrib" );
415
416 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
417 int value = 10;
418 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );
Lee Thomason21be8822012-07-15 17:27:22 -0700419 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800420 XMLTest( "Programmatic DOM", value, 10 );
421
422 doc->Print();
423
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700424 {
425 XMLPrinter streamer;
426 doc->Print( &streamer );
427 printf( "%s", streamer.CStr() );
428 }
429 {
430 XMLPrinter streamer( 0, true );
431 doc->Print( &streamer );
432 XMLTest( "Compact mode", "<element><sub attrib=\"1\"/><sub/></element>", streamer.CStr(), false );
433 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700434 doc->SaveFile( "./resources/out/pretty.xml" );
435 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800436 delete doc;
437 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800438 {
439 // Test: Dream
440 // XML1 : 1,187,569 bytes in 31,209 allocations
441 // XML2 : 469,073 bytes in 323 allocations
442 //int newStart = gNew;
443 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300444 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800445
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400446 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800447 doc.PrintError();
448
449 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400450 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800451 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
452 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
453 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
454 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400455 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800456 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400457 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800458
459 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400460 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800461 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400462 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800463 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
464 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
465 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
466 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400467 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800468
469 //gNewTotal = gNew - newStart;
470 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800471
472
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800473 {
474 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
475 "<passages count=\"006\" formatversion=\"20020620\">\n"
476 " <wrong error>\n"
477 "</passages>";
478
479 XMLDocument doc;
480 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800481 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800482 }
483
484 {
485 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
486
487 XMLDocument doc;
488 doc.Parse( str );
489
490 XMLElement* ele = doc.FirstChildElement();
491
492 int iVal, result;
493 double dVal;
494
495 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700496 XMLTest( "Query attribute: int as double", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800497 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
498 result = ele->QueryDoubleAttribute( "attr1", &dVal );
499 XMLTest( "Query attribute: double as double", (int)dVal, 2 );
500 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700501 XMLTest( "Query attribute: double as int", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800502 XMLTest( "Query attribute: double as int", iVal, 2 );
503 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700504 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800505 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700506 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800507 }
508
509 {
510 const char* str = "<doc/>";
511
512 XMLDocument doc;
513 doc.Parse( str );
514
515 XMLElement* ele = doc.FirstChildElement();
516
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800517 int iVal, iVal2;
518 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800519
520 ele->SetAttribute( "str", "strValue" );
521 ele->SetAttribute( "int", 1 );
522 ele->SetAttribute( "double", -1.0 );
523
524 const char* cStr = ele->Attribute( "str" );
525 ele->QueryIntAttribute( "int", &iVal );
526 ele->QueryDoubleAttribute( "double", &dVal );
527
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800528 ele->QueryAttribute( "int", &iVal2 );
529 ele->QueryAttribute( "double", &dVal2 );
530
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700531 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800532 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
533 XMLTest( "Attribute round trip. int.", 1, iVal );
534 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800535 XMLTest( "Alternate query", true, iVal == iVal2 );
536 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800537 }
538
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800539 {
540 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300541 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800542
543 // Get the attribute "value" from the "Russian" element and check it.
544 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700545 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800546 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
547
548 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
549
550 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
551 0xd1U, 0x81U, 0xd1U, 0x81U,
552 0xd0U, 0xbaU, 0xd0U, 0xb8U,
553 0xd0U, 0xb9U, 0 };
554 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
555
556 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
557 XMLTest( "UTF-8: Browsing russian element name.",
558 russianText,
559 text->Value() );
560
561 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400562 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800563
564 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800565 int okay = 0;
566
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200567 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300568 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800569
570 if ( saved && verify )
571 {
572 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700573 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800574 while ( fgets( verifyBuf, 256, verify ) )
575 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700576 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800577 fgets( savedBuf, 256, saved );
578 NullLineEndings( verifyBuf );
579 NullLineEndings( savedBuf );
580
581 if ( strcmp( verifyBuf, savedBuf ) )
582 {
583 printf( "verify:%s<\n", verifyBuf );
584 printf( "saved :%s<\n", savedBuf );
585 okay = 0;
586 break;
587 }
588 }
589 }
590 if ( saved )
591 fclose( saved );
592 if ( verify )
593 fclose( verify );
594 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
595 }
596
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800597 // --------GetText()-----------
598 {
599 const char* str = "<foo>This is text</foo>";
600 XMLDocument doc;
601 doc.Parse( str );
602 const XMLElement* element = doc.RootElement();
603
604 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
605
606 str = "<foo><b>This is text</b></foo>";
607 doc.Parse( str );
608 element = doc.RootElement();
609
610 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
611 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800612
Lee Thomasond6277762012-02-22 16:00:12 -0800613
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800614 // ---------- CDATA ---------------
615 {
616 const char* str = "<xmlElement>"
617 "<![CDATA["
618 "I am > the rules!\n"
619 "...since I make symbolic puns"
620 "]]>"
621 "</xmlElement>";
622 XMLDocument doc;
623 doc.Parse( str );
624 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800625
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700626 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800627 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800628 false );
629 }
630
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800631 // ----------- CDATA -------------
632 {
633 const char* str = "<xmlElement>"
634 "<![CDATA["
635 "<b>I am > the rules!</b>\n"
636 "...since I make symbolic puns"
637 "]]>"
638 "</xmlElement>";
639 XMLDocument doc;
640 doc.Parse( str );
641 doc.Print();
642
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700643 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800644 "<b>I am > the rules!</b>\n...since I make symbolic puns",
645 false );
646 }
647
648 // InsertAfterChild causes crash.
649 {
650 // InsertBeforeChild and InsertAfterChild causes crash.
651 XMLDocument doc;
652 XMLElement* parent = doc.NewElement( "Parent" );
653 doc.InsertFirstChild( parent );
654
655 XMLElement* childText0 = doc.NewElement( "childText0" );
656 XMLElement* childText1 = doc.NewElement( "childText1" );
657
658 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
659 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
660
661 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
662 }
Lee Thomasond6277762012-02-22 16:00:12 -0800663
664 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800665 // Entities not being written correctly.
666 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800667
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800668 const char* passages =
669 "<?xml version=\"1.0\" standalone=\"no\" ?>"
670 "<passages count=\"006\" formatversion=\"20020620\">"
671 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
672 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
673 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800674
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800675 XMLDocument doc;
676 doc.Parse( passages );
677 XMLElement* psg = doc.RootElement()->FirstChildElement();
678 const char* context = psg->Attribute( "context" );
679 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 -0800680
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800681 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800682
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400683 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800684 if ( textfile )
685 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800686 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800687 psg->Accept( &streamer );
688 fclose( textfile );
689 }
Thomas Roß0922b732012-09-23 16:31:22 +0200690
691 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800692 TIXMLASSERT( textfile );
693 if ( textfile )
694 {
695 char buf[ 1024 ];
696 fgets( buf, 1024, textfile );
697 XMLTest( "Entity transformation: write. ",
698 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
699 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
700 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700701 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800702 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800703 }
704
705 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800706 // Suppress entities.
707 const char* passages =
708 "<?xml version=\"1.0\" standalone=\"no\" ?>"
709 "<passages count=\"006\" formatversion=\"20020620\">"
710 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
711 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700712
Lee Thomason6f381b72012-03-02 12:59:39 -0800713 XMLDocument doc( false );
714 doc.Parse( passages );
715
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700716 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800717 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
718 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
719 "Crazy &ttk;" );
720 doc.Print();
721 }
722
723 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400724 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800725
726 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400727 doc.Parse( test );
728 XMLTest( "dot in names", doc.Error(), false );
729 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
730 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800731 }
732
733 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400734 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800735
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400736 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800737 doc.Parse( test );
738
739 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
740 XMLTest( "Entity with one digit.",
741 text->Value(), "1.1 Start easy ignore fin thickness\n",
742 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400743 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800744
745 {
746 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700747 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800748 const char* doctype =
749 "<?xml version=\"1.0\" ?>"
750 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
751 "<!ELEMENT title (#PCDATA)>"
752 "<!ELEMENT books (title,authors)>"
753 "<element />";
754
755 XMLDocument doc;
756 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400757 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800758 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400759 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800760 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700761
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800762 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
763 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
764
765 }
766
767 {
768 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700769 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800770 "<!-- Somewhat<evil> -->";
771 XMLDocument doc;
772 doc.Parse( doctype );
773
774 XMLComment* comment = doc.FirstChild()->ToComment();
775
776 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
777 }
778 {
779 // Double attributes
780 const char* doctype = "<element attr='red' attr='blue' />";
781
782 XMLDocument doc;
783 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700784
Lee Thomason2fa81722012-11-09 12:37:46 -0800785 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 -0800786 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800787 }
788
789 {
790 // Embedded null in stream.
791 const char* doctype = "<element att\0r='red' attr='blue' />";
792
793 XMLDocument doc;
794 doc.Parse( doctype );
795 XMLTest( "Embedded null throws error.", true, doc.Error() );
796 }
797
798 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700799 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800800 const char* str = " ";
801 XMLDocument doc;
802 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -0800803 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800804 }
805
806 {
807 // Low entities
808 XMLDocument doc;
809 doc.Parse( "<test>&#x0e;</test>" );
810 const char result[] = { 0x0e, 0 };
811 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
812 doc.Print();
813 }
814
815 {
816 // Attribute values with trailing quotes not handled correctly
817 XMLDocument doc;
818 doc.Parse( "<foo attribute=bar\" />" );
819 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
820 }
821
822 {
823 // [ 1663758 ] Failure to report error on bad XML
824 XMLDocument xml;
825 xml.Parse("<x>");
826 XMLTest("Missing end tag at end of input", xml.Error(), true);
827 xml.Parse("<x> ");
828 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
829 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -0800830 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700831 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800832
833
834 {
835 // [ 1475201 ] TinyXML parses entities in comments
836 XMLDocument xml;
837 xml.Parse("<!-- declarations for <head> & <body> -->"
838 "<!-- far &amp; away -->" );
839
840 XMLNode* e0 = xml.FirstChild();
841 XMLNode* e1 = e0->NextSibling();
842 XMLComment* c0 = e0->ToComment();
843 XMLComment* c1 = e1->ToComment();
844
845 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
846 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
847 }
848
849 {
850 XMLDocument xml;
851 xml.Parse( "<Parent>"
852 "<child1 att=''/>"
853 "<!-- With this comment, child2 will not be parsed! -->"
854 "<child2 att=''/>"
855 "</Parent>" );
856 xml.Print();
857
858 int count = 0;
859
860 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
861 ele;
862 ele = ele->NextSibling() )
863 {
864 ++count;
865 }
866
867 XMLTest( "Comments iterate correctly.", 3, count );
868 }
869
870 {
871 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
872 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
873 buf[60] = 239;
874 buf[61] = 0;
875
876 XMLDocument doc;
877 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700878 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800879
880
881 {
882 // bug 1827248 Error while parsing a little bit malformed file
883 // Actually not malformed - should work.
884 XMLDocument xml;
885 xml.Parse( "<attributelist> </attributelist >" );
886 XMLTest( "Handle end tag whitespace", false, xml.Error() );
887 }
888
889 {
890 // This one must not result in an infinite loop
891 XMLDocument xml;
892 xml.Parse( "<infinite>loop" );
893 XMLTest( "Infinite loop test.", true, true );
894 }
895#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800896 {
897 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
898 XMLDocument doc;
899 doc.Parse( pub );
900
901 XMLDocument clone;
902 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
903 XMLNode* copy = node->ShallowClone( &clone );
904 clone.InsertEndChild( copy );
905 }
906
907 clone.Print();
908
909 int count=0;
910 const XMLNode* a=clone.FirstChild();
911 const XMLNode* b=doc.FirstChild();
912 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
913 ++count;
914 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
915 }
916 XMLTest( "Clone and Equal", 4, count );
917 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800918
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700919 {
920 // This shouldn't crash.
921 XMLDocument doc;
922 if(XML_NO_ERROR != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
923 {
924 doc.PrintError();
925 }
926 XMLTest( "Error in snprinf handling.", true, doc.Error() );
927 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700928
Lee Thomason5e3803c2012-04-16 08:57:05 -0700929 {
930 // Attribute ordering.
931 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
932 XMLDocument doc;
933 doc.Parse( xml );
934 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700935
Lee Thomason5e3803c2012-04-16 08:57:05 -0700936 const XMLAttribute* a = ele->FirstAttribute();
937 XMLTest( "Attribute order", "1", a->Value() );
938 a = a->Next();
939 XMLTest( "Attribute order", "2", a->Value() );
940 a = a->Next();
941 XMLTest( "Attribute order", "3", a->Value() );
942 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700943
Lee Thomason5e3803c2012-04-16 08:57:05 -0700944 ele->DeleteAttribute( "attrib2" );
945 a = ele->FirstAttribute();
946 XMLTest( "Attribute order", "1", a->Value() );
947 a = a->Next();
948 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700949
Lee Thomason5e3803c2012-04-16 08:57:05 -0700950 ele->DeleteAttribute( "attrib1" );
951 ele->DeleteAttribute( "attrib3" );
952 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
953 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700954
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700955 {
956 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -0700957 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
958 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
959 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
960 XMLDocument doc0;
961 doc0.Parse( xml0 );
962 XMLDocument doc1;
963 doc1.Parse( xml1 );
964 XMLDocument doc2;
965 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700966
Lee Thomason78a773d2012-07-02 10:10:19 -0700967 XMLElement* ele = 0;
968 ele = doc0.FirstChildElement();
969 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
970 ele = doc1.FirstChildElement();
971 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
972 ele = doc2.FirstChildElement();
973 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700974 }
975
976 {
977 // Make sure we don't go into an infinite loop.
978 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
979 XMLDocument doc;
980 doc.Parse( xml );
981 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
982 XMLElement* ele1 = ele0->NextSiblingElement();
983 bool equal = ele0->ShallowEqual( ele1 );
984
985 XMLTest( "Infinite loop in shallow equal.", true, equal );
986 }
987
Lee Thomason5708f812012-03-28 17:46:41 -0700988 // -------- Handles ------------
989 {
990 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
991 XMLDocument doc;
992 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -0700993
994 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
995 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
996
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -0700997 XMLHandle docH( doc );
998 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -0700999 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001000 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001001
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001002 {
1003 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1004 XMLDocument doc;
1005 doc.Parse( xml );
1006 XMLConstHandle docH( doc );
1007
1008 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1009 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1010
1011 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001012 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001013 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001014 {
1015 // Default Declaration & BOM
1016 XMLDocument doc;
1017 doc.InsertEndChild( doc.NewDeclaration() );
1018 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001019
Lee Thomasonf68c4382012-04-28 14:37:11 -07001020 XMLPrinter printer;
1021 doc.Print( &printer );
1022
1023 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1024 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001025 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001026 }
Lee Thomason21be8822012-07-15 17:27:22 -07001027 {
1028 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1029 XMLDocument doc;
1030 doc.Parse( xml );
1031 XMLTest( "Ill formed XML", true, doc.Error() );
1032 }
1033
1034 // QueryXYZText
1035 {
1036 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1037 XMLDocument doc;
1038 doc.Parse( xml );
1039
1040 const XMLElement* pointElement = doc.RootElement();
1041
1042 int intValue = 0;
1043 unsigned unsignedValue = 0;
1044 float floatValue = 0;
1045 double doubleValue = 0;
1046 bool boolValue = false;
1047
1048 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1049 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1050 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1051 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1052 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1053
1054
1055 XMLTest( "QueryIntText", intValue, 1, false );
1056 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1057 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1058 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1059 XMLTest( "QueryBoolText", boolValue, true, false );
1060 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001061
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001062 {
1063 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1064 XMLDocument doc;
1065 doc.Parse( xml );
1066 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1067 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001068
1069 {
1070 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1071 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001072 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001073 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1074 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001075
1076 {
1077 const char* xml = "<3lement></3lement>";
1078 XMLDocument doc;
1079 doc.Parse( xml );
1080 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1081 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001082
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001083 {
1084 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1085 XMLDocument doc;
1086 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001087 XMLTest( "Set length of incoming data", doc.Error(), false );
1088 }
1089
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001090 {
1091 XMLDocument doc;
1092 doc.LoadFile( "resources/dream.xml" );
1093 doc.Clear();
1094 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1095 }
1096
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001097 // ----------- Whitespace ------------
1098 {
1099 const char* xml = "<element>"
1100 "<a> This \nis &apos; text &apos; </a>"
1101 "<b> This is &apos; text &apos; \n</b>"
1102 "<c>This is &apos; \n\n text &apos;</c>"
1103 "</element>";
1104 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1105 doc.Parse( xml );
1106
1107 const XMLElement* element = doc.FirstChildElement();
1108 for( const XMLElement* parent = element->FirstChildElement();
1109 parent;
1110 parent = parent->NextSiblingElement() )
1111 {
1112 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1113 }
1114 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001115
Lee Thomasonae9ab072012-10-24 10:17:53 -07001116#if 0
1117 {
1118 // Passes if assert doesn't fire.
1119 XMLDocument xmlDoc;
1120
1121 xmlDoc.NewDeclaration();
1122 xmlDoc.NewComment("Configuration file");
1123
1124 XMLElement *root = xmlDoc.NewElement("settings");
1125 root->SetAttribute("version", 2);
1126 }
1127#endif
1128
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001129 {
1130 const char* xml = "<element> </element>";
1131 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1132 doc.Parse( xml );
1133 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1134 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001135
Lee Thomason (grinliz)fc6320e2012-09-23 20:25:50 -07001136#if 0 // the question being explored is what kind of print to use:
1137 // https://github.com/leethomason/tinyxml2/issues/63
1138 {
1139 const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9'/>";
1140 XMLDocument doc;
1141 doc.Parse( xml );
1142 doc.FirstChildElement()->SetAttribute( "attrA", 123456789.123456789 );
1143 doc.FirstChildElement()->SetAttribute( "attrB", 1.001e9 );
1144 doc.Print();
1145 }
1146#endif
1147
Lee Thomason5b0a6772012-11-19 13:54:42 -08001148 {
1149 // An assert should not fire.
1150 const char* xml = "<element/>";
1151 XMLDocument doc;
1152 doc.Parse( xml );
1153 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1154 XMLTest( "Tracking unused elements", true, ele != 0, false );
1155 }
1156
Lee Thomasona6412ac2012-12-13 15:39:11 -08001157
1158 {
1159 const char* xml = "<parent><child>abc</child></parent>";
1160 XMLDocument doc;
1161 doc.Parse( xml );
1162 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1163
1164 XMLPrinter printer;
1165 ele->Accept( &printer );
1166 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1167 }
1168
1169
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001170 {
1171 XMLDocument doc;
1172 XMLError error = doc.LoadFile( "resources/empty.xml" );
1173 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
1174 }
1175
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001176 {
1177 // BOM preservation
1178 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1179 {
1180 XMLDocument doc;
1181 XMLTest( "BOM preservation (parse)", XML_NO_ERROR, doc.Parse( xml_bom_preservation ), false );
1182 XMLPrinter printer;
1183 doc.Print( &printer );
1184
1185 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1186 doc.SaveFile( "resources/bomtest.xml" );
1187 }
1188 {
1189 XMLDocument doc;
1190 doc.LoadFile( "resources/bomtest.xml" );
1191 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1192
1193 XMLPrinter printer;
1194 doc.Print( &printer );
1195 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1196 }
1197 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001198
Lee Thomason6f381b72012-03-02 12:59:39 -08001199 // ----------- Performance tracking --------------
1200 {
1201#if defined( _MSC_VER )
1202 __int64 start, end, freq;
1203 QueryPerformanceFrequency( (LARGE_INTEGER*) &freq );
1204#endif
1205
Bruno Diasa2d4e6e2012-05-07 04:58:11 -03001206 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason6f381b72012-03-02 12:59:39 -08001207 fseek( fp, 0, SEEK_END );
1208 long size = ftell( fp );
1209 fseek( fp, 0, SEEK_SET );
1210
1211 char* mem = new char[size+1];
1212 fread( mem, size, 1, fp );
1213 fclose( fp );
1214 mem[size] = 0;
1215
1216#if defined( _MSC_VER )
1217 QueryPerformanceCounter( (LARGE_INTEGER*) &start );
1218#else
1219 clock_t cstart = clock();
1220#endif
1221 static const int COUNT = 10;
1222 for( int i=0; i<COUNT; ++i ) {
1223 XMLDocument doc;
1224 doc.Parse( mem );
1225 }
1226#if defined( _MSC_VER )
1227 QueryPerformanceCounter( (LARGE_INTEGER*) &end );
1228#else
1229 clock_t cend = clock();
1230#endif
1231
1232 delete [] mem;
1233
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001234 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001235#ifdef DEBUG
1236 "DEBUG";
1237#else
1238 "Release";
1239#endif
1240
1241#if defined( _MSC_VER )
1242 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end-start) / ( (double)freq * (double)COUNT) );
1243#else
1244 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart)/(double)COUNT );
1245#endif
1246 }
1247
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001248 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001249 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001250 //_CrtMemDumpStatistics( &endMemState );
1251
1252 _CrtMemState diffMemState;
1253 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1254 _CrtMemDumpStatistics( &diffMemState );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001255 //printf( "new total=%d\n", gNewTotal );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001256 #endif
1257
1258 printf ("\nPass %d, Fail %d\n", gPass, gFail);
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001259 return 0;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001260}