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