blob: 2807fc3072a141f1c1120e34e364d1c586b4bf4a [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-->
464 // <sub attrib="1" />
465 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800466 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800467 // <element>
468
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800469 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800470 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
471
472 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
473 for( int i=0; i<3; ++i ) {
474 sub[i]->SetAttribute( "attrib", i );
475 }
476 element->InsertEndChild( sub[2] );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300477
478 const int dummyInitialValue = 1000;
479 int dummyValue = dummyInitialValue;
480
Lee Thomason1ff38e02012-02-14 18:18:16 -0800481 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Dmitry-Me7d8dfb92017-08-01 17:48:54 +0300482 comment->SetUserData(&dummyValue);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800483 element->InsertAfterChild( comment, sub[0] );
484 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800485 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800486 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800487 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
488 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
489 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700490 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800491 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Dmitry-Mecaed4ec2017-08-11 17:39:47 +0300492 XMLTest("User data - pointer", true, &dummyValue == comment->GetUserData(), false);
493 XMLTest("User data - value behind pointer", dummyInitialValue, dummyValue, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800494
495 // And now deletion:
496 element->DeleteChild( sub[2] );
497 doc->DeleteNode( comment );
498
499 element->FirstChildElement()->SetAttribute( "attrib", true );
500 element->LastChildElement()->DeleteAttribute( "attrib" );
501
502 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300503 const int defaultIntValue = 10;
504 const int replacementIntValue = 20;
505 int value1 = defaultIntValue;
506 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300507 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
508 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
Dmitry-Me3d20c5d2017-07-10 18:28:19 +0300509 XMLTest( "Programmatic DOM", defaultIntValue, value1 );
510 XMLTest( "Programmatic DOM", replacementIntValue, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800511
512 doc->Print();
513
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700514 {
515 XMLPrinter streamer;
516 doc->Print( &streamer );
517 printf( "%s", streamer.CStr() );
518 }
519 {
520 XMLPrinter streamer( 0, true );
521 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200522 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700523 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700524 doc->SaveFile( "./resources/out/pretty.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300525 XMLTest( "Save pretty.xml", false, doc->Error() );
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700526 doc->SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300527 XMLTest( "Save compact.xml", false, doc->Error() );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800528 delete doc;
529 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800530 {
531 // Test: Dream
532 // XML1 : 1,187,569 bytes in 31,209 allocations
533 // XML2 : 469,073 bytes in 323 allocations
534 //int newStart = gNew;
535 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300536 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300537 XMLTest( "Load dream.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800538
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400539 doc.SaveFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300540 XMLTest( "Save dreamout.xml", false, doc.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800541 doc.PrintError();
542
543 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400544 doc.FirstChild()->ToDeclaration()->Value() );
Dmitry-Mef5af9512018-03-23 21:01:25 +0300545 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() != 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800546 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
547 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
548 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400549 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800550 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400551 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800552
553 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400554 doc2.LoadFile( "resources/out/dreamout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300555 XMLTest( "Load dreamout.xml", false, doc2.Error() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800556 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400557 doc2.FirstChild()->ToDeclaration()->Value() );
Dmitry-Mef5af9512018-03-23 21:01:25 +0300558 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() != 0 );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800559 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
560 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
561 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400562 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800563
564 //gNewTotal = gNew - newStart;
565 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800566
567
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800568 {
569 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
570 "<passages count=\"006\" formatversion=\"20020620\">\n"
571 " <wrong error>\n"
572 "</passages>";
573
574 XMLDocument doc;
575 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300576 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomasona36f7ac2017-12-28 13:48:54 -0800577 const char* errorStr = doc.ErrorStr();
578 XMLTest("Formatted error string",
Lee Thomasonc4836462018-06-29 15:57:55 -0700579 "Error=XML_ERROR_PARSING_ATTRIBUTE ErrorID=7 (0x7) Line number=3: XMLElement name=wrong",
Lee Thomasona36f7ac2017-12-28 13:48:54 -0800580 errorStr);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800581 }
582
583 {
584 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
585
586 XMLDocument doc;
587 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300588 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800589
590 XMLElement* ele = doc.FirstChildElement();
591
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300592 int iVal;
593 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800594 double dVal;
595
596 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300597 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
598 XMLTest( "Query attribute: int as double", 1, (int)dVal );
599 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700600
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800601 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300602 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
603 XMLTest( "Query attribute: double as double", 2.0, dVal );
604 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700605
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800606 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300607 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
608 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700609
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800610 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300611 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
612 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700613
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800614 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300615 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
616 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800617 }
618
619 {
620 const char* str = "<doc/>";
621
622 XMLDocument doc;
623 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300624 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800625
626 XMLElement* ele = doc.FirstChildElement();
627
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800628 int iVal, iVal2;
629 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800630
631 ele->SetAttribute( "str", "strValue" );
632 ele->SetAttribute( "int", 1 );
633 ele->SetAttribute( "double", -1.0 );
634
635 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300636 {
637 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
638 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
639 }
640 {
641 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
642 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
643 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800644
Dmitry-Me2087a272017-07-10 18:13:07 +0300645 {
646 int queryResult = ele->QueryAttribute( "int", &iVal2 );
647 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
648 }
649 {
650 int queryResult = ele->QueryAttribute( "double", &dVal2 );
651 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
652 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800653
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300654 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800655 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
656 XMLTest( "Attribute round trip. int.", 1, iVal );
657 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800658 XMLTest( "Alternate query", true, iVal == iVal2 );
659 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700660 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
Lee Thomasonc4836462018-06-29 15:57:55 -0700661 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800662 }
663
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800664 {
665 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300666 doc.LoadFile( "resources/utf8test.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300667 XMLTest( "Load utf8test.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800668
669 // Get the attribute "value" from the "Russian" element and check it.
670 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700671 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800672 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
673
674 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
675
676 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
677 0xd1U, 0x81U, 0xd1U, 0x81U,
678 0xd0U, 0xbaU, 0xd0U, 0xb8U,
679 0xd0U, 0xb9U, 0 };
680 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
681
682 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
683 XMLTest( "UTF-8: Browsing russian element name.",
684 russianText,
685 text->Value() );
686
687 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400688 doc.SaveFile( "resources/out/utf8testout.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +0300689 XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800690
691 // Check the round trip.
Dmitry-Me520009e2017-08-10 17:50:03 +0300692 bool roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800693
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200694 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300695 XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
696
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300697 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Dmitry-Me520009e2017-08-10 17:50:03 +0300698 XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800699
700 if ( saved && verify )
701 {
Dmitry-Me520009e2017-08-10 17:50:03 +0300702 roundTripOkay = true;
PKEuSc28ba3a2012-07-16 03:08:47 -0700703 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800704 while ( fgets( verifyBuf, 256, verify ) )
705 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700706 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800707 fgets( savedBuf, 256, saved );
708 NullLineEndings( verifyBuf );
709 NullLineEndings( savedBuf );
710
711 if ( strcmp( verifyBuf, savedBuf ) )
712 {
713 printf( "verify:%s<\n", verifyBuf );
714 printf( "saved :%s<\n", savedBuf );
Dmitry-Me520009e2017-08-10 17:50:03 +0300715 roundTripOkay = false;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800716 break;
717 }
718 }
719 }
720 if ( saved )
721 fclose( saved );
722 if ( verify )
723 fclose( verify );
Dmitry-Me520009e2017-08-10 17:50:03 +0300724 XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800725 }
726
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800727 // --------GetText()-----------
728 {
729 const char* str = "<foo>This is text</foo>";
730 XMLDocument doc;
731 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300732 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800733 const XMLElement* element = doc.RootElement();
734
735 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
736
737 str = "<foo><b>This is text</b></foo>";
738 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300739 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800740 element = doc.RootElement();
741
742 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
743 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800744
Lee Thomasond6277762012-02-22 16:00:12 -0800745
Uli Kusterer321072e2014-01-21 01:57:38 +0100746 // --------SetText()-----------
747 {
748 const char* str = "<foo></foo>";
749 XMLDocument doc;
750 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300751 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100752 XMLElement* element = doc.RootElement();
753
Lee Thomason9c0678a2014-01-24 10:18:27 -0800754 element->SetText("darkness.");
755 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100756
Lee Thomason9c0678a2014-01-24 10:18:27 -0800757 element->SetText("blue flame.");
758 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100759
760 str = "<foo/>";
761 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300762 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100763 element = doc.RootElement();
764
Lee Thomason9c0678a2014-01-24 10:18:27 -0800765 element->SetText("The driver");
766 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100767
Lee Thomason9c0678a2014-01-24 10:18:27 -0800768 element->SetText("<b>horses</b>");
769 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
770 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100771
772 str = "<foo><bar>Text in nested element</bar></foo>";
773 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300774 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100775 element = doc.RootElement();
Lee Thomasonc4836462018-06-29 15:57:55 -0700776
Lee Thomason9c0678a2014-01-24 10:18:27 -0800777 element->SetText("wolves");
778 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800779
780 str = "<foo/>";
781 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300782 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800783 element = doc.RootElement();
Lee Thomasonc4836462018-06-29 15:57:55 -0700784
Lee Thomason5bb2d802014-01-24 10:42:57 -0800785 element->SetText( "str" );
786 XMLTest( "SetText types", "str", element->GetText() );
787
788 element->SetText( 1 );
789 XMLTest( "SetText types", "1", element->GetText() );
790
791 element->SetText( 1U );
792 XMLTest( "SetText types", "1", element->GetText() );
793
794 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200795 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800796
797 element->SetText( 1.5f );
798 XMLTest( "SetText types", "1.5", element->GetText() );
799
800 element->SetText( 1.5 );
801 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100802 }
803
Lee Thomason51c12712016-06-04 20:18:49 -0700804 // ---------- Attributes ---------
805 {
806 static const int64_t BIG = -123456789012345678;
807 XMLDocument doc;
808 XMLElement* element = doc.NewElement("element");
809 doc.InsertFirstChild(element);
810
811 {
812 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300813 {
814 int v = 0;
815 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
816 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
817 XMLTest("Attribute: int", -100, v, true);
818 }
819 {
820 int v = 0;
821 int queryResult = element->QueryAttribute("attrib", &v);
822 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
823 XMLTest("Attribute: int", -100, v, true);
824 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700825 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700826 }
827 {
828 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300829 {
830 unsigned v = 0;
831 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
832 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
833 XMLTest("Attribute: unsigned", unsigned(100), v, true);
834 }
835 {
836 unsigned v = 0;
837 int queryResult = element->QueryAttribute("attrib", &v);
838 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
839 XMLTest("Attribute: unsigned", unsigned(100), v, true);
840 }
Lee Thomason5b00e062017-12-28 14:07:47 -0800841 {
842 const char* v = "failed";
Dmitry-Me63d8de62018-01-09 00:20:45 +0300843 XMLError queryResult = element->QueryStringAttribute("not-attrib", &v);
Lee Thomason5b00e062017-12-28 14:07:47 -0800844 XMLTest("Attribute: string default", false, queryResult == XML_SUCCESS);
845 queryResult = element->QueryStringAttribute("attrib", &v);
Dmitry-Me63d8de62018-01-09 00:20:45 +0300846 XMLTest("Attribute: string", XML_SUCCESS, queryResult, true);
Lee Thomason5b00e062017-12-28 14:07:47 -0800847 XMLTest("Attribute: string", "100", v);
848 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700849 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700850 }
851 {
852 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300853 {
854 int64_t v = 0;
855 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
856 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
857 XMLTest("Attribute: int64_t", BIG, v, true);
858 }
859 {
860 int64_t v = 0;
861 int queryResult = element->QueryAttribute("attrib", &v);
862 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
863 XMLTest("Attribute: int64_t", BIG, v, true);
864 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700865 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700866 }
867 {
868 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300869 {
870 bool v = false;
871 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
872 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
873 XMLTest("Attribute: bool", true, v, true);
874 }
875 {
876 bool v = false;
877 int queryResult = element->QueryAttribute("attrib", &v);
878 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
879 XMLTest("Attribute: bool", true, v, true);
880 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700881 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700882 }
883 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800884 element->SetAttribute("attrib", true);
885 const char* result = element->Attribute("attrib");
886 XMLTest("Bool true is 'true'", "true", result);
887
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800888 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800889 element->SetAttribute("attrib", true);
890 result = element->Attribute("attrib");
891 XMLTest("Bool true is '1'", "1", result);
892
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800893 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800894 }
895 {
Lee Thomason51c12712016-06-04 20:18:49 -0700896 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300897 {
898 double v = 0;
899 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
900 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
901 XMLTest("Attribute: double", 100.0, v, true);
902 }
903 {
904 double v = 0;
905 int queryResult = element->QueryAttribute("attrib", &v);
906 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
907 XMLTest("Attribute: double", 100.0, v, true);
908 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700909 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700910 }
911 {
912 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300913 {
914 float v = 0;
915 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
916 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
917 XMLTest("Attribute: float", 100.0f, v, true);
918 }
919 {
920 float v = 0;
921 int queryResult = element->QueryAttribute("attrib", &v);
922 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
923 XMLTest("Attribute: float", 100.0f, v, true);
924 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700925 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700926 }
927 {
928 element->SetText(BIG);
929 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300930 XMLError queryResult = element->QueryInt64Text(&v);
931 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700932 XMLTest("Element: int64_t", BIG, v, true);
933 }
934 }
935
936 // ---------- XMLPrinter stream mode ------
937 {
938 {
Dmitry-Mec0fad292017-08-09 19:05:42 +0300939 FILE* printerfp = fopen("resources/out/printer.xml", "w");
940 XMLTest("Open printer.xml", true, printerfp != 0);
Lee Thomason51c12712016-06-04 20:18:49 -0700941 XMLPrinter printer(printerfp);
942 printer.OpenElement("foo");
943 printer.PushAttribute("attrib-text", "text");
944 printer.PushAttribute("attrib-int", int(1));
945 printer.PushAttribute("attrib-unsigned", unsigned(2));
946 printer.PushAttribute("attrib-int64", int64_t(3));
947 printer.PushAttribute("attrib-bool", true);
948 printer.PushAttribute("attrib-double", 4.0);
949 printer.CloseElement();
950 fclose(printerfp);
951 }
952 {
953 XMLDocument doc;
Dmitry-Mec0fad292017-08-09 19:05:42 +0300954 doc.LoadFile("resources/out/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300955 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700956
957 const XMLDocument& cdoc = doc;
958
959 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
960 XMLTest("attrib-text", "text", attrib->Value(), true);
961 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
962 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
963 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
964 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
965 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
966 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
967 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
968 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
969 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
970 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
971 }
972
973 }
974
Uli Kusterer321072e2014-01-21 01:57:38 +0100975
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976 // ---------- CDATA ---------------
977 {
978 const char* str = "<xmlElement>"
979 "<![CDATA["
980 "I am > the rules!\n"
981 "...since I make symbolic puns"
982 "]]>"
983 "</xmlElement>";
984 XMLDocument doc;
985 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300986 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800987 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800988
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300989 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
990 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800991 false );
992 }
993
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800994 // ----------- CDATA -------------
995 {
996 const char* str = "<xmlElement>"
997 "<![CDATA["
998 "<b>I am > the rules!</b>\n"
999 "...since I make symbolic puns"
1000 "]]>"
1001 "</xmlElement>";
1002 XMLDocument doc;
1003 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +03001004 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001005 doc.Print();
1006
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001007 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001008 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001009 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001010 false );
1011 }
1012
1013 // InsertAfterChild causes crash.
1014 {
1015 // InsertBeforeChild and InsertAfterChild causes crash.
1016 XMLDocument doc;
1017 XMLElement* parent = doc.NewElement( "Parent" );
1018 doc.InsertFirstChild( parent );
1019
1020 XMLElement* childText0 = doc.NewElement( "childText0" );
1021 XMLElement* childText1 = doc.NewElement( "childText1" );
1022
1023 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001024 XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001025 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
Dmitry-Me8e063702017-08-01 17:40:40 +03001026 XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001027
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001028 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001029 }
Lee Thomasond6277762012-02-22 16:00:12 -08001030
1031 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001032 // Entities not being written correctly.
1033 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -08001034
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001035 const char* passages =
1036 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1037 "<passages count=\"006\" formatversion=\"20020620\">"
1038 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1039 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
1040 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -08001041
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001042 XMLDocument doc;
1043 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001044 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001045 XMLElement* psg = doc.RootElement()->FirstChildElement();
1046 const char* context = psg->Attribute( "context" );
1047 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 -08001048
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001049 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -08001050
Dmitry-Me520009e2017-08-10 17:50:03 +03001051 const char* textFilePath = "resources/out/textfile.txt";
1052 FILE* textfile = fopen( textFilePath, "w" );
1053 XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001054 if ( textfile )
1055 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001056 XMLPrinter streamer( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001057 bool acceptResult = psg->Accept( &streamer );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001058 fclose( textfile );
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001059 XMLTest( "Entity transformation: Accept", true, acceptResult );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001060 }
Thomas Roß0922b732012-09-23 16:31:22 +02001061
Dmitry-Me520009e2017-08-10 17:50:03 +03001062 textfile = fopen( textFilePath, "r" );
1063 XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001064 if ( textfile )
1065 {
1066 char buf[ 1024 ];
1067 fgets( buf, 1024, textfile );
1068 XMLTest( "Entity transformation: write. ",
1069 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
1070 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
1071 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -07001072 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001073 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001074 }
1075
1076 {
Lee Thomason6f381b72012-03-02 12:59:39 -08001077 // Suppress entities.
1078 const char* passages =
1079 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1080 "<passages count=\"006\" formatversion=\"20020620\">"
1081 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1082 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001083
Lee Thomason6f381b72012-03-02 12:59:39 -08001084 XMLDocument doc( false );
1085 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001086 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001087
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001088 XMLTest( "No entity parsing.",
1089 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1090 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1091 XMLTest( "No entity parsing.", "Crazy &ttk;",
1092 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001093 doc.Print();
1094 }
1095
1096 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001097 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001098
1099 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001100 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001101 XMLTest( "dot in names", false, doc.Error() );
1102 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1103 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001104 }
1105
1106 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001107 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001108
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001109 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001110 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001111 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001112
1113 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1114 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001115 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001116 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001117 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001118
1119 {
1120 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001121 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001122 const char* doctype =
1123 "<?xml version=\"1.0\" ?>"
1124 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1125 "<!ELEMENT title (#PCDATA)>"
1126 "<!ELEMENT books (title,authors)>"
1127 "<element />";
1128
1129 XMLDocument doc;
1130 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001131 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001132 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001133 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001134 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001135 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001136 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001137 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001138
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001139 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1140 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1141
1142 }
1143
1144 {
1145 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001146 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001147 "<!-- Somewhat<evil> -->";
1148 XMLDocument doc;
1149 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001150 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001151
1152 XMLComment* comment = doc.FirstChild()->ToComment();
1153
1154 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1155 }
1156 {
1157 // Double attributes
1158 const char* doctype = "<element attr='red' attr='blue' />";
1159
1160 XMLDocument doc;
1161 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001162
Lee Thomason2fa81722012-11-09 12:37:46 -08001163 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 -08001164 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001165 }
1166
1167 {
1168 // Embedded null in stream.
1169 const char* doctype = "<element att\0r='red' attr='blue' />";
1170
1171 XMLDocument doc;
1172 doc.Parse( doctype );
1173 XMLTest( "Embedded null throws error.", true, doc.Error() );
1174 }
1175
1176 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001177 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001178 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001179 XMLDocument doc;
1180 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001181 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomasona36f7ac2017-12-28 13:48:54 -08001182
1183 // But be sure there is an error string!
1184 const char* errorStr = doc.ErrorStr();
1185 XMLTest("Error string should be set",
Lee Thomasonc4836462018-06-29 15:57:55 -07001186 "Error=XML_ERROR_EMPTY_DOCUMENT ErrorID=13 (0xd) Line number=0",
Lee Thomasona36f7ac2017-12-28 13:48:54 -08001187 errorStr);
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001188 }
1189
1190 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001191 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1192 const char* str = " ";
1193 XMLDocument doc;
1194 doc.Parse( str );
1195 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1196 }
1197
1198 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001199 // Low entities
1200 XMLDocument doc;
1201 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001202 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001203 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001204 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001205 doc.Print();
1206 }
1207
1208 {
1209 // Attribute values with trailing quotes not handled correctly
1210 XMLDocument doc;
1211 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001212 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001213 }
1214
1215 {
1216 // [ 1663758 ] Failure to report error on bad XML
1217 XMLDocument xml;
1218 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001219 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001220 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001221 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001222 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001223 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001224 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001225
1226
1227 {
1228 // [ 1475201 ] TinyXML parses entities in comments
1229 XMLDocument xml;
1230 xml.Parse("<!-- declarations for <head> & <body> -->"
1231 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001232 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001233
1234 XMLNode* e0 = xml.FirstChild();
1235 XMLNode* e1 = e0->NextSibling();
1236 XMLComment* c0 = e0->ToComment();
1237 XMLComment* c1 = e1->ToComment();
1238
1239 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1240 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1241 }
1242
1243 {
1244 XMLDocument xml;
1245 xml.Parse( "<Parent>"
1246 "<child1 att=''/>"
1247 "<!-- With this comment, child2 will not be parsed! -->"
1248 "<child2 att=''/>"
1249 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001250 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001251 xml.Print();
1252
1253 int count = 0;
1254
1255 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1256 ele;
1257 ele = ele->NextSibling() )
1258 {
1259 ++count;
1260 }
1261
1262 XMLTest( "Comments iterate correctly.", 3, count );
1263 }
1264
1265 {
1266 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1267 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1268 buf[60] = 239;
1269 buf[61] = 0;
1270
1271 XMLDocument doc;
1272 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001273 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001274 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001275
1276
1277 {
1278 // bug 1827248 Error while parsing a little bit malformed file
1279 // Actually not malformed - should work.
1280 XMLDocument xml;
1281 xml.Parse( "<attributelist> </attributelist >" );
1282 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1283 }
1284
1285 {
1286 // This one must not result in an infinite loop
1287 XMLDocument xml;
1288 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001289 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001290 XMLTest( "Infinite loop test.", true, true );
1291 }
1292#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001293 {
1294 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1295 XMLDocument doc;
1296 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001297 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001298
1299 XMLDocument clone;
1300 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1301 XMLNode* copy = node->ShallowClone( &clone );
1302 clone.InsertEndChild( copy );
1303 }
1304
1305 clone.Print();
1306
1307 int count=0;
1308 const XMLNode* a=clone.FirstChild();
1309 const XMLNode* b=doc.FirstChild();
1310 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1311 ++count;
1312 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1313 }
1314 XMLTest( "Clone and Equal", 4, count );
1315 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001316
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001317 {
Lee Thomason7085f002017-06-01 18:09:43 -07001318 // Deep Cloning of root element.
1319 XMLDocument doc2;
1320 XMLPrinter printer1;
1321 {
1322 // Make sure doc1 is deleted before we test doc2
1323 const char* xml =
1324 "<root>"
1325 " <child1 foo='bar'/>"
1326 " <!-- comment thing -->"
1327 " <child2 val='1'>Text</child2>"
1328 "</root>";
1329 XMLDocument doc;
1330 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001331 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001332
1333 doc.Print(&printer1);
1334 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1335 doc2.InsertFirstChild(root);
1336 }
1337 XMLPrinter printer2;
1338 doc2.Print(&printer2);
1339
1340 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1341 }
1342
1343 {
1344 // Deep Cloning of sub element.
1345 XMLDocument doc2;
1346 XMLPrinter printer1;
1347 {
1348 // Make sure doc1 is deleted before we test doc2
1349 const char* xml =
1350 "<?xml version ='1.0'?>"
1351 "<root>"
1352 " <child1 foo='bar'/>"
1353 " <!-- comment thing -->"
1354 " <child2 val='1'>Text</child2>"
1355 "</root>";
1356 XMLDocument doc;
1357 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001358 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001359
1360 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001361 bool acceptResult = subElement->Accept(&printer1);
1362 XMLTest( "Accept before deep cloning", true, acceptResult );
Lee Thomason7085f002017-06-01 18:09:43 -07001363
1364 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1365 doc2.InsertFirstChild(clonedSubElement);
1366 }
1367 XMLPrinter printer2;
1368 doc2.Print(&printer2);
1369
1370 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1371 }
1372
1373 {
1374 // Deep cloning of document.
1375 XMLDocument doc2;
1376 XMLPrinter printer1;
1377 {
1378 // Make sure doc1 is deleted before we test doc2
1379 const char* xml =
1380 "<?xml version ='1.0'?>"
1381 "<!-- Top level comment. -->"
1382 "<root>"
1383 " <child1 foo='bar'/>"
1384 " <!-- comment thing -->"
1385 " <child2 val='1'>Text</child2>"
1386 "</root>";
1387 XMLDocument doc;
1388 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001389 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001390 doc.Print(&printer1);
1391
1392 doc.DeepCopy(&doc2);
1393 }
1394 XMLPrinter printer2;
1395 doc2.Print(&printer2);
1396
1397 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1398 }
1399
1400
1401 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001402 // This shouldn't crash.
1403 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001404 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001405 {
1406 doc.PrintError();
1407 }
1408 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1409 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001410
Lee Thomason5e3803c2012-04-16 08:57:05 -07001411 {
1412 // Attribute ordering.
1413 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1414 XMLDocument doc;
1415 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001416 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001417 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001418
Lee Thomason5e3803c2012-04-16 08:57:05 -07001419 const XMLAttribute* a = ele->FirstAttribute();
1420 XMLTest( "Attribute order", "1", a->Value() );
1421 a = a->Next();
1422 XMLTest( "Attribute order", "2", a->Value() );
1423 a = a->Next();
1424 XMLTest( "Attribute order", "3", a->Value() );
1425 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001426
Lee Thomason5e3803c2012-04-16 08:57:05 -07001427 ele->DeleteAttribute( "attrib2" );
1428 a = ele->FirstAttribute();
1429 XMLTest( "Attribute order", "1", a->Value() );
1430 a = a->Next();
1431 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001432
Lee Thomason5e3803c2012-04-16 08:57:05 -07001433 ele->DeleteAttribute( "attrib1" );
1434 ele->DeleteAttribute( "attrib3" );
Dmitry-Mebc6920b2017-08-03 18:46:31 +03001435 XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001436 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001437
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001438 {
1439 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001440 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1441 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1442 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1443 XMLDocument doc0;
1444 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001445 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001446 XMLDocument doc1;
1447 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001448 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001449 XMLDocument doc2;
1450 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001451 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001452
Lee Thomason78a773d2012-07-02 10:10:19 -07001453 XMLElement* ele = 0;
1454 ele = doc0.FirstChildElement();
1455 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1456 ele = doc1.FirstChildElement();
1457 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1458 ele = doc2.FirstChildElement();
1459 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001460 }
1461
1462 {
1463 // Make sure we don't go into an infinite loop.
1464 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1465 XMLDocument doc;
1466 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001467 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001468 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1469 XMLElement* ele1 = ele0->NextSiblingElement();
1470 bool equal = ele0->ShallowEqual( ele1 );
1471
1472 XMLTest( "Infinite loop in shallow equal.", true, equal );
1473 }
1474
Lee Thomason5708f812012-03-28 17:46:41 -07001475 // -------- Handles ------------
1476 {
1477 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1478 XMLDocument doc;
1479 doc.Parse( xml );
Dmitry-Me938560f2018-03-15 01:30:39 +03001480 XMLTest( "Handle, parse element with attribute and nested element", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001481
Dmitry-Me938560f2018-03-15 01:30:39 +03001482 {
1483 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1484 XMLTest( "Handle, non-const, element is found", true, ele != 0 );
1485 XMLTest( "Handle, non-const, element name matches", "sub", ele->Value() );
1486 }
Lee Thomason5708f812012-03-28 17:46:41 -07001487
Dmitry-Me938560f2018-03-15 01:30:39 +03001488 {
1489 XMLHandle docH( doc );
1490 XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1491 XMLTest( "Handle, non-const, element not found", true, ele == 0 );
1492 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001493
Dmitry-Me938560f2018-03-15 01:30:39 +03001494 {
1495 const XMLElement* ele = XMLConstHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1496 XMLTest( "Handle, const, element is found", true, ele != 0 );
1497 XMLTest( "Handle, const, element name matches", "sub", ele->Value() );
1498 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001499
Dmitry-Me938560f2018-03-15 01:30:39 +03001500 {
1501 XMLConstHandle docH( doc );
1502 const XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
1503 XMLTest( "Handle, const, element not found", true, ele == 0 );
1504 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001505 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001506 {
1507 // Default Declaration & BOM
1508 XMLDocument doc;
1509 doc.InsertEndChild( doc.NewDeclaration() );
1510 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001511
Lee Thomasonf68c4382012-04-28 14:37:11 -07001512 XMLPrinter printer;
1513 doc.Print( &printer );
1514
1515 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001516 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1517 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001518 }
Lee Thomason21be8822012-07-15 17:27:22 -07001519 {
1520 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1521 XMLDocument doc;
1522 doc.Parse( xml );
1523 XMLTest( "Ill formed XML", true, doc.Error() );
1524 }
1525
wangkirinf12d7a22019-07-02 16:58:38 +08001526 {
1527 //API:IntText(),UnsignedText(),Int64Text(),DoubleText(),BoolText() and FloatText() test
1528 const char* xml = "<point> <IntText>-24</IntText> <UnsignedText>42</UnsignedText> \
1529 <Int64Text>38</Int64Text> <BoolText>true</BoolText> <DoubleText>2.35</DoubleText> </point>";
1530 XMLDocument doc;
1531 doc.Parse( xml );
1532 const XMLElement* pointElement = doc.RootElement();
1533 int test1;
1534 test1 = pointElement->FirstChildElement("IntText")->IntText();
1535 XMLTest( "IntText() test",-24,test1);
1536 unsigned test2;
1537 test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
1538 XMLTest( "UnsignedText() test",42,test2);
1539 int64_t test3;
1540 test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
1541 XMLTest( "Int64Text() test",38,test3);
1542 double test4;
1543 test4 = pointElement->FirstChildElement("DoubleText")->DoubleText();
1544 XMLTest( "DoubleText() test",2.35,test4);
1545 float test5;
1546 test5 = pointElement->FirstChildElement("DoubleText")->FloatText();
1547 XMLTest( "FloatText()) test",2.35,test5);
1548 bool test6;
1549 test6 = pointElement->FirstChildElement("BoolText")->BoolText();
1550 XMLTest( "FloatText()) test",true,test6);
1551 }
1552
1553 {
1554 //API:ShallowEqual() test
1555 const char* xml = "<playlist id = 'playlist'>"
1556 "<property name = 'track_name'>voice</property>"
1557 "</playlist>";
1558 XMLDocument doc;
1559 doc.Parse( xml );
1560 const XMLNode* PlaylistNode = doc.RootElement();
1561 const XMLNode* PropertyNode = PlaylistNode->FirstChildElement();
1562 bool result;
1563 result = PlaylistNode->ShallowEqual(PropertyNode);
1564 XMLTest("ShallowEqual() test",false,result);
1565 result = PlaylistNode->ShallowEqual(PlaylistNode);
1566 XMLTest("ShallowEqual() test",true,result);
1567 }
1568
1569 {
1570 //API: previousSiblingElement() and NextSiblingElement() test
1571 const char* xml = "<playlist id = 'playlist'>"
1572 "<property name = 'track_name'>voice</property>"
1573 "<entry out = '946' producer = '2_playlist1' in = '0'/>"
1574 "<blank length = '1'/>"
1575 "</playlist>";
1576 XMLDocument doc;
1577 doc.Parse( xml );
1578 XMLElement* ElementPlaylist = doc.FirstChildElement("playlist");
1579 XMLTest("previousSiblingElement() test",true,ElementPlaylist != 0);
1580 const XMLElement* pre = ElementPlaylist->PreviousSiblingElement();
1581 XMLTest("previousSiblingElement() test",true,pre == 0);
1582 const XMLElement* ElementBlank = ElementPlaylist->FirstChildElement("entry")->NextSiblingElement("blank");
1583 XMLTest("NextSiblingElement() test",true,ElementBlank != 0);
1584 const XMLElement* next = ElementBlank->NextSiblingElement();
1585 XMLTest("NextSiblingElement() test",true,next == 0);
1586 const XMLElement* ElementEntry = ElementBlank->PreviousSiblingElement("entry");
1587 XMLTest("PreviousSiblingElement test",true,ElementEntry != 0);
1588 }
1589
Lee Thomason21be8822012-07-15 17:27:22 -07001590 // QueryXYZText
1591 {
1592 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1593 XMLDocument doc;
1594 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001595 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001596
1597 const XMLElement* pointElement = doc.RootElement();
1598
Dmitry-Me43c019d2017-08-02 18:05:23 +03001599 {
1600 int intValue = 0;
1601 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1602 XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
1603 XMLTest( "QueryIntText", 1, intValue, false );
1604 }
Lee Thomason21be8822012-07-15 17:27:22 -07001605
Dmitry-Me43c019d2017-08-02 18:05:23 +03001606 {
1607 unsigned unsignedValue = 0;
1608 XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1609 XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
1610 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1611 }
Lee Thomason21be8822012-07-15 17:27:22 -07001612
Dmitry-Me43c019d2017-08-02 18:05:23 +03001613 {
1614 float floatValue = 0;
1615 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1616 XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
1617 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1618 }
Lee Thomason21be8822012-07-15 17:27:22 -07001619
Dmitry-Me43c019d2017-08-02 18:05:23 +03001620 {
1621 double doubleValue = 0;
1622 XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1623 XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
1624 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1625 }
1626
1627 {
1628 bool boolValue = false;
1629 XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1630 XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
1631 XMLTest( "QueryBoolText", true, boolValue, false );
1632 }
Lee Thomason21be8822012-07-15 17:27:22 -07001633 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001634
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001635 {
1636 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1637 XMLDocument doc;
1638 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001639 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001640 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001641
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001642 {
1643 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1644 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001645 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001646 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001647 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001648
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001649 {
1650 const char* xml = "<3lement></3lement>";
1651 XMLDocument doc;
1652 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001653 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001654 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001655
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001656 {
1657 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1658 XMLDocument doc;
1659 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001660 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001661 }
1662
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001663 {
1664 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001665 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001666 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001667 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001668 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001669 XMLTest( "Load dream.xml", false, doc.Error() );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001670 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001671 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001672 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001673 }
Dmitry-Me985ea1f2017-08-28 18:36:29 +03001674
1675 {
1676 XMLDocument doc;
1677 XMLTest( "No error initially", false, doc.Error() );
1678 XMLError error = doc.Parse( "This is not XML" );
1679 XMLTest( "Error after invalid XML", true, doc.Error() );
1680 XMLTest( "Error after invalid XML", error, doc.ErrorID() );
1681 doc.Clear();
1682 XMLTest( "No error after Clear()", false, doc.Error() );
1683 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001684
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001685 // ----------- Whitespace ------------
1686 {
1687 const char* xml = "<element>"
1688 "<a> This \nis &apos; text &apos; </a>"
1689 "<b> This is &apos; text &apos; \n</b>"
1690 "<c>This is &apos; \n\n text &apos;</c>"
1691 "</element>";
1692 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1693 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001694 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001695
1696 const XMLElement* element = doc.FirstChildElement();
1697 for( const XMLElement* parent = element->FirstChildElement();
1698 parent;
1699 parent = parent->NextSiblingElement() )
1700 {
1701 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1702 }
1703 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001704
Lee Thomasonae9ab072012-10-24 10:17:53 -07001705#if 0
1706 {
1707 // Passes if assert doesn't fire.
1708 XMLDocument xmlDoc;
1709
1710 xmlDoc.NewDeclaration();
1711 xmlDoc.NewComment("Configuration file");
1712
1713 XMLElement *root = xmlDoc.NewElement("settings");
1714 root->SetAttribute("version", 2);
1715 }
1716#endif
1717
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001718 {
1719 const char* xml = "<element> </element>";
1720 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1721 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001722 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001723 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1724 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001725
Lee Thomason5b0a6772012-11-19 13:54:42 -08001726 {
1727 // An assert should not fire.
1728 const char* xml = "<element/>";
1729 XMLDocument doc;
1730 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001731 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001732 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1733 XMLTest( "Tracking unused elements", true, ele != 0, false );
1734 }
1735
Lee Thomasona6412ac2012-12-13 15:39:11 -08001736
1737 {
1738 const char* xml = "<parent><child>abc</child></parent>";
1739 XMLDocument doc;
1740 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001741 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001742 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1743
1744 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001745 bool acceptResult = ele->Accept( &printer );
1746 XMLTest( "Accept of sub-element", true, acceptResult );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001747 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1748 }
1749
1750
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001751 {
1752 XMLDocument doc;
1753 XMLError error = doc.LoadFile( "resources/empty.xml" );
1754 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001755 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001756 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001757 }
1758
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001759 {
1760 // BOM preservation
1761 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1762 {
1763 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001764 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001765 XMLPrinter printer;
1766 doc.Print( &printer );
1767
1768 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1769 doc.SaveFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001770 XMLTest( "Save bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001771 }
1772 {
1773 XMLDocument doc;
1774 doc.LoadFile( "resources/bomtest.xml" );
Dmitry-Me46b70ce2017-07-10 17:54:24 +03001775 XMLTest( "Load bomtest.xml", false, doc.Error() );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001776 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1777
1778 XMLPrinter printer;
1779 doc.Print( &printer );
1780 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1781 }
1782 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001783
Michael Daumlinged523282013-10-23 07:47:29 +02001784 {
1785 // Insertion with Removal
1786 const char* xml = "<?xml version=\"1.0\" ?>"
1787 "<root>"
1788 "<one>"
1789 "<subtree>"
1790 "<elem>element 1</elem>text<!-- comment -->"
1791 "</subtree>"
1792 "</one>"
1793 "<two/>"
1794 "</root>";
1795 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1796 "<root>"
1797 "<one/>"
1798 "<two>"
1799 "<subtree>"
1800 "<elem>element 1</elem>text<!-- comment -->"
1801 "</subtree>"
1802 "</two>"
1803 "</root>";
1804 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1805 "<root>"
1806 "<one/>"
1807 "<subtree>"
1808 "<elem>element 1</elem>text<!-- comment -->"
1809 "</subtree>"
1810 "<two/>"
1811 "</root>";
1812 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1813 "<root>"
1814 "<one/>"
1815 "<two/>"
1816 "<subtree>"
1817 "<elem>element 1</elem>text<!-- comment -->"
1818 "</subtree>"
1819 "</root>";
1820
1821 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001822 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001823 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001824 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1825 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1826 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001827 XMLPrinter printer1(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001828 bool acceptResult = doc.Accept(&printer1);
1829 XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001830 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001831
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001832 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001833 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001834 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1835 two = doc.RootElement()->FirstChildElement("two");
1836 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001837 XMLPrinter printer2(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001838 acceptResult = doc.Accept(&printer2);
1839 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001840 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001841
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001842 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001843 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001844 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1845 subtree = one->FirstChildElement("subtree");
1846 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001847 XMLPrinter printer3(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001848 acceptResult = doc.Accept(&printer3);
1849 XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001850 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001851
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001852 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001853 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001854 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1855 two = doc.RootElement()->FirstChildElement("two");
Dmitry-Me17814942018-10-16 00:11:39 +03001856 XMLTest("<two> is the last child at root level", true, two == doc.RootElement()->LastChildElement());
Michael Daumlinged523282013-10-23 07:47:29 +02001857 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001858 XMLPrinter printer4(0, true);
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001859 acceptResult = doc.Accept(&printer4);
1860 XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001861 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001862 }
1863
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001864 {
1865 const char* xml = "<svg width = \"128\" height = \"128\">"
1866 " <text> </text>"
1867 "</svg>";
1868 XMLDocument doc;
1869 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001870 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001871 doc.Print();
1872 }
1873
Lee Thomason92e521b2014-11-15 17:45:51 -08001874 {
1875 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001876 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1877 XMLDocument doc;
1878 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001879 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001880 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001881 }
1882
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001883#if 1
Lee Thomasonc4836462018-06-29 15:57:55 -07001884 // the question being explored is what kind of print to use:
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001885 // https://github.com/leethomason/tinyxml2/issues/63
1886 {
1887 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1888 const char* xml = "<element/>";
1889 XMLDocument doc;
1890 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001891 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001892 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1893 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1894 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1895 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1896 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1897 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1898
1899 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1900 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1901 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1902 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1903 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1904 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1905
1906 doc.Print();
1907
1908 /* The result of this test is platform, compiler, and library version dependent. :("
1909 XMLPrinter printer;
1910 doc.Print( &printer );
Lee Thomasonc4836462018-06-29 15:57:55 -07001911 XMLTest( "Float and double formatting.",
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001912 "<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 -07001913 printer.CStr(),
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001914 true );
1915 */
1916 }
1917#endif
Lee Thomasonc4836462018-06-29 15:57:55 -07001918
Lee Thomasonf07b9522014-10-30 13:25:12 -07001919 {
1920 // Issue #184
1921 // If it doesn't assert, it passes. Caused by objects
1922 // getting created during parsing which are then
1923 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001924 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001925 {
1926 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001927 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001928 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001929 }
1930 {
1931 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001932 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001933 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001934 doc.Clear();
1935 }
1936 }
Lee Thomasonc4836462018-06-29 15:57:55 -07001937
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001938 {
Peter Matula50689912018-01-09 12:52:26 +01001939 // If this doesn't assert in TINYXML2_DEBUG, all is well.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001940 tinyxml2::XMLDocument doc;
1941 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1942 doc.DeleteNode(pRoot);
1943 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001944
Dmitry-Mee5790db2017-07-28 17:54:38 +03001945 {
1946 XMLDocument doc;
1947 XMLElement* root = doc.NewElement( "Root" );
1948 XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
1949 doc.InsertEndChild( root );
1950 XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
1951 }
1952
1953 {
Peter Matula50689912018-01-09 12:52:26 +01001954 // If this doesn't assert in TINYXML2_DEBUG, all is well.
Dmitry-Mee5790db2017-07-28 17:54:38 +03001955 XMLDocument doc;
1956 XMLElement* unlinkedRoot = doc.NewElement( "Root" );
1957 XMLElement* linkedRoot = doc.NewElement( "Root" );
1958 doc.InsertFirstChild( linkedRoot );
1959 unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
1960 unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
1961 }
1962
Dmitry-Me8b67d742014-12-22 11:35:12 +03001963 {
Peter Matula50689912018-01-09 12:52:26 +01001964 // Should not assert in TINYXML2_DEBUG
Dmitry-Me8b67d742014-12-22 11:35:12 +03001965 XMLPrinter printer;
1966 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001967
Dmitry-Me6f51c802015-03-14 13:25:03 +03001968 {
1969 // Issue 291. Should not crash
1970 const char* xml = "&#0</a>";
1971 XMLDocument doc;
1972 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001973 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001974
1975 XMLPrinter printer;
1976 doc.Print( &printer );
1977 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001978 {
Lee Thomasonc4836462018-06-29 15:57:55 -07001979 // Issue 299. Can print elements that are not linked in.
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001980 // Will crash if issue not fixed.
1981 XMLDocument doc;
1982 XMLElement* newElement = doc.NewElement( "printme" );
1983 XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03001984 bool acceptResult = newElement->Accept( &printer );
1985 XMLTest( "printme - Accept()", true, acceptResult );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001986 // Delete the node to avoid possible memory leak report in debug output
1987 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001988 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001989 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001990 // Issue 302. Clear errors from LoadFile/SaveFile
1991 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001992 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001993 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001994 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001995 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001996 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001997 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001998
Dmitry-Med9852a52015-03-25 10:17:49 +03001999 {
2000 // If a document fails to load then subsequent
2001 // successful loads should clear the error
2002 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03002003 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03002004 doc.LoadFile( "resources/no-such-file.xml" );
2005 XMLTest( "No such file - should fail", true, doc.Error() );
2006
2007 doc.LoadFile( "resources/dream.xml" );
2008 XMLTest( "Error should be cleared", false, doc.Error() );
2009 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05302010
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05302011 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002012 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07002013 const char* xml0 = "<?xml version=\"1.0\" ?>"
2014 " <!-- xml version=\"1.1\" -->"
2015 "<first />";
2016 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002017 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07002018 "<first />";
2019 const char* xml2 = "<first />"
2020 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002021 const char* xml3 = "<first></first>"
2022 "<?xml version=\"1.0\" ?>";
2023
2024 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
2025
Lee Thomason85492022015-05-22 11:07:45 -07002026 XMLDocument doc;
2027 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002028 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07002029 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002030 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07002031 doc.Parse(xml2);
Dmitry-Me6a18a312018-03-23 21:09:13 +03002032 XMLTest("Test that declaration after self-closed child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002033 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002034 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03002035 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002036 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05302037 }
Dmitry-Med9852a52015-03-25 10:17:49 +03002038
Lee Thomason85492022015-05-22 11:07:45 -07002039 {
2040 // No matter - before or after successfully parsing a text -
Dmitry-Me26043362017-08-30 17:40:15 +03002041 // calling XMLDocument::Value() used to cause an assert in debug.
orbitcowboy22b21ec2018-07-17 11:52:57 +02002042 // Null must be returned.
Lee Thomason85492022015-05-22 11:07:45 -07002043 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
2044 "<first />"
2045 "<second />";
2046 XMLDocument* doc = new XMLDocument();
2047 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2048 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03002049 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07002050 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
2051 delete doc;
2052 }
2053
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002054 {
2055 XMLDocument doc;
2056 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
Dmitry-Med3f6c632017-08-30 17:43:14 +03002057 const XMLError error = static_cast<XMLError>(i);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002058 const char* name = XMLDocument::ErrorIDToName(error);
Dmitry-Me95f687b2018-03-23 20:56:46 +03002059 XMLTest( "ErrorName() not null after ClearError()", true, name != 0 );
2060 if( name == 0 ) {
2061 // passing null pointer into strlen() is undefined behavior, so
2062 // compiler is allowed to optimise away the null test above if it's
2063 // as reachable as the strlen() call
2064 continue;
2065 }
2066 XMLTest( "ErrorName() not empty after ClearError()", true, strlen(name) > 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03002067 }
2068 }
2069
Lee Thomason816d3fa2017-06-05 14:35:55 -07002070 {
Derek Quambe69ae62018-04-18 13:40:46 -05002071 const char* html("<!DOCTYPE html><html><body><p>test</p><p><br/></p></body></html>");
2072 XMLDocument doc(false);
2073 doc.Parse(html);
2074
2075 XMLPrinter printer(0, true);
2076 doc.Print(&printer);
2077
2078 XMLTest(html, html, printer.CStr());
2079 }
2080
2081 {
Lee Thomasonc4836462018-06-29 15:57:55 -07002082 // Evil memory leaks.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07002083 // If an XMLElement (etc) is allocated via NewElement() (etc.)
2084 // and NOT added to the XMLDocument, what happens?
2085 //
2086 // Previously (buggy):
2087 // The memory would be free'd when the XMLDocument is
Dmitry-Mea9e75d12017-09-08 19:05:23 +03002088 // destructed. But the XMLElement destructor wasn't called, so
2089 // memory allocated for the XMLElement text would not be free'd.
2090 // In practice this meant strings allocated for the XMLElement
2091 // text would be leaked. An edge case, but annoying.
Lee Thomasonb754ddf2017-06-14 15:02:38 -07002092 // Now:
Dmitry-Mea9e75d12017-09-08 19:05:23 +03002093 // The XMLElement destructor is called. But the unlinked nodes
2094 // have to be tracked using a list. This has a minor performance
2095 // impact that can become significant if you have a lot of
2096 // unlinked nodes. (But why would you do that?)
2097 // The only way to see this bug was in a Visual C++ runtime debug heap
2098 // leak tracker. This is compiled in by default on Windows Debug and
2099 // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
Lee Thomason816d3fa2017-06-05 14:35:55 -07002100 {
2101 XMLDocument doc;
2102 doc.NewElement("LEAK 1");
2103 }
2104 {
2105 XMLDocument doc;
2106 XMLElement* ele = doc.NewElement("LEAK 2");
2107 doc.DeleteNode(ele);
2108 }
2109 }
2110
Lee Thomason224ef772017-06-16 09:45:26 -07002111 {
Lee Thomasonf928c352018-04-05 09:24:20 -07002112 // Bad bad crash. Parsing error results in stack overflow, if uncaught.
2113 const char* TESTS[] = {
2114 "./resources/xmltest-5330.xml",
2115 "./resources/xmltest-4636783552757760.xml",
2116 "./resources/xmltest-5720541257269248.xml",
2117 0
2118 };
2119 for (int i=0; TESTS[i]; ++i) {
2120 XMLDocument doc;
2121 doc.LoadFile(TESTS[i]);
Lee Thomasone2d02e12018-04-05 15:57:48 -07002122 XMLTest("Stack overflow prevented.", XML_ELEMENT_DEPTH_EXCEEDED, doc.ErrorID());
Lee Thomasonf928c352018-04-05 09:24:20 -07002123 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002124 }
Lee Thomasondb13a822018-07-28 14:56:20 -07002125 {
2126 const char* TESTS[] = {
2127 "./resources/xmltest-5662204197076992.xml", // Security-level performance issue.
2128 0
2129 };
2130 for (int i = 0; TESTS[i]; ++i) {
2131 XMLDocument doc;
2132 doc.LoadFile(TESTS[i]);
2133 // Need only not crash / lock up.
2134 XMLTest("Fuzz attack prevented.", true, true);
2135 }
2136 }
Lee Thomasond946dda2018-04-05 09:11:08 -07002137 {
Lee Thomason224ef772017-06-16 09:45:26 -07002138 // Crashing reported via email.
2139 const char* xml =
2140 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07002141 "<property name='track_name'>voice</property>"
2142 "<property name='audio_track'>1</property>"
2143 "<entry out = '604' producer = '4_playlist1' in = '0' />"
2144 "<blank length = '1' />"
2145 "<entry out = '1625' producer = '3_playlist' in = '0' />"
2146 "<blank length = '2' />"
2147 "<entry out = '946' producer = '2_playlist1' in = '0' />"
2148 "<blank length = '1' />"
2149 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07002150 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07002151
Lee Thomason224ef772017-06-16 09:45:26 -07002152 // It's not a good idea to delete elements as you walk the
2153 // list. I'm not sure this technically should work; but it's
2154 // an interesting test case.
2155 XMLDocument doc;
2156 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002157 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03002158
2159 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07002160 XMLTest("Crash bug parsing", true, playlist != 0);
2161
Dmitry-Meb41e24a2017-09-27 18:51:01 +03002162 {
2163 const char* elementName = "entry";
2164 XMLElement* entry = playlist->FirstChildElement(elementName);
2165 XMLTest("Crash bug parsing", true, entry != 0);
2166 while (entry) {
2167 XMLElement* todelete = entry;
2168 entry = entry->NextSiblingElement(elementName);
2169 playlist->DeleteChild(todelete);
2170 }
2171 entry = playlist->FirstChildElement(elementName);
2172 XMLTest("Crash bug parsing", true, entry == 0);
2173 }
2174 {
2175 const char* elementName = "blank";
2176 XMLElement* blank = playlist->FirstChildElement(elementName);
2177 XMLTest("Crash bug parsing", true, blank != 0);
2178 while (blank) {
2179 XMLElement* todelete = blank;
2180 blank = blank->NextSiblingElement(elementName);
2181 playlist->DeleteChild(todelete);
2182 }
2183 XMLTest("Crash bug parsing", true, blank == 0);
2184 }
Lee Thomason224ef772017-06-16 09:45:26 -07002185
2186 tinyxml2::XMLPrinter printer;
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002187 const bool acceptResult = playlist->Accept(&printer);
2188 XMLTest("Crash bug parsing - Accept()", true, acceptResult);
Lee Thomason224ef772017-06-16 09:45:26 -07002189 printf("%s\n", printer.CStr());
2190
Lee Thomasonc4836462018-06-29 15:57:55 -07002191 // No test; it only need to not crash.
Lee Thomason82bb0742017-06-16 09:48:20 -07002192 // Still, wrap it up with a sanity check
2193 int nProperty = 0;
2194 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
2195 nProperty++;
2196 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03002197 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07002198 }
2199
kezenatorec694152016-11-26 17:21:43 +10002200 // ----------- Line Number Tracking --------------
2201 {
Lee Thomasone90e9012016-12-24 07:34:39 -08002202 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10002203 {
Thierry Lelegard7f0f7542017-09-01 10:14:16 +02002204 TestUtil() : str() {}
2205
kezenatorec694152016-11-26 17:21:43 +10002206 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
2207 {
2208 XMLDocument doc;
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002209 const XMLError parseError = doc.Parse(docStr);
kezenatorec694152016-11-26 17:21:43 +10002210
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002211 XMLTest(testString, parseError, doc.ErrorID());
kezenatorec694152016-11-26 17:21:43 +10002212 XMLTest(testString, true, doc.Error());
Dmitry-Me8d40f7a2017-08-09 19:10:08 +03002213 XMLTest(testString, expected_error, parseError);
Lee Thomasonf49b9652017-10-11 10:57:49 -07002214 XMLTest(testString, expectedLine, doc.ErrorLineNum());
kezenatorec694152016-11-26 17:21:43 +10002215 };
2216
2217 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
2218 {
2219 XMLDocument doc;
2220 doc.Parse(docStr);
2221 XMLTest(testString, false, doc.Error());
2222 TestDocLines(testString, doc, expectedLines);
2223 }
2224
2225 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
2226 {
2227 XMLDocument doc;
2228 doc.LoadFile(file_name);
2229 XMLTest(testString, false, doc.Error());
2230 TestDocLines(testString, doc, expectedLines);
2231 }
2232
2233 private:
2234 DynArray<char, 10> str;
2235
2236 void Push(char type, int lineNum)
2237 {
2238 str.Push(type);
2239 str.Push(char('0' + (lineNum / 10)));
2240 str.Push(char('0' + (lineNum % 10)));
2241 }
2242
2243 bool VisitEnter(const XMLDocument& doc)
2244 {
kezenator19d8ea82016-11-29 19:50:27 +10002245 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002246 return true;
2247 }
2248 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
2249 {
kezenator19d8ea82016-11-29 19:50:27 +10002250 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002251 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10002252 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002253 return true;
2254 }
2255 bool Visit(const XMLDeclaration& declaration)
2256 {
kezenator19d8ea82016-11-29 19:50:27 +10002257 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002258 return true;
2259 }
2260 bool Visit(const XMLText& text)
2261 {
kezenator19d8ea82016-11-29 19:50:27 +10002262 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002263 return true;
2264 }
2265 bool Visit(const XMLComment& comment)
2266 {
kezenator19d8ea82016-11-29 19:50:27 +10002267 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002268 return true;
2269 }
2270 bool Visit(const XMLUnknown& unknown)
2271 {
kezenator19d8ea82016-11-29 19:50:27 +10002272 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002273 return true;
2274 }
2275
2276 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2277 {
2278 str.Clear();
Dmitry-Mef0f2e992017-09-25 17:38:42 +03002279 const bool acceptResult = doc.Accept(this);
2280 XMLTest(testString, true, acceptResult);
kezenatorec694152016-11-26 17:21:43 +10002281 str.Push(0);
2282 XMLTest(testString, expectedLines, str.Mem());
2283 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002284 } tester;
kezenatorec694152016-11-26 17:21:43 +10002285
Lee Thomasone90e9012016-12-24 07:34:39 -08002286 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2287 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2288 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2289 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2290 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2291 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2292 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2293 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2294 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2295 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2296 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002297
Lee Thomasone90e9012016-12-24 07:34:39 -08002298 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002299 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002300
2301 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2302 "<root a='b' \n" // 2 Element Attribute
2303 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2304 "newline in text \n" // 4 Text
2305 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2306 " cdata test ]]><!-- comment -->\n" // 6 Comment
2307 "<! unknown></root>", // 7 Unknown
2308
kezenatorec694152016-11-26 17:21:43 +10002309 "D01L01E02A02A03T03E03T04E05T05C06U07");
2310
Lee Thomasone90e9012016-12-24 07:34:39 -08002311 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002312 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002313
2314 "\r\n" // 1 Doc (arguably should be line 2)
2315 "<?xml version=\"1.0\"?>\n" // 2 DecL
2316 "<root>\r\n" // 3 Element
2317 "\n" // 4
2318 "text contining new line \n" // 5 Text
2319 " and also containing crlf \r\n" // 6
2320 "<sub><![CDATA[\n" // 7 Element Text
2321 "cdata containing new line \n" // 8
2322 " and also containing cflr\r\n" // 9
2323 "]]></sub><sub2/></root>", // 10 Element
2324
kezenatorec694152016-11-26 17:21:43 +10002325 "D01L02E03T05E07T07E10");
2326
Lee Thomasone90e9012016-12-24 07:34:39 -08002327 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002328 "LineNumbers-File",
2329 "resources/utf8test.xml",
2330 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2331 }
2332
Lee Thomasonf49b9652017-10-11 10:57:49 -07002333 {
2334 const char* xml = "<Hello>Text</Error>";
2335 XMLDocument doc;
2336 doc.Parse(xml);
2337 XMLTest("Test mismatched elements.", true, doc.Error());
2338 XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
2339 // For now just make sure calls work & doesn't crash.
2340 // May solidify the error output in the future.
2341 printf("%s\n", doc.ErrorStr());
2342 doc.PrintError();
2343 }
2344
Lee Thomason85492022015-05-22 11:07:45 -07002345 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002346 {
2347#if defined( _MSC_VER )
2348 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002349 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002350#endif
2351
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002352 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002353 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002354 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002355 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002356 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002357
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002358 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002359 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002360 size_t bytesRead = fread(mem, 1, size, perfFP);
2361 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002362 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002363 mem[size] = 0;
2364
2365#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002366 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002367#else
2368 clock_t cstart = clock();
2369#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002370 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002371 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002372 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002373 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002374 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002375 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002376 }
2377#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002378 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002379#else
2380 clock_t cend = clock();
2381#endif
Dmitry-Me1ab85872017-08-10 17:28:10 +03002382 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002383
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002384 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002385
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002386 static const char* note =
Peter Matula50689912018-01-09 12:52:26 +01002387#ifdef TINYXML2_DEBUG
Lee Thomason6f381b72012-03-02 12:59:39 -08002388 "DEBUG";
2389#else
2390 "Release";
2391#endif
2392
2393#if defined( _MSC_VER )
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002394 const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002395#else
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002396 const double duration = (double)(cend - cstart) / (double)COUNT;
Lee Thomason6f381b72012-03-02 12:59:39 -08002397#endif
Dmitry-Me6f4c4e72017-07-27 12:06:56 +03002398 printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
Lee Thomason6f381b72012-03-02 12:59:39 -08002399 }
2400
Peter Matula50689912018-01-09 12:52:26 +01002401#if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
Dmitry-Mede381df2017-07-26 18:05:25 +03002402 {
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002403 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002404
2405 _CrtMemState diffMemState;
2406 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2407 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002408
2409 {
2410 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2411 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2412 }
Dmitry-Mede381df2017-07-26 18:05:25 +03002413 }
2414#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -08002415
2416 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002417
2418 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002419}