blob: 028953e49081799ef3ad5ff5e0c489a7f9af3fbe [file] [log] [blame]
Lee Thomason5b0a6772012-11-19 13:54:42 -08001#if defined( _MSC_VER )
Serhat Eser Erdemca5d6842014-04-17 14:06:15 +02002 #if !defined( _CRT_SECURE_NO_WARNINGS )
3 #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
4 #endif
Lee Thomason5b0a6772012-11-19 13:54:42 -08005#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08006
Lee Thomason5b0a6772012-11-19 13:54:42 -08007#include "tinyxml2.h"
kbinny62bf29a152017-06-23 18:15:25 +00008#include <cerrno>
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07009#include <cstdlib>
10#include <cstring>
11#include <ctime>
U-Lama\Leee13c3e62011-12-28 14:36:55 -080012
kbinny62bf29a152017-06-23 18:15:25 +000013#if defined( _MSC_VER ) || defined (WIN32)
Lee Thomason1ff38e02012-02-14 18:18:16 -080014 #include <crtdbg.h>
Lee Thomason6f381b72012-03-02 12:59:39 -080015 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080017 _CrtMemState startMemState;
Lee Thomason53858b42017-06-01 19:09:16 -070018 _CrtMemState endMemState;
kbinny62bf29a152017-06-23 18:15:25 +000019#else
20 #include <sys/stat.h>
21 #include <sys/types.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080022#endif
Lee Thomasone9ecdab2012-02-13 18:11:20 -080023
U-Lama\Leee13c3e62011-12-28 14:36:55 -080024using namespace tinyxml2;
Anton Indrawan8a0006c2014-11-20 18:27:07 +010025using namespace std;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080026int gPass = 0;
27int gFail = 0;
28
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080029
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070030bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080031{
Sarat Addepalli13b2d732015-05-19 12:44:57 +053032 bool pass;
33 if ( !expected && !found )
34 pass = true;
35 else if ( !expected || !found )
36 pass = false;
Lee Thomasonc4836462018-06-29 15:57:55 -070037 else
Sarat Addepallid608c562015-05-20 10:19:00 +053038 pass = !strcmp( expected, found );
Lee Thomason1ff38e02012-02-14 18:18:16 -080039 if ( pass )
40 printf ("[pass]");
41 else
42 printf ("[fail]");
43
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070044 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080045 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070046 }
47 else {
48 if ( extraNL ) {
49 printf( " %s\n", testString );
50 printf( "%s\n", expected );
51 printf( "%s\n", found );
52 }
53 else {
54 printf (" %s [%s][%s]\n", testString, expected, found);
55 }
56 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080057
58 if ( pass )
59 ++gPass;
60 else
61 ++gFail;
62 return pass;
63}
64
kezenator5a700712016-11-26 13:54:42 +100065bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
66{
Lee Thomasone90e9012016-12-24 07:34:39 -080067 return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
kezenator5a700712016-11-26 13:54:42 +100068}
69
70bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
71{
72 return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
73}
Lee Thomason1ff38e02012-02-14 18:18:16 -080074
Lee Thomason21be8822012-07-15 17:27:22 -070075template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080076{
77 bool pass = ( expected == found );
78 if ( pass )
79 printf ("[pass]");
80 else
81 printf ("[fail]");
82
U-Stream\Lee09a11c52012-02-17 08:31:16 -080083 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080084 printf (" %s\n", testString);
Dmitry-Meed3e9dc2018-10-17 00:27:33 +030085 else {
86 char expectedAsString[64];
87 XMLUtil::ToStr(expected, expectedAsString, sizeof(expectedAsString));
88
89 char foundAsString[64];
90 XMLUtil::ToStr(found, foundAsString, sizeof(foundAsString));
91
92 printf (" %s [%s][%s]\n", testString, expectedAsString, foundAsString );
93 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080094
95 if ( pass )
96 ++gPass;
97 else
98 ++gFail;
99 return pass;
100}
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800101
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800102
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800103void NullLineEndings( char* p )
104{
105 while( p && *p ) {
106 if ( *p == '\n' || *p == '\r' ) {
107 *p = 0;
108 return;
109 }
110 ++p;
111 }
112}
113
114
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700115int example_1()
116{
117 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300118 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700119
120 return doc.ErrorID();
121}
Lee Thomasoncf100692017-12-10 20:03:39 -0800122/** @page Example_1 Load an XML File
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200123 * @dontinclude ./xmltest.cpp
124 * Basic XML file loading.
125 * The basic syntax to load an XML file from
126 * disk and check for an error. (ErrorID()
127 * will return 0 for no error.)
128 * @skip example_1()
129 * @until }
130 */
Lee Thomasonc4836462018-06-29 15:57:55 -0700131
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700132
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700133int example_2()
134{
135 static const char* xml = "<element/>";
136 XMLDocument doc;
137 doc.Parse( xml );
138
139 return doc.ErrorID();
140}
Lee Thomasoncf100692017-12-10 20:03:39 -0800141/** @page Example_2 Parse an XML from char buffer
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200142 * @dontinclude ./xmltest.cpp
143 * Basic XML string parsing.
144 * The basic syntax to parse an XML for
145 * a char* and check for an error. (ErrorID()
146 * will return 0 for no error.)
147 * @skip example_2()
148 * @until }
149 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700150
151
152int example_3()
153{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700154 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700155 "<?xml version=\"1.0\"?>"
156 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
157 "<PLAY>"
158 "<TITLE>A Midsummer Night's Dream</TITLE>"
159 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700160
161 XMLDocument doc;
162 doc.Parse( xml );
163
164 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
165 const char* title = titleElement->GetText();
166 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700167
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700168 XMLText* textNode = titleElement->FirstChild()->ToText();
169 title = textNode->Value();
170 printf( "Name of play (2): %s\n", title );
171
172 return doc.ErrorID();
173}
Lee Thomasoncf100692017-12-10 20:03:39 -0800174/** @page Example_3 Get information out of XML
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200175 @dontinclude ./xmltest.cpp
176 In this example, we navigate a simple XML
177 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700178 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200179 checking; working code should check for null
180 pointers when walking an XML tree, or use
181 XMLHandle.
Lee Thomasonc4836462018-06-29 15:57:55 -0700182
183 (The XML is an excerpt from "dream.xml").
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200184
185 @skip example_3()
186 @until </PLAY>";
187
188 The structure of the XML file is:
189
190 <ul>
191 <li>(declaration)</li>
192 <li>(dtd stuff)</li>
193 <li>Element "PLAY"</li>
194 <ul>
195 <li>Element "TITLE"</li>
196 <ul>
197 <li>Text "A Midsummer Night's Dream"</li>
198 </ul>
199 </ul>
200 </ul>
201
Lee Thomasonc4836462018-06-29 15:57:55 -0700202 For this example, we want to print out the
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200203 title of the play. The text of the title (what
204 we want) is child of the "TITLE" element which
205 is a child of the "PLAY" element.
206
207 We want to skip the declaration and dtd, so the
208 method FirstChildElement() is a good choice. The
209 FirstChildElement() of the Document is the "PLAY"
210 Element, the FirstChildElement() of the "PLAY" Element
211 is the "TITLE" Element.
212
213 @until ( "TITLE" );
214
215 We can then use the convenience function GetText()
216 to get the title of the play.
217
218 @until title );
219
220 Text is just another Node in the XML DOM. And in
221 fact you should be a little cautious with it, as
Lee Thomasonc4836462018-06-29 15:57:55 -0700222 text nodes can contain elements.
223
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200224 @verbatim
225 Consider: A Midsummer Night's <b>Dream</b>
226 @endverbatim
227
228 It is more correct to actually query the Text Node
229 if in doubt:
230
231 @until title );
232
233 Noting that here we use FirstChild() since we are
234 looking for XMLText, not an element, and ToText()
Lee Thomasonc4836462018-06-29 15:57:55 -0700235 is a cast from a Node to a XMLText.
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200236*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700237
238
Lee Thomason21be8822012-07-15 17:27:22 -0700239bool example_4()
240{
241 static const char* xml =
242 "<information>"
243 " <attributeApproach v='2' />"
244 " <textApproach>"
245 " <v>2</v>"
246 " </textApproach>"
247 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700248
Lee Thomason21be8822012-07-15 17:27:22 -0700249 XMLDocument doc;
250 doc.Parse( xml );
251
252 int v0 = 0;
253 int v1 = 0;
254
255 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
256 attributeApproachElement->QueryIntAttribute( "v", &v0 );
257
258 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
259 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
260
261 printf( "Both values are the same: %d and %d\n", v0, v1 );
262
263 return !doc.Error() && ( v0 == v1 );
264}
Lee Thomasoncf100692017-12-10 20:03:39 -0800265/** @page Example_4 Read attributes and text information.
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200266 @dontinclude ./xmltest.cpp
267
268 There are fundamentally 2 ways of writing a key-value
269 pair into an XML file. (Something that's always annoyed
270 me about XML.) Either by using attributes, or by writing
271 the key name into an element and the value into
272 the text node wrapped by the element. Both approaches
273 are illustrated in this example, which shows two ways
274 to encode the value "2" into the key "v":
275
276 @skip example_4()
277 @until "</information>";
278
Lee Thomasonc4836462018-06-29 15:57:55 -0700279 TinyXML-2 has accessors for both approaches.
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200280
281 When using an attribute, you navigate to the XMLElement
282 with that attribute and use the QueryIntAttribute()
283 group of methods. (Also QueryFloatAttribute(), etc.)
284
285 @skip XMLElement* attributeApproachElement
286 @until &v0 );
287
288 When using the text approach, you need to navigate
289 down one more step to the XMLElement that contains
290 the text. Note the extra FirstChildElement( "v" )
291 in the code below. The value of the text can then
292 be safely queried with the QueryIntText() group
293 of methods. (Also QueryFloatText(), etc.)
294
295 @skip XMLElement* textApproachElement
296 @until &v1 );
297*/
Lee Thomason21be8822012-07-15 17:27:22 -0700298
299
Lee Thomason178e4cc2013-01-25 16:19:05 -0800300int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800301{
Peter Matula50689912018-01-09 12:52:26 +0100302 #if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800303 _CrtMemCheckpoint( &startMemState );
Dmitry-Me99916592014-10-23 11:37:03 +0400304 // Enable MS Visual C++ debug heap memory leaks dump on exit
305 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
Dmitry-Meed785702017-06-15 13:39:53 +0300306 {
307 int leaksOnStart = _CrtDumpMemoryLeaks();
308 XMLTest( "No leaks on start?", FALSE, leaksOnStart );
309 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700310 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800311
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300312 {
313 TIXMLASSERT( true );
314 }
315
Lee Thomason178e4cc2013-01-25 16:19:05 -0800316 if ( argc > 1 ) {
317 XMLDocument* doc = new XMLDocument();
318 clock_t startTime = clock();
319 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100320 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800321 int errorID = doc->ErrorID();
322 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100323 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800324
325 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
326 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700327 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
328 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
329 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800330 }
331 exit(0);
332 }
333
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300334 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700335 if ( !fp ) {
336 printf( "Error opening test file 'dream.xml'.\n"
337 "Is your working directory the same as where \n"
338 "the xmltest.cpp and dream.xml file are?\n\n"
339 #if defined( _MSC_VER )
340 "In windows Visual Studio you may need to set\n"
341 "Properties->Debugging->Working Directory to '..'\n"
342 #endif
343 );
344 exit( 1 );
345 }
346 fclose( fp );
347
Lee Thomasoncf100692017-12-10 20:03:39 -0800348 XMLTest( "Example_1", 0, example_1() );
349 XMLTest( "Example_2", 0, example_2() );
350 XMLTest( "Example_3", 0, example_3() );
351 XMLTest( "Example_4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700352
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700353 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700354
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800355 {
Lee Thomason43f59302012-02-06 18:18:11 -0800356 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400357 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800358 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400359 "<element><subelement></subelement></element>",
360 "<element><subelement><subsub/></subelement></element>",
361 "<!--comment beside elements--><element><subelement></subelement></element>",
362 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
363 "<element attrib1='foo' attrib2=\"bar\" ></element>",
364 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800365 "<element>Text inside element.</element>",
366 "<element><b></b></element>",
367 "<element>Text inside and <b>bolded</b> in the element.</element>",
368 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800369 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800370 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800371 0
372 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800373 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800374 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800375 doc.Parse( test[i] );
Dmitry-Me68578f42017-07-03 18:21:23 +0300376 XMLTest( "Element test", false, doc.Error() );
Lee Thomason5cae8972012-01-24 18:03:07 -0800377 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800378 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800379 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800380 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800382 {
383 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400384 " line 2\r"
385 " line 3\r\n"
386 " line 4\n\r"
387 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800388
389 XMLDocument doc;
390 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300391 XMLTest( "Hello world declaration", false, doc.Error() );
Lee Thomasond6277762012-02-22 16:00:12 -0800392 doc.Print();
393 }
394
Lee Thomason2c85a712012-01-31 08:24:24 -0800395 {
Dmitry-Mee8f4a8b2017-09-15 19:34:36 +0300396 // This test is pre-test for the next one
397 // (where Element1 is inserted "after itself".
398 // This code didn't use to crash.
399 XMLDocument doc;
400 XMLElement* element1 = doc.NewElement("Element1");
401 XMLElement* element2 = doc.NewElement("Element2");
402 doc.InsertEndChild(element1);
403 doc.InsertEndChild(element2);
404 doc.InsertAfterChild(element2, element2);
405 doc.InsertAfterChild(element2, element2);
406 }
407
408 {
409 XMLDocument doc;
410 XMLElement* element1 = doc.NewElement("Element1");
411 XMLElement* element2 = doc.NewElement("Element2");
412 doc.InsertEndChild(element1);
413 doc.InsertEndChild(element2);
414
415 // This insertion "after itself"
416 // used to cause invalid memory access and crash
417 doc.InsertAfterChild(element1, element1);
418 doc.InsertAfterChild(element1, element1);
419 doc.InsertAfterChild(element2, element2);
420 doc.InsertAfterChild(element2, element2);
421 }
422
423 {
Lee Thomason2c85a712012-01-31 08:24:24 -0800424 static const char* test = "<element>Text before.</element>";
425 XMLDocument doc;
426 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300427 XMLTest( "Element text before", false, doc.Error() );
Lee Thomason2c85a712012-01-31 08:24:24 -0800428 XMLElement* root = doc.FirstChildElement();
429 XMLElement* newElement = doc.NewElement( "Subelement" );
430 root->InsertEndChild( newElement );
431 doc.Print();
432 }
Lee Thomasond1983222012-02-06 08:41:24 -0800433 {
434 XMLDocument* doc = new XMLDocument();
435 static const char* test = "<element><sub/></element>";
436 doc->Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300437 XMLTest( "Element with sub element", false, doc->Error() );
Lee Thomasond1983222012-02-06 08:41:24 -0800438 delete doc;
439 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800440 {
Dmitry-Me8e063702017-08-01 17:40:40 +0300441 // Test: Programmatic DOM nodes insertion return values
442 XMLDocument doc;
443
444 XMLNode* first = doc.NewElement( "firstElement" );
445 XMLTest( "New element", true, first != 0 );
446 XMLNode* firstAfterInsertion = doc.InsertFirstChild( first );
447 XMLTest( "New element inserted first", true, firstAfterInsertion == first );
448
449 XMLNode* last = doc.NewElement( "lastElement" );
450 XMLTest( "New element", true, last != 0 );
451 XMLNode* lastAfterInsertion = doc.InsertEndChild( last );
452 XMLTest( "New element inserted last", true, lastAfterInsertion == last );
453
454 XMLNode* middle = doc.NewElement( "middleElement" );
455 XMLTest( "New element", true, middle != 0 );
456 XMLNode* middleAfterInsertion = doc.InsertAfterChild( first, middle );
457 XMLTest( "New element inserted middle", true, middleAfterInsertion == middle );
458 }
459 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800460 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800461 // Build:
462 // <element>
463 // <!--comment-->
Wang Kirin4add9582019-04-29 09:54:45 +0800464 // <sub attrib="0" />
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800465 // <sub attrib="1" />
Wang Kirin4add9582019-04-29 09:54:45 +0800466 // <sub attrib="2" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800467 // <element>
468
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800469 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800470 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
471
472 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
473 for( int i=0; i<3; ++i ) {
474 sub[i]->SetAttribute( "attrib", i );
475 }
476 element->InsertEndChild( sub[2] );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300477
478 const int dummyInitialValue = 1000;
479 int dummyValue = dummyInitialValue;
480
Lee Thomason1ff38e02012-02-14 18:18:16 -0800481 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300482 comment->SetUserData(&dummyValue);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800483 element->InsertAfterChild( comment, sub[0] );
484 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800485 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800486 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800487 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
488 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
489 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700490 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800491 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Dmitry-Mecaed4ec2017-08-11 17:39:47 +0300492 XMLTest("User data - pointer", true, &dummyValue == comment->GetUserData(), false);
493 XMLTest("User data - value behind pointer", dummyInitialValue, dummyValue, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800494
495 // And now deletion:
496 element->DeleteChild( sub[2] );
497 doc->DeleteNode( comment );
498
499 element->FirstChildElement()->SetAttribute( "attrib", true );
500 element->LastChildElement()->DeleteAttribute( "attrib" );
501
502 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300503 const int defaultIntValue = 10;
504 const int replacementIntValue = 20;
505 int value1 = defaultIntValue;
506 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300507 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
508 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300509 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
510 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800511
512 doc->Print();
513
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700514 {
515 XMLPrinter streamer;
516 doc->Print( &streamer );
517 printf( "%s", streamer.CStr() );
518 }
519 {
520 XMLPrinter streamer( 0, true );
521 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200522 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700523 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700524 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300525 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700526 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300527 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800528 delete doc;
529 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800530 {
531 // Test: Dream
532 // XML1 : 1,187,569 bytes in 31,209 allocations
533 // XML2 : 469,073 bytes in 323 allocations
534 //int newStart = gNew;
535 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300536 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300537 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800538
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400539 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300540 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800541 doc.PrintError();
542
543 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400544 doc.FirstChild()->ToDeclaration()->Value() );
Dmitry-Mef5af9512018-03-23 21:01:25 +0300545 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() != 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800546 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
547 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
548 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400549 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800550 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400551 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800552
553 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400554 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300555 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800556 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400557 doc2.FirstChild()->ToDeclaration()->Value() );
Dmitry-Mef5af9512018-03-23 21:01:25 +0300558 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() != 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800559 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
560 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
561 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400562 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800563
564 //gNewTotal = gNew - newStart;
565 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800566
567
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800568 {
569 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
570 "<passages count=\"006\" formatversion=\"20020620\">\n"
571 " <wrong error>\n"
572 "</passages>";
573
574 XMLDocument doc;
575 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300576 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomasona36f7ac2017-12-28 13:48:54 -0800577 const char* errorStr = doc.ErrorStr();
578 XMLTest("Formatted error string",
Lee Thomasonc4836462018-06-29 15:57:55 -0700579 "Error=XML_ERROR_PARSING_ATTRIBUTE ErrorID=7 (0x7) Line number=3: XMLElement name=wrong",
Lee Thomasona36f7ac2017-12-28 13:48:54 -0800580 errorStr);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800581 }
582
583 {
584 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
585
586 XMLDocument doc;
587 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300588 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800589
590 XMLElement* ele = doc.FirstChildElement();
591
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300592 int iVal;
593 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800594 double dVal;
595
596 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300597 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
598 XMLTest( "Query attribute: int as double", 1, (int)dVal );
599 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700600
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800601 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300602 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
603 XMLTest( "Query attribute: double as double", 2.0, dVal );
604 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700605
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800606 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300607 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
608 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700609
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800610 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300611 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
612 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700613
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800614 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300615 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
616 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800617 }
618
619 {
620 const char* str = "<doc/>";
621
622 XMLDocument doc;
623 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300624 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800625
626 XMLElement* ele = doc.FirstChildElement();
627
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800628 int iVal, iVal2;
629 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800630
631 ele->SetAttribute( "str", "strValue" );
632 ele->SetAttribute( "int", 1 );
633 ele->SetAttribute( "double", -1.0 );
634
635 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300636 {
637 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
638 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
639 }
640 {
641 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
642 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
643 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800644
Dmitry-Me2087a272017-07-10 18:13:07 +0300645 {
646 int queryResult = ele->QueryAttribute( "int", &iVal2 );
647 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
648 }
649 {
650 int queryResult = ele->QueryAttribute( "double", &dVal2 );
651 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
652 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800653
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300654 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800655 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
656 XMLTest( "Attribute round trip. int.", 1, iVal );
657 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800658 XMLTest( "Alternate query", true, iVal == iVal2 );
659 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700660 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
Lee Thomasonc4836462018-06-29 15:57:55 -0700661 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800662 }
663
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800664 {
665 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300666 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300667 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800668
669 // Get the attribute "value" from the "Russian" element and check it.
670 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700671 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800672 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
673
674 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
675
676 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
677 0xd1U, 0x81U, 0xd1U, 0x81U,
678 0xd0U, 0xbaU, 0xd0U, 0xb8U,
679 0xd0U, 0xb9U, 0 };
680 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
681
682 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
683 XMLTest( "UTF-8: Browsing russian element name.",
684 russianText,
685 text->Value() );
686
687 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400688 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300689 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800690
691 // Check the round trip.
Dmitry-Me520009e2017-08-10 17:50:03 +0300692 bool roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800693
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200694 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300695 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
696
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300697 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300698 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800699
700 if ( saved && verify )
701 {
Dmitry-Me520009e2017-08-10 17:50:03 +0300702 roundTripOkay = true;
PKEuSc28ba3a2012-07-16 03:08:47 -0700703 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800704 while ( fgets( verifyBuf, 256, verify ) )
705 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700706 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800707 fgets( savedBuf, 256, saved );
708 NullLineEndings( verifyBuf );
709 NullLineEndings( savedBuf );
710
711 if ( strcmp( verifyBuf, savedBuf ) )
712 {
713 printf( "verify:%s<\n", verifyBuf );
714 printf( "saved :%s<\n", savedBuf );
Dmitry-Me520009e2017-08-10 17:50:03 +0300715 roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800716 break;
717 }
718 }
719 }
720 if ( saved )
721 fclose( saved );
722 if ( verify )
723 fclose( verify );
Dmitry-Me520009e2017-08-10 17:50:03 +0300724 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800725 }
726
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800727 // --------GetText()-----------
728 {
729 const char* str = "<foo>This is text</foo>";
730 XMLDocument doc;
731 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300732 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800733 const XMLElement* element = doc.RootElement();
734
735 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
736
737 str = "<foo><b>This is text</b></foo>";
738 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300739 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800740 element = doc.RootElement();
741
742 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
743 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800744
Lee Thomasond6277762012-02-22 16:00:12 -0800745
Uli Kusterer321072e2014-01-21 01:57:38 +0100746 // --------SetText()-----------
747 {
748 const char* str = "<foo></foo>";
749 XMLDocument doc;
750 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300751 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100752 XMLElement* element = doc.RootElement();
753
Lee Thomason9c0678a2014-01-24 10:18:27 -0800754 element->SetText("darkness.");
755 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100756
Lee Thomason9c0678a2014-01-24 10:18:27 -0800757 element->SetText("blue flame.");
758 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100759
760 str = "<foo/>";
761 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300762 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100763 element = doc.RootElement();
764
Lee Thomason9c0678a2014-01-24 10:18:27 -0800765 element->SetText("The driver");
766 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100767
Lee Thomason9c0678a2014-01-24 10:18:27 -0800768 element->SetText("<b>horses</b>");
769 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
770 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100771
772 str = "<foo><bar>Text in nested element</bar></foo>";
773 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300774 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100775 element = doc.RootElement();
Lee Thomasonc4836462018-06-29 15:57:55 -0700776
Lee Thomason9c0678a2014-01-24 10:18:27 -0800777 element->SetText("wolves");
778 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800779
780 str = "<foo/>";
781 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300782 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800783 element = doc.RootElement();
Lee Thomasonc4836462018-06-29 15:57:55 -0700784
Lee Thomason5bb2d802014-01-24 10:42:57 -0800785 element->SetText( "str" );
786 XMLTest( "SetText types", "str", element->GetText() );
787
788 element->SetText( 1 );
789 XMLTest( "SetText types", "1", element->GetText() );
790
791 element->SetText( 1U );
792 XMLTest( "SetText types", "1", element->GetText() );
793
794 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200795 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800796
797 element->SetText( 1.5f );
798 XMLTest( "SetText types", "1.5", element->GetText() );
799
800 element->SetText( 1.5 );
801 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100802 }
803
Lee Thomason51c12712016-06-04 20:18:49 -0700804 // ---------- Attributes ---------
805 {
806 static const int64_t BIG = -123456789012345678;
Lee Thomasoneffdf952019-08-10 17:49:42 -0700807 static const uint64_t BIG_POS = 123456789012345678;
Lee Thomason51c12712016-06-04 20:18:49 -0700808 XMLDocument doc;
809 XMLElement* element = doc.NewElement("element");
810 doc.InsertFirstChild(element);
811
812 {
813 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300814 {
815 int v = 0;
816 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
817 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
818 XMLTest("Attribute: int", -100, v, true);
819 }
820 {
821 int v = 0;
822 int queryResult = element->QueryAttribute("attrib", &v);
823 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
824 XMLTest("Attribute: int", -100, v, true);
825 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700826 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700827 }
828 {
829 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300830 {
831 unsigned v = 0;
832 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
833 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
834 XMLTest("Attribute: unsigned", unsigned(100), v, true);
835 }
836 {
837 unsigned v = 0;
838 int queryResult = element->QueryAttribute("attrib", &v);
839 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
840 XMLTest("Attribute: unsigned", unsigned(100), v, true);
841 }
Lee Thomason5b00e062017-12-28 14:07:47 -0800842 {
843 const char* v = "failed";
Dmitry-Me63d8de62018-01-09 00:20:45 +0300844 XMLError queryResult = element->QueryStringAttribute("not-attrib", &v);
Lee Thomason5b00e062017-12-28 14:07:47 -0800845 XMLTest("Attribute: string default", false, queryResult == XML_SUCCESS);
846 queryResult = element->QueryStringAttribute("attrib", &v);
Dmitry-Me63d8de62018-01-09 00:20:45 +0300847 XMLTest("Attribute: string", XML_SUCCESS, queryResult, true);
Lee Thomason5b00e062017-12-28 14:07:47 -0800848 XMLTest("Attribute: string", "100", v);
849 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700850 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700851 }
852 {
853 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300854 {
855 int64_t v = 0;
856 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
857 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
858 XMLTest("Attribute: int64_t", BIG, v, true);
859 }
860 {
861 int64_t v = 0;
862 int queryResult = element->QueryAttribute("attrib", &v);
863 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
864 XMLTest("Attribute: int64_t", BIG, v, true);
865 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700866 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700867 }
Lee Thomasoneffdf952019-08-10 17:49:42 -0700868 {
869 element->SetAttribute("attrib", BIG_POS);
870 {
871 uint64_t v = 0;
872 XMLError queryResult = element->QueryUnsigned64Attribute("attrib", &v);
873 XMLTest("Attribute: uint64_t", XML_SUCCESS, queryResult, true);
874 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
875 }
876 {
877 uint64_t v = 0;
878 int queryResult = element->QueryAttribute("attrib", &v);
879 XMLTest("Attribute: uint64_t", (int)XML_SUCCESS, queryResult, true);
880 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
881 }
882 XMLTest("Attribute: uint64_t", BIG_POS, element->Unsigned64Attribute("attrib"), true);
883 }
884 {
Lee Thomason51c12712016-06-04 20:18:49 -0700885 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300886 {
887 bool v = false;
888 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
889 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
890 XMLTest("Attribute: bool", true, v, true);
891 }
892 {
893 bool v = false;
894 int queryResult = element->QueryAttribute("attrib", &v);
895 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
896 XMLTest("Attribute: bool", true, v, true);
897 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700898 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700899 }
900 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800901 element->SetAttribute("attrib", true);
902 const char* result = element->Attribute("attrib");
903 XMLTest("Bool true is 'true'", "true", result);
904
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800905 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800906 element->SetAttribute("attrib", true);
907 result = element->Attribute("attrib");
908 XMLTest("Bool true is '1'", "1", result);
909
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800910 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800911 }
912 {
Lee Thomason51c12712016-06-04 20:18:49 -0700913 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300914 {
915 double v = 0;
916 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
917 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
918 XMLTest("Attribute: double", 100.0, v, true);
919 }
920 {
921 double v = 0;
922 int queryResult = element->QueryAttribute("attrib", &v);
923 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
924 XMLTest("Attribute: double", 100.0, v, true);
925 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700926 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700927 }
928 {
929 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300930 {
931 float v = 0;
932 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
933 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
934 XMLTest("Attribute: float", 100.0f, v, true);
935 }
936 {
937 float v = 0;
938 int queryResult = element->QueryAttribute("attrib", &v);
939 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
940 XMLTest("Attribute: float", 100.0f, v, true);
941 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700942 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700943 }
944 {
945 element->SetText(BIG);
946 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300947 XMLError queryResult = element->QueryInt64Text(&v);
948 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700949 XMLTest("Element: int64_t", BIG, v, true);
950 }
Lee Thomasoneffdf952019-08-10 17:49:42 -0700951 {
952 element->SetText(BIG_POS);
953 uint64_t v = 0;
954 XMLError queryResult = element->QueryUnsigned64Text(&v);
955 XMLTest("Element: uint64_t", XML_SUCCESS, queryResult, true);
956 XMLTest("Element: uint64_t", BIG_POS, v, true);
957 }
958 }
Lee Thomason51c12712016-06-04 20:18:49 -0700959
960 // ---------- XMLPrinter stream mode ------
961 {
962 {
Dmitry-Mec0fad292017-08-09 19:05:42 +0300963 FILE* printerfp = fopen("resources/out/printer.xml", "w");
964 XMLTest("Open printer.xml", true, printerfp != 0);
Lee Thomason51c12712016-06-04 20:18:49 -0700965 XMLPrinter printer(printerfp);
966 printer.OpenElement("foo");
967 printer.PushAttribute("attrib-text", "text");
968 printer.PushAttribute("attrib-int", int(1));
969 printer.PushAttribute("attrib-unsigned", unsigned(2));
970 printer.PushAttribute("attrib-int64", int64_t(3));
Lee Thomasoneffdf952019-08-10 17:49:42 -0700971 printer.PushAttribute("attrib-uint64", uint64_t(37));
972 printer.PushAttribute("attrib-bool", true);
Lee Thomason51c12712016-06-04 20:18:49 -0700973 printer.PushAttribute("attrib-double", 4.0);
974 printer.CloseElement();
975 fclose(printerfp);
976 }
977 {
978 XMLDocument doc;
Dmitry-Mec0fad292017-08-09 19:05:42 +0300979 doc.LoadFile("resources/out/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300980 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700981
982 const XMLDocument& cdoc = doc;
983
984 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
985 XMLTest("attrib-text", "text", attrib->Value(), true);
986 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
987 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
988 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
989 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
990 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
991 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
Lee Thomasoneffdf952019-08-10 17:49:42 -0700992 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-uint64");
993 XMLTest("attrib-uint64", uint64_t(37), attrib->Unsigned64Value(), true);
994 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
Lee Thomason51c12712016-06-04 20:18:49 -0700995 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
996 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
997 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
998 }
999
1000 }
1001
Uli Kusterer321072e2014-01-21 01:57:38 +01001002
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001003 // ---------- CDATA ---------------
1004 {
1005 const char* str = "<xmlElement>"
1006 "<![CDATA["
1007 "I am > the rules!\n"
1008 "...since I make symbolic puns"
1009 "]]>"
1010 "</xmlElement>";
1011 XMLDocument doc;
1012 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +03001013 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001014 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -08001015
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001016 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
1017 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -08001018 false );
1019 }
1020
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001021 // ----------- CDATA -------------
1022 {
1023 const char* str = "<xmlElement>"
1024 "<![CDATA["
1025 "<b>I am > the rules!</b>\n"
1026 "...since I make symbolic puns"
1027 "]]>"
1028 "</xmlElement>";
1029 XMLDocument doc;
1030 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +03001031 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001032 doc.Print();
1033
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001034 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001035 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001036 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001037 false );
1038 }
1039
1040 // InsertAfterChild causes crash.
1041 {
1042 // InsertBeforeChild and InsertAfterChild causes crash.
1043 XMLDocument doc;
1044 XMLElement* parent = doc.NewElement( "Parent" );
1045 doc.InsertFirstChild( parent );
1046
1047 XMLElement* childText0 = doc.NewElement( "childText0" );
1048 XMLElement* childText1 = doc.NewElement( "childText1" );
1049
1050 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001051 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001052 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001053 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001054
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001055 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001056 }
Lee Thomasond6277762012-02-22 16:00:12 -08001057
1058 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001059 // Entities not being written correctly.
1060 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -08001061
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001062 const char* passages =
1063 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1064 "<passages count=\"006\" formatversion=\"20020620\">"
1065 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1066 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
1067 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -08001068
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001069 XMLDocument doc;
1070 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001071 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001072 XMLElement* psg = doc.RootElement()->FirstChildElement();
1073 const char* context = psg->Attribute( "context" );
1074 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 -08001075
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001076 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -08001077
Dmitry-Me520009e2017-08-10 17:50:03 +03001078 const char* textFilePath = "resources/out/textfile.txt";
1079 FILE* textfile = fopen( textFilePath, "w" );
1080 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001081 if ( textfile )
1082 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001083 XMLPrinter streamer( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001084 bool acceptResult = psg->Accept( &streamer );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001085 fclose( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001086 XMLTest( "Entity transformation: Accept", true, acceptResult );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001087 }
Thomas Roß0922b732012-09-23 16:31:22 +02001088
Dmitry-Me520009e2017-08-10 17:50:03 +03001089 textfile = fopen( textFilePath, "r" );
1090 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001091 if ( textfile )
1092 {
1093 char buf[ 1024 ];
1094 fgets( buf, 1024, textfile );
1095 XMLTest( "Entity transformation: write. ",
1096 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1097 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1098 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001099 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001100 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001101 }
1102
1103 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001104 // Suppress entities.
1105 const char* passages =
1106 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1107 "<passages count=\"006\" formatversion=\"20020620\">"
1108 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1109 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001110
Lee Thomason6f381b72012-03-02 12:59:39 -08001111 XMLDocument doc( false );
1112 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001113 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001114
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001115 XMLTest( "No entity parsing.",
1116 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1117 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1118 XMLTest( "No entity parsing.", "Crazy &ttk;",
1119 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001120 doc.Print();
1121 }
1122
1123 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001124 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001125
1126 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001127 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001128 XMLTest( "dot in names", false, doc.Error() );
1129 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1130 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001131 }
1132
1133 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001134 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001135
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001136 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001137 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001138 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001139
1140 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1141 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001142 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001143 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001144 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001145
1146 {
1147 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001148 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001149 const char* doctype =
1150 "<?xml version=\"1.0\" ?>"
1151 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1152 "<!ELEMENT title (#PCDATA)>"
1153 "<!ELEMENT books (title,authors)>"
1154 "<element />";
1155
1156 XMLDocument doc;
1157 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001158 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001159 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001160 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001161 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001162 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001163 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001164 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001165
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001166 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1167 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1168
1169 }
1170
1171 {
1172 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001173 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001174 "<!-- Somewhat<evil> -->";
1175 XMLDocument doc;
1176 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001177 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001178
1179 XMLComment* comment = doc.FirstChild()->ToComment();
1180
1181 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1182 }
1183 {
1184 // Double attributes
1185 const char* doctype = "<element attr='red' attr='blue' />";
1186
1187 XMLDocument doc;
1188 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001189
Lee Thomason2fa81722012-11-09 12:37:46 -08001190 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 -08001191 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001192 }
1193
1194 {
1195 // Embedded null in stream.
1196 const char* doctype = "<element att\0r='red' attr='blue' />";
1197
1198 XMLDocument doc;
1199 doc.Parse( doctype );
1200 XMLTest( "Embedded null throws error.", true, doc.Error() );
1201 }
1202
1203 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001204 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001205 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001206 XMLDocument doc;
1207 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001208 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomasona36f7ac2017-12-28 13:48:54 -08001209
1210 // But be sure there is an error string!
1211 const char* errorStr = doc.ErrorStr();
1212 XMLTest("Error string should be set",
Lee Thomasonc4836462018-06-29 15:57:55 -07001213 "Error=XML_ERROR_EMPTY_DOCUMENT ErrorID=13 (0xd) Line number=0",
Lee Thomasona36f7ac2017-12-28 13:48:54 -08001214 errorStr);
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001215 }
1216
1217 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001218 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1219 const char* str = " ";
1220 XMLDocument doc;
1221 doc.Parse( str );
1222 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1223 }
1224
1225 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001226 // Low entities
1227 XMLDocument doc;
1228 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001229 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001230 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001231 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001232 doc.Print();
1233 }
1234
1235 {
1236 // Attribute values with trailing quotes not handled correctly
1237 XMLDocument doc;
1238 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001239 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001240 }
1241
1242 {
1243 // [ 1663758 ] Failure to report error on bad XML
1244 XMLDocument xml;
1245 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001246 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001247 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001248 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001249 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001250 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001251 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001252
1253
1254 {
1255 // [ 1475201 ] TinyXML parses entities in comments
1256 XMLDocument xml;
1257 xml.Parse("<!-- declarations for <head> & <body> -->"
1258 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001259 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001260
1261 XMLNode* e0 = xml.FirstChild();
1262 XMLNode* e1 = e0->NextSibling();
1263 XMLComment* c0 = e0->ToComment();
1264 XMLComment* c1 = e1->ToComment();
1265
1266 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1267 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1268 }
1269
1270 {
1271 XMLDocument xml;
1272 xml.Parse( "<Parent>"
1273 "<child1 att=''/>"
1274 "<!-- With this comment, child2 will not be parsed! -->"
1275 "<child2 att=''/>"
1276 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001277 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001278 xml.Print();
1279
1280 int count = 0;
1281
1282 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1283 ele;
1284 ele = ele->NextSibling() )
1285 {
1286 ++count;
1287 }
1288
1289 XMLTest( "Comments iterate correctly.", 3, count );
1290 }
1291
1292 {
Alanscut8916a3c2019-09-16 17:03:12 +08001293 // trying to repro [1874301]. If it doesn't go into an infinite loop, all is well.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001294 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1295 buf[60] = 239;
1296 buf[61] = 0;
1297
1298 XMLDocument doc;
1299 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001300 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001301 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001302
1303
1304 {
1305 // bug 1827248 Error while parsing a little bit malformed file
1306 // Actually not malformed - should work.
1307 XMLDocument xml;
1308 xml.Parse( "<attributelist> </attributelist >" );
1309 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1310 }
1311
1312 {
1313 // This one must not result in an infinite loop
1314 XMLDocument xml;
1315 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001316 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001317 XMLTest( "Infinite loop test.", true, true );
1318 }
1319#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001320 {
1321 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1322 XMLDocument doc;
1323 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001324 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001325
1326 XMLDocument clone;
1327 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1328 XMLNode* copy = node->ShallowClone( &clone );
1329 clone.InsertEndChild( copy );
1330 }
1331
1332 clone.Print();
1333
1334 int count=0;
1335 const XMLNode* a=clone.FirstChild();
1336 const XMLNode* b=doc.FirstChild();
1337 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1338 ++count;
1339 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1340 }
1341 XMLTest( "Clone and Equal", 4, count );
1342 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001343
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001344 {
Lee Thomason7085f002017-06-01 18:09:43 -07001345 // Deep Cloning of root element.
1346 XMLDocument doc2;
1347 XMLPrinter printer1;
1348 {
1349 // Make sure doc1 is deleted before we test doc2
1350 const char* xml =
1351 "<root>"
1352 " <child1 foo='bar'/>"
1353 " <!-- comment thing -->"
1354 " <child2 val='1'>Text</child2>"
1355 "</root>";
1356 XMLDocument doc;
1357 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001358 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001359
1360 doc.Print(&printer1);
1361 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1362 doc2.InsertFirstChild(root);
1363 }
1364 XMLPrinter printer2;
1365 doc2.Print(&printer2);
1366
1367 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1368 }
1369
1370 {
1371 // Deep Cloning of sub element.
1372 XMLDocument doc2;
1373 XMLPrinter printer1;
1374 {
1375 // Make sure doc1 is deleted before we test doc2
1376 const char* xml =
1377 "<?xml version ='1.0'?>"
1378 "<root>"
1379 " <child1 foo='bar'/>"
1380 " <!-- comment thing -->"
1381 " <child2 val='1'>Text</child2>"
1382 "</root>";
1383 XMLDocument doc;
1384 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001385 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001386
1387 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001388 bool acceptResult = subElement->Accept(&printer1);
1389 XMLTest( "Accept before deep cloning", true, acceptResult );
Lee Thomason7085f002017-06-01 18:09:43 -07001390
1391 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1392 doc2.InsertFirstChild(clonedSubElement);
1393 }
1394 XMLPrinter printer2;
1395 doc2.Print(&printer2);
1396
1397 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1398 }
1399
1400 {
1401 // Deep cloning of document.
1402 XMLDocument doc2;
1403 XMLPrinter printer1;
1404 {
1405 // Make sure doc1 is deleted before we test doc2
1406 const char* xml =
1407 "<?xml version ='1.0'?>"
1408 "<!-- Top level comment. -->"
1409 "<root>"
1410 " <child1 foo='bar'/>"
1411 " <!-- comment thing -->"
1412 " <child2 val='1'>Text</child2>"
1413 "</root>";
1414 XMLDocument doc;
1415 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001416 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001417 doc.Print(&printer1);
1418
1419 doc.DeepCopy(&doc2);
1420 }
1421 XMLPrinter printer2;
1422 doc2.Print(&printer2);
1423
1424 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1425 }
1426
1427
1428 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001429 // This shouldn't crash.
1430 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001431 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001432 {
1433 doc.PrintError();
1434 }
1435 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1436 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001437
Lee Thomason5e3803c2012-04-16 08:57:05 -07001438 {
1439 // Attribute ordering.
1440 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1441 XMLDocument doc;
1442 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001443 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001444 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001445
Lee Thomason5e3803c2012-04-16 08:57:05 -07001446 const XMLAttribute* a = ele->FirstAttribute();
1447 XMLTest( "Attribute order", "1", a->Value() );
1448 a = a->Next();
1449 XMLTest( "Attribute order", "2", a->Value() );
1450 a = a->Next();
1451 XMLTest( "Attribute order", "3", a->Value() );
1452 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001453
Lee Thomason5e3803c2012-04-16 08:57:05 -07001454 ele->DeleteAttribute( "attrib2" );
1455 a = ele->FirstAttribute();
1456 XMLTest( "Attribute order", "1", a->Value() );
1457 a = a->Next();
1458 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001459
Lee Thomason5e3803c2012-04-16 08:57:05 -07001460 ele->DeleteAttribute( "attrib1" );
1461 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001462 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001463 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001464
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001465 {
1466 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001467 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1468 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1469 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1470 XMLDocument doc0;
1471 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001472 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001473 XMLDocument doc1;
1474 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001475 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001476 XMLDocument doc2;
1477 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001478 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001479
Lee Thomason78a773d2012-07-02 10:10:19 -07001480 XMLElement* ele = 0;
1481 ele = doc0.FirstChildElement();
1482 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1483 ele = doc1.FirstChildElement();
1484 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1485 ele = doc2.FirstChildElement();
1486 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001487 }
1488
1489 {
1490 // Make sure we don't go into an infinite loop.
1491 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1492 XMLDocument doc;
1493 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001494 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001495 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1496 XMLElement* ele1 = ele0->NextSiblingElement();
1497 bool equal = ele0->ShallowEqual( ele1 );
1498
1499 XMLTest( "Infinite loop in shallow equal.", true, equal );
1500 }
1501
Lee Thomason5708f812012-03-28 17:46:41 -07001502 // -------- Handles ------------
1503 {
1504 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1505 XMLDocument doc;
1506 doc.Parse( xml );
Dmitry-Me938560f2018-03-15 01:30:39 +03001507 XMLTest( "Handle, parse element with attribute and nested element", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001508
Dmitry-Me938560f2018-03-15 01:30:39 +03001509 {
1510 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1511 XMLTest( "Handle, non-const, element is found", true, ele != 0 );
1512 XMLTest( "Handle, non-const, element name matches", "sub", ele->Value() );
1513 }
Lee Thomason5708f812012-03-28 17:46:41 -07001514
Dmitry-Me938560f2018-03-15 01:30:39 +03001515 {
1516 XMLHandle docH( doc );
1517 XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1518 XMLTest( "Handle, non-const, element not found", true, ele == 0 );
1519 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001520
Dmitry-Me938560f2018-03-15 01:30:39 +03001521 {
1522 const XMLElement* ele = XMLConstHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1523 XMLTest( "Handle, const, element is found", true, ele != 0 );
1524 XMLTest( "Handle, const, element name matches", "sub", ele->Value() );
1525 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001526
Dmitry-Me938560f2018-03-15 01:30:39 +03001527 {
1528 XMLConstHandle docH( doc );
1529 const XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1530 XMLTest( "Handle, const, element not found", true, ele == 0 );
1531 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001532 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001533 {
1534 // Default Declaration & BOM
1535 XMLDocument doc;
1536 doc.InsertEndChild( doc.NewDeclaration() );
1537 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001538
Lee Thomasonf68c4382012-04-28 14:37:11 -07001539 XMLPrinter printer;
1540 doc.Print( &printer );
1541
1542 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001543 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1544 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001545 }
Lee Thomason21be8822012-07-15 17:27:22 -07001546 {
1547 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1548 XMLDocument doc;
1549 doc.Parse( xml );
1550 XMLTest( "Ill formed XML", true, doc.Error() );
1551 }
1552
Lee Thomason50daa322019-08-10 18:00:57 -07001553 {
1554 //API:IntText(),UnsignedText(),Int64Text(),DoubleText(),BoolText() and FloatText() test
1555 const char* xml = "<point> <IntText>-24</IntText> <UnsignedText>42</UnsignedText> \
wangkirinf12d7a22019-07-02 16:58:38 +08001556 <Int64Text>38</Int64Text> <BoolText>true</BoolText> <DoubleText>2.35</DoubleText> </point>";
Lee Thomason50daa322019-08-10 18:00:57 -07001557 XMLDocument doc;
1558 doc.Parse(xml);
1559
1560 const XMLElement* pointElement = doc.RootElement();
1561 int test1 = pointElement->FirstChildElement("IntText")->IntText();
1562 XMLTest("IntText() test", -24, test1);
1563
1564 unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
1565 XMLTest("UnsignedText() test", static_cast<unsigned>(42), test2);
1566
1567 int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
1568 XMLTest("Int64Text() test", static_cast<int64_t>(38), test3);
1569
1570 double test4 = pointElement->FirstChildElement("DoubleText")->DoubleText();
1571 XMLTest("DoubleText() test", 2.35, test4);
1572
1573 float test5 = pointElement->FirstChildElement("DoubleText")->FloatText();
1574 XMLTest("FloatText()) test", 2.35f, test5);
1575
1576 bool test6 = pointElement->FirstChildElement("BoolText")->BoolText();
1577 XMLTest("FloatText()) test", true, test6);
1578 }
wangkirinf12d7a22019-07-02 16:58:38 +08001579
1580 {
1581 //API:ShallowEqual() test
1582 const char* xml = "<playlist id = 'playlist'>"
1583 "<property name = 'track_name'>voice</property>"
1584 "</playlist>";
1585 XMLDocument doc;
1586 doc.Parse( xml );
1587 const XMLNode* PlaylistNode = doc.RootElement();
1588 const XMLNode* PropertyNode = PlaylistNode->FirstChildElement();
1589 bool result;
1590 result = PlaylistNode->ShallowEqual(PropertyNode);
1591 XMLTest("ShallowEqual() test",false,result);
1592 result = PlaylistNode->ShallowEqual(PlaylistNode);
1593 XMLTest("ShallowEqual() test",true,result);
1594 }
1595
1596 {
1597 //API: previousSiblingElement() and NextSiblingElement() test
1598 const char* xml = "<playlist id = 'playlist'>"
1599 "<property name = 'track_name'>voice</property>"
1600 "<entry out = '946' producer = '2_playlist1' in = '0'/>"
1601 "<blank length = '1'/>"
1602 "</playlist>";
1603 XMLDocument doc;
1604 doc.Parse( xml );
1605 XMLElement* ElementPlaylist = doc.FirstChildElement("playlist");
1606 XMLTest("previousSiblingElement() test",true,ElementPlaylist != 0);
1607 const XMLElement* pre = ElementPlaylist->PreviousSiblingElement();
1608 XMLTest("previousSiblingElement() test",true,pre == 0);
1609 const XMLElement* ElementBlank = ElementPlaylist->FirstChildElement("entry")->NextSiblingElement("blank");
1610 XMLTest("NextSiblingElement() test",true,ElementBlank != 0);
1611 const XMLElement* next = ElementBlank->NextSiblingElement();
1612 XMLTest("NextSiblingElement() test",true,next == 0);
1613 const XMLElement* ElementEntry = ElementBlank->PreviousSiblingElement("entry");
1614 XMLTest("PreviousSiblingElement test",true,ElementEntry != 0);
1615 }
1616
Lee Thomason21be8822012-07-15 17:27:22 -07001617 // QueryXYZText
1618 {
1619 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1620 XMLDocument doc;
1621 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001622 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001623
1624 const XMLElement* pointElement = doc.RootElement();
1625
Dmitry-Me43c019d2017-08-02 18:05:23 +03001626 {
1627 int intValue = 0;
1628 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1629 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1630 XMLTest( "QueryIntText", 1, intValue, false );
1631 }
Lee Thomason21be8822012-07-15 17:27:22 -07001632
Dmitry-Me43c019d2017-08-02 18:05:23 +03001633 {
1634 unsigned unsignedValue = 0;
1635 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1636 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1637 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1638 }
Lee Thomason21be8822012-07-15 17:27:22 -07001639
Dmitry-Me43c019d2017-08-02 18:05:23 +03001640 {
1641 float floatValue = 0;
1642 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1643 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1644 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1645 }
Lee Thomason21be8822012-07-15 17:27:22 -07001646
Dmitry-Me43c019d2017-08-02 18:05:23 +03001647 {
1648 double doubleValue = 0;
1649 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1650 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1651 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1652 }
1653
1654 {
1655 bool boolValue = false;
1656 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1657 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1658 XMLTest( "QueryBoolText", true, boolValue, false );
1659 }
Lee Thomason21be8822012-07-15 17:27:22 -07001660 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001661
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001662 {
1663 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1664 XMLDocument doc;
1665 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001666 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001667 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001668
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001669 {
1670 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1671 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001672 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001673 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001674 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001675
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001676 {
1677 const char* xml = "<3lement></3lement>";
1678 XMLDocument doc;
1679 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001680 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001681 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001682
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001683 {
1684 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1685 XMLDocument doc;
1686 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001687 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001688 }
1689
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001690 {
1691 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001692 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001693 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001694 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001695 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001696 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001697 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001698 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001699 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001700 }
Dmitry-Me985ea1f2017-08-28 18:36:29 +03001701
1702 {
1703 XMLDocument doc;
1704 XMLTest( "No error initially", false, doc.Error() );
1705 XMLError error = doc.Parse( "This is not XML" );
1706 XMLTest( "Error after invalid XML", true, doc.Error() );
1707 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1708 doc.Clear();
1709 XMLTest( "No error after Clear()", false, doc.Error() );
1710 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001711
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001712 // ----------- Whitespace ------------
1713 {
1714 const char* xml = "<element>"
1715 "<a> This \nis &apos; text &apos; </a>"
1716 "<b> This is &apos; text &apos; \n</b>"
1717 "<c>This is &apos; \n\n text &apos;</c>"
1718 "</element>";
1719 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1720 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001721 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001722
1723 const XMLElement* element = doc.FirstChildElement();
1724 for( const XMLElement* parent = element->FirstChildElement();
1725 parent;
1726 parent = parent->NextSiblingElement() )
1727 {
1728 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1729 }
1730 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001731
Lee Thomasonae9ab072012-10-24 10:17:53 -07001732#if 0
1733 {
1734 // Passes if assert doesn't fire.
1735 XMLDocument xmlDoc;
1736
1737 xmlDoc.NewDeclaration();
1738 xmlDoc.NewComment("Configuration file");
1739
1740 XMLElement *root = xmlDoc.NewElement("settings");
1741 root->SetAttribute("version", 2);
1742 }
1743#endif
1744
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001745 {
1746 const char* xml = "<element> </element>";
1747 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1748 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001749 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001750 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1751 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001752
Lee Thomason5b0a6772012-11-19 13:54:42 -08001753 {
1754 // An assert should not fire.
1755 const char* xml = "<element/>";
1756 XMLDocument doc;
1757 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001758 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001759 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1760 XMLTest( "Tracking unused elements", true, ele != 0, false );
1761 }
1762
Lee Thomasona6412ac2012-12-13 15:39:11 -08001763
1764 {
1765 const char* xml = "<parent><child>abc</child></parent>";
1766 XMLDocument doc;
1767 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001768 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001769 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1770
1771 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001772 bool acceptResult = ele->Accept( &printer );
1773 XMLTest( "Accept of sub-element", true, acceptResult );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001774 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1775 }
1776
1777
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001778 {
1779 XMLDocument doc;
1780 XMLError error = doc.LoadFile( "resources/empty.xml" );
1781 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001782 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001783 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001784 }
1785
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001786 {
1787 // BOM preservation
1788 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1789 {
1790 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001791 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001792 XMLPrinter printer;
1793 doc.Print( &printer );
1794
1795 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
Wang Kirine08c2d22019-05-30 15:25:04 +08001796 doc.SaveFile( "resources/out/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001797 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001798 }
1799 {
1800 XMLDocument doc;
Wang Kirine08c2d22019-05-30 15:25:04 +08001801 doc.LoadFile( "resources/out/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001802 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001803 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1804
1805 XMLPrinter printer;
1806 doc.Print( &printer );
1807 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1808 }
1809 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001810
Michael Daumlinged523282013-10-23 07:47:29 +02001811 {
1812 // Insertion with Removal
1813 const char* xml = "<?xml version=\"1.0\" ?>"
1814 "<root>"
1815 "<one>"
1816 "<subtree>"
1817 "<elem>element 1</elem>text<!-- comment -->"
1818 "</subtree>"
1819 "</one>"
1820 "<two/>"
1821 "</root>";
1822 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1823 "<root>"
1824 "<one/>"
1825 "<two>"
1826 "<subtree>"
1827 "<elem>element 1</elem>text<!-- comment -->"
1828 "</subtree>"
1829 "</two>"
1830 "</root>";
1831 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1832 "<root>"
1833 "<one/>"
1834 "<subtree>"
1835 "<elem>element 1</elem>text<!-- comment -->"
1836 "</subtree>"
1837 "<two/>"
1838 "</root>";
1839 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1840 "<root>"
1841 "<one/>"
1842 "<two/>"
1843 "<subtree>"
1844 "<elem>element 1</elem>text<!-- comment -->"
1845 "</subtree>"
1846 "</root>";
1847
1848 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001849 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001850 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001851 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1852 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1853 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001854 XMLPrinter printer1(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001855 bool acceptResult = doc.Accept(&printer1);
1856 XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001857 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001858
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001859 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001860 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001861 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1862 two = doc.RootElement()->FirstChildElement("two");
1863 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001864 XMLPrinter printer2(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001865 acceptResult = doc.Accept(&printer2);
1866 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001867 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001868
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001869 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001870 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001871 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1872 subtree = one->FirstChildElement("subtree");
1873 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001874 XMLPrinter printer3(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001875 acceptResult = doc.Accept(&printer3);
1876 XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001877 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001878
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001879 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001880 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001881 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1882 two = doc.RootElement()->FirstChildElement("two");
Dmitry-Me17814942018-10-16 00:11:39 +03001883 XMLTest("<two> is the last child at root level", true, two == doc.RootElement()->LastChildElement());
Michael Daumlinged523282013-10-23 07:47:29 +02001884 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001885 XMLPrinter printer4(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001886 acceptResult = doc.Accept(&printer4);
1887 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001888 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001889 }
1890
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001891 {
1892 const char* xml = "<svg width = \"128\" height = \"128\">"
1893 " <text> </text>"
1894 "</svg>";
1895 XMLDocument doc;
1896 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001897 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001898 doc.Print();
1899 }
1900
Lee Thomason92e521b2014-11-15 17:45:51 -08001901 {
1902 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001903 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1904 XMLDocument doc;
1905 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001906 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001907 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001908 }
1909
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001910#if 1
Lee Thomasonc4836462018-06-29 15:57:55 -07001911 // the question being explored is what kind of print to use:
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001912 // https://github.com/leethomason/tinyxml2/issues/63
1913 {
1914 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1915 const char* xml = "<element/>";
1916 XMLDocument doc;
1917 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001918 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001919 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1920 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1921 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1922 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1923 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1924 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1925
1926 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1927 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1928 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1929 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1930 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1931 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1932
1933 doc.Print();
1934
1935 /* The result of this test is platform, compiler, and library version dependent. :("
1936 XMLPrinter printer;
1937 doc.Print( &printer );
Lee Thomasonc4836462018-06-29 15:57:55 -07001938 XMLTest( "Float and double formatting.",
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001939 "<element attrA-f64=\"123456789.12345679\" attrB-f64=\"1001000000\" attrC-f64=\"1e+20\" attrD-f64=\"0.123456789\" attrA-f32=\"1.2345679e+08\" attrB-f32=\"1.001e+09\" attrC-f32=\"1e+20\" attrD-f32=\"0.12345679\"/>\n",
Lee Thomasonc4836462018-06-29 15:57:55 -07001940 printer.CStr(),
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001941 true );
1942 */
1943 }
1944#endif
Lee Thomasonc4836462018-06-29 15:57:55 -07001945
Lee Thomasonf07b9522014-10-30 13:25:12 -07001946 {
1947 // Issue #184
1948 // If it doesn't assert, it passes. Caused by objects
1949 // getting created during parsing which are then
1950 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001951 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001952 {
1953 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001954 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001955 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001956 }
1957 {
1958 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001959 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001960 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001961 doc.Clear();
1962 }
1963 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001964
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001965 {
Peter Matula50689912018-01-09 12:52:26 +01001966 // If this doesn't assert in TINYXML2_DEBUG, all is well.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001967 tinyxml2::XMLDocument doc;
1968 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1969 doc.DeleteNode(pRoot);
1970 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001971
Dmitry-Mee5790db2017-07-28 17:54:38 +03001972 {
1973 XMLDocument doc;
1974 XMLElement* root = doc.NewElement( "Root" );
1975 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1976 doc.InsertEndChild( root );
1977 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1978 }
1979
1980 {
Peter Matula50689912018-01-09 12:52:26 +01001981 // If this doesn't assert in TINYXML2_DEBUG, all is well.
Dmitry-Mee5790db2017-07-28 17:54:38 +03001982 XMLDocument doc;
1983 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1984 XMLElement* linkedRoot = doc.NewElement( "Root" );
1985 doc.InsertFirstChild( linkedRoot );
1986 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1987 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1988 }
1989
Dmitry-Me8b67d742014-12-22 11:35:12 +03001990 {
Peter Matula50689912018-01-09 12:52:26 +01001991 // Should not assert in TINYXML2_DEBUG
Dmitry-Me8b67d742014-12-22 11:35:12 +03001992 XMLPrinter printer;
1993 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001994
Dmitry-Me6f51c802015-03-14 13:25:03 +03001995 {
1996 // Issue 291. Should not crash
1997 const char* xml = "&#0</a>";
1998 XMLDocument doc;
1999 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03002000 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03002001
2002 XMLPrinter printer;
2003 doc.Print( &printer );
2004 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00002005 {
Lee Thomasonc4836462018-06-29 15:57:55 -07002006 // Issue 299. Can print elements that are not linked in.
Ant Mitchell148cc1a2015-03-24 15:12:35 +00002007 // Will crash if issue not fixed.
2008 XMLDocument doc;
2009 XMLElement* newElement = doc.NewElement( "printme" );
2010 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002011 bool acceptResult = newElement->Accept( &printer );
2012 XMLTest( "printme - Accept()", true, acceptResult );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03002013 // Delete the node to avoid possible memory leak report in debug output
2014 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00002015 }
Lee Thomasonf6577832015-03-26 11:18:21 -07002016 {
Ant Mitchell189198f2015-03-24 16:20:36 +00002017 // Issue 302. Clear errors from LoadFile/SaveFile
2018 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03002019 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00002020 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03002021 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00002022 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03002023 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00002024 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03002025
Dmitry-Med9852a52015-03-25 10:17:49 +03002026 {
2027 // If a document fails to load then subsequent
2028 // successful loads should clear the error
2029 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03002030 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03002031 doc.LoadFile( "resources/no-such-file.xml" );
2032 XMLTest( "No such file - should fail", true, doc.Error() );
2033
2034 doc.LoadFile( "resources/dream.xml" );
2035 XMLTest( "Error should be cleared", false, doc.Error() );
2036 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05302037
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05302038 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002039 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07002040 const char* xml0 = "<?xml version=\"1.0\" ?>"
2041 " <!-- xml version=\"1.1\" -->"
2042 "<first />";
2043 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002044 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07002045 "<first />";
2046 const char* xml2 = "<first />"
2047 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002048 const char* xml3 = "<first></first>"
2049 "<?xml version=\"1.0\" ?>";
2050
2051 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
2052
Lee Thomason85492022015-05-22 11:07:45 -07002053 XMLDocument doc;
2054 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002055 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07002056 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002057 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07002058 doc.Parse(xml2);
Dmitry-Me6a18a312018-03-23 21:09:13 +03002059 XMLTest("Test that declaration after self-closed child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002060 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002061 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002062 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002063 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05302064 }
Dmitry-Med9852a52015-03-25 10:17:49 +03002065
Lee Thomason85492022015-05-22 11:07:45 -07002066 {
2067 // No matter - before or after successfully parsing a text -
Dmitry-Me26043362017-08-30 17:40:15 +03002068 // calling XMLDocument::Value() used to cause an assert in debug.
orbitcowboy22b21ec2018-07-17 11:52:57 +02002069 // Null must be returned.
Lee Thomason85492022015-05-22 11:07:45 -07002070 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
2071 "<first />"
2072 "<second />";
2073 XMLDocument* doc = new XMLDocument();
2074 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2075 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03002076 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07002077 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2078 delete doc;
2079 }
2080
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002081 {
2082 XMLDocument doc;
2083 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
Dmitry-Med3f6c632017-08-30 17:43:14 +03002084 const XMLError error = static_cast<XMLError>(i);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002085 const char* name = XMLDocument::ErrorIDToName(error);
Dmitry-Me95f687b2018-03-23 20:56:46 +03002086 XMLTest( "ErrorName() not null after ClearError()", true, name != 0 );
2087 if( name == 0 ) {
2088 // passing null pointer into strlen() is undefined behavior, so
2089 // compiler is allowed to optimise away the null test above if it's
2090 // as reachable as the strlen() call
2091 continue;
2092 }
2093 XMLTest( "ErrorName() not empty after ClearError()", true, strlen(name) > 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002094 }
2095 }
2096
Lee Thomason816d3fa2017-06-05 14:35:55 -07002097 {
Derek Quambe69ae62018-04-18 13:40:46 -05002098 const char* html("<!DOCTYPE html><html><body><p>test</p><p><br/></p></body></html>");
2099 XMLDocument doc(false);
2100 doc.Parse(html);
2101
2102 XMLPrinter printer(0, true);
2103 doc.Print(&printer);
2104
2105 XMLTest(html, html, printer.CStr());
2106 }
2107
2108 {
Lee Thomasonc4836462018-06-29 15:57:55 -07002109 // Evil memory leaks.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07002110 // If an XMLElement (etc) is allocated via NewElement() (etc.)
2111 // and NOT added to the XMLDocument, what happens?
2112 //
2113 // Previously (buggy):
2114 // The memory would be free'd when the XMLDocument is
Dmitry-Mea9e75d12017-09-08 19:05:23 +03002115 // destructed. But the XMLElement destructor wasn't called, so
2116 // memory allocated for the XMLElement text would not be free'd.
2117 // In practice this meant strings allocated for the XMLElement
2118 // text would be leaked. An edge case, but annoying.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07002119 // Now:
Dmitry-Mea9e75d12017-09-08 19:05:23 +03002120 // The XMLElement destructor is called. But the unlinked nodes
2121 // have to be tracked using a list. This has a minor performance
2122 // impact that can become significant if you have a lot of
2123 // unlinked nodes. (But why would you do that?)
2124 // The only way to see this bug was in a Visual C++ runtime debug heap
2125 // leak tracker. This is compiled in by default on Windows Debug and
2126 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
Lee Thomason816d3fa2017-06-05 14:35:55 -07002127 {
2128 XMLDocument doc;
2129 doc.NewElement("LEAK 1");
2130 }
2131 {
2132 XMLDocument doc;
2133 XMLElement* ele = doc.NewElement("LEAK 2");
2134 doc.DeleteNode(ele);
2135 }
2136 }
2137
Lee Thomason224ef772017-06-16 09:45:26 -07002138 {
Lee Thomasonf928c352018-04-05 09:24:20 -07002139 // Bad bad crash. Parsing error results in stack overflow, if uncaught.
2140 const char* TESTS[] = {
2141 "./resources/xmltest-5330.xml",
2142 "./resources/xmltest-4636783552757760.xml",
2143 "./resources/xmltest-5720541257269248.xml",
2144 0
2145 };
2146 for (int i=0; TESTS[i]; ++i) {
2147 XMLDocument doc;
2148 doc.LoadFile(TESTS[i]);
Lee Thomasone2d02e12018-04-05 15:57:48 -07002149 XMLTest("Stack overflow prevented.", XML_ELEMENT_DEPTH_EXCEEDED, doc.ErrorID());
Lee Thomasonf928c352018-04-05 09:24:20 -07002150 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002151 }
Lee Thomasondb13a822018-07-28 14:56:20 -07002152 {
2153 const char* TESTS[] = {
2154 "./resources/xmltest-5662204197076992.xml", // Security-level performance issue.
2155 0
2156 };
2157 for (int i = 0; TESTS[i]; ++i) {
2158 XMLDocument doc;
2159 doc.LoadFile(TESTS[i]);
2160 // Need only not crash / lock up.
2161 XMLTest("Fuzz attack prevented.", true, true);
2162 }
2163 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002164 {
Lee Thomason224ef772017-06-16 09:45:26 -07002165 // Crashing reported via email.
2166 const char* xml =
2167 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07002168 "<property name='track_name'>voice</property>"
2169 "<property name='audio_track'>1</property>"
2170 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2171 "<blank length = '1' />"
2172 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2173 "<blank length = '2' />"
2174 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2175 "<blank length = '1' />"
2176 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07002177 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07002178
Lee Thomason224ef772017-06-16 09:45:26 -07002179 // It's not a good idea to delete elements as you walk the
2180 // list. I'm not sure this technically should work; but it's
2181 // an interesting test case.
2182 XMLDocument doc;
2183 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002184 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03002185
2186 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07002187 XMLTest("Crash bug parsing", true, playlist != 0);
2188
Dmitry-Meb41e24a2017-09-27 18:51:01 +03002189 {
2190 const char* elementName = "entry";
2191 XMLElement* entry = playlist->FirstChildElement(elementName);
2192 XMLTest("Crash bug parsing", true, entry != 0);
2193 while (entry) {
2194 XMLElement* todelete = entry;
2195 entry = entry->NextSiblingElement(elementName);
2196 playlist->DeleteChild(todelete);
2197 }
2198 entry = playlist->FirstChildElement(elementName);
2199 XMLTest("Crash bug parsing", true, entry == 0);
2200 }
2201 {
2202 const char* elementName = "blank";
2203 XMLElement* blank = playlist->FirstChildElement(elementName);
2204 XMLTest("Crash bug parsing", true, blank != 0);
2205 while (blank) {
2206 XMLElement* todelete = blank;
2207 blank = blank->NextSiblingElement(elementName);
2208 playlist->DeleteChild(todelete);
2209 }
2210 XMLTest("Crash bug parsing", true, blank == 0);
2211 }
Lee Thomason224ef772017-06-16 09:45:26 -07002212
2213 tinyxml2::XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002214 const bool acceptResult = playlist->Accept(&printer);
2215 XMLTest("Crash bug parsing - Accept()", true, acceptResult);
Lee Thomason224ef772017-06-16 09:45:26 -07002216 printf("%s\n", printer.CStr());
2217
Lee Thomasonc4836462018-06-29 15:57:55 -07002218 // No test; it only need to not crash.
Lee Thomason82bb0742017-06-16 09:48:20 -07002219 // Still, wrap it up with a sanity check
2220 int nProperty = 0;
2221 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2222 nProperty++;
2223 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002224 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07002225 }
2226
kezenatorec694152016-11-26 17:21:43 +10002227 // ----------- Line Number Tracking --------------
2228 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002229 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002230 {
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002231 TestUtil() : str() {}
2232
kezenatorec694152016-11-26 17:21:43 +10002233 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2234 {
2235 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002236 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002237
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002238 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002239 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002240 XMLTest(testString, expected_error, parseError);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002241 XMLTest(testString, expectedLine, doc.ErrorLineNum());
kezenatorec694152016-11-26 17:21:43 +10002242 };
2243
2244 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2245 {
2246 XMLDocument doc;
2247 doc.Parse(docStr);
2248 XMLTest(testString, false, doc.Error());
2249 TestDocLines(testString, doc, expectedLines);
2250 }
2251
2252 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2253 {
2254 XMLDocument doc;
2255 doc.LoadFile(file_name);
2256 XMLTest(testString, false, doc.Error());
2257 TestDocLines(testString, doc, expectedLines);
2258 }
2259
2260 private:
2261 DynArray<char, 10> str;
2262
2263 void Push(char type, int lineNum)
2264 {
2265 str.Push(type);
2266 str.Push(char('0' + (lineNum / 10)));
2267 str.Push(char('0' + (lineNum % 10)));
2268 }
2269
2270 bool VisitEnter(const XMLDocument& doc)
2271 {
kezenator19d8ea82016-11-29 19:50:27 +10002272 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002273 return true;
2274 }
2275 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2276 {
kezenator19d8ea82016-11-29 19:50:27 +10002277 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002278 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002279 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002280 return true;
2281 }
2282 bool Visit(const XMLDeclaration& declaration)
2283 {
kezenator19d8ea82016-11-29 19:50:27 +10002284 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002285 return true;
2286 }
2287 bool Visit(const XMLText& text)
2288 {
kezenator19d8ea82016-11-29 19:50:27 +10002289 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002290 return true;
2291 }
2292 bool Visit(const XMLComment& comment)
2293 {
kezenator19d8ea82016-11-29 19:50:27 +10002294 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002295 return true;
2296 }
2297 bool Visit(const XMLUnknown& unknown)
2298 {
kezenator19d8ea82016-11-29 19:50:27 +10002299 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002300 return true;
2301 }
2302
2303 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2304 {
2305 str.Clear();
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002306 const bool acceptResult = doc.Accept(this);
2307 XMLTest(testString, true, acceptResult);
kezenatorec694152016-11-26 17:21:43 +10002308 str.Push(0);
2309 XMLTest(testString, expectedLines, str.Mem());
2310 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002311 } tester;
kezenatorec694152016-11-26 17:21:43 +10002312
Lee Thomasone90e9012016-12-24 07:34:39 -08002313 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2314 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2315 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2316 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2317 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2318 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2319 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2320 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2321 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2322 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2323 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002324
Lee Thomasone90e9012016-12-24 07:34:39 -08002325 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002326 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002327
2328 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2329 "<root a='b' \n" // 2 Element Attribute
2330 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2331 "newline in text \n" // 4 Text
2332 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2333 " cdata test ]]><!-- comment -->\n" // 6 Comment
2334 "<! unknown></root>", // 7 Unknown
2335
kezenatorec694152016-11-26 17:21:43 +10002336 "D01L01E02A02A03T03E03T04E05T05C06U07");
2337
Lee Thomasone90e9012016-12-24 07:34:39 -08002338 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002339 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002340
2341 "\r\n" // 1 Doc (arguably should be line 2)
2342 "<?xml version=\"1.0\"?>\n" // 2 DecL
2343 "<root>\r\n" // 3 Element
2344 "\n" // 4
2345 "text contining new line \n" // 5 Text
2346 " and also containing crlf \r\n" // 6
2347 "<sub><![CDATA[\n" // 7 Element Text
2348 "cdata containing new line \n" // 8
2349 " and also containing cflr\r\n" // 9
2350 "]]></sub><sub2/></root>", // 10 Element
2351
kezenatorec694152016-11-26 17:21:43 +10002352 "D01L02E03T05E07T07E10");
2353
Lee Thomasone90e9012016-12-24 07:34:39 -08002354 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002355 "LineNumbers-File",
2356 "resources/utf8test.xml",
2357 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2358 }
2359
Lee Thomasonf49b9652017-10-11 10:57:49 -07002360 {
2361 const char* xml = "<Hello>Text</Error>";
2362 XMLDocument doc;
2363 doc.Parse(xml);
2364 XMLTest("Test mismatched elements.", true, doc.Error());
2365 XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2366 // For now just make sure calls work & doesn't crash.
2367 // May solidify the error output in the future.
2368 printf("%s\n", doc.ErrorStr());
2369 doc.PrintError();
2370 }
2371
Lee Thomason85492022015-05-22 11:07:45 -07002372 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002373 {
2374#if defined( _MSC_VER )
2375 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002376 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002377#endif
2378
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002379 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002380 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002381 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002382 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002383 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002384
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002385 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002386 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002387 size_t bytesRead = fread(mem, 1, size, perfFP);
2388 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002389 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002390 mem[size] = 0;
2391
2392#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002393 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002394#else
2395 clock_t cstart = clock();
2396#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002397 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002398 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002399 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002400 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002401 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002402 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002403 }
2404#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002405 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002406#else
2407 clock_t cend = clock();
2408#endif
Dmitry-Me1ab85872017-08-10 17:28:10 +03002409 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002410
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002411 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002412
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002413 static const char* note =
Peter Matula50689912018-01-09 12:52:26 +01002414#ifdef TINYXML2_DEBUG
Lee Thomason6f381b72012-03-02 12:59:39 -08002415 "DEBUG";
2416#else
2417 "Release";
2418#endif
2419
2420#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002421 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002422#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002423 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002424#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002425 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002426 }
2427
Peter Matula50689912018-01-09 12:52:26 +01002428#if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
Dmitry-Mede381df2017-07-26 18:05:25 +03002429 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002430 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002431
2432 _CrtMemState diffMemState;
2433 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2434 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002435
2436 {
2437 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2438 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2439 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002440 }
2441#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002442
2443 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002444
2445 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002446}