blob: 5f7cb300f03e8a26c6cab62a09b106a89e701653 [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 );
292 }
293 exit(0);
294 }
295
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300296 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700297 if ( !fp ) {
298 printf( "Error opening test file 'dream.xml'.\n"
299 "Is your working directory the same as where \n"
300 "the xmltest.cpp and dream.xml file are?\n\n"
301 #if defined( _MSC_VER )
302 "In windows Visual Studio you may need to set\n"
303 "Properties->Debugging->Working Directory to '..'\n"
304 #endif
305 );
306 exit( 1 );
307 }
308 fclose( fp );
309
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700310 XMLTest( "Example-1", 0, example_1() );
311 XMLTest( "Example-2", 0, example_2() );
312 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700313 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700314
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700315 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700316
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800317 {
Lee Thomason43f59302012-02-06 18:18:11 -0800318 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400319 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800320 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400321 "<element><subelement></subelement></element>",
322 "<element><subelement><subsub/></subelement></element>",
323 "<!--comment beside elements--><element><subelement></subelement></element>",
324 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
325 "<element attrib1='foo' attrib2=\"bar\" ></element>",
326 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800327 "<element>Text inside element.</element>",
328 "<element><b></b></element>",
329 "<element>Text inside and <b>bolded</b> in the element.</element>",
330 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800331 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800332 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800333 0
334 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800335 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800336 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800337 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800338 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800339 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800340 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800341 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800342#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800343 {
344 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400345 " line 2\r"
346 " line 3\r\n"
347 " line 4\n\r"
348 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800349
350 XMLDocument doc;
351 doc.Parse( test );
352 doc.Print();
353 }
354
Lee Thomason2c85a712012-01-31 08:24:24 -0800355 {
356 static const char* test = "<element>Text before.</element>";
357 XMLDocument doc;
358 doc.Parse( test );
359 XMLElement* root = doc.FirstChildElement();
360 XMLElement* newElement = doc.NewElement( "Subelement" );
361 root->InsertEndChild( newElement );
362 doc.Print();
363 }
Lee Thomasond1983222012-02-06 08:41:24 -0800364 {
365 XMLDocument* doc = new XMLDocument();
366 static const char* test = "<element><sub/></element>";
367 doc->Parse( test );
368 delete doc;
369 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800370 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800371 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800372 // Build:
373 // <element>
374 // <!--comment-->
375 // <sub attrib="1" />
376 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800377 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800378 // <element>
379
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800380 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800381 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
382
383 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
384 for( int i=0; i<3; ++i ) {
385 sub[i]->SetAttribute( "attrib", i );
386 }
387 element->InsertEndChild( sub[2] );
388 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
389 element->InsertAfterChild( comment, sub[0] );
390 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800391 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800392 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800393 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
394 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
395 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700396 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800397 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800398
399 // And now deletion:
400 element->DeleteChild( sub[2] );
401 doc->DeleteNode( comment );
402
403 element->FirstChildElement()->SetAttribute( "attrib", true );
404 element->LastChildElement()->DeleteAttribute( "attrib" );
405
406 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
407 int value = 10;
408 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );
Lee Thomason21be8822012-07-15 17:27:22 -0700409 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800410 XMLTest( "Programmatic DOM", value, 10 );
411
412 doc->Print();
413
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700414 {
415 XMLPrinter streamer;
416 doc->Print( &streamer );
417 printf( "%s", streamer.CStr() );
418 }
419 {
420 XMLPrinter streamer( 0, true );
421 doc->Print( &streamer );
422 XMLTest( "Compact mode", "<element><sub attrib=\"1\"/><sub/></element>", streamer.CStr(), false );
423 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700424 doc->SaveFile( "./resources/out/pretty.xml" );
425 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800426 delete doc;
427 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800428 {
429 // Test: Dream
430 // XML1 : 1,187,569 bytes in 31,209 allocations
431 // XML2 : 469,073 bytes in 323 allocations
432 //int newStart = gNew;
433 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300434 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800435
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400436 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800437 doc.PrintError();
438
439 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400440 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800441 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
442 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
443 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
444 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400445 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800446 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400447 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800448
449 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400450 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800451 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400452 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800453 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
454 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
455 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
456 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400457 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800458
459 //gNewTotal = gNew - newStart;
460 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800461
462
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800463 {
464 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
465 "<passages count=\"006\" formatversion=\"20020620\">\n"
466 " <wrong error>\n"
467 "</passages>";
468
469 XMLDocument doc;
470 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800471 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800472 }
473
474 {
475 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
476
477 XMLDocument doc;
478 doc.Parse( str );
479
480 XMLElement* ele = doc.FirstChildElement();
481
482 int iVal, result;
483 double dVal;
484
485 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700486 XMLTest( "Query attribute: int as double", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800487 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
488 result = ele->QueryDoubleAttribute( "attr1", &dVal );
489 XMLTest( "Query attribute: double as double", (int)dVal, 2 );
490 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700491 XMLTest( "Query attribute: double as int", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800492 XMLTest( "Query attribute: double as int", iVal, 2 );
493 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700494 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800495 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700496 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800497 }
498
499 {
500 const char* str = "<doc/>";
501
502 XMLDocument doc;
503 doc.Parse( str );
504
505 XMLElement* ele = doc.FirstChildElement();
506
507 int iVal;
508 double dVal;
509
510 ele->SetAttribute( "str", "strValue" );
511 ele->SetAttribute( "int", 1 );
512 ele->SetAttribute( "double", -1.0 );
513
514 const char* cStr = ele->Attribute( "str" );
515 ele->QueryIntAttribute( "int", &iVal );
516 ele->QueryDoubleAttribute( "double", &dVal );
517
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700518 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800519 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
520 XMLTest( "Attribute round trip. int.", 1, iVal );
521 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
522 }
523
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800524 {
525 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300526 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800527
528 // Get the attribute "value" from the "Russian" element and check it.
529 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700530 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800531 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
532
533 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
534
535 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
536 0xd1U, 0x81U, 0xd1U, 0x81U,
537 0xd0U, 0xbaU, 0xd0U, 0xb8U,
538 0xd0U, 0xb9U, 0 };
539 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
540
541 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
542 XMLTest( "UTF-8: Browsing russian element name.",
543 russianText,
544 text->Value() );
545
546 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400547 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800548
549 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550 int okay = 0;
551
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200552 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300553 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800554
555 if ( saved && verify )
556 {
557 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700558 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800559 while ( fgets( verifyBuf, 256, verify ) )
560 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700561 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800562 fgets( savedBuf, 256, saved );
563 NullLineEndings( verifyBuf );
564 NullLineEndings( savedBuf );
565
566 if ( strcmp( verifyBuf, savedBuf ) )
567 {
568 printf( "verify:%s<\n", verifyBuf );
569 printf( "saved :%s<\n", savedBuf );
570 okay = 0;
571 break;
572 }
573 }
574 }
575 if ( saved )
576 fclose( saved );
577 if ( verify )
578 fclose( verify );
579 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
580 }
581
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800582 // --------GetText()-----------
583 {
584 const char* str = "<foo>This is text</foo>";
585 XMLDocument doc;
586 doc.Parse( str );
587 const XMLElement* element = doc.RootElement();
588
589 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
590
591 str = "<foo><b>This is text</b></foo>";
592 doc.Parse( str );
593 element = doc.RootElement();
594
595 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
596 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800597
Lee Thomasond6277762012-02-22 16:00:12 -0800598
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800599 // ---------- CDATA ---------------
600 {
601 const char* str = "<xmlElement>"
602 "<![CDATA["
603 "I am > the rules!\n"
604 "...since I make symbolic puns"
605 "]]>"
606 "</xmlElement>";
607 XMLDocument doc;
608 doc.Parse( str );
609 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800610
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700611 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800612 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800613 false );
614 }
615
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800616 // ----------- CDATA -------------
617 {
618 const char* str = "<xmlElement>"
619 "<![CDATA["
620 "<b>I am > the rules!</b>\n"
621 "...since I make symbolic puns"
622 "]]>"
623 "</xmlElement>";
624 XMLDocument doc;
625 doc.Parse( str );
626 doc.Print();
627
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700628 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800629 "<b>I am > the rules!</b>\n...since I make symbolic puns",
630 false );
631 }
632
633 // InsertAfterChild causes crash.
634 {
635 // InsertBeforeChild and InsertAfterChild causes crash.
636 XMLDocument doc;
637 XMLElement* parent = doc.NewElement( "Parent" );
638 doc.InsertFirstChild( parent );
639
640 XMLElement* childText0 = doc.NewElement( "childText0" );
641 XMLElement* childText1 = doc.NewElement( "childText1" );
642
643 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
644 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
645
646 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
647 }
Lee Thomasond6277762012-02-22 16:00:12 -0800648
649 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800650 // Entities not being written correctly.
651 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800652
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800653 const char* passages =
654 "<?xml version=\"1.0\" standalone=\"no\" ?>"
655 "<passages count=\"006\" formatversion=\"20020620\">"
656 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
657 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
658 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800659
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800660 XMLDocument doc;
661 doc.Parse( passages );
662 XMLElement* psg = doc.RootElement()->FirstChildElement();
663 const char* context = psg->Attribute( "context" );
664 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 -0800665
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800666 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800667
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400668 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800669 if ( textfile )
670 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800671 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800672 psg->Accept( &streamer );
673 fclose( textfile );
674 }
Thomas Roß0922b732012-09-23 16:31:22 +0200675
676 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800677 TIXMLASSERT( textfile );
678 if ( textfile )
679 {
680 char buf[ 1024 ];
681 fgets( buf, 1024, textfile );
682 XMLTest( "Entity transformation: write. ",
683 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
684 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
685 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700686 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800687 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800688 }
689
690 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800691 // Suppress entities.
692 const char* passages =
693 "<?xml version=\"1.0\" standalone=\"no\" ?>"
694 "<passages count=\"006\" formatversion=\"20020620\">"
695 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
696 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700697
Lee Thomason6f381b72012-03-02 12:59:39 -0800698 XMLDocument doc( false );
699 doc.Parse( passages );
700
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700701 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800702 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
703 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
704 "Crazy &ttk;" );
705 doc.Print();
706 }
707
708 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400709 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800710
711 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400712 doc.Parse( test );
713 XMLTest( "dot in names", doc.Error(), false );
714 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
715 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800716 }
717
718 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400719 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800720
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400721 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800722 doc.Parse( test );
723
724 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
725 XMLTest( "Entity with one digit.",
726 text->Value(), "1.1 Start easy ignore fin thickness\n",
727 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400728 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800729
730 {
731 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700732 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800733 const char* doctype =
734 "<?xml version=\"1.0\" ?>"
735 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
736 "<!ELEMENT title (#PCDATA)>"
737 "<!ELEMENT books (title,authors)>"
738 "<element />";
739
740 XMLDocument doc;
741 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400742 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800743 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400744 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800745 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700746
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800747 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
748 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
749
750 }
751
752 {
753 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700754 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800755 "<!-- Somewhat<evil> -->";
756 XMLDocument doc;
757 doc.Parse( doctype );
758
759 XMLComment* comment = doc.FirstChild()->ToComment();
760
761 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
762 }
763 {
764 // Double attributes
765 const char* doctype = "<element attr='red' attr='blue' />";
766
767 XMLDocument doc;
768 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700769
Lee Thomason2fa81722012-11-09 12:37:46 -0800770 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 -0800771 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800772 }
773
774 {
775 // Embedded null in stream.
776 const char* doctype = "<element att\0r='red' attr='blue' />";
777
778 XMLDocument doc;
779 doc.Parse( doctype );
780 XMLTest( "Embedded null throws error.", true, doc.Error() );
781 }
782
783 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700784 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800785 const char* str = " ";
786 XMLDocument doc;
787 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -0800788 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800789 }
790
791 {
792 // Low entities
793 XMLDocument doc;
794 doc.Parse( "<test>&#x0e;</test>" );
795 const char result[] = { 0x0e, 0 };
796 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
797 doc.Print();
798 }
799
800 {
801 // Attribute values with trailing quotes not handled correctly
802 XMLDocument doc;
803 doc.Parse( "<foo attribute=bar\" />" );
804 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
805 }
806
807 {
808 // [ 1663758 ] Failure to report error on bad XML
809 XMLDocument xml;
810 xml.Parse("<x>");
811 XMLTest("Missing end tag at end of input", xml.Error(), true);
812 xml.Parse("<x> ");
813 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
814 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -0800815 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700816 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800817
818
819 {
820 // [ 1475201 ] TinyXML parses entities in comments
821 XMLDocument xml;
822 xml.Parse("<!-- declarations for <head> & <body> -->"
823 "<!-- far &amp; away -->" );
824
825 XMLNode* e0 = xml.FirstChild();
826 XMLNode* e1 = e0->NextSibling();
827 XMLComment* c0 = e0->ToComment();
828 XMLComment* c1 = e1->ToComment();
829
830 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
831 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
832 }
833
834 {
835 XMLDocument xml;
836 xml.Parse( "<Parent>"
837 "<child1 att=''/>"
838 "<!-- With this comment, child2 will not be parsed! -->"
839 "<child2 att=''/>"
840 "</Parent>" );
841 xml.Print();
842
843 int count = 0;
844
845 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
846 ele;
847 ele = ele->NextSibling() )
848 {
849 ++count;
850 }
851
852 XMLTest( "Comments iterate correctly.", 3, count );
853 }
854
855 {
856 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
857 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
858 buf[60] = 239;
859 buf[61] = 0;
860
861 XMLDocument doc;
862 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700863 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800864
865
866 {
867 // bug 1827248 Error while parsing a little bit malformed file
868 // Actually not malformed - should work.
869 XMLDocument xml;
870 xml.Parse( "<attributelist> </attributelist >" );
871 XMLTest( "Handle end tag whitespace", false, xml.Error() );
872 }
873
874 {
875 // This one must not result in an infinite loop
876 XMLDocument xml;
877 xml.Parse( "<infinite>loop" );
878 XMLTest( "Infinite loop test.", true, true );
879 }
880#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800881 {
882 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
883 XMLDocument doc;
884 doc.Parse( pub );
885
886 XMLDocument clone;
887 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
888 XMLNode* copy = node->ShallowClone( &clone );
889 clone.InsertEndChild( copy );
890 }
891
892 clone.Print();
893
894 int count=0;
895 const XMLNode* a=clone.FirstChild();
896 const XMLNode* b=doc.FirstChild();
897 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
898 ++count;
899 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
900 }
901 XMLTest( "Clone and Equal", 4, count );
902 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800903
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700904 {
905 // This shouldn't crash.
906 XMLDocument doc;
907 if(XML_NO_ERROR != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
908 {
909 doc.PrintError();
910 }
911 XMLTest( "Error in snprinf handling.", true, doc.Error() );
912 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700913
Lee Thomason5e3803c2012-04-16 08:57:05 -0700914 {
915 // Attribute ordering.
916 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
917 XMLDocument doc;
918 doc.Parse( xml );
919 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700920
Lee Thomason5e3803c2012-04-16 08:57:05 -0700921 const XMLAttribute* a = ele->FirstAttribute();
922 XMLTest( "Attribute order", "1", a->Value() );
923 a = a->Next();
924 XMLTest( "Attribute order", "2", a->Value() );
925 a = a->Next();
926 XMLTest( "Attribute order", "3", a->Value() );
927 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700928
Lee Thomason5e3803c2012-04-16 08:57:05 -0700929 ele->DeleteAttribute( "attrib2" );
930 a = ele->FirstAttribute();
931 XMLTest( "Attribute order", "1", a->Value() );
932 a = a->Next();
933 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700934
Lee Thomason5e3803c2012-04-16 08:57:05 -0700935 ele->DeleteAttribute( "attrib1" );
936 ele->DeleteAttribute( "attrib3" );
937 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
938 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700939
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700940 {
941 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -0700942 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
943 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
944 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
945 XMLDocument doc0;
946 doc0.Parse( xml0 );
947 XMLDocument doc1;
948 doc1.Parse( xml1 );
949 XMLDocument doc2;
950 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700951
Lee Thomason78a773d2012-07-02 10:10:19 -0700952 XMLElement* ele = 0;
953 ele = doc0.FirstChildElement();
954 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
955 ele = doc1.FirstChildElement();
956 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
957 ele = doc2.FirstChildElement();
958 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700959 }
960
961 {
962 // Make sure we don't go into an infinite loop.
963 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
964 XMLDocument doc;
965 doc.Parse( xml );
966 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
967 XMLElement* ele1 = ele0->NextSiblingElement();
968 bool equal = ele0->ShallowEqual( ele1 );
969
970 XMLTest( "Infinite loop in shallow equal.", true, equal );
971 }
972
Lee Thomason5708f812012-03-28 17:46:41 -0700973 // -------- Handles ------------
974 {
975 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
976 XMLDocument doc;
977 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -0700978
979 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
980 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
981
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -0700982 XMLHandle docH( doc );
983 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -0700984 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -0700985 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700986
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -0700987 {
988 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
989 XMLDocument doc;
990 doc.Parse( xml );
991 XMLConstHandle docH( doc );
992
993 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
994 XMLTest( "Handle, success, const", ele->Value(), "sub" );
995
996 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -0700997 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -0700998 }
Lee Thomasonf68c4382012-04-28 14:37:11 -0700999 {
1000 // Default Declaration & BOM
1001 XMLDocument doc;
1002 doc.InsertEndChild( doc.NewDeclaration() );
1003 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001004
Lee Thomasonf68c4382012-04-28 14:37:11 -07001005 XMLPrinter printer;
1006 doc.Print( &printer );
1007
1008 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1009 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001010 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001011 }
Lee Thomason21be8822012-07-15 17:27:22 -07001012 {
1013 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1014 XMLDocument doc;
1015 doc.Parse( xml );
1016 XMLTest( "Ill formed XML", true, doc.Error() );
1017 }
1018
1019 // QueryXYZText
1020 {
1021 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1022 XMLDocument doc;
1023 doc.Parse( xml );
1024
1025 const XMLElement* pointElement = doc.RootElement();
1026
1027 int intValue = 0;
1028 unsigned unsignedValue = 0;
1029 float floatValue = 0;
1030 double doubleValue = 0;
1031 bool boolValue = false;
1032
1033 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1034 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1035 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1036 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1037 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1038
1039
1040 XMLTest( "QueryIntText", intValue, 1, false );
1041 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1042 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1043 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1044 XMLTest( "QueryBoolText", boolValue, true, false );
1045 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001046
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001047 {
1048 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1049 XMLDocument doc;
1050 doc.Parse( xml );
1051 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1052 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001053
1054 {
1055 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1056 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001057 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001058 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1059 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001060
1061 {
1062 const char* xml = "<3lement></3lement>";
1063 XMLDocument doc;
1064 doc.Parse( xml );
1065 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1066 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001067
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001068 {
1069 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1070 XMLDocument doc;
1071 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001072 XMLTest( "Set length of incoming data", doc.Error(), false );
1073 }
1074
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001075 {
1076 XMLDocument doc;
1077 doc.LoadFile( "resources/dream.xml" );
1078 doc.Clear();
1079 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1080 }
1081
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001082 // ----------- Whitespace ------------
1083 {
1084 const char* xml = "<element>"
1085 "<a> This \nis &apos; text &apos; </a>"
1086 "<b> This is &apos; text &apos; \n</b>"
1087 "<c>This is &apos; \n\n text &apos;</c>"
1088 "</element>";
1089 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1090 doc.Parse( xml );
1091
1092 const XMLElement* element = doc.FirstChildElement();
1093 for( const XMLElement* parent = element->FirstChildElement();
1094 parent;
1095 parent = parent->NextSiblingElement() )
1096 {
1097 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1098 }
1099 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001100
Lee Thomasonae9ab072012-10-24 10:17:53 -07001101#if 0
1102 {
1103 // Passes if assert doesn't fire.
1104 XMLDocument xmlDoc;
1105
1106 xmlDoc.NewDeclaration();
1107 xmlDoc.NewComment("Configuration file");
1108
1109 XMLElement *root = xmlDoc.NewElement("settings");
1110 root->SetAttribute("version", 2);
1111 }
1112#endif
1113
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001114 {
1115 const char* xml = "<element> </element>";
1116 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1117 doc.Parse( xml );
1118 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1119 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001120
Lee Thomason (grinliz)fc6320e2012-09-23 20:25:50 -07001121#if 0 // the question being explored is what kind of print to use:
1122 // https://github.com/leethomason/tinyxml2/issues/63
1123 {
1124 const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9'/>";
1125 XMLDocument doc;
1126 doc.Parse( xml );
1127 doc.FirstChildElement()->SetAttribute( "attrA", 123456789.123456789 );
1128 doc.FirstChildElement()->SetAttribute( "attrB", 1.001e9 );
1129 doc.Print();
1130 }
1131#endif
1132
Lee Thomason5b0a6772012-11-19 13:54:42 -08001133 {
1134 // An assert should not fire.
1135 const char* xml = "<element/>";
1136 XMLDocument doc;
1137 doc.Parse( xml );
1138 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1139 XMLTest( "Tracking unused elements", true, ele != 0, false );
1140 }
1141
Lee Thomasona6412ac2012-12-13 15:39:11 -08001142
1143 {
1144 const char* xml = "<parent><child>abc</child></parent>";
1145 XMLDocument doc;
1146 doc.Parse( xml );
1147 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1148
1149 XMLPrinter printer;
1150 ele->Accept( &printer );
1151 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1152 }
1153
1154
Lee Thomason6f381b72012-03-02 12:59:39 -08001155 // ----------- Performance tracking --------------
1156 {
1157#if defined( _MSC_VER )
1158 __int64 start, end, freq;
1159 QueryPerformanceFrequency( (LARGE_INTEGER*) &freq );
1160#endif
1161
Bruno Diasa2d4e6e2012-05-07 04:58:11 -03001162 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason6f381b72012-03-02 12:59:39 -08001163 fseek( fp, 0, SEEK_END );
1164 long size = ftell( fp );
1165 fseek( fp, 0, SEEK_SET );
1166
1167 char* mem = new char[size+1];
1168 fread( mem, size, 1, fp );
1169 fclose( fp );
1170 mem[size] = 0;
1171
1172#if defined( _MSC_VER )
1173 QueryPerformanceCounter( (LARGE_INTEGER*) &start );
1174#else
1175 clock_t cstart = clock();
1176#endif
1177 static const int COUNT = 10;
1178 for( int i=0; i<COUNT; ++i ) {
1179 XMLDocument doc;
1180 doc.Parse( mem );
1181 }
1182#if defined( _MSC_VER )
1183 QueryPerformanceCounter( (LARGE_INTEGER*) &end );
1184#else
1185 clock_t cend = clock();
1186#endif
1187
1188 delete [] mem;
1189
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001190 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001191#ifdef DEBUG
1192 "DEBUG";
1193#else
1194 "Release";
1195#endif
1196
1197#if defined( _MSC_VER )
1198 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end-start) / ( (double)freq * (double)COUNT) );
1199#else
1200 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart)/(double)COUNT );
1201#endif
1202 }
1203
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001204 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001205 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001206 //_CrtMemDumpStatistics( &endMemState );
1207
1208 _CrtMemState diffMemState;
1209 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1210 _CrtMemDumpStatistics( &diffMemState );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001211 //printf( "new total=%d\n", gNewTotal );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001212 #endif
1213
1214 printf ("\nPass %d, Fail %d\n", gPass, gFail);
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001215 return 0;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001216}