blob: 7f196f117a55cc7138c3c3b0ae623748965d788a [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
Lee Thomason46379652020-07-02 15:23:00 -0700635 const char* answer = 0;
636 ele->QueryAttribute("str", &answer);
637 XMLTest("Query char attribute", "strValue", answer);
638
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800639 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300640 {
641 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
642 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
643 }
644 {
645 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
646 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
647 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800648
Dmitry-Me2087a272017-07-10 18:13:07 +0300649 {
cugone5e765732021-05-09 02:05:54 -0500650 XMLError queryResult = ele->QueryAttribute( "int", &iVal2 );
Dmitry-Me2087a272017-07-10 18:13:07 +0300651 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
652 }
653 {
cugone5e765732021-05-09 02:05:54 -0500654 XMLError queryResult = ele->QueryAttribute( "double", &dVal2 );
Dmitry-Me2087a272017-07-10 18:13:07 +0300655 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
656 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800657
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300658 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800659 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
660 XMLTest( "Attribute round trip. int.", 1, iVal );
661 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800662 XMLTest( "Alternate query", true, iVal == iVal2 );
663 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700664 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
Lee Thomasonc4836462018-06-29 15:57:55 -0700665 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800666 }
667
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800668 {
669 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300670 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300671 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800672
673 // Get the attribute "value" from the "Russian" element and check it.
674 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700675 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800676 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
677
678 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
679
680 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
681 0xd1U, 0x81U, 0xd1U, 0x81U,
682 0xd0U, 0xbaU, 0xd0U, 0xb8U,
683 0xd0U, 0xb9U, 0 };
684 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
685
686 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
687 XMLTest( "UTF-8: Browsing russian element name.",
688 russianText,
689 text->Value() );
690
691 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400692 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300693 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800694
695 // Check the round trip.
Dmitry-Me520009e2017-08-10 17:50:03 +0300696 bool roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800697
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200698 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300699 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
700
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300701 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300702 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800703
704 if ( saved && verify )
705 {
Dmitry-Me520009e2017-08-10 17:50:03 +0300706 roundTripOkay = true;
PKEuSc28ba3a2012-07-16 03:08:47 -0700707 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800708 while ( fgets( verifyBuf, 256, verify ) )
709 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700710 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800711 fgets( savedBuf, 256, saved );
712 NullLineEndings( verifyBuf );
713 NullLineEndings( savedBuf );
714
715 if ( strcmp( verifyBuf, savedBuf ) )
716 {
717 printf( "verify:%s<\n", verifyBuf );
718 printf( "saved :%s<\n", savedBuf );
Dmitry-Me520009e2017-08-10 17:50:03 +0300719 roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800720 break;
721 }
722 }
723 }
724 if ( saved )
725 fclose( saved );
726 if ( verify )
727 fclose( verify );
Dmitry-Me520009e2017-08-10 17:50:03 +0300728 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800729 }
730
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800731 // --------GetText()-----------
732 {
733 const char* str = "<foo>This is text</foo>";
734 XMLDocument doc;
735 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300736 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800737 const XMLElement* element = doc.RootElement();
738
739 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
740
741 str = "<foo><b>This is text</b></foo>";
742 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300743 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800744 element = doc.RootElement();
745
746 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
747 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800748
Lee Thomasond6277762012-02-22 16:00:12 -0800749
Uli Kusterer321072e2014-01-21 01:57:38 +0100750 // --------SetText()-----------
751 {
752 const char* str = "<foo></foo>";
753 XMLDocument doc;
754 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300755 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100756 XMLElement* element = doc.RootElement();
757
Lee Thomason9c0678a2014-01-24 10:18:27 -0800758 element->SetText("darkness.");
759 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100760
Lee Thomason9c0678a2014-01-24 10:18:27 -0800761 element->SetText("blue flame.");
762 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100763
764 str = "<foo/>";
765 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300766 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100767 element = doc.RootElement();
768
Lee Thomason9c0678a2014-01-24 10:18:27 -0800769 element->SetText("The driver");
770 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100771
Lee Thomason9c0678a2014-01-24 10:18:27 -0800772 element->SetText("<b>horses</b>");
773 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
774 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100775
776 str = "<foo><bar>Text in nested element</bar></foo>";
777 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300778 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100779 element = doc.RootElement();
Lee Thomasonc4836462018-06-29 15:57:55 -0700780
Lee Thomason9c0678a2014-01-24 10:18:27 -0800781 element->SetText("wolves");
782 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800783
784 str = "<foo/>";
785 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300786 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800787 element = doc.RootElement();
Lee Thomasonc4836462018-06-29 15:57:55 -0700788
Lee Thomason5bb2d802014-01-24 10:42:57 -0800789 element->SetText( "str" );
790 XMLTest( "SetText types", "str", element->GetText() );
791
792 element->SetText( 1 );
793 XMLTest( "SetText types", "1", element->GetText() );
794
795 element->SetText( 1U );
796 XMLTest( "SetText types", "1", element->GetText() );
797
798 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200799 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800800
801 element->SetText( 1.5f );
802 XMLTest( "SetText types", "1.5", element->GetText() );
803
804 element->SetText( 1.5 );
805 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100806 }
807
Lee Thomason51c12712016-06-04 20:18:49 -0700808 // ---------- Attributes ---------
809 {
810 static const int64_t BIG = -123456789012345678;
Lee Thomasoneffdf952019-08-10 17:49:42 -0700811 static const uint64_t BIG_POS = 123456789012345678;
Lee Thomason51c12712016-06-04 20:18:49 -0700812 XMLDocument doc;
813 XMLElement* element = doc.NewElement("element");
814 doc.InsertFirstChild(element);
815
816 {
817 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300818 {
819 int v = 0;
820 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
821 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
822 XMLTest("Attribute: int", -100, v, true);
823 }
824 {
825 int v = 0;
cugone5e765732021-05-09 02:05:54 -0500826 XMLError queryResult = element->QueryAttribute("attrib", &v);
Dmitry-Me2087a272017-07-10 18:13:07 +0300827 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
828 XMLTest("Attribute: int", -100, v, true);
829 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700830 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700831 }
832 {
833 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300834 {
835 unsigned v = 0;
836 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
837 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
838 XMLTest("Attribute: unsigned", unsigned(100), v, true);
839 }
840 {
841 unsigned v = 0;
cugone5e765732021-05-09 02:05:54 -0500842 XMLError queryResult = element->QueryAttribute("attrib", &v);
Dmitry-Me2087a272017-07-10 18:13:07 +0300843 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
844 XMLTest("Attribute: unsigned", unsigned(100), v, true);
845 }
Lee Thomason5b00e062017-12-28 14:07:47 -0800846 {
847 const char* v = "failed";
Dmitry-Me63d8de62018-01-09 00:20:45 +0300848 XMLError queryResult = element->QueryStringAttribute("not-attrib", &v);
Lee Thomason5b00e062017-12-28 14:07:47 -0800849 XMLTest("Attribute: string default", false, queryResult == XML_SUCCESS);
850 queryResult = element->QueryStringAttribute("attrib", &v);
Dmitry-Me63d8de62018-01-09 00:20:45 +0300851 XMLTest("Attribute: string", XML_SUCCESS, queryResult, true);
Lee Thomason5b00e062017-12-28 14:07:47 -0800852 XMLTest("Attribute: string", "100", v);
853 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700854 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700855 }
856 {
857 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300858 {
859 int64_t v = 0;
860 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
861 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
862 XMLTest("Attribute: int64_t", BIG, v, true);
863 }
864 {
865 int64_t v = 0;
cugone5e765732021-05-09 02:05:54 -0500866 XMLError queryResult = element->QueryAttribute("attrib", &v);
Dmitry-Me2087a272017-07-10 18:13:07 +0300867 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
868 XMLTest("Attribute: int64_t", BIG, v, true);
869 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700870 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700871 }
Lee Thomasoneffdf952019-08-10 17:49:42 -0700872 {
873 element->SetAttribute("attrib", BIG_POS);
874 {
875 uint64_t v = 0;
876 XMLError queryResult = element->QueryUnsigned64Attribute("attrib", &v);
877 XMLTest("Attribute: uint64_t", XML_SUCCESS, queryResult, true);
878 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
879 }
880 {
881 uint64_t v = 0;
cugone5e765732021-05-09 02:05:54 -0500882 XMLError queryResult = element->QueryAttribute("attrib", &v);
Lee Thomasoneffdf952019-08-10 17:49:42 -0700883 XMLTest("Attribute: uint64_t", (int)XML_SUCCESS, queryResult, true);
884 XMLTest("Attribute: uint64_t", BIG_POS, v, true);
885 }
886 XMLTest("Attribute: uint64_t", BIG_POS, element->Unsigned64Attribute("attrib"), true);
887 }
888 {
Lee Thomason51c12712016-06-04 20:18:49 -0700889 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300890 {
891 bool v = false;
892 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
893 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
894 XMLTest("Attribute: bool", true, v, true);
895 }
896 {
897 bool v = false;
cugone5e765732021-05-09 02:05:54 -0500898 XMLError queryResult = element->QueryAttribute("attrib", &v);
Dmitry-Me2087a272017-07-10 18:13:07 +0300899 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
900 XMLTest("Attribute: bool", true, v, true);
901 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700902 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700903 }
904 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800905 element->SetAttribute("attrib", true);
906 const char* result = element->Attribute("attrib");
907 XMLTest("Bool true is 'true'", "true", result);
908
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800909 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800910 element->SetAttribute("attrib", true);
911 result = element->Attribute("attrib");
912 XMLTest("Bool true is '1'", "1", result);
913
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800914 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800915 }
916 {
Lee Thomason51c12712016-06-04 20:18:49 -0700917 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300918 {
919 double v = 0;
920 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
921 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
922 XMLTest("Attribute: double", 100.0, v, true);
923 }
924 {
925 double v = 0;
cugone5e765732021-05-09 02:05:54 -0500926 XMLError queryResult = element->QueryAttribute("attrib", &v);
Dmitry-Me2087a272017-07-10 18:13:07 +0300927 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
928 XMLTest("Attribute: double", 100.0, v, true);
929 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700930 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700931 }
932 {
933 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300934 {
935 float v = 0;
936 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
937 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
938 XMLTest("Attribute: float", 100.0f, v, true);
939 }
940 {
941 float v = 0;
cugone5e765732021-05-09 02:05:54 -0500942 XMLError queryResult = element->QueryAttribute("attrib", &v);
Dmitry-Me2087a272017-07-10 18:13:07 +0300943 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
944 XMLTest("Attribute: float", 100.0f, v, true);
945 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700946 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700947 }
948 {
949 element->SetText(BIG);
950 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300951 XMLError queryResult = element->QueryInt64Text(&v);
952 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700953 XMLTest("Element: int64_t", BIG, v, true);
954 }
Lee Thomasoneffdf952019-08-10 17:49:42 -0700955 {
956 element->SetText(BIG_POS);
957 uint64_t v = 0;
958 XMLError queryResult = element->QueryUnsigned64Text(&v);
959 XMLTest("Element: uint64_t", XML_SUCCESS, queryResult, true);
960 XMLTest("Element: uint64_t", BIG_POS, v, true);
961 }
962 }
Lee Thomason51c12712016-06-04 20:18:49 -0700963
964 // ---------- XMLPrinter stream mode ------
965 {
966 {
Dmitry-Mec0fad292017-08-09 19:05:42 +0300967 FILE* printerfp = fopen("resources/out/printer.xml", "w");
968 XMLTest("Open printer.xml", true, printerfp != 0);
Lee Thomason51c12712016-06-04 20:18:49 -0700969 XMLPrinter printer(printerfp);
970 printer.OpenElement("foo");
971 printer.PushAttribute("attrib-text", "text");
972 printer.PushAttribute("attrib-int", int(1));
973 printer.PushAttribute("attrib-unsigned", unsigned(2));
974 printer.PushAttribute("attrib-int64", int64_t(3));
Lee Thomason37ccc712020-03-01 16:52:42 -0800975 printer.PushAttribute("attrib-uint64", uint64_t(37));
976 printer.PushAttribute("attrib-bool", true);
Lee Thomason51c12712016-06-04 20:18:49 -0700977 printer.PushAttribute("attrib-double", 4.0);
978 printer.CloseElement();
979 fclose(printerfp);
980 }
981 {
982 XMLDocument doc;
Dmitry-Mec0fad292017-08-09 19:05:42 +0300983 doc.LoadFile("resources/out/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300984 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700985
986 const XMLDocument& cdoc = doc;
987
988 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
989 XMLTest("attrib-text", "text", attrib->Value(), true);
990 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
991 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
992 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
993 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
994 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
995 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
Lee Thomason37ccc712020-03-01 16:52:42 -0800996 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-uint64");
997 XMLTest("attrib-uint64", uint64_t(37), attrib->Unsigned64Value(), true);
998 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
Lee Thomason51c12712016-06-04 20:18:49 -0700999 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
1000 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
1001 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
1002 }
Lee Thomason37ccc712020-03-01 16:52:42 -08001003 // Add API_testcatse :PushDeclaration();PushText();PushComment()
1004 {
1005 FILE* fp1 = fopen("resources/out/printer_1.xml", "w");
1006 XMLPrinter printer(fp1);
Lee Thomason51c12712016-06-04 20:18:49 -07001007
Lee Thomason37ccc712020-03-01 16:52:42 -08001008 printer.PushDeclaration("version = '1.0' enconding = 'utf-8'");
Alanscut7d9ca1e2019-09-27 15:46:45 +08001009
Lee Thomason37ccc712020-03-01 16:52:42 -08001010 printer.OpenElement("foo");
1011 printer.PushAttribute("attrib-text", "text");
Alanscut7d9ca1e2019-09-27 15:46:45 +08001012
Lee Thomason37ccc712020-03-01 16:52:42 -08001013 printer.OpenElement("text");
1014 printer.PushText("Tinyxml2");
1015 printer.CloseElement();
Alanscut7d9ca1e2019-09-27 15:46:45 +08001016
Lee Thomason37ccc712020-03-01 16:52:42 -08001017 printer.OpenElement("int");
1018 printer.PushText(int(11));
1019 printer.CloseElement();
1020
1021 printer.OpenElement("unsigned");
1022 printer.PushText(unsigned(12));
1023 printer.CloseElement();
1024
1025 printer.OpenElement("int64_t");
1026 printer.PushText(int64_t(13));
1027 printer.CloseElement();
1028
1029 printer.OpenElement("uint64_t");
1030 printer.PushText(uint64_t(14));
1031 printer.CloseElement();
1032
1033 printer.OpenElement("bool");
1034 printer.PushText(true);
1035 printer.CloseElement();
1036
1037 printer.OpenElement("float");
1038 printer.PushText("1.56");
1039 printer.CloseElement();
1040
1041 printer.OpenElement("double");
1042 printer.PushText("12.12");
1043 printer.CloseElement();
1044
1045 printer.OpenElement("comment");
1046 printer.PushComment("this is Tinyxml2");
1047 printer.CloseElement();
1048
1049 printer.CloseElement();
1050 fclose(fp1);
1051 }
1052 {
1053 XMLDocument doc;
1054 doc.LoadFile("resources/out/printer_1.xml");
1055 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
1056
1057 const XMLDocument& cdoc = doc;
1058
1059 const XMLElement* root = cdoc.FirstChildElement("foo");
1060
1061 const char* text_value;
1062 text_value = root->FirstChildElement("text")->GetText();
1063 XMLTest("PushText( const char* text, bool cdata=false ) test", "Tinyxml2", text_value);
1064
1065 int int_value;
1066 int_value = root->FirstChildElement("int")->IntText();
1067 XMLTest("PushText( int value ) test", 11, int_value);
1068
1069 unsigned unsigned_value;
1070 unsigned_value = root->FirstChildElement("unsigned")->UnsignedText();
1071 XMLTest("PushText( unsigned value ) test", (unsigned)12, unsigned_value);
1072
1073 int64_t int64_t_value;
1074 int64_t_value = root->FirstChildElement("int64_t")->Int64Text();
1075 XMLTest("PushText( int64_t value ) test", (int64_t) 13, int64_t_value);
1076
1077 uint64_t uint64_t_value;
1078 uint64_t_value = root->FirstChildElement("uint64_t")->Unsigned64Text();
1079 XMLTest("PushText( uint64_t value ) test", (uint64_t) 14, uint64_t_value);
1080
1081 float float_value;
1082 float_value = root->FirstChildElement("float")->FloatText();
1083 XMLTest("PushText( float value ) test", 1.56f, float_value);
1084
1085 double double_value;
1086 double_value = root->FirstChildElement("double")->DoubleText();
1087 XMLTest("PushText( double value ) test", 12.12, double_value);
1088
1089 bool bool_value;
1090 bool_value = root->FirstChildElement("bool")->BoolText();
1091 XMLTest("PushText( bool value ) test", true, bool_value);
1092
1093 const XMLComment* comment = root->FirstChildElement("comment")->FirstChild()->ToComment();
1094 const char* comment_value = comment->Value();
1095 XMLTest("PushComment() test", "this is Tinyxml2", comment_value);
1096
1097 const XMLDeclaration* declaration = cdoc.FirstChild()->ToDeclaration();
1098 const char* declaration_value = declaration->Value();
1099 XMLTest("PushDeclaration() test", "version = '1.0' enconding = 'utf-8'", declaration_value);
1100 }
Lee Thomason51c12712016-06-04 20:18:49 -07001101 }
1102
Uli Kusterer321072e2014-01-21 01:57:38 +01001103
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001104 // ---------- CDATA ---------------
1105 {
1106 const char* str = "<xmlElement>"
1107 "<![CDATA["
1108 "I am > the rules!\n"
1109 "...since I make symbolic puns"
1110 "]]>"
1111 "</xmlElement>";
1112 XMLDocument doc;
1113 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +03001114 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001115 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -08001116
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001117 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
1118 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -08001119 false );
1120 }
1121
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001122 // ----------- CDATA -------------
1123 {
1124 const char* str = "<xmlElement>"
1125 "<![CDATA["
1126 "<b>I am > the rules!</b>\n"
1127 "...since I make symbolic puns"
1128 "]]>"
1129 "</xmlElement>";
1130 XMLDocument doc;
1131 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +03001132 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001133 doc.Print();
1134
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001135 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001136 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001137 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001138 false );
1139 }
1140
1141 // InsertAfterChild causes crash.
1142 {
1143 // InsertBeforeChild and InsertAfterChild causes crash.
1144 XMLDocument doc;
1145 XMLElement* parent = doc.NewElement( "Parent" );
1146 doc.InsertFirstChild( parent );
1147
1148 XMLElement* childText0 = doc.NewElement( "childText0" );
1149 XMLElement* childText1 = doc.NewElement( "childText1" );
1150
1151 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001152 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001153 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001154 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001155
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001156 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001157 }
Lee Thomasond6277762012-02-22 16:00:12 -08001158
1159 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001160 // Entities not being written correctly.
1161 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -08001162
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001163 const char* passages =
1164 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1165 "<passages count=\"006\" formatversion=\"20020620\">"
1166 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1167 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
1168 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -08001169
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001170 XMLDocument doc;
1171 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001172 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001173 XMLElement* psg = doc.RootElement()->FirstChildElement();
1174 const char* context = psg->Attribute( "context" );
1175 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 -08001176
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001177 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -08001178
Dmitry-Me520009e2017-08-10 17:50:03 +03001179 const char* textFilePath = "resources/out/textfile.txt";
1180 FILE* textfile = fopen( textFilePath, "w" );
1181 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001182 if ( textfile )
1183 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001184 XMLPrinter streamer( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001185 bool acceptResult = psg->Accept( &streamer );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001186 fclose( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001187 XMLTest( "Entity transformation: Accept", true, acceptResult );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001188 }
Thomas Roß0922b732012-09-23 16:31:22 +02001189
Dmitry-Me520009e2017-08-10 17:50:03 +03001190 textfile = fopen( textFilePath, "r" );
1191 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001192 if ( textfile )
1193 {
1194 char buf[ 1024 ];
1195 fgets( buf, 1024, textfile );
1196 XMLTest( "Entity transformation: write. ",
1197 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1198 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1199 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001200 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001201 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001202 }
1203
1204 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001205 // Suppress entities.
1206 const char* passages =
1207 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1208 "<passages count=\"006\" formatversion=\"20020620\">"
1209 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1210 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001211
Lee Thomason6f381b72012-03-02 12:59:39 -08001212 XMLDocument doc( false );
1213 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001214 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001215
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001216 XMLTest( "No entity parsing.",
1217 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1218 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1219 XMLTest( "No entity parsing.", "Crazy &ttk;",
1220 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001221 doc.Print();
1222 }
1223
1224 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001225 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001226
1227 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001228 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001229 XMLTest( "dot in names", false, doc.Error() );
1230 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1231 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001232 }
1233
1234 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001235 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001236
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001237 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001238 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001239 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001240
1241 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1242 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001243 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001244 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001245 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001246
1247 {
1248 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001249 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001250 const char* doctype =
1251 "<?xml version=\"1.0\" ?>"
1252 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1253 "<!ELEMENT title (#PCDATA)>"
1254 "<!ELEMENT books (title,authors)>"
1255 "<element />";
1256
1257 XMLDocument doc;
1258 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001259 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001260 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001261 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001262 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001263 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001264 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001265 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001266
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001267 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1268 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1269
1270 }
1271
1272 {
1273 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001274 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001275 "<!-- Somewhat<evil> -->";
1276 XMLDocument doc;
1277 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001278 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001279
1280 XMLComment* comment = doc.FirstChild()->ToComment();
1281
1282 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1283 }
1284 {
1285 // Double attributes
1286 const char* doctype = "<element attr='red' attr='blue' />";
1287
1288 XMLDocument doc;
1289 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001290
Lee Thomason2fa81722012-11-09 12:37:46 -08001291 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 -08001292 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001293 }
1294
1295 {
1296 // Embedded null in stream.
1297 const char* doctype = "<element att\0r='red' attr='blue' />";
1298
1299 XMLDocument doc;
1300 doc.Parse( doctype );
1301 XMLTest( "Embedded null throws error.", true, doc.Error() );
1302 }
1303
1304 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001305 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001306 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001307 XMLDocument doc;
1308 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001309 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomasona36f7ac2017-12-28 13:48:54 -08001310
1311 // But be sure there is an error string!
1312 const char* errorStr = doc.ErrorStr();
1313 XMLTest("Error string should be set",
Lee Thomasonc4836462018-06-29 15:57:55 -07001314 "Error=XML_ERROR_EMPTY_DOCUMENT ErrorID=13 (0xd) Line number=0",
Lee Thomasona36f7ac2017-12-28 13:48:54 -08001315 errorStr);
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001316 }
1317
1318 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001319 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1320 const char* str = " ";
1321 XMLDocument doc;
1322 doc.Parse( str );
1323 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1324 }
1325
1326 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001327 // Low entities
1328 XMLDocument doc;
1329 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001330 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001331 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001332 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001333 doc.Print();
1334 }
1335
1336 {
1337 // Attribute values with trailing quotes not handled correctly
1338 XMLDocument doc;
1339 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001340 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001341 }
1342
1343 {
1344 // [ 1663758 ] Failure to report error on bad XML
1345 XMLDocument xml;
1346 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001347 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001348 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001349 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001350 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001351 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001352 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001353
1354
1355 {
1356 // [ 1475201 ] TinyXML parses entities in comments
1357 XMLDocument xml;
1358 xml.Parse("<!-- declarations for <head> & <body> -->"
1359 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001360 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001361
1362 XMLNode* e0 = xml.FirstChild();
1363 XMLNode* e1 = e0->NextSibling();
1364 XMLComment* c0 = e0->ToComment();
1365 XMLComment* c1 = e1->ToComment();
1366
1367 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1368 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1369 }
1370
1371 {
1372 XMLDocument xml;
1373 xml.Parse( "<Parent>"
1374 "<child1 att=''/>"
1375 "<!-- With this comment, child2 will not be parsed! -->"
1376 "<child2 att=''/>"
1377 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001378 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001379 xml.Print();
1380
1381 int count = 0;
1382
1383 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1384 ele;
1385 ele = ele->NextSibling() )
1386 {
1387 ++count;
1388 }
1389
1390 XMLTest( "Comments iterate correctly.", 3, count );
1391 }
1392
1393 {
Alanscut8916a3c2019-09-16 17:03:12 +08001394 // 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 -08001395 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1396 buf[60] = 239;
1397 buf[61] = 0;
1398
1399 XMLDocument doc;
1400 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001401 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001402 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001403
1404
1405 {
1406 // bug 1827248 Error while parsing a little bit malformed file
1407 // Actually not malformed - should work.
1408 XMLDocument xml;
1409 xml.Parse( "<attributelist> </attributelist >" );
1410 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1411 }
1412
1413 {
1414 // This one must not result in an infinite loop
1415 XMLDocument xml;
1416 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001417 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001418 XMLTest( "Infinite loop test.", true, true );
1419 }
1420#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001421 {
1422 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1423 XMLDocument doc;
1424 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001425 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001426
1427 XMLDocument clone;
1428 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1429 XMLNode* copy = node->ShallowClone( &clone );
1430 clone.InsertEndChild( copy );
1431 }
1432
1433 clone.Print();
1434
1435 int count=0;
1436 const XMLNode* a=clone.FirstChild();
1437 const XMLNode* b=doc.FirstChild();
1438 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1439 ++count;
1440 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1441 }
1442 XMLTest( "Clone and Equal", 4, count );
1443 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001444
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001445 {
Lee Thomason7085f002017-06-01 18:09:43 -07001446 // Deep Cloning of root element.
1447 XMLDocument doc2;
1448 XMLPrinter printer1;
1449 {
1450 // Make sure doc1 is deleted before we test doc2
1451 const char* xml =
1452 "<root>"
1453 " <child1 foo='bar'/>"
1454 " <!-- comment thing -->"
1455 " <child2 val='1'>Text</child2>"
1456 "</root>";
1457 XMLDocument doc;
1458 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001459 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001460
1461 doc.Print(&printer1);
1462 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1463 doc2.InsertFirstChild(root);
1464 }
1465 XMLPrinter printer2;
1466 doc2.Print(&printer2);
1467
1468 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1469 }
1470
1471 {
1472 // Deep Cloning of sub element.
1473 XMLDocument doc2;
1474 XMLPrinter printer1;
1475 {
1476 // Make sure doc1 is deleted before we test doc2
1477 const char* xml =
1478 "<?xml version ='1.0'?>"
1479 "<root>"
1480 " <child1 foo='bar'/>"
1481 " <!-- comment thing -->"
1482 " <child2 val='1'>Text</child2>"
1483 "</root>";
1484 XMLDocument doc;
1485 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001486 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001487
1488 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001489 bool acceptResult = subElement->Accept(&printer1);
1490 XMLTest( "Accept before deep cloning", true, acceptResult );
Lee Thomason7085f002017-06-01 18:09:43 -07001491
1492 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1493 doc2.InsertFirstChild(clonedSubElement);
1494 }
1495 XMLPrinter printer2;
1496 doc2.Print(&printer2);
1497
1498 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1499 }
1500
1501 {
1502 // Deep cloning of document.
1503 XMLDocument doc2;
1504 XMLPrinter printer1;
1505 {
1506 // Make sure doc1 is deleted before we test doc2
1507 const char* xml =
1508 "<?xml version ='1.0'?>"
1509 "<!-- Top level comment. -->"
1510 "<root>"
1511 " <child1 foo='bar'/>"
1512 " <!-- comment thing -->"
1513 " <child2 val='1'>Text</child2>"
1514 "</root>";
1515 XMLDocument doc;
1516 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001517 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001518 doc.Print(&printer1);
1519
1520 doc.DeepCopy(&doc2);
1521 }
1522 XMLPrinter printer2;
1523 doc2.Print(&printer2);
1524
1525 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1526 }
1527
1528
1529 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001530 // This shouldn't crash.
1531 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001532 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001533 {
1534 doc.PrintError();
1535 }
1536 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1537 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001538
Lee Thomason5e3803c2012-04-16 08:57:05 -07001539 {
1540 // Attribute ordering.
1541 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1542 XMLDocument doc;
1543 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001544 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001545 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001546
Lee Thomason5e3803c2012-04-16 08:57:05 -07001547 const XMLAttribute* a = ele->FirstAttribute();
1548 XMLTest( "Attribute order", "1", a->Value() );
1549 a = a->Next();
1550 XMLTest( "Attribute order", "2", a->Value() );
1551 a = a->Next();
1552 XMLTest( "Attribute order", "3", a->Value() );
1553 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001554
Lee Thomason5e3803c2012-04-16 08:57:05 -07001555 ele->DeleteAttribute( "attrib2" );
1556 a = ele->FirstAttribute();
1557 XMLTest( "Attribute order", "1", a->Value() );
1558 a = a->Next();
1559 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001560
Lee Thomason5e3803c2012-04-16 08:57:05 -07001561 ele->DeleteAttribute( "attrib1" );
1562 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001563 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001564 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001565
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001566 {
1567 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001568 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1569 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1570 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1571 XMLDocument doc0;
1572 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001573 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001574 XMLDocument doc1;
1575 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001576 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001577 XMLDocument doc2;
1578 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001579 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001580
Lee Thomason78a773d2012-07-02 10:10:19 -07001581 XMLElement* ele = 0;
1582 ele = doc0.FirstChildElement();
1583 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1584 ele = doc1.FirstChildElement();
1585 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1586 ele = doc2.FirstChildElement();
1587 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001588 }
1589
1590 {
1591 // Make sure we don't go into an infinite loop.
1592 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1593 XMLDocument doc;
1594 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001595 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001596 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1597 XMLElement* ele1 = ele0->NextSiblingElement();
1598 bool equal = ele0->ShallowEqual( ele1 );
1599
1600 XMLTest( "Infinite loop in shallow equal.", true, equal );
1601 }
1602
Lee Thomason5708f812012-03-28 17:46:41 -07001603 // -------- Handles ------------
1604 {
1605 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1606 XMLDocument doc;
1607 doc.Parse( xml );
Dmitry-Me938560f2018-03-15 01:30:39 +03001608 XMLTest( "Handle, parse element with attribute and nested element", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001609
Dmitry-Me938560f2018-03-15 01:30:39 +03001610 {
1611 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1612 XMLTest( "Handle, non-const, element is found", true, ele != 0 );
1613 XMLTest( "Handle, non-const, element name matches", "sub", ele->Value() );
1614 }
Lee Thomason5708f812012-03-28 17:46:41 -07001615
Dmitry-Me938560f2018-03-15 01:30:39 +03001616 {
1617 XMLHandle docH( doc );
1618 XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1619 XMLTest( "Handle, non-const, element not found", true, ele == 0 );
1620 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001621
Dmitry-Me938560f2018-03-15 01:30:39 +03001622 {
1623 const XMLElement* ele = XMLConstHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1624 XMLTest( "Handle, const, element is found", true, ele != 0 );
1625 XMLTest( "Handle, const, element name matches", "sub", ele->Value() );
1626 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001627
Dmitry-Me938560f2018-03-15 01:30:39 +03001628 {
1629 XMLConstHandle docH( doc );
1630 const XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1631 XMLTest( "Handle, const, element not found", true, ele == 0 );
1632 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001633 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001634 {
1635 // Default Declaration & BOM
1636 XMLDocument doc;
1637 doc.InsertEndChild( doc.NewDeclaration() );
1638 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001639
Lee Thomasonf68c4382012-04-28 14:37:11 -07001640 XMLPrinter printer;
1641 doc.Print( &printer );
1642
1643 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001644 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1645 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001646 }
Lee Thomason21be8822012-07-15 17:27:22 -07001647 {
1648 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1649 XMLDocument doc;
1650 doc.Parse( xml );
1651 XMLTest( "Ill formed XML", true, doc.Error() );
1652 }
1653
Lee Thomason50daa322019-08-10 18:00:57 -07001654 {
1655 //API:IntText(),UnsignedText(),Int64Text(),DoubleText(),BoolText() and FloatText() test
1656 const char* xml = "<point> <IntText>-24</IntText> <UnsignedText>42</UnsignedText> \
wangkirinf12d7a22019-07-02 16:58:38 +08001657 <Int64Text>38</Int64Text> <BoolText>true</BoolText> <DoubleText>2.35</DoubleText> </point>";
Lee Thomason50daa322019-08-10 18:00:57 -07001658 XMLDocument doc;
1659 doc.Parse(xml);
1660
1661 const XMLElement* pointElement = doc.RootElement();
1662 int test1 = pointElement->FirstChildElement("IntText")->IntText();
1663 XMLTest("IntText() test", -24, test1);
1664
1665 unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
1666 XMLTest("UnsignedText() test", static_cast<unsigned>(42), test2);
1667
1668 int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
1669 XMLTest("Int64Text() test", static_cast<int64_t>(38), test3);
1670
1671 double test4 = pointElement->FirstChildElement("DoubleText")->DoubleText();
1672 XMLTest("DoubleText() test", 2.35, test4);
1673
1674 float test5 = pointElement->FirstChildElement("DoubleText")->FloatText();
1675 XMLTest("FloatText()) test", 2.35f, test5);
1676
1677 bool test6 = pointElement->FirstChildElement("BoolText")->BoolText();
1678 XMLTest("FloatText()) test", true, test6);
1679 }
wangkirinf12d7a22019-07-02 16:58:38 +08001680
netcandfb45cb2020-02-15 21:35:58 +08001681 {
Lee Thomason18468b82020-06-13 17:35:21 -07001682 // hex value test
1683 const char* xml = "<point> <IntText> 0x2020</IntText> <UnsignedText>0X2020</UnsignedText> \
1684 <Int64Text> 0x1234</Int64Text></point>";
netcandfb45cb2020-02-15 21:35:58 +08001685 XMLDocument doc;
1686 doc.Parse(xml);
1687
1688 const XMLElement* pointElement = doc.RootElement();
1689 int test1 = pointElement->FirstChildElement("IntText")->IntText();
Lee Thomason18468b82020-06-13 17:35:21 -07001690 XMLTest("IntText() hex value test", 0x2020, test1);
netcandfb45cb2020-02-15 21:35:58 +08001691
1692 unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
1693 XMLTest("UnsignedText() hex value test", static_cast<unsigned>(0x2020), test2);
1694
1695 int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
Lee Thomason18468b82020-06-13 17:35:21 -07001696 XMLTest("Int64Text() hex value test", static_cast<int64_t>(0x1234), test3);
netcandfb45cb2020-02-15 21:35:58 +08001697 }
1698
wangkirinf12d7a22019-07-02 16:58:38 +08001699 {
1700 //API:ShallowEqual() test
1701 const char* xml = "<playlist id = 'playlist'>"
1702 "<property name = 'track_name'>voice</property>"
1703 "</playlist>";
1704 XMLDocument doc;
1705 doc.Parse( xml );
1706 const XMLNode* PlaylistNode = doc.RootElement();
1707 const XMLNode* PropertyNode = PlaylistNode->FirstChildElement();
1708 bool result;
1709 result = PlaylistNode->ShallowEqual(PropertyNode);
1710 XMLTest("ShallowEqual() test",false,result);
1711 result = PlaylistNode->ShallowEqual(PlaylistNode);
1712 XMLTest("ShallowEqual() test",true,result);
1713 }
1714
1715 {
1716 //API: previousSiblingElement() and NextSiblingElement() test
1717 const char* xml = "<playlist id = 'playlist'>"
1718 "<property name = 'track_name'>voice</property>"
1719 "<entry out = '946' producer = '2_playlist1' in = '0'/>"
1720 "<blank length = '1'/>"
1721 "</playlist>";
1722 XMLDocument doc;
1723 doc.Parse( xml );
1724 XMLElement* ElementPlaylist = doc.FirstChildElement("playlist");
1725 XMLTest("previousSiblingElement() test",true,ElementPlaylist != 0);
1726 const XMLElement* pre = ElementPlaylist->PreviousSiblingElement();
1727 XMLTest("previousSiblingElement() test",true,pre == 0);
1728 const XMLElement* ElementBlank = ElementPlaylist->FirstChildElement("entry")->NextSiblingElement("blank");
1729 XMLTest("NextSiblingElement() test",true,ElementBlank != 0);
1730 const XMLElement* next = ElementBlank->NextSiblingElement();
1731 XMLTest("NextSiblingElement() test",true,next == 0);
1732 const XMLElement* ElementEntry = ElementBlank->PreviousSiblingElement("entry");
1733 XMLTest("PreviousSiblingElement test",true,ElementEntry != 0);
1734 }
1735
Lee Thomason21be8822012-07-15 17:27:22 -07001736 // QueryXYZText
1737 {
1738 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1739 XMLDocument doc;
1740 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001741 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001742
1743 const XMLElement* pointElement = doc.RootElement();
1744
Dmitry-Me43c019d2017-08-02 18:05:23 +03001745 {
1746 int intValue = 0;
1747 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1748 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1749 XMLTest( "QueryIntText", 1, intValue, false );
1750 }
Lee Thomason21be8822012-07-15 17:27:22 -07001751
Dmitry-Me43c019d2017-08-02 18:05:23 +03001752 {
1753 unsigned unsignedValue = 0;
1754 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1755 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1756 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1757 }
Lee Thomason21be8822012-07-15 17:27:22 -07001758
Dmitry-Me43c019d2017-08-02 18:05:23 +03001759 {
1760 float floatValue = 0;
1761 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1762 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1763 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1764 }
Lee Thomason21be8822012-07-15 17:27:22 -07001765
Dmitry-Me43c019d2017-08-02 18:05:23 +03001766 {
1767 double doubleValue = 0;
1768 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1769 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1770 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1771 }
1772
1773 {
1774 bool boolValue = false;
1775 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1776 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1777 XMLTest( "QueryBoolText", true, boolValue, false );
1778 }
Lee Thomason21be8822012-07-15 17:27:22 -07001779 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001780
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001781 {
1782 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1783 XMLDocument doc;
1784 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001785 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001786 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001787
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001788 {
1789 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1790 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001791 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001792 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001793 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001794
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001795 {
1796 const char* xml = "<3lement></3lement>";
1797 XMLDocument doc;
1798 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001799 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001800 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001801
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001802 {
1803 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1804 XMLDocument doc;
1805 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001806 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001807 }
1808
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001809 {
1810 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001811 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001812 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001813 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001814 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001815 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001816 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001817 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001818 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001819 }
Dmitry-Me985ea1f2017-08-28 18:36:29 +03001820
1821 {
1822 XMLDocument doc;
1823 XMLTest( "No error initially", false, doc.Error() );
1824 XMLError error = doc.Parse( "This is not XML" );
1825 XMLTest( "Error after invalid XML", true, doc.Error() );
1826 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1827 doc.Clear();
1828 XMLTest( "No error after Clear()", false, doc.Error() );
1829 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001830
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001831 // ----------- Whitespace ------------
1832 {
1833 const char* xml = "<element>"
1834 "<a> This \nis &apos; text &apos; </a>"
1835 "<b> This is &apos; text &apos; \n</b>"
1836 "<c>This is &apos; \n\n text &apos;</c>"
1837 "</element>";
1838 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1839 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001840 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001841
1842 const XMLElement* element = doc.FirstChildElement();
1843 for( const XMLElement* parent = element->FirstChildElement();
1844 parent;
1845 parent = parent->NextSiblingElement() )
1846 {
1847 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1848 }
1849 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001850
Lee Thomasonae9ab072012-10-24 10:17:53 -07001851#if 0
1852 {
1853 // Passes if assert doesn't fire.
1854 XMLDocument xmlDoc;
1855
1856 xmlDoc.NewDeclaration();
1857 xmlDoc.NewComment("Configuration file");
1858
1859 XMLElement *root = xmlDoc.NewElement("settings");
1860 root->SetAttribute("version", 2);
1861 }
1862#endif
1863
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001864 {
1865 const char* xml = "<element> </element>";
1866 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1867 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001868 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001869 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1870 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001871
Lee Thomason5b0a6772012-11-19 13:54:42 -08001872 {
1873 // An assert should not fire.
1874 const char* xml = "<element/>";
1875 XMLDocument doc;
1876 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001877 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001878 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1879 XMLTest( "Tracking unused elements", true, ele != 0, false );
1880 }
1881
Lee Thomasona6412ac2012-12-13 15:39:11 -08001882
1883 {
1884 const char* xml = "<parent><child>abc</child></parent>";
1885 XMLDocument doc;
1886 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001887 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001888 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1889
1890 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001891 bool acceptResult = ele->Accept( &printer );
1892 XMLTest( "Accept of sub-element", true, acceptResult );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001893 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1894 }
1895
1896
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001897 {
1898 XMLDocument doc;
1899 XMLError error = doc.LoadFile( "resources/empty.xml" );
1900 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001901 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001902 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001903 }
1904
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001905 {
1906 // BOM preservation
1907 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1908 {
1909 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001910 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001911 XMLPrinter printer;
1912 doc.Print( &printer );
1913
1914 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
Wang Kirine08c2d22019-05-30 15:25:04 +08001915 doc.SaveFile( "resources/out/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001916 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001917 }
1918 {
1919 XMLDocument doc;
Wang Kirine08c2d22019-05-30 15:25:04 +08001920 doc.LoadFile( "resources/out/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001921 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001922 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1923
1924 XMLPrinter printer;
1925 doc.Print( &printer );
1926 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1927 }
1928 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001929
Michael Daumlinged523282013-10-23 07:47:29 +02001930 {
1931 // Insertion with Removal
1932 const char* xml = "<?xml version=\"1.0\" ?>"
1933 "<root>"
1934 "<one>"
1935 "<subtree>"
1936 "<elem>element 1</elem>text<!-- comment -->"
1937 "</subtree>"
1938 "</one>"
1939 "<two/>"
1940 "</root>";
1941 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1942 "<root>"
1943 "<one/>"
1944 "<two>"
1945 "<subtree>"
1946 "<elem>element 1</elem>text<!-- comment -->"
1947 "</subtree>"
1948 "</two>"
1949 "</root>";
1950 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1951 "<root>"
1952 "<one/>"
1953 "<subtree>"
1954 "<elem>element 1</elem>text<!-- comment -->"
1955 "</subtree>"
1956 "<two/>"
1957 "</root>";
1958 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1959 "<root>"
1960 "<one/>"
1961 "<two/>"
1962 "<subtree>"
1963 "<elem>element 1</elem>text<!-- comment -->"
1964 "</subtree>"
1965 "</root>";
1966
1967 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001968 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001969 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001970 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1971 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1972 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001973 XMLPrinter printer1(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001974 bool acceptResult = doc.Accept(&printer1);
1975 XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001976 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001977
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001978 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001979 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001980 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1981 two = doc.RootElement()->FirstChildElement("two");
1982 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001983 XMLPrinter printer2(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001984 acceptResult = doc.Accept(&printer2);
1985 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001986 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001987
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001988 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001989 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001990 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1991 subtree = one->FirstChildElement("subtree");
1992 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001993 XMLPrinter printer3(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001994 acceptResult = doc.Accept(&printer3);
1995 XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001996 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001997
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001998 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001999 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02002000 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
2001 two = doc.RootElement()->FirstChildElement("two");
Dmitry-Me17814942018-10-16 00:11:39 +03002002 XMLTest("<two> is the last child at root level", true, two == doc.RootElement()->LastChildElement());
Michael Daumlinged523282013-10-23 07:47:29 +02002003 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002004 XMLPrinter printer4(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002005 acceptResult = doc.Accept(&printer4);
2006 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002007 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02002008 }
2009
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002010 {
2011 const char* xml = "<svg width = \"128\" height = \"128\">"
2012 " <text> </text>"
2013 "</svg>";
2014 XMLDocument doc;
2015 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03002016 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002017 doc.Print();
2018 }
2019
Lee Thomason92e521b2014-11-15 17:45:51 -08002020 {
2021 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002022 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
2023 XMLDocument doc;
2024 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03002025 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002026 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08002027 }
2028
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002029#if 1
Lee Thomasonc4836462018-06-29 15:57:55 -07002030 // the question being explored is what kind of print to use:
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002031 // https://github.com/leethomason/tinyxml2/issues/63
2032 {
2033 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
2034 const char* xml = "<element/>";
2035 XMLDocument doc;
2036 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03002037 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002038 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
2039 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
2040 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
2041 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
2042 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
2043 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
2044
2045 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
2046 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
2047 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
2048 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
2049 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
2050 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
2051
2052 doc.Print();
2053
2054 /* The result of this test is platform, compiler, and library version dependent. :("
2055 XMLPrinter printer;
2056 doc.Print( &printer );
Lee Thomasonc4836462018-06-29 15:57:55 -07002057 XMLTest( "Float and double formatting.",
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002058 "<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 -07002059 printer.CStr(),
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002060 true );
2061 */
2062 }
2063#endif
Lee Thomasonc4836462018-06-29 15:57:55 -07002064
Lee Thomasonf07b9522014-10-30 13:25:12 -07002065 {
2066 // Issue #184
2067 // If it doesn't assert, it passes. Caused by objects
2068 // getting created during parsing which are then
2069 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03002070 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07002071 {
2072 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03002073 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03002074 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07002075 }
2076 {
2077 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03002078 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03002079 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07002080 doc.Clear();
2081 }
2082 }
Lee Thomasonc4836462018-06-29 15:57:55 -07002083
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002084 {
Peter Matula50689912018-01-09 12:52:26 +01002085 // If this doesn't assert in TINYXML2_DEBUG, all is well.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08002086 tinyxml2::XMLDocument doc;
2087 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
2088 doc.DeleteNode(pRoot);
2089 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002090
Dmitry-Mee5790db2017-07-28 17:54:38 +03002091 {
2092 XMLDocument doc;
2093 XMLElement* root = doc.NewElement( "Root" );
2094 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
2095 doc.InsertEndChild( root );
2096 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
2097 }
2098
2099 {
Peter Matula50689912018-01-09 12:52:26 +01002100 // If this doesn't assert in TINYXML2_DEBUG, all is well.
Dmitry-Mee5790db2017-07-28 17:54:38 +03002101 XMLDocument doc;
2102 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
2103 XMLElement* linkedRoot = doc.NewElement( "Root" );
2104 doc.InsertFirstChild( linkedRoot );
2105 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
2106 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
2107 }
2108
Dmitry-Me8b67d742014-12-22 11:35:12 +03002109 {
Peter Matula50689912018-01-09 12:52:26 +01002110 // Should not assert in TINYXML2_DEBUG
Dmitry-Me8b67d742014-12-22 11:35:12 +03002111 XMLPrinter printer;
2112 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08002113
Dmitry-Me6f51c802015-03-14 13:25:03 +03002114 {
2115 // Issue 291. Should not crash
2116 const char* xml = "&#0</a>";
2117 XMLDocument doc;
2118 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03002119 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03002120
2121 XMLPrinter printer;
2122 doc.Print( &printer );
2123 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00002124 {
Lee Thomasonc4836462018-06-29 15:57:55 -07002125 // Issue 299. Can print elements that are not linked in.
Ant Mitchell148cc1a2015-03-24 15:12:35 +00002126 // Will crash if issue not fixed.
2127 XMLDocument doc;
2128 XMLElement* newElement = doc.NewElement( "printme" );
2129 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002130 bool acceptResult = newElement->Accept( &printer );
2131 XMLTest( "printme - Accept()", true, acceptResult );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03002132 // Delete the node to avoid possible memory leak report in debug output
2133 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00002134 }
Lee Thomasonf6577832015-03-26 11:18:21 -07002135 {
Ant Mitchell189198f2015-03-24 16:20:36 +00002136 // Issue 302. Clear errors from LoadFile/SaveFile
2137 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03002138 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00002139 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03002140 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00002141 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03002142 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00002143 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03002144
Dmitry-Med9852a52015-03-25 10:17:49 +03002145 {
2146 // If a document fails to load then subsequent
2147 // successful loads should clear the error
2148 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03002149 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03002150 doc.LoadFile( "resources/no-such-file.xml" );
2151 XMLTest( "No such file - should fail", true, doc.Error() );
2152
2153 doc.LoadFile( "resources/dream.xml" );
2154 XMLTest( "Error should be cleared", false, doc.Error() );
2155 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05302156
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05302157 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002158 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07002159 const char* xml0 = "<?xml version=\"1.0\" ?>"
2160 " <!-- xml version=\"1.1\" -->"
2161 "<first />";
2162 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002163 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07002164 "<first />";
2165 const char* xml2 = "<first />"
2166 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002167 const char* xml3 = "<first></first>"
2168 "<?xml version=\"1.0\" ?>";
2169
2170 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
2171
Lee Thomason85492022015-05-22 11:07:45 -07002172 XMLDocument doc;
2173 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002174 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07002175 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002176 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07002177 doc.Parse(xml2);
Dmitry-Me6a18a312018-03-23 21:09:13 +03002178 XMLTest("Test that declaration after self-closed child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002179 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002180 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002181 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002182 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05302183 }
Dmitry-Med9852a52015-03-25 10:17:49 +03002184
Lee Thomason85492022015-05-22 11:07:45 -07002185 {
2186 // No matter - before or after successfully parsing a text -
Dmitry-Me26043362017-08-30 17:40:15 +03002187 // calling XMLDocument::Value() used to cause an assert in debug.
orbitcowboy22b21ec2018-07-17 11:52:57 +02002188 // Null must be returned.
Lee Thomason85492022015-05-22 11:07:45 -07002189 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
2190 "<first />"
2191 "<second />";
2192 XMLDocument* doc = new XMLDocument();
2193 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2194 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03002195 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07002196 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2197 delete doc;
2198 }
2199
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002200 {
2201 XMLDocument doc;
2202 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
Dmitry-Med3f6c632017-08-30 17:43:14 +03002203 const XMLError error = static_cast<XMLError>(i);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002204 const char* name = XMLDocument::ErrorIDToName(error);
Dmitry-Me95f687b2018-03-23 20:56:46 +03002205 XMLTest( "ErrorName() not null after ClearError()", true, name != 0 );
2206 if( name == 0 ) {
2207 // passing null pointer into strlen() is undefined behavior, so
2208 // compiler is allowed to optimise away the null test above if it's
2209 // as reachable as the strlen() call
2210 continue;
2211 }
2212 XMLTest( "ErrorName() not empty after ClearError()", true, strlen(name) > 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002213 }
2214 }
2215
Lee Thomason816d3fa2017-06-05 14:35:55 -07002216 {
Derek Quambe69ae62018-04-18 13:40:46 -05002217 const char* html("<!DOCTYPE html><html><body><p>test</p><p><br/></p></body></html>");
2218 XMLDocument doc(false);
2219 doc.Parse(html);
2220
2221 XMLPrinter printer(0, true);
2222 doc.Print(&printer);
2223
2224 XMLTest(html, html, printer.CStr());
2225 }
2226
2227 {
Lee Thomasonc4836462018-06-29 15:57:55 -07002228 // Evil memory leaks.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07002229 // If an XMLElement (etc) is allocated via NewElement() (etc.)
2230 // and NOT added to the XMLDocument, what happens?
2231 //
2232 // Previously (buggy):
2233 // The memory would be free'd when the XMLDocument is
Dmitry-Mea9e75d12017-09-08 19:05:23 +03002234 // destructed. But the XMLElement destructor wasn't called, so
2235 // memory allocated for the XMLElement text would not be free'd.
2236 // In practice this meant strings allocated for the XMLElement
2237 // text would be leaked. An edge case, but annoying.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07002238 // Now:
Dmitry-Mea9e75d12017-09-08 19:05:23 +03002239 // The XMLElement destructor is called. But the unlinked nodes
2240 // have to be tracked using a list. This has a minor performance
2241 // impact that can become significant if you have a lot of
2242 // unlinked nodes. (But why would you do that?)
2243 // The only way to see this bug was in a Visual C++ runtime debug heap
2244 // leak tracker. This is compiled in by default on Windows Debug and
2245 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
Lee Thomason816d3fa2017-06-05 14:35:55 -07002246 {
2247 XMLDocument doc;
2248 doc.NewElement("LEAK 1");
2249 }
2250 {
2251 XMLDocument doc;
2252 XMLElement* ele = doc.NewElement("LEAK 2");
2253 doc.DeleteNode(ele);
2254 }
2255 }
2256
Lee Thomason224ef772017-06-16 09:45:26 -07002257 {
Lee Thomasonf928c352018-04-05 09:24:20 -07002258 // Bad bad crash. Parsing error results in stack overflow, if uncaught.
2259 const char* TESTS[] = {
2260 "./resources/xmltest-5330.xml",
2261 "./resources/xmltest-4636783552757760.xml",
2262 "./resources/xmltest-5720541257269248.xml",
2263 0
2264 };
2265 for (int i=0; TESTS[i]; ++i) {
2266 XMLDocument doc;
2267 doc.LoadFile(TESTS[i]);
Lee Thomasone2d02e12018-04-05 15:57:48 -07002268 XMLTest("Stack overflow prevented.", XML_ELEMENT_DEPTH_EXCEEDED, doc.ErrorID());
Lee Thomasonf928c352018-04-05 09:24:20 -07002269 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002270 }
Lee Thomasondb13a822018-07-28 14:56:20 -07002271 {
2272 const char* TESTS[] = {
2273 "./resources/xmltest-5662204197076992.xml", // Security-level performance issue.
2274 0
2275 };
2276 for (int i = 0; TESTS[i]; ++i) {
2277 XMLDocument doc;
2278 doc.LoadFile(TESTS[i]);
2279 // Need only not crash / lock up.
2280 XMLTest("Fuzz attack prevented.", true, true);
2281 }
2282 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002283 {
Lee Thomason224ef772017-06-16 09:45:26 -07002284 // Crashing reported via email.
2285 const char* xml =
2286 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07002287 "<property name='track_name'>voice</property>"
2288 "<property name='audio_track'>1</property>"
2289 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2290 "<blank length = '1' />"
2291 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2292 "<blank length = '2' />"
2293 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2294 "<blank length = '1' />"
2295 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07002296 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07002297
Lee Thomason224ef772017-06-16 09:45:26 -07002298 // It's not a good idea to delete elements as you walk the
2299 // list. I'm not sure this technically should work; but it's
2300 // an interesting test case.
2301 XMLDocument doc;
2302 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002303 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03002304
2305 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07002306 XMLTest("Crash bug parsing", true, playlist != 0);
2307
Dmitry-Meb41e24a2017-09-27 18:51:01 +03002308 {
2309 const char* elementName = "entry";
2310 XMLElement* entry = playlist->FirstChildElement(elementName);
2311 XMLTest("Crash bug parsing", true, entry != 0);
2312 while (entry) {
2313 XMLElement* todelete = entry;
2314 entry = entry->NextSiblingElement(elementName);
2315 playlist->DeleteChild(todelete);
2316 }
2317 entry = playlist->FirstChildElement(elementName);
2318 XMLTest("Crash bug parsing", true, entry == 0);
2319 }
2320 {
2321 const char* elementName = "blank";
2322 XMLElement* blank = playlist->FirstChildElement(elementName);
2323 XMLTest("Crash bug parsing", true, blank != 0);
2324 while (blank) {
2325 XMLElement* todelete = blank;
2326 blank = blank->NextSiblingElement(elementName);
2327 playlist->DeleteChild(todelete);
2328 }
2329 XMLTest("Crash bug parsing", true, blank == 0);
2330 }
Lee Thomason224ef772017-06-16 09:45:26 -07002331
2332 tinyxml2::XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002333 const bool acceptResult = playlist->Accept(&printer);
2334 XMLTest("Crash bug parsing - Accept()", true, acceptResult);
Lee Thomason224ef772017-06-16 09:45:26 -07002335 printf("%s\n", printer.CStr());
2336
Lee Thomasonc4836462018-06-29 15:57:55 -07002337 // No test; it only need to not crash.
Lee Thomason82bb0742017-06-16 09:48:20 -07002338 // Still, wrap it up with a sanity check
2339 int nProperty = 0;
2340 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2341 nProperty++;
2342 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002343 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07002344 }
2345
kezenatorec694152016-11-26 17:21:43 +10002346 // ----------- Line Number Tracking --------------
2347 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002348 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002349 {
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002350 TestUtil() : str() {}
2351
kezenatorec694152016-11-26 17:21:43 +10002352 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2353 {
2354 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002355 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002356
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002357 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002358 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002359 XMLTest(testString, expected_error, parseError);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002360 XMLTest(testString, expectedLine, doc.ErrorLineNum());
kezenatorec694152016-11-26 17:21:43 +10002361 };
2362
2363 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2364 {
2365 XMLDocument doc;
2366 doc.Parse(docStr);
2367 XMLTest(testString, false, doc.Error());
2368 TestDocLines(testString, doc, expectedLines);
2369 }
2370
2371 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2372 {
2373 XMLDocument doc;
2374 doc.LoadFile(file_name);
2375 XMLTest(testString, false, doc.Error());
2376 TestDocLines(testString, doc, expectedLines);
2377 }
2378
2379 private:
2380 DynArray<char, 10> str;
2381
2382 void Push(char type, int lineNum)
2383 {
2384 str.Push(type);
2385 str.Push(char('0' + (lineNum / 10)));
2386 str.Push(char('0' + (lineNum % 10)));
2387 }
2388
2389 bool VisitEnter(const XMLDocument& doc)
2390 {
kezenator19d8ea82016-11-29 19:50:27 +10002391 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002392 return true;
2393 }
2394 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2395 {
kezenator19d8ea82016-11-29 19:50:27 +10002396 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002397 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002398 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002399 return true;
2400 }
2401 bool Visit(const XMLDeclaration& declaration)
2402 {
kezenator19d8ea82016-11-29 19:50:27 +10002403 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002404 return true;
2405 }
2406 bool Visit(const XMLText& text)
2407 {
kezenator19d8ea82016-11-29 19:50:27 +10002408 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002409 return true;
2410 }
2411 bool Visit(const XMLComment& comment)
2412 {
kezenator19d8ea82016-11-29 19:50:27 +10002413 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002414 return true;
2415 }
2416 bool Visit(const XMLUnknown& unknown)
2417 {
kezenator19d8ea82016-11-29 19:50:27 +10002418 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002419 return true;
2420 }
2421
2422 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2423 {
2424 str.Clear();
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002425 const bool acceptResult = doc.Accept(this);
2426 XMLTest(testString, true, acceptResult);
kezenatorec694152016-11-26 17:21:43 +10002427 str.Push(0);
2428 XMLTest(testString, expectedLines, str.Mem());
2429 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002430 } tester;
kezenatorec694152016-11-26 17:21:43 +10002431
Lee Thomasone90e9012016-12-24 07:34:39 -08002432 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2433 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2434 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2435 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2436 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2437 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2438 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2439 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2440 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2441 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2442 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002443
Lee Thomasone90e9012016-12-24 07:34:39 -08002444 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002445 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002446
2447 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2448 "<root a='b' \n" // 2 Element Attribute
2449 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2450 "newline in text \n" // 4 Text
2451 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2452 " cdata test ]]><!-- comment -->\n" // 6 Comment
2453 "<! unknown></root>", // 7 Unknown
2454
kezenatorec694152016-11-26 17:21:43 +10002455 "D01L01E02A02A03T03E03T04E05T05C06U07");
2456
Lee Thomasone90e9012016-12-24 07:34:39 -08002457 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002458 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002459
2460 "\r\n" // 1 Doc (arguably should be line 2)
2461 "<?xml version=\"1.0\"?>\n" // 2 DecL
2462 "<root>\r\n" // 3 Element
2463 "\n" // 4
2464 "text contining new line \n" // 5 Text
2465 " and also containing crlf \r\n" // 6
2466 "<sub><![CDATA[\n" // 7 Element Text
2467 "cdata containing new line \n" // 8
2468 " and also containing cflr\r\n" // 9
2469 "]]></sub><sub2/></root>", // 10 Element
2470
kezenatorec694152016-11-26 17:21:43 +10002471 "D01L02E03T05E07T07E10");
2472
Lee Thomasone90e9012016-12-24 07:34:39 -08002473 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002474 "LineNumbers-File",
2475 "resources/utf8test.xml",
2476 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2477 }
2478
Lee Thomasonf49b9652017-10-11 10:57:49 -07002479 {
2480 const char* xml = "<Hello>Text</Error>";
2481 XMLDocument doc;
2482 doc.Parse(xml);
2483 XMLTest("Test mismatched elements.", true, doc.Error());
2484 XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2485 // For now just make sure calls work & doesn't crash.
2486 // May solidify the error output in the future.
2487 printf("%s\n", doc.ErrorStr());
2488 doc.PrintError();
2489 }
2490
Lee Thomason85492022015-05-22 11:07:45 -07002491 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002492 {
2493#if defined( _MSC_VER )
2494 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002495 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002496#endif
2497
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002498 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002499 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002500 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002501 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002502 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002503
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002504 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002505 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002506 size_t bytesRead = fread(mem, 1, size, perfFP);
2507 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002508 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002509 mem[size] = 0;
2510
2511#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002512 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002513#else
2514 clock_t cstart = clock();
2515#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002516 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002517 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002518 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002519 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002520 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002521 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002522 }
2523#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002524 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002525#else
2526 clock_t cend = clock();
2527#endif
Dmitry-Me1ab85872017-08-10 17:28:10 +03002528 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002529
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002530 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002531
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002532 static const char* note =
Peter Matula50689912018-01-09 12:52:26 +01002533#ifdef TINYXML2_DEBUG
Lee Thomason6f381b72012-03-02 12:59:39 -08002534 "DEBUG";
2535#else
2536 "Release";
2537#endif
2538
2539#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002540 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002541#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002542 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002543#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002544 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002545 }
2546
Peter Matula50689912018-01-09 12:52:26 +01002547#if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
Dmitry-Mede381df2017-07-26 18:05:25 +03002548 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002549 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002550
2551 _CrtMemState diffMemState;
2552 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2553 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002554
2555 {
2556 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2557 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2558 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002559 }
2560#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002561
2562 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002563
2564 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002565}