blob: c654348f9aa60cf3454af52c8987cbae7856fae7 [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
U-Stream\Lee09a11c52012-02-17 08:31:16 -080028bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true )
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
U-Stream\Lee09a11c52012-02-17 08:31:16 -080036 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080037 printf (" %s\n", testString);
38 else
39 printf (" %s [%s][%s]\n", testString, expected, found);
40
41 if ( pass )
42 ++gPass;
43 else
44 ++gFail;
45 return pass;
46}
47
48
Lee Thomason21be8822012-07-15 17:27:22 -070049template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080050{
51 bool pass = ( expected == found );
52 if ( pass )
53 printf ("[pass]");
54 else
55 printf ("[fail]");
56
U-Stream\Lee09a11c52012-02-17 08:31:16 -080057 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080058 printf (" %s\n", testString);
59 else
Lee Thomasonc8312792012-07-16 12:44:41 -070060 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080061
62 if ( pass )
63 ++gPass;
64 else
65 ++gFail;
66 return pass;
67}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080068
U-Lama\Leee13c3e62011-12-28 14:36:55 -080069
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080070void NullLineEndings( char* p )
71{
72 while( p && *p ) {
73 if ( *p == '\n' || *p == '\r' ) {
74 *p = 0;
75 return;
76 }
77 ++p;
78 }
79}
80
81
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070082int example_1()
83{
84 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -030085 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070086
87 return doc.ErrorID();
88}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +020089/** @page Example-1 Load an XML File
90 * @dontinclude ./xmltest.cpp
91 * Basic XML file loading.
92 * The basic syntax to load an XML file from
93 * disk and check for an error. (ErrorID()
94 * will return 0 for no error.)
95 * @skip example_1()
96 * @until }
97 */
98
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070099
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700100int example_2()
101{
102 static const char* xml = "<element/>";
103 XMLDocument doc;
104 doc.Parse( xml );
105
106 return doc.ErrorID();
107}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200108/** @page Example-2 Parse an XML from char buffer
109 * @dontinclude ./xmltest.cpp
110 * Basic XML string parsing.
111 * The basic syntax to parse an XML for
112 * a char* and check for an error. (ErrorID()
113 * will return 0 for no error.)
114 * @skip example_2()
115 * @until }
116 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700117
118
119int example_3()
120{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700121 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700122 "<?xml version=\"1.0\"?>"
123 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
124 "<PLAY>"
125 "<TITLE>A Midsummer Night's Dream</TITLE>"
126 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700127
128 XMLDocument doc;
129 doc.Parse( xml );
130
131 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
132 const char* title = titleElement->GetText();
133 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700134
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700135 XMLText* textNode = titleElement->FirstChild()->ToText();
136 title = textNode->Value();
137 printf( "Name of play (2): %s\n", title );
138
139 return doc.ErrorID();
140}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200141/** @page Example-3 Get information out of XML
142 @dontinclude ./xmltest.cpp
143 In this example, we navigate a simple XML
144 file, and read some interesting text. Note
145 that this is examlpe doesn't use error
146 checking; working code should check for null
147 pointers when walking an XML tree, or use
148 XMLHandle.
149
150 (The XML is an excerpt from "dream.xml").
151
152 @skip example_3()
153 @until </PLAY>";
154
155 The structure of the XML file is:
156
157 <ul>
158 <li>(declaration)</li>
159 <li>(dtd stuff)</li>
160 <li>Element "PLAY"</li>
161 <ul>
162 <li>Element "TITLE"</li>
163 <ul>
164 <li>Text "A Midsummer Night's Dream"</li>
165 </ul>
166 </ul>
167 </ul>
168
169 For this example, we want to print out the
170 title of the play. The text of the title (what
171 we want) is child of the "TITLE" element which
172 is a child of the "PLAY" element.
173
174 We want to skip the declaration and dtd, so the
175 method FirstChildElement() is a good choice. The
176 FirstChildElement() of the Document is the "PLAY"
177 Element, the FirstChildElement() of the "PLAY" Element
178 is the "TITLE" Element.
179
180 @until ( "TITLE" );
181
182 We can then use the convenience function GetText()
183 to get the title of the play.
184
185 @until title );
186
187 Text is just another Node in the XML DOM. And in
188 fact you should be a little cautious with it, as
189 text nodes can contain elements.
190
191 @verbatim
192 Consider: A Midsummer Night's <b>Dream</b>
193 @endverbatim
194
195 It is more correct to actually query the Text Node
196 if in doubt:
197
198 @until title );
199
200 Noting that here we use FirstChild() since we are
201 looking for XMLText, not an element, and ToText()
202 is a cast from a Node to a XMLText.
203*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700204
205
Lee Thomason21be8822012-07-15 17:27:22 -0700206bool example_4()
207{
208 static const char* xml =
209 "<information>"
210 " <attributeApproach v='2' />"
211 " <textApproach>"
212 " <v>2</v>"
213 " </textApproach>"
214 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700215
Lee Thomason21be8822012-07-15 17:27:22 -0700216 XMLDocument doc;
217 doc.Parse( xml );
218
219 int v0 = 0;
220 int v1 = 0;
221
222 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
223 attributeApproachElement->QueryIntAttribute( "v", &v0 );
224
225 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
226 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
227
228 printf( "Both values are the same: %d and %d\n", v0, v1 );
229
230 return !doc.Error() && ( v0 == v1 );
231}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200232/** @page Example-4 Read attributes and text information.
233 @dontinclude ./xmltest.cpp
234
235 There are fundamentally 2 ways of writing a key-value
236 pair into an XML file. (Something that's always annoyed
237 me about XML.) Either by using attributes, or by writing
238 the key name into an element and the value into
239 the text node wrapped by the element. Both approaches
240 are illustrated in this example, which shows two ways
241 to encode the value "2" into the key "v":
242
243 @skip example_4()
244 @until "</information>";
245
246 TinyXML-2 has accessors for both approaches.
247
248 When using an attribute, you navigate to the XMLElement
249 with that attribute and use the QueryIntAttribute()
250 group of methods. (Also QueryFloatAttribute(), etc.)
251
252 @skip XMLElement* attributeApproachElement
253 @until &v0 );
254
255 When using the text approach, you need to navigate
256 down one more step to the XMLElement that contains
257 the text. Note the extra FirstChildElement( "v" )
258 in the code below. The value of the text can then
259 be safely queried with the QueryIntText() group
260 of methods. (Also QueryFloatText(), etc.)
261
262 @skip XMLElement* textApproachElement
263 @until &v1 );
264*/
Lee Thomason21be8822012-07-15 17:27:22 -0700265
266
Lee Thomason178e4cc2013-01-25 16:19:05 -0800267int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800268{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800269 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800270 _CrtMemCheckpoint( &startMemState );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700271 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800272
Martinsh Shaiters39ddc262013-01-15 21:53:08 +0200273 #if defined(_MSC_VER) || defined(MINGW32) || defined(__MINGW32__)
Lee Thomasone9699e62012-07-25 12:24:23 -0700274 _mkdir( "resources/out/" );
275 #else
276 mkdir( "resources/out/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
277 #endif
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400278
Lee Thomason178e4cc2013-01-25 16:19:05 -0800279 if ( argc > 1 ) {
280 XMLDocument* doc = new XMLDocument();
281 clock_t startTime = clock();
282 doc->LoadFile( argv[1] );
283 clock_t loadTime = clock();
284 int errorID = doc->ErrorID();
285 delete doc; doc = 0;
286 clock_t deleteTime = clock();
287
288 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
289 if ( !errorID ) {
290 printf( "Load time=%d\n", loadTime - startTime );
291 printf( "Delete time=%d\n", deleteTime - loadTime );
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -0800292 printf( "Total time=%d\n", deleteTime - startTime );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800293 }
294 exit(0);
295 }
296
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300297 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700298 if ( !fp ) {
299 printf( "Error opening test file 'dream.xml'.\n"
300 "Is your working directory the same as where \n"
301 "the xmltest.cpp and dream.xml file are?\n\n"
302 #if defined( _MSC_VER )
303 "In windows Visual Studio you may need to set\n"
304 "Properties->Debugging->Working Directory to '..'\n"
305 #endif
306 );
307 exit( 1 );
308 }
309 fclose( fp );
310
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700311 XMLTest( "Example-1", 0, example_1() );
312 XMLTest( "Example-2", 0, example_2() );
313 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700314 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700315
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700316 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700317
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800318 {
Lee Thomason43f59302012-02-06 18:18:11 -0800319 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400320 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800321 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400322 "<element><subelement></subelement></element>",
323 "<element><subelement><subsub/></subelement></element>",
324 "<!--comment beside elements--><element><subelement></subelement></element>",
325 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
326 "<element attrib1='foo' attrib2=\"bar\" ></element>",
327 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800328 "<element>Text inside element.</element>",
329 "<element><b></b></element>",
330 "<element>Text inside and <b>bolded</b> in the element.</element>",
331 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800332 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800333 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800334 0
335 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800336 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800337 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800338 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800339 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800340 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800341 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800342 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800343#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800344 {
345 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400346 " line 2\r"
347 " line 3\r\n"
348 " line 4\n\r"
349 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800350
351 XMLDocument doc;
352 doc.Parse( test );
353 doc.Print();
354 }
355
Lee Thomason2c85a712012-01-31 08:24:24 -0800356 {
357 static const char* test = "<element>Text before.</element>";
358 XMLDocument doc;
359 doc.Parse( test );
360 XMLElement* root = doc.FirstChildElement();
361 XMLElement* newElement = doc.NewElement( "Subelement" );
362 root->InsertEndChild( newElement );
363 doc.Print();
364 }
Lee Thomasond1983222012-02-06 08:41:24 -0800365 {
366 XMLDocument* doc = new XMLDocument();
367 static const char* test = "<element><sub/></element>";
368 doc->Parse( test );
369 delete doc;
370 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800371 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800372 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800373 // Build:
374 // <element>
375 // <!--comment-->
376 // <sub attrib="1" />
377 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800378 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800379 // <element>
380
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800381 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800382 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
383
384 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
385 for( int i=0; i<3; ++i ) {
386 sub[i]->SetAttribute( "attrib", i );
387 }
388 element->InsertEndChild( sub[2] );
389 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
390 element->InsertAfterChild( comment, sub[0] );
391 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800392 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800393 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800394 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
395 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
396 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700397 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800398 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800399
400 // And now deletion:
401 element->DeleteChild( sub[2] );
402 doc->DeleteNode( comment );
403
404 element->FirstChildElement()->SetAttribute( "attrib", true );
405 element->LastChildElement()->DeleteAttribute( "attrib" );
406
407 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
408 int value = 10;
409 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );
Lee Thomason21be8822012-07-15 17:27:22 -0700410 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800411 XMLTest( "Programmatic DOM", value, 10 );
412
413 doc->Print();
414
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700415 {
416 XMLPrinter streamer;
417 doc->Print( &streamer );
418 printf( "%s", streamer.CStr() );
419 }
420 {
421 XMLPrinter streamer( 0, true );
422 doc->Print( &streamer );
423 XMLTest( "Compact mode", "<element><sub attrib=\"1\"/><sub/></element>", streamer.CStr(), false );
424 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700425 doc->SaveFile( "./resources/out/pretty.xml" );
426 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800427 delete doc;
428 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800429 {
430 // Test: Dream
431 // XML1 : 1,187,569 bytes in 31,209 allocations
432 // XML2 : 469,073 bytes in 323 allocations
433 //int newStart = gNew;
434 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300435 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800436
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400437 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800438 doc.PrintError();
439
440 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400441 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800442 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
443 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
444 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
445 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400446 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800447 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400448 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800449
450 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400451 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800452 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400453 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800454 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
455 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
456 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
457 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400458 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800459
460 //gNewTotal = gNew - newStart;
461 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800462
463
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800464 {
465 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
466 "<passages count=\"006\" formatversion=\"20020620\">\n"
467 " <wrong error>\n"
468 "</passages>";
469
470 XMLDocument doc;
471 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800472 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800473 }
474
475 {
476 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
477
478 XMLDocument doc;
479 doc.Parse( str );
480
481 XMLElement* ele = doc.FirstChildElement();
482
483 int iVal, result;
484 double dVal;
485
486 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700487 XMLTest( "Query attribute: int as double", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800488 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
489 result = ele->QueryDoubleAttribute( "attr1", &dVal );
490 XMLTest( "Query attribute: double as double", (int)dVal, 2 );
491 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700492 XMLTest( "Query attribute: double as int", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800493 XMLTest( "Query attribute: double as int", iVal, 2 );
494 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700495 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800496 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700497 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800498 }
499
500 {
501 const char* str = "<doc/>";
502
503 XMLDocument doc;
504 doc.Parse( str );
505
506 XMLElement* ele = doc.FirstChildElement();
507
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800508 int iVal, iVal2;
509 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800510
511 ele->SetAttribute( "str", "strValue" );
512 ele->SetAttribute( "int", 1 );
513 ele->SetAttribute( "double", -1.0 );
514
515 const char* cStr = ele->Attribute( "str" );
516 ele->QueryIntAttribute( "int", &iVal );
517 ele->QueryDoubleAttribute( "double", &dVal );
518
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800519 ele->QueryAttribute( "int", &iVal2 );
520 ele->QueryAttribute( "double", &dVal2 );
521
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700522 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800523 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
524 XMLTest( "Attribute round trip. int.", 1, iVal );
525 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800526 XMLTest( "Alternate query", true, iVal == iVal2 );
527 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800528 }
529
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800530 {
531 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300532 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800533
534 // Get the attribute "value" from the "Russian" element and check it.
535 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700536 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800537 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
538
539 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
540
541 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
542 0xd1U, 0x81U, 0xd1U, 0x81U,
543 0xd0U, 0xbaU, 0xd0U, 0xb8U,
544 0xd0U, 0xb9U, 0 };
545 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
546
547 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
548 XMLTest( "UTF-8: Browsing russian element name.",
549 russianText,
550 text->Value() );
551
552 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400553 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800554
555 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800556 int okay = 0;
557
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200558 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300559 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800560
561 if ( saved && verify )
562 {
563 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700564 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800565 while ( fgets( verifyBuf, 256, verify ) )
566 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700567 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800568 fgets( savedBuf, 256, saved );
569 NullLineEndings( verifyBuf );
570 NullLineEndings( savedBuf );
571
572 if ( strcmp( verifyBuf, savedBuf ) )
573 {
574 printf( "verify:%s<\n", verifyBuf );
575 printf( "saved :%s<\n", savedBuf );
576 okay = 0;
577 break;
578 }
579 }
580 }
581 if ( saved )
582 fclose( saved );
583 if ( verify )
584 fclose( verify );
585 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
586 }
587
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800588 // --------GetText()-----------
589 {
590 const char* str = "<foo>This is text</foo>";
591 XMLDocument doc;
592 doc.Parse( str );
593 const XMLElement* element = doc.RootElement();
594
595 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
596
597 str = "<foo><b>This is text</b></foo>";
598 doc.Parse( str );
599 element = doc.RootElement();
600
601 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
602 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800603
Lee Thomasond6277762012-02-22 16:00:12 -0800604
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800605 // ---------- CDATA ---------------
606 {
607 const char* str = "<xmlElement>"
608 "<![CDATA["
609 "I am > the rules!\n"
610 "...since I make symbolic puns"
611 "]]>"
612 "</xmlElement>";
613 XMLDocument doc;
614 doc.Parse( str );
615 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800616
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700617 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800618 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800619 false );
620 }
621
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800622 // ----------- CDATA -------------
623 {
624 const char* str = "<xmlElement>"
625 "<![CDATA["
626 "<b>I am > the rules!</b>\n"
627 "...since I make symbolic puns"
628 "]]>"
629 "</xmlElement>";
630 XMLDocument doc;
631 doc.Parse( str );
632 doc.Print();
633
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700634 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800635 "<b>I am > the rules!</b>\n...since I make symbolic puns",
636 false );
637 }
638
639 // InsertAfterChild causes crash.
640 {
641 // InsertBeforeChild and InsertAfterChild causes crash.
642 XMLDocument doc;
643 XMLElement* parent = doc.NewElement( "Parent" );
644 doc.InsertFirstChild( parent );
645
646 XMLElement* childText0 = doc.NewElement( "childText0" );
647 XMLElement* childText1 = doc.NewElement( "childText1" );
648
649 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
650 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
651
652 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
653 }
Lee Thomasond6277762012-02-22 16:00:12 -0800654
655 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800656 // Entities not being written correctly.
657 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800658
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800659 const char* passages =
660 "<?xml version=\"1.0\" standalone=\"no\" ?>"
661 "<passages count=\"006\" formatversion=\"20020620\">"
662 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
663 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
664 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800665
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800666 XMLDocument doc;
667 doc.Parse( passages );
668 XMLElement* psg = doc.RootElement()->FirstChildElement();
669 const char* context = psg->Attribute( "context" );
670 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 -0800671
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800672 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800673
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400674 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800675 if ( textfile )
676 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800677 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800678 psg->Accept( &streamer );
679 fclose( textfile );
680 }
Thomas Roß0922b732012-09-23 16:31:22 +0200681
682 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800683 TIXMLASSERT( textfile );
684 if ( textfile )
685 {
686 char buf[ 1024 ];
687 fgets( buf, 1024, textfile );
688 XMLTest( "Entity transformation: write. ",
689 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
690 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
691 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700692 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800693 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800694 }
695
696 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800697 // Suppress entities.
698 const char* passages =
699 "<?xml version=\"1.0\" standalone=\"no\" ?>"
700 "<passages count=\"006\" formatversion=\"20020620\">"
701 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
702 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700703
Lee Thomason6f381b72012-03-02 12:59:39 -0800704 XMLDocument doc( false );
705 doc.Parse( passages );
706
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700707 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800708 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
709 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
710 "Crazy &ttk;" );
711 doc.Print();
712 }
713
714 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400715 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800716
717 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400718 doc.Parse( test );
719 XMLTest( "dot in names", doc.Error(), false );
720 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
721 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800722 }
723
724 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400725 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800726
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400727 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800728 doc.Parse( test );
729
730 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
731 XMLTest( "Entity with one digit.",
732 text->Value(), "1.1 Start easy ignore fin thickness\n",
733 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400734 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800735
736 {
737 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700738 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800739 const char* doctype =
740 "<?xml version=\"1.0\" ?>"
741 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
742 "<!ELEMENT title (#PCDATA)>"
743 "<!ELEMENT books (title,authors)>"
744 "<element />";
745
746 XMLDocument doc;
747 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400748 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800749 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400750 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800751 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700752
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800753 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
754 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
755
756 }
757
758 {
759 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700760 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800761 "<!-- Somewhat<evil> -->";
762 XMLDocument doc;
763 doc.Parse( doctype );
764
765 XMLComment* comment = doc.FirstChild()->ToComment();
766
767 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
768 }
769 {
770 // Double attributes
771 const char* doctype = "<element attr='red' attr='blue' />";
772
773 XMLDocument doc;
774 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700775
Lee Thomason2fa81722012-11-09 12:37:46 -0800776 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 -0800777 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800778 }
779
780 {
781 // Embedded null in stream.
782 const char* doctype = "<element att\0r='red' attr='blue' />";
783
784 XMLDocument doc;
785 doc.Parse( doctype );
786 XMLTest( "Embedded null throws error.", true, doc.Error() );
787 }
788
789 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700790 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800791 const char* str = " ";
792 XMLDocument doc;
793 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -0800794 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800795 }
796
797 {
798 // Low entities
799 XMLDocument doc;
800 doc.Parse( "<test>&#x0e;</test>" );
801 const char result[] = { 0x0e, 0 };
802 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
803 doc.Print();
804 }
805
806 {
807 // Attribute values with trailing quotes not handled correctly
808 XMLDocument doc;
809 doc.Parse( "<foo attribute=bar\" />" );
810 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
811 }
812
813 {
814 // [ 1663758 ] Failure to report error on bad XML
815 XMLDocument xml;
816 xml.Parse("<x>");
817 XMLTest("Missing end tag at end of input", xml.Error(), true);
818 xml.Parse("<x> ");
819 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
820 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -0800821 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700822 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800823
824
825 {
826 // [ 1475201 ] TinyXML parses entities in comments
827 XMLDocument xml;
828 xml.Parse("<!-- declarations for <head> & <body> -->"
829 "<!-- far &amp; away -->" );
830
831 XMLNode* e0 = xml.FirstChild();
832 XMLNode* e1 = e0->NextSibling();
833 XMLComment* c0 = e0->ToComment();
834 XMLComment* c1 = e1->ToComment();
835
836 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
837 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
838 }
839
840 {
841 XMLDocument xml;
842 xml.Parse( "<Parent>"
843 "<child1 att=''/>"
844 "<!-- With this comment, child2 will not be parsed! -->"
845 "<child2 att=''/>"
846 "</Parent>" );
847 xml.Print();
848
849 int count = 0;
850
851 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
852 ele;
853 ele = ele->NextSibling() )
854 {
855 ++count;
856 }
857
858 XMLTest( "Comments iterate correctly.", 3, count );
859 }
860
861 {
862 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
863 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
864 buf[60] = 239;
865 buf[61] = 0;
866
867 XMLDocument doc;
868 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700869 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800870
871
872 {
873 // bug 1827248 Error while parsing a little bit malformed file
874 // Actually not malformed - should work.
875 XMLDocument xml;
876 xml.Parse( "<attributelist> </attributelist >" );
877 XMLTest( "Handle end tag whitespace", false, xml.Error() );
878 }
879
880 {
881 // This one must not result in an infinite loop
882 XMLDocument xml;
883 xml.Parse( "<infinite>loop" );
884 XMLTest( "Infinite loop test.", true, true );
885 }
886#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800887 {
888 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
889 XMLDocument doc;
890 doc.Parse( pub );
891
892 XMLDocument clone;
893 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
894 XMLNode* copy = node->ShallowClone( &clone );
895 clone.InsertEndChild( copy );
896 }
897
898 clone.Print();
899
900 int count=0;
901 const XMLNode* a=clone.FirstChild();
902 const XMLNode* b=doc.FirstChild();
903 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
904 ++count;
905 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
906 }
907 XMLTest( "Clone and Equal", 4, count );
908 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800909
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700910 {
911 // This shouldn't crash.
912 XMLDocument doc;
913 if(XML_NO_ERROR != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
914 {
915 doc.PrintError();
916 }
917 XMLTest( "Error in snprinf handling.", true, doc.Error() );
918 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700919
Lee Thomason5e3803c2012-04-16 08:57:05 -0700920 {
921 // Attribute ordering.
922 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
923 XMLDocument doc;
924 doc.Parse( xml );
925 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700926
Lee Thomason5e3803c2012-04-16 08:57:05 -0700927 const XMLAttribute* a = ele->FirstAttribute();
928 XMLTest( "Attribute order", "1", a->Value() );
929 a = a->Next();
930 XMLTest( "Attribute order", "2", a->Value() );
931 a = a->Next();
932 XMLTest( "Attribute order", "3", a->Value() );
933 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700934
Lee Thomason5e3803c2012-04-16 08:57:05 -0700935 ele->DeleteAttribute( "attrib2" );
936 a = ele->FirstAttribute();
937 XMLTest( "Attribute order", "1", a->Value() );
938 a = a->Next();
939 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700940
Lee Thomason5e3803c2012-04-16 08:57:05 -0700941 ele->DeleteAttribute( "attrib1" );
942 ele->DeleteAttribute( "attrib3" );
943 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
944 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700945
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700946 {
947 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -0700948 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
949 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
950 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
951 XMLDocument doc0;
952 doc0.Parse( xml0 );
953 XMLDocument doc1;
954 doc1.Parse( xml1 );
955 XMLDocument doc2;
956 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700957
Lee Thomason78a773d2012-07-02 10:10:19 -0700958 XMLElement* ele = 0;
959 ele = doc0.FirstChildElement();
960 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
961 ele = doc1.FirstChildElement();
962 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
963 ele = doc2.FirstChildElement();
964 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700965 }
966
967 {
968 // Make sure we don't go into an infinite loop.
969 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
970 XMLDocument doc;
971 doc.Parse( xml );
972 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
973 XMLElement* ele1 = ele0->NextSiblingElement();
974 bool equal = ele0->ShallowEqual( ele1 );
975
976 XMLTest( "Infinite loop in shallow equal.", true, equal );
977 }
978
Lee Thomason5708f812012-03-28 17:46:41 -0700979 // -------- Handles ------------
980 {
981 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
982 XMLDocument doc;
983 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -0700984
985 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
986 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
987
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -0700988 XMLHandle docH( doc );
989 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -0700990 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -0700991 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700992
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -0700993 {
994 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
995 XMLDocument doc;
996 doc.Parse( xml );
997 XMLConstHandle docH( doc );
998
999 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1000 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1001
1002 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001003 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001004 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001005 {
1006 // Default Declaration & BOM
1007 XMLDocument doc;
1008 doc.InsertEndChild( doc.NewDeclaration() );
1009 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001010
Lee Thomasonf68c4382012-04-28 14:37:11 -07001011 XMLPrinter printer;
1012 doc.Print( &printer );
1013
1014 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1015 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001016 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001017 }
Lee Thomason21be8822012-07-15 17:27:22 -07001018 {
1019 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1020 XMLDocument doc;
1021 doc.Parse( xml );
1022 XMLTest( "Ill formed XML", true, doc.Error() );
1023 }
1024
1025 // QueryXYZText
1026 {
1027 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1028 XMLDocument doc;
1029 doc.Parse( xml );
1030
1031 const XMLElement* pointElement = doc.RootElement();
1032
1033 int intValue = 0;
1034 unsigned unsignedValue = 0;
1035 float floatValue = 0;
1036 double doubleValue = 0;
1037 bool boolValue = false;
1038
1039 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1040 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1041 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1042 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1043 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1044
1045
1046 XMLTest( "QueryIntText", intValue, 1, false );
1047 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1048 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1049 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1050 XMLTest( "QueryBoolText", boolValue, true, false );
1051 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001052
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001053 {
1054 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1055 XMLDocument doc;
1056 doc.Parse( xml );
1057 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1058 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001059
1060 {
1061 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1062 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001063 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001064 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1065 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001066
1067 {
1068 const char* xml = "<3lement></3lement>";
1069 XMLDocument doc;
1070 doc.Parse( xml );
1071 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1072 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001073
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001074 {
1075 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1076 XMLDocument doc;
1077 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001078 XMLTest( "Set length of incoming data", doc.Error(), false );
1079 }
1080
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001081 {
1082 XMLDocument doc;
1083 doc.LoadFile( "resources/dream.xml" );
1084 doc.Clear();
1085 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1086 }
1087
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001088 // ----------- Whitespace ------------
1089 {
1090 const char* xml = "<element>"
1091 "<a> This \nis &apos; text &apos; </a>"
1092 "<b> This is &apos; text &apos; \n</b>"
1093 "<c>This is &apos; \n\n text &apos;</c>"
1094 "</element>";
1095 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1096 doc.Parse( xml );
1097
1098 const XMLElement* element = doc.FirstChildElement();
1099 for( const XMLElement* parent = element->FirstChildElement();
1100 parent;
1101 parent = parent->NextSiblingElement() )
1102 {
1103 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1104 }
1105 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001106
Lee Thomasonae9ab072012-10-24 10:17:53 -07001107#if 0
1108 {
1109 // Passes if assert doesn't fire.
1110 XMLDocument xmlDoc;
1111
1112 xmlDoc.NewDeclaration();
1113 xmlDoc.NewComment("Configuration file");
1114
1115 XMLElement *root = xmlDoc.NewElement("settings");
1116 root->SetAttribute("version", 2);
1117 }
1118#endif
1119
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001120 {
1121 const char* xml = "<element> </element>";
1122 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1123 doc.Parse( xml );
1124 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1125 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001126
Lee Thomason (grinliz)fc6320e2012-09-23 20:25:50 -07001127#if 0 // the question being explored is what kind of print to use:
1128 // https://github.com/leethomason/tinyxml2/issues/63
1129 {
1130 const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9'/>";
1131 XMLDocument doc;
1132 doc.Parse( xml );
1133 doc.FirstChildElement()->SetAttribute( "attrA", 123456789.123456789 );
1134 doc.FirstChildElement()->SetAttribute( "attrB", 1.001e9 );
1135 doc.Print();
1136 }
1137#endif
1138
Lee Thomason5b0a6772012-11-19 13:54:42 -08001139 {
1140 // An assert should not fire.
1141 const char* xml = "<element/>";
1142 XMLDocument doc;
1143 doc.Parse( xml );
1144 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1145 XMLTest( "Tracking unused elements", true, ele != 0, false );
1146 }
1147
Lee Thomasona6412ac2012-12-13 15:39:11 -08001148
1149 {
1150 const char* xml = "<parent><child>abc</child></parent>";
1151 XMLDocument doc;
1152 doc.Parse( xml );
1153 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1154
1155 XMLPrinter printer;
1156 ele->Accept( &printer );
1157 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1158 }
1159
1160
Lee Thomason6f381b72012-03-02 12:59:39 -08001161 // ----------- Performance tracking --------------
1162 {
1163#if defined( _MSC_VER )
1164 __int64 start, end, freq;
1165 QueryPerformanceFrequency( (LARGE_INTEGER*) &freq );
1166#endif
1167
Bruno Diasa2d4e6e2012-05-07 04:58:11 -03001168 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason6f381b72012-03-02 12:59:39 -08001169 fseek( fp, 0, SEEK_END );
1170 long size = ftell( fp );
1171 fseek( fp, 0, SEEK_SET );
1172
1173 char* mem = new char[size+1];
1174 fread( mem, size, 1, fp );
1175 fclose( fp );
1176 mem[size] = 0;
1177
1178#if defined( _MSC_VER )
1179 QueryPerformanceCounter( (LARGE_INTEGER*) &start );
1180#else
1181 clock_t cstart = clock();
1182#endif
1183 static const int COUNT = 10;
1184 for( int i=0; i<COUNT; ++i ) {
1185 XMLDocument doc;
1186 doc.Parse( mem );
1187 }
1188#if defined( _MSC_VER )
1189 QueryPerformanceCounter( (LARGE_INTEGER*) &end );
1190#else
1191 clock_t cend = clock();
1192#endif
1193
1194 delete [] mem;
1195
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001196 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001197#ifdef DEBUG
1198 "DEBUG";
1199#else
1200 "Release";
1201#endif
1202
1203#if defined( _MSC_VER )
1204 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end-start) / ( (double)freq * (double)COUNT) );
1205#else
1206 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart)/(double)COUNT );
1207#endif
1208 }
1209
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001210 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001211 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001212 //_CrtMemDumpStatistics( &endMemState );
1213
1214 _CrtMemState diffMemState;
1215 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1216 _CrtMemDumpStatistics( &diffMemState );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001217 //printf( "new total=%d\n", gNewTotal );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001218 #endif
1219
1220 printf ("\nPass %d, Fail %d\n", gPass, gFail);
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001221 return 0;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001222}