blob: 8a13382112b864296eda1ee8d80d9dc71b48e8e5 [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
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700267int 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
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300279 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700280 if ( !fp ) {
281 printf( "Error opening test file 'dream.xml'.\n"
282 "Is your working directory the same as where \n"
283 "the xmltest.cpp and dream.xml file are?\n\n"
284 #if defined( _MSC_VER )
285 "In windows Visual Studio you may need to set\n"
286 "Properties->Debugging->Working Directory to '..'\n"
287 #endif
288 );
289 exit( 1 );
290 }
291 fclose( fp );
292
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700293 XMLTest( "Example-1", 0, example_1() );
294 XMLTest( "Example-2", 0, example_2() );
295 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700296 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700297
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700298 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700299
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800300 {
Lee Thomason43f59302012-02-06 18:18:11 -0800301 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400302 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800303 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400304 "<element><subelement></subelement></element>",
305 "<element><subelement><subsub/></subelement></element>",
306 "<!--comment beside elements--><element><subelement></subelement></element>",
307 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
308 "<element attrib1='foo' attrib2=\"bar\" ></element>",
309 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800310 "<element>Text inside element.</element>",
311 "<element><b></b></element>",
312 "<element>Text inside and <b>bolded</b> in the element.</element>",
313 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800314 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800315 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800316 0
317 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800318 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800319 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800320 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800321 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800322 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800323 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800324 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800325#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800326 {
327 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400328 " line 2\r"
329 " line 3\r\n"
330 " line 4\n\r"
331 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800332
333 XMLDocument doc;
334 doc.Parse( test );
335 doc.Print();
336 }
337
Lee Thomason2c85a712012-01-31 08:24:24 -0800338 {
339 static const char* test = "<element>Text before.</element>";
340 XMLDocument doc;
341 doc.Parse( test );
342 XMLElement* root = doc.FirstChildElement();
343 XMLElement* newElement = doc.NewElement( "Subelement" );
344 root->InsertEndChild( newElement );
345 doc.Print();
346 }
Lee Thomasond1983222012-02-06 08:41:24 -0800347 {
348 XMLDocument* doc = new XMLDocument();
349 static const char* test = "<element><sub/></element>";
350 doc->Parse( test );
351 delete doc;
352 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800353 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800354 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800355 // Build:
356 // <element>
357 // <!--comment-->
358 // <sub attrib="1" />
359 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800360 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800361 // <element>
362
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800363 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800364 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
365
366 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
367 for( int i=0; i<3; ++i ) {
368 sub[i]->SetAttribute( "attrib", i );
369 }
370 element->InsertEndChild( sub[2] );
371 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
372 element->InsertAfterChild( comment, sub[0] );
373 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800374 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800375 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800376 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
377 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
378 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700379 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800380 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800381
382 // And now deletion:
383 element->DeleteChild( sub[2] );
384 doc->DeleteNode( comment );
385
386 element->FirstChildElement()->SetAttribute( "attrib", true );
387 element->LastChildElement()->DeleteAttribute( "attrib" );
388
389 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
390 int value = 10;
391 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );
Lee Thomason21be8822012-07-15 17:27:22 -0700392 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800393 XMLTest( "Programmatic DOM", value, 10 );
394
395 doc->Print();
396
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700397 {
398 XMLPrinter streamer;
399 doc->Print( &streamer );
400 printf( "%s", streamer.CStr() );
401 }
402 {
403 XMLPrinter streamer( 0, true );
404 doc->Print( &streamer );
405 XMLTest( "Compact mode", "<element><sub attrib=\"1\"/><sub/></element>", streamer.CStr(), false );
406 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700407 doc->SaveFile( "./resources/out/pretty.xml" );
408 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800409 delete doc;
410 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800411 {
412 // Test: Dream
413 // XML1 : 1,187,569 bytes in 31,209 allocations
414 // XML2 : 469,073 bytes in 323 allocations
415 //int newStart = gNew;
416 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300417 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800418
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400419 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800420 doc.PrintError();
421
422 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400423 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800424 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
425 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
426 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
427 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400428 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800429 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400430 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800431
432 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400433 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800434 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400435 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800436 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
437 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
438 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
439 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400440 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800441
442 //gNewTotal = gNew - newStart;
443 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800444
445
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800446 {
447 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
448 "<passages count=\"006\" formatversion=\"20020620\">\n"
449 " <wrong error>\n"
450 "</passages>";
451
452 XMLDocument doc;
453 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800454 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800455 }
456
457 {
458 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
459
460 XMLDocument doc;
461 doc.Parse( str );
462
463 XMLElement* ele = doc.FirstChildElement();
464
465 int iVal, result;
466 double dVal;
467
468 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700469 XMLTest( "Query attribute: int as double", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800470 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
471 result = ele->QueryDoubleAttribute( "attr1", &dVal );
472 XMLTest( "Query attribute: double as double", (int)dVal, 2 );
473 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700474 XMLTest( "Query attribute: double as int", result, (int)XML_NO_ERROR );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800475 XMLTest( "Query attribute: double as int", iVal, 2 );
476 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700477 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800478 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700479 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800480 }
481
482 {
483 const char* str = "<doc/>";
484
485 XMLDocument doc;
486 doc.Parse( str );
487
488 XMLElement* ele = doc.FirstChildElement();
489
490 int iVal;
491 double dVal;
492
493 ele->SetAttribute( "str", "strValue" );
494 ele->SetAttribute( "int", 1 );
495 ele->SetAttribute( "double", -1.0 );
496
497 const char* cStr = ele->Attribute( "str" );
498 ele->QueryIntAttribute( "int", &iVal );
499 ele->QueryDoubleAttribute( "double", &dVal );
500
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700501 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800502 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
503 XMLTest( "Attribute round trip. int.", 1, iVal );
504 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
505 }
506
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800507 {
508 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300509 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800510
511 // Get the attribute "value" from the "Russian" element and check it.
512 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700513 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800514 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
515
516 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
517
518 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
519 0xd1U, 0x81U, 0xd1U, 0x81U,
520 0xd0U, 0xbaU, 0xd0U, 0xb8U,
521 0xd0U, 0xb9U, 0 };
522 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
523
524 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
525 XMLTest( "UTF-8: Browsing russian element name.",
526 russianText,
527 text->Value() );
528
529 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400530 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800531
532 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800533 int okay = 0;
534
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200535 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300536 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800537
538 if ( saved && verify )
539 {
540 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700541 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800542 while ( fgets( verifyBuf, 256, verify ) )
543 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700544 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800545 fgets( savedBuf, 256, saved );
546 NullLineEndings( verifyBuf );
547 NullLineEndings( savedBuf );
548
549 if ( strcmp( verifyBuf, savedBuf ) )
550 {
551 printf( "verify:%s<\n", verifyBuf );
552 printf( "saved :%s<\n", savedBuf );
553 okay = 0;
554 break;
555 }
556 }
557 }
558 if ( saved )
559 fclose( saved );
560 if ( verify )
561 fclose( verify );
562 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
563 }
564
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800565 // --------GetText()-----------
566 {
567 const char* str = "<foo>This is text</foo>";
568 XMLDocument doc;
569 doc.Parse( str );
570 const XMLElement* element = doc.RootElement();
571
572 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
573
574 str = "<foo><b>This is text</b></foo>";
575 doc.Parse( str );
576 element = doc.RootElement();
577
578 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
579 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800580
Lee Thomasond6277762012-02-22 16:00:12 -0800581
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800582 // ---------- CDATA ---------------
583 {
584 const char* str = "<xmlElement>"
585 "<![CDATA["
586 "I am > the rules!\n"
587 "...since I make symbolic puns"
588 "]]>"
589 "</xmlElement>";
590 XMLDocument doc;
591 doc.Parse( str );
592 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800593
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700594 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800595 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800596 false );
597 }
598
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800599 // ----------- CDATA -------------
600 {
601 const char* str = "<xmlElement>"
602 "<![CDATA["
603 "<b>I am > the rules!</b>\n"
604 "...since I make symbolic puns"
605 "]]>"
606 "</xmlElement>";
607 XMLDocument doc;
608 doc.Parse( str );
609 doc.Print();
610
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700611 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800612 "<b>I am > the rules!</b>\n...since I make symbolic puns",
613 false );
614 }
615
616 // InsertAfterChild causes crash.
617 {
618 // InsertBeforeChild and InsertAfterChild causes crash.
619 XMLDocument doc;
620 XMLElement* parent = doc.NewElement( "Parent" );
621 doc.InsertFirstChild( parent );
622
623 XMLElement* childText0 = doc.NewElement( "childText0" );
624 XMLElement* childText1 = doc.NewElement( "childText1" );
625
626 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
627 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
628
629 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
630 }
Lee Thomasond6277762012-02-22 16:00:12 -0800631
632 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800633 // Entities not being written correctly.
634 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800635
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800636 const char* passages =
637 "<?xml version=\"1.0\" standalone=\"no\" ?>"
638 "<passages count=\"006\" formatversion=\"20020620\">"
639 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
640 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
641 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800642
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800643 XMLDocument doc;
644 doc.Parse( passages );
645 XMLElement* psg = doc.RootElement()->FirstChildElement();
646 const char* context = psg->Attribute( "context" );
647 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 -0800648
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800649 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800650
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400651 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800652 if ( textfile )
653 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800654 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800655 psg->Accept( &streamer );
656 fclose( textfile );
657 }
Thomas Roß0922b732012-09-23 16:31:22 +0200658
659 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800660 TIXMLASSERT( textfile );
661 if ( textfile )
662 {
663 char buf[ 1024 ];
664 fgets( buf, 1024, textfile );
665 XMLTest( "Entity transformation: write. ",
666 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
667 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
668 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700669 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800670 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800671 }
672
673 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800674 // Suppress entities.
675 const char* passages =
676 "<?xml version=\"1.0\" standalone=\"no\" ?>"
677 "<passages count=\"006\" formatversion=\"20020620\">"
678 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
679 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700680
Lee Thomason6f381b72012-03-02 12:59:39 -0800681 XMLDocument doc( false );
682 doc.Parse( passages );
683
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700684 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800685 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
686 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
687 "Crazy &ttk;" );
688 doc.Print();
689 }
690
691 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400692 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800693
694 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400695 doc.Parse( test );
696 XMLTest( "dot in names", doc.Error(), false );
697 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
698 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800699 }
700
701 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400702 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800703
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400704 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800705 doc.Parse( test );
706
707 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
708 XMLTest( "Entity with one digit.",
709 text->Value(), "1.1 Start easy ignore fin thickness\n",
710 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400711 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800712
713 {
714 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700715 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800716 const char* doctype =
717 "<?xml version=\"1.0\" ?>"
718 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
719 "<!ELEMENT title (#PCDATA)>"
720 "<!ELEMENT books (title,authors)>"
721 "<element />";
722
723 XMLDocument doc;
724 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400725 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800726 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400727 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800728 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700729
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800730 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
731 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
732
733 }
734
735 {
736 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700737 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800738 "<!-- Somewhat<evil> -->";
739 XMLDocument doc;
740 doc.Parse( doctype );
741
742 XMLComment* comment = doc.FirstChild()->ToComment();
743
744 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
745 }
746 {
747 // Double attributes
748 const char* doctype = "<element attr='red' attr='blue' />";
749
750 XMLDocument doc;
751 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700752
Lee Thomason2fa81722012-11-09 12:37:46 -0800753 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 -0800754 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800755 }
756
757 {
758 // Embedded null in stream.
759 const char* doctype = "<element att\0r='red' attr='blue' />";
760
761 XMLDocument doc;
762 doc.Parse( doctype );
763 XMLTest( "Embedded null throws error.", true, doc.Error() );
764 }
765
766 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700767 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800768 const char* str = " ";
769 XMLDocument doc;
770 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -0800771 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800772 }
773
774 {
775 // Low entities
776 XMLDocument doc;
777 doc.Parse( "<test>&#x0e;</test>" );
778 const char result[] = { 0x0e, 0 };
779 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
780 doc.Print();
781 }
782
783 {
784 // Attribute values with trailing quotes not handled correctly
785 XMLDocument doc;
786 doc.Parse( "<foo attribute=bar\" />" );
787 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
788 }
789
790 {
791 // [ 1663758 ] Failure to report error on bad XML
792 XMLDocument xml;
793 xml.Parse("<x>");
794 XMLTest("Missing end tag at end of input", xml.Error(), true);
795 xml.Parse("<x> ");
796 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
797 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -0800798 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700799 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800800
801
802 {
803 // [ 1475201 ] TinyXML parses entities in comments
804 XMLDocument xml;
805 xml.Parse("<!-- declarations for <head> & <body> -->"
806 "<!-- far &amp; away -->" );
807
808 XMLNode* e0 = xml.FirstChild();
809 XMLNode* e1 = e0->NextSibling();
810 XMLComment* c0 = e0->ToComment();
811 XMLComment* c1 = e1->ToComment();
812
813 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
814 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
815 }
816
817 {
818 XMLDocument xml;
819 xml.Parse( "<Parent>"
820 "<child1 att=''/>"
821 "<!-- With this comment, child2 will not be parsed! -->"
822 "<child2 att=''/>"
823 "</Parent>" );
824 xml.Print();
825
826 int count = 0;
827
828 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
829 ele;
830 ele = ele->NextSibling() )
831 {
832 ++count;
833 }
834
835 XMLTest( "Comments iterate correctly.", 3, count );
836 }
837
838 {
839 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
840 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
841 buf[60] = 239;
842 buf[61] = 0;
843
844 XMLDocument doc;
845 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700846 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800847
848
849 {
850 // bug 1827248 Error while parsing a little bit malformed file
851 // Actually not malformed - should work.
852 XMLDocument xml;
853 xml.Parse( "<attributelist> </attributelist >" );
854 XMLTest( "Handle end tag whitespace", false, xml.Error() );
855 }
856
857 {
858 // This one must not result in an infinite loop
859 XMLDocument xml;
860 xml.Parse( "<infinite>loop" );
861 XMLTest( "Infinite loop test.", true, true );
862 }
863#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800864 {
865 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
866 XMLDocument doc;
867 doc.Parse( pub );
868
869 XMLDocument clone;
870 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
871 XMLNode* copy = node->ShallowClone( &clone );
872 clone.InsertEndChild( copy );
873 }
874
875 clone.Print();
876
877 int count=0;
878 const XMLNode* a=clone.FirstChild();
879 const XMLNode* b=doc.FirstChild();
880 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
881 ++count;
882 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
883 }
884 XMLTest( "Clone and Equal", 4, count );
885 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800886
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700887 {
888 // This shouldn't crash.
889 XMLDocument doc;
890 if(XML_NO_ERROR != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
891 {
892 doc.PrintError();
893 }
894 XMLTest( "Error in snprinf handling.", true, doc.Error() );
895 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700896
Lee Thomason5e3803c2012-04-16 08:57:05 -0700897 {
898 // Attribute ordering.
899 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
900 XMLDocument doc;
901 doc.Parse( xml );
902 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700903
Lee Thomason5e3803c2012-04-16 08:57:05 -0700904 const XMLAttribute* a = ele->FirstAttribute();
905 XMLTest( "Attribute order", "1", a->Value() );
906 a = a->Next();
907 XMLTest( "Attribute order", "2", a->Value() );
908 a = a->Next();
909 XMLTest( "Attribute order", "3", a->Value() );
910 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700911
Lee Thomason5e3803c2012-04-16 08:57:05 -0700912 ele->DeleteAttribute( "attrib2" );
913 a = ele->FirstAttribute();
914 XMLTest( "Attribute order", "1", a->Value() );
915 a = a->Next();
916 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700917
Lee Thomason5e3803c2012-04-16 08:57:05 -0700918 ele->DeleteAttribute( "attrib1" );
919 ele->DeleteAttribute( "attrib3" );
920 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
921 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700922
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700923 {
924 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -0700925 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
926 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
927 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
928 XMLDocument doc0;
929 doc0.Parse( xml0 );
930 XMLDocument doc1;
931 doc1.Parse( xml1 );
932 XMLDocument doc2;
933 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700934
Lee Thomason78a773d2012-07-02 10:10:19 -0700935 XMLElement* ele = 0;
936 ele = doc0.FirstChildElement();
937 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
938 ele = doc1.FirstChildElement();
939 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
940 ele = doc2.FirstChildElement();
941 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700942 }
943
944 {
945 // Make sure we don't go into an infinite loop.
946 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
947 XMLDocument doc;
948 doc.Parse( xml );
949 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
950 XMLElement* ele1 = ele0->NextSiblingElement();
951 bool equal = ele0->ShallowEqual( ele1 );
952
953 XMLTest( "Infinite loop in shallow equal.", true, equal );
954 }
955
Lee Thomason5708f812012-03-28 17:46:41 -0700956 // -------- Handles ------------
957 {
958 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
959 XMLDocument doc;
960 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -0700961
962 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
963 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
964
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -0700965 XMLHandle docH( doc );
966 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -0700967 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -0700968 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700969
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -0700970 {
971 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
972 XMLDocument doc;
973 doc.Parse( xml );
974 XMLConstHandle docH( doc );
975
976 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
977 XMLTest( "Handle, success, const", ele->Value(), "sub" );
978
979 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -0700980 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -0700981 }
Lee Thomasonf68c4382012-04-28 14:37:11 -0700982 {
983 // Default Declaration & BOM
984 XMLDocument doc;
985 doc.InsertEndChild( doc.NewDeclaration() );
986 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700987
Lee Thomasonf68c4382012-04-28 14:37:11 -0700988 XMLPrinter printer;
989 doc.Print( &printer );
990
991 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
992 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -0700993 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -0700994 }
Lee Thomason21be8822012-07-15 17:27:22 -0700995 {
996 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
997 XMLDocument doc;
998 doc.Parse( xml );
999 XMLTest( "Ill formed XML", true, doc.Error() );
1000 }
1001
1002 // QueryXYZText
1003 {
1004 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1005 XMLDocument doc;
1006 doc.Parse( xml );
1007
1008 const XMLElement* pointElement = doc.RootElement();
1009
1010 int intValue = 0;
1011 unsigned unsignedValue = 0;
1012 float floatValue = 0;
1013 double doubleValue = 0;
1014 bool boolValue = false;
1015
1016 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1017 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1018 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1019 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1020 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1021
1022
1023 XMLTest( "QueryIntText", intValue, 1, false );
1024 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1025 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1026 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1027 XMLTest( "QueryBoolText", boolValue, true, false );
1028 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001029
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001030 {
1031 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1032 XMLDocument doc;
1033 doc.Parse( xml );
1034 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1035 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001036
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001037 {
1038 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1039 XMLDocument doc;
1040 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001041 XMLTest( "Set length of incoming data", doc.Error(), false );
1042 }
1043
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001044 // ----------- Whitespace ------------
1045 {
1046 const char* xml = "<element>"
1047 "<a> This \nis &apos; text &apos; </a>"
1048 "<b> This is &apos; text &apos; \n</b>"
1049 "<c>This is &apos; \n\n text &apos;</c>"
1050 "</element>";
1051 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1052 doc.Parse( xml );
1053
1054 const XMLElement* element = doc.FirstChildElement();
1055 for( const XMLElement* parent = element->FirstChildElement();
1056 parent;
1057 parent = parent->NextSiblingElement() )
1058 {
1059 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1060 }
1061 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001062
Lee Thomasonae9ab072012-10-24 10:17:53 -07001063#if 0
1064 {
1065 // Passes if assert doesn't fire.
1066 XMLDocument xmlDoc;
1067
1068 xmlDoc.NewDeclaration();
1069 xmlDoc.NewComment("Configuration file");
1070
1071 XMLElement *root = xmlDoc.NewElement("settings");
1072 root->SetAttribute("version", 2);
1073 }
1074#endif
1075
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001076 {
1077 const char* xml = "<element> </element>";
1078 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1079 doc.Parse( xml );
1080 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1081 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001082
Lee Thomason (grinliz)fc6320e2012-09-23 20:25:50 -07001083#if 0 // the question being explored is what kind of print to use:
1084 // https://github.com/leethomason/tinyxml2/issues/63
1085 {
1086 const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9'/>";
1087 XMLDocument doc;
1088 doc.Parse( xml );
1089 doc.FirstChildElement()->SetAttribute( "attrA", 123456789.123456789 );
1090 doc.FirstChildElement()->SetAttribute( "attrB", 1.001e9 );
1091 doc.Print();
1092 }
1093#endif
1094
Lee Thomason5b0a6772012-11-19 13:54:42 -08001095 {
1096 // An assert should not fire.
1097 const char* xml = "<element/>";
1098 XMLDocument doc;
1099 doc.Parse( xml );
1100 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1101 XMLTest( "Tracking unused elements", true, ele != 0, false );
1102 }
1103
Lee Thomasona6412ac2012-12-13 15:39:11 -08001104
1105 {
1106 const char* xml = "<parent><child>abc</child></parent>";
1107 XMLDocument doc;
1108 doc.Parse( xml );
1109 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1110
1111 XMLPrinter printer;
1112 ele->Accept( &printer );
1113 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1114 }
1115
1116
Lee Thomason6f381b72012-03-02 12:59:39 -08001117 // ----------- Performance tracking --------------
1118 {
1119#if defined( _MSC_VER )
1120 __int64 start, end, freq;
1121 QueryPerformanceFrequency( (LARGE_INTEGER*) &freq );
1122#endif
1123
Bruno Diasa2d4e6e2012-05-07 04:58:11 -03001124 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason6f381b72012-03-02 12:59:39 -08001125 fseek( fp, 0, SEEK_END );
1126 long size = ftell( fp );
1127 fseek( fp, 0, SEEK_SET );
1128
1129 char* mem = new char[size+1];
1130 fread( mem, size, 1, fp );
1131 fclose( fp );
1132 mem[size] = 0;
1133
1134#if defined( _MSC_VER )
1135 QueryPerformanceCounter( (LARGE_INTEGER*) &start );
1136#else
1137 clock_t cstart = clock();
1138#endif
1139 static const int COUNT = 10;
1140 for( int i=0; i<COUNT; ++i ) {
1141 XMLDocument doc;
1142 doc.Parse( mem );
1143 }
1144#if defined( _MSC_VER )
1145 QueryPerformanceCounter( (LARGE_INTEGER*) &end );
1146#else
1147 clock_t cend = clock();
1148#endif
1149
1150 delete [] mem;
1151
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001152 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001153#ifdef DEBUG
1154 "DEBUG";
1155#else
1156 "Release";
1157#endif
1158
1159#if defined( _MSC_VER )
1160 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end-start) / ( (double)freq * (double)COUNT) );
1161#else
1162 printf( "\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart)/(double)COUNT );
1163#endif
1164 }
1165
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001166 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001167 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001168 //_CrtMemDumpStatistics( &endMemState );
1169
1170 _CrtMemState diffMemState;
1171 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1172 _CrtMemDumpStatistics( &diffMemState );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001173 //printf( "new total=%d\n", gNewTotal );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001174 #endif
1175
1176 printf ("\nPass %d, Fail %d\n", gPass, gFail);
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001177 return 0;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001178}