blob: 67f7c5f80ea84466426fbcd35ed362c586a4b056 [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;
Sarat Addepallid608c562015-05-20 10:19:00 +053037 else
38 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);
85 else
Lee Thomasonc8312792012-07-16 12:44:41 -070086 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080087
88 if ( pass )
89 ++gPass;
90 else
91 ++gFail;
92 return pass;
93}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080094
U-Lama\Leee13c3e62011-12-28 14:36:55 -080095
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080096void NullLineEndings( char* p )
97{
98 while( p && *p ) {
99 if ( *p == '\n' || *p == '\r' ) {
100 *p = 0;
101 return;
102 }
103 ++p;
104 }
105}
106
107
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700108int example_1()
109{
110 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300111 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700112
113 return doc.ErrorID();
114}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200115/** @page Example-1 Load an XML File
116 * @dontinclude ./xmltest.cpp
117 * Basic XML file loading.
118 * The basic syntax to load an XML file from
119 * disk and check for an error. (ErrorID()
120 * will return 0 for no error.)
121 * @skip example_1()
122 * @until }
123 */
124
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700125
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700126int example_2()
127{
128 static const char* xml = "<element/>";
129 XMLDocument doc;
130 doc.Parse( xml );
131
132 return doc.ErrorID();
133}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200134/** @page Example-2 Parse an XML from char buffer
135 * @dontinclude ./xmltest.cpp
136 * Basic XML string parsing.
137 * The basic syntax to parse an XML for
138 * a char* and check for an error. (ErrorID()
139 * will return 0 for no error.)
140 * @skip example_2()
141 * @until }
142 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700143
144
145int example_3()
146{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700147 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700148 "<?xml version=\"1.0\"?>"
149 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
150 "<PLAY>"
151 "<TITLE>A Midsummer Night's Dream</TITLE>"
152 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700153
154 XMLDocument doc;
155 doc.Parse( xml );
156
157 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
158 const char* title = titleElement->GetText();
159 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700160
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700161 XMLText* textNode = titleElement->FirstChild()->ToText();
162 title = textNode->Value();
163 printf( "Name of play (2): %s\n", title );
164
165 return doc.ErrorID();
166}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200167/** @page Example-3 Get information out of XML
168 @dontinclude ./xmltest.cpp
169 In this example, we navigate a simple XML
170 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700171 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200172 checking; working code should check for null
173 pointers when walking an XML tree, or use
174 XMLHandle.
175
176 (The XML is an excerpt from "dream.xml").
177
178 @skip example_3()
179 @until </PLAY>";
180
181 The structure of the XML file is:
182
183 <ul>
184 <li>(declaration)</li>
185 <li>(dtd stuff)</li>
186 <li>Element "PLAY"</li>
187 <ul>
188 <li>Element "TITLE"</li>
189 <ul>
190 <li>Text "A Midsummer Night's Dream"</li>
191 </ul>
192 </ul>
193 </ul>
194
195 For this example, we want to print out the
196 title of the play. The text of the title (what
197 we want) is child of the "TITLE" element which
198 is a child of the "PLAY" element.
199
200 We want to skip the declaration and dtd, so the
201 method FirstChildElement() is a good choice. The
202 FirstChildElement() of the Document is the "PLAY"
203 Element, the FirstChildElement() of the "PLAY" Element
204 is the "TITLE" Element.
205
206 @until ( "TITLE" );
207
208 We can then use the convenience function GetText()
209 to get the title of the play.
210
211 @until title );
212
213 Text is just another Node in the XML DOM. And in
214 fact you should be a little cautious with it, as
215 text nodes can contain elements.
216
217 @verbatim
218 Consider: A Midsummer Night's <b>Dream</b>
219 @endverbatim
220
221 It is more correct to actually query the Text Node
222 if in doubt:
223
224 @until title );
225
226 Noting that here we use FirstChild() since we are
227 looking for XMLText, not an element, and ToText()
228 is a cast from a Node to a XMLText.
229*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700230
231
Lee Thomason21be8822012-07-15 17:27:22 -0700232bool example_4()
233{
234 static const char* xml =
235 "<information>"
236 " <attributeApproach v='2' />"
237 " <textApproach>"
238 " <v>2</v>"
239 " </textApproach>"
240 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700241
Lee Thomason21be8822012-07-15 17:27:22 -0700242 XMLDocument doc;
243 doc.Parse( xml );
244
245 int v0 = 0;
246 int v1 = 0;
247
248 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
249 attributeApproachElement->QueryIntAttribute( "v", &v0 );
250
251 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
252 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
253
254 printf( "Both values are the same: %d and %d\n", v0, v1 );
255
256 return !doc.Error() && ( v0 == v1 );
257}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200258/** @page Example-4 Read attributes and text information.
259 @dontinclude ./xmltest.cpp
260
261 There are fundamentally 2 ways of writing a key-value
262 pair into an XML file. (Something that's always annoyed
263 me about XML.) Either by using attributes, or by writing
264 the key name into an element and the value into
265 the text node wrapped by the element. Both approaches
266 are illustrated in this example, which shows two ways
267 to encode the value "2" into the key "v":
268
269 @skip example_4()
270 @until "</information>";
271
272 TinyXML-2 has accessors for both approaches.
273
274 When using an attribute, you navigate to the XMLElement
275 with that attribute and use the QueryIntAttribute()
276 group of methods. (Also QueryFloatAttribute(), etc.)
277
278 @skip XMLElement* attributeApproachElement
279 @until &v0 );
280
281 When using the text approach, you need to navigate
282 down one more step to the XMLElement that contains
283 the text. Note the extra FirstChildElement( "v" )
284 in the code below. The value of the text can then
285 be safely queried with the QueryIntText() group
286 of methods. (Also QueryFloatText(), etc.)
287
288 @skip XMLElement* textApproachElement
289 @until &v1 );
290*/
Lee Thomason21be8822012-07-15 17:27:22 -0700291
292
Lee Thomason178e4cc2013-01-25 16:19:05 -0800293int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800294{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800295 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800296 _CrtMemCheckpoint( &startMemState );
Dmitry-Me99916592014-10-23 11:37:03 +0400297 // Enable MS Visual C++ debug heap memory leaks dump on exit
298 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
Dmitry-Meed785702017-06-15 13:39:53 +0300299 {
300 int leaksOnStart = _CrtDumpMemoryLeaks();
301 XMLTest( "No leaks on start?", FALSE, leaksOnStart );
302 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700303 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800304
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300305 {
306 TIXMLASSERT( true );
307 }
308
Lee Thomason178e4cc2013-01-25 16:19:05 -0800309 if ( argc > 1 ) {
310 XMLDocument* doc = new XMLDocument();
311 clock_t startTime = clock();
312 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100313 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800314 int errorID = doc->ErrorID();
315 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100316 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800317
318 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
319 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700320 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
321 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
322 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800323 }
324 exit(0);
325 }
326
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300327 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700328 if ( !fp ) {
329 printf( "Error opening test file 'dream.xml'.\n"
330 "Is your working directory the same as where \n"
331 "the xmltest.cpp and dream.xml file are?\n\n"
332 #if defined( _MSC_VER )
333 "In windows Visual Studio you may need to set\n"
334 "Properties->Debugging->Working Directory to '..'\n"
335 #endif
336 );
337 exit( 1 );
338 }
339 fclose( fp );
340
Lee Thomason3a6e51a2017-07-06 17:08:37 -0700341#if 0
kbinny62bf29a152017-06-23 18:15:25 +0000342#if defined WIN32
Lee Thomasone4dc7212017-07-06 17:05:01 -0700343 if ( !CreateDirectory( L"resources\\out", NULL ) && GetLastError() != ERROR_ALREADY_EXISTS ) {
kbinny62bf29a152017-06-23 18:15:25 +0000344#else
kbinny629720fba2017-06-27 01:40:33 +0000345 if ( mkdir( "resources/out", S_IRWXU | S_IRGRP | S_IXGRP ) == -1 && errno != EEXIST ) {
kbinny62bf29a152017-06-23 18:15:25 +0000346#endif
347 printf( "Unable to create directory 'resources/out': %s\n", strerror( errno ) );
348 exit( 1 );
349 }
Lee Thomason3a6e51a2017-07-06 17:08:37 -0700350#endif
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700351 XMLTest( "Example-1", 0, example_1() );
352 XMLTest( "Example-2", 0, example_2() );
353 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700354 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700355
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700356 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700357
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800358 {
Lee Thomason43f59302012-02-06 18:18:11 -0800359 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400360 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800361 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400362 "<element><subelement></subelement></element>",
363 "<element><subelement><subsub/></subelement></element>",
364 "<!--comment beside elements--><element><subelement></subelement></element>",
365 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
366 "<element attrib1='foo' attrib2=\"bar\" ></element>",
367 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800368 "<element>Text inside element.</element>",
369 "<element><b></b></element>",
370 "<element>Text inside and <b>bolded</b> in the element.</element>",
371 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800372 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800373 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800374 0
375 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800376 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800377 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800378 doc.Parse( test[i] );
Dmitry-Me68578f42017-07-03 18:21:23 +0300379 XMLTest( "Element test", false, doc.Error() );
Lee Thomason5cae8972012-01-24 18:03:07 -0800380 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800381 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800382 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800383 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800384#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800385 {
386 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400387 " line 2\r"
388 " line 3\r\n"
389 " line 4\n\r"
390 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800391
392 XMLDocument doc;
393 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300394 XMLTest( "Hello world declaration", false, doc.Error() );
Lee Thomasond6277762012-02-22 16:00:12 -0800395 doc.Print();
396 }
397
Lee Thomason2c85a712012-01-31 08:24:24 -0800398 {
399 static const char* test = "<element>Text before.</element>";
400 XMLDocument doc;
401 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300402 XMLTest( "Element text before", false, doc.Error() );
Lee Thomason2c85a712012-01-31 08:24:24 -0800403 XMLElement* root = doc.FirstChildElement();
404 XMLElement* newElement = doc.NewElement( "Subelement" );
405 root->InsertEndChild( newElement );
406 doc.Print();
407 }
Lee Thomasond1983222012-02-06 08:41:24 -0800408 {
409 XMLDocument* doc = new XMLDocument();
410 static const char* test = "<element><sub/></element>";
411 doc->Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +0300412 XMLTest( "Element with sub element", false, doc->Error() );
Lee Thomasond1983222012-02-06 08:41:24 -0800413 delete doc;
414 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800415 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800416 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800417 // Build:
418 // <element>
419 // <!--comment-->
420 // <sub attrib="1" />
421 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800422 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800423 // <element>
424
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800425 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800426 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
427
428 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
429 for( int i=0; i<3; ++i ) {
430 sub[i]->SetAttribute( "attrib", i );
431 }
432 element->InsertEndChild( sub[2] );
433 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700434 comment->SetUserData((void*)2);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800435 element->InsertAfterChild( comment, sub[0] );
436 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800437 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800438 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800439 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
440 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
441 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700442 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800443 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Lee Thomasonc9445462016-07-17 22:53:48 -0700444 XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800445
446 // And now deletion:
447 element->DeleteChild( sub[2] );
448 doc->DeleteNode( comment );
449
450 element->FirstChildElement()->SetAttribute( "attrib", true );
451 element->LastChildElement()->DeleteAttribute( "attrib" );
452
453 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700454 int value1 = 10;
455 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300456 XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
457 XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
458 XMLTest( "Programmatic DOM", 10, value1 );
459 XMLTest( "Programmatic DOM", 10, value2 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800460
461 doc->Print();
462
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700463 {
464 XMLPrinter streamer;
465 doc->Print( &streamer );
466 printf( "%s", streamer.CStr() );
467 }
468 {
469 XMLPrinter streamer( 0, true );
470 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200471 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700472 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700473 doc->SaveFile( "./resources/out/pretty.xml" );
474 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800475 delete doc;
476 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800477 {
478 // Test: Dream
479 // XML1 : 1,187,569 bytes in 31,209 allocations
480 // XML2 : 469,073 bytes in 323 allocations
481 //int newStart = gNew;
482 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300483 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800484
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400485 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800486 doc.PrintError();
487
488 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400489 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800490 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
491 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
492 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
493 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400494 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800495 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400496 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800497
498 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400499 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800500 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400501 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800502 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
503 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
504 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
505 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400506 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800507
508 //gNewTotal = gNew - newStart;
509 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800510
511
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800512 {
513 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
514 "<passages count=\"006\" formatversion=\"20020620\">\n"
515 " <wrong error>\n"
516 "</passages>";
517
518 XMLDocument doc;
519 doc.Parse( error );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300520 XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800521 }
522
523 {
524 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
525
526 XMLDocument doc;
527 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300528 XMLTest( "Top level attributes", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800529
530 XMLElement* ele = doc.FirstChildElement();
531
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300532 int iVal;
533 XMLError result;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800534 double dVal;
535
536 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300537 XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
538 XMLTest( "Query attribute: int as double", 1, (int)dVal );
539 XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700540
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800541 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300542 XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
543 XMLTest( "Query attribute: double as double", 2.0, dVal );
544 XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700545
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800546 result = ele->QueryIntAttribute( "attr1", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300547 XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
548 XMLTest( "Query attribute: double as int", 2, iVal );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700549
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800550 result = ele->QueryIntAttribute( "attr2", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300551 XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
552 XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700553
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800554 result = ele->QueryIntAttribute( "bar", &iVal );
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300555 XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
556 XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800557 }
558
559 {
560 const char* str = "<doc/>";
561
562 XMLDocument doc;
563 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300564 XMLTest( "Empty top element", false, doc.Error() );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800565
566 XMLElement* ele = doc.FirstChildElement();
567
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800568 int iVal, iVal2;
569 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800570
571 ele->SetAttribute( "str", "strValue" );
572 ele->SetAttribute( "int", 1 );
573 ele->SetAttribute( "double", -1.0 );
574
575 const char* cStr = ele->Attribute( "str" );
Dmitry-Me2087a272017-07-10 18:13:07 +0300576 {
577 XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
578 XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
579 }
580 {
581 XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
582 XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
583 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800584
Dmitry-Me2087a272017-07-10 18:13:07 +0300585 {
586 int queryResult = ele->QueryAttribute( "int", &iVal2 );
587 XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
588 }
589 {
590 int queryResult = ele->QueryAttribute( "double", &dVal2 );
591 XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
592 }
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800593
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300594 XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800595 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
596 XMLTest( "Attribute round trip. int.", 1, iVal );
597 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800598 XMLTest( "Alternate query", true, iVal == iVal2 );
599 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700600 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
601 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800602 }
603
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800604 {
605 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300606 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800607
608 // Get the attribute "value" from the "Russian" element and check it.
609 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700610 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800611 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
612
613 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
614
615 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
616 0xd1U, 0x81U, 0xd1U, 0x81U,
617 0xd0U, 0xbaU, 0xd0U, 0xb8U,
618 0xd0U, 0xb9U, 0 };
619 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
620
621 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
622 XMLTest( "UTF-8: Browsing russian element name.",
623 russianText,
624 text->Value() );
625
626 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400627 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800628
629 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800630 int okay = 0;
631
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200632 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300633 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800634
635 if ( saved && verify )
636 {
637 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700638 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800639 while ( fgets( verifyBuf, 256, verify ) )
640 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700641 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800642 fgets( savedBuf, 256, saved );
643 NullLineEndings( verifyBuf );
644 NullLineEndings( savedBuf );
645
646 if ( strcmp( verifyBuf, savedBuf ) )
647 {
648 printf( "verify:%s<\n", verifyBuf );
649 printf( "saved :%s<\n", savedBuf );
650 okay = 0;
651 break;
652 }
653 }
654 }
655 if ( saved )
656 fclose( saved );
657 if ( verify )
658 fclose( verify );
659 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
660 }
661
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800662 // --------GetText()-----------
663 {
664 const char* str = "<foo>This is text</foo>";
665 XMLDocument doc;
666 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300667 XMLTest( "Double whitespace", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800668 const XMLElement* element = doc.RootElement();
669
670 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
671
672 str = "<foo><b>This is text</b></foo>";
673 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300674 XMLTest( "Bold text simulation", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800675 element = doc.RootElement();
676
677 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
678 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800679
Lee Thomasond6277762012-02-22 16:00:12 -0800680
Uli Kusterer321072e2014-01-21 01:57:38 +0100681 // --------SetText()-----------
682 {
683 const char* str = "<foo></foo>";
684 XMLDocument doc;
685 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300686 XMLTest( "Empty closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100687 XMLElement* element = doc.RootElement();
688
Lee Thomason9c0678a2014-01-24 10:18:27 -0800689 element->SetText("darkness.");
690 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100691
Lee Thomason9c0678a2014-01-24 10:18:27 -0800692 element->SetText("blue flame.");
693 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100694
695 str = "<foo/>";
696 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300697 XMLTest( "Empty self-closed element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100698 element = doc.RootElement();
699
Lee Thomason9c0678a2014-01-24 10:18:27 -0800700 element->SetText("The driver");
701 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100702
Lee Thomason9c0678a2014-01-24 10:18:27 -0800703 element->SetText("<b>horses</b>");
704 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
705 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100706
707 str = "<foo><bar>Text in nested element</bar></foo>";
708 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300709 XMLTest( "Text in nested element", false, doc.Error() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100710 element = doc.RootElement();
711
Lee Thomason9c0678a2014-01-24 10:18:27 -0800712 element->SetText("wolves");
713 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800714
715 str = "<foo/>";
716 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300717 XMLTest( "Empty self-closed element round 2", false, doc.Error() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800718 element = doc.RootElement();
719
720 element->SetText( "str" );
721 XMLTest( "SetText types", "str", element->GetText() );
722
723 element->SetText( 1 );
724 XMLTest( "SetText types", "1", element->GetText() );
725
726 element->SetText( 1U );
727 XMLTest( "SetText types", "1", element->GetText() );
728
729 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200730 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800731
732 element->SetText( 1.5f );
733 XMLTest( "SetText types", "1.5", element->GetText() );
734
735 element->SetText( 1.5 );
736 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100737 }
738
Lee Thomason51c12712016-06-04 20:18:49 -0700739 // ---------- Attributes ---------
740 {
741 static const int64_t BIG = -123456789012345678;
742 XMLDocument doc;
743 XMLElement* element = doc.NewElement("element");
744 doc.InsertFirstChild(element);
745
746 {
747 element->SetAttribute("attrib", int(-100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300748 {
749 int v = 0;
750 XMLError queryResult = element->QueryIntAttribute("attrib", &v);
751 XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
752 XMLTest("Attribute: int", -100, v, true);
753 }
754 {
755 int v = 0;
756 int queryResult = element->QueryAttribute("attrib", &v);
757 XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
758 XMLTest("Attribute: int", -100, v, true);
759 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700760 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700761 }
762 {
763 element->SetAttribute("attrib", unsigned(100));
Dmitry-Me2087a272017-07-10 18:13:07 +0300764 {
765 unsigned v = 0;
766 XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
767 XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
768 XMLTest("Attribute: unsigned", unsigned(100), v, true);
769 }
770 {
771 unsigned v = 0;
772 int queryResult = element->QueryAttribute("attrib", &v);
773 XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
774 XMLTest("Attribute: unsigned", unsigned(100), v, true);
775 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700776 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700777 }
778 {
779 element->SetAttribute("attrib", BIG);
Dmitry-Me2087a272017-07-10 18:13:07 +0300780 {
781 int64_t v = 0;
782 XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
783 XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
784 XMLTest("Attribute: int64_t", BIG, v, true);
785 }
786 {
787 int64_t v = 0;
788 int queryResult = element->QueryAttribute("attrib", &v);
789 XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
790 XMLTest("Attribute: int64_t", BIG, v, true);
791 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700792 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700793 }
794 {
795 element->SetAttribute("attrib", true);
Dmitry-Me2087a272017-07-10 18:13:07 +0300796 {
797 bool v = false;
798 XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
799 XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
800 XMLTest("Attribute: bool", true, v, true);
801 }
802 {
803 bool v = false;
804 int queryResult = element->QueryAttribute("attrib", &v);
805 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
806 XMLTest("Attribute: bool", true, v, true);
807 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700808 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700809 }
810 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800811 element->SetAttribute("attrib", true);
812 const char* result = element->Attribute("attrib");
813 XMLTest("Bool true is 'true'", "true", result);
814
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800815 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800816 element->SetAttribute("attrib", true);
817 result = element->Attribute("attrib");
818 XMLTest("Bool true is '1'", "1", result);
819
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800820 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800821 }
822 {
Lee Thomason51c12712016-06-04 20:18:49 -0700823 element->SetAttribute("attrib", 100.0);
Dmitry-Me2087a272017-07-10 18:13:07 +0300824 {
825 double v = 0;
826 XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
827 XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
828 XMLTest("Attribute: double", 100.0, v, true);
829 }
830 {
831 double v = 0;
832 int queryResult = element->QueryAttribute("attrib", &v);
833 XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
834 XMLTest("Attribute: double", 100.0, v, true);
835 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700836 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700837 }
838 {
839 element->SetAttribute("attrib", 100.0f);
Dmitry-Me2087a272017-07-10 18:13:07 +0300840 {
841 float v = 0;
842 XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
843 XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
844 XMLTest("Attribute: float", 100.0f, v, true);
845 }
846 {
847 float v = 0;
848 int queryResult = element->QueryAttribute("attrib", &v);
849 XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
850 XMLTest("Attribute: float", 100.0f, v, true);
851 }
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700852 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700853 }
854 {
855 element->SetText(BIG);
856 int64_t v = 0;
Dmitry-Me2087a272017-07-10 18:13:07 +0300857 XMLError queryResult = element->QueryInt64Text(&v);
858 XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
Lee Thomason51c12712016-06-04 20:18:49 -0700859 XMLTest("Element: int64_t", BIG, v, true);
860 }
861 }
862
863 // ---------- XMLPrinter stream mode ------
864 {
865 {
866 FILE* printerfp = fopen("resources/printer.xml", "w");
867 XMLPrinter printer(printerfp);
868 printer.OpenElement("foo");
869 printer.PushAttribute("attrib-text", "text");
870 printer.PushAttribute("attrib-int", int(1));
871 printer.PushAttribute("attrib-unsigned", unsigned(2));
872 printer.PushAttribute("attrib-int64", int64_t(3));
873 printer.PushAttribute("attrib-bool", true);
874 printer.PushAttribute("attrib-double", 4.0);
875 printer.CloseElement();
876 fclose(printerfp);
877 }
878 {
879 XMLDocument doc;
880 doc.LoadFile("resources/printer.xml");
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300881 XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700882
883 const XMLDocument& cdoc = doc;
884
885 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
886 XMLTest("attrib-text", "text", attrib->Value(), true);
887 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
888 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
889 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
890 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
891 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
892 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
893 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
894 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
895 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
896 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
897 }
898
899 }
900
Uli Kusterer321072e2014-01-21 01:57:38 +0100901
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800902 // ---------- CDATA ---------------
903 {
904 const char* str = "<xmlElement>"
905 "<![CDATA["
906 "I am > the rules!\n"
907 "...since I make symbolic puns"
908 "]]>"
909 "</xmlElement>";
910 XMLDocument doc;
911 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300912 XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800913 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800914
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300915 XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
916 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomasond6277762012-02-22 16:00:12 -0800917 false );
918 }
919
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800920 // ----------- CDATA -------------
921 {
922 const char* str = "<xmlElement>"
923 "<![CDATA["
924 "<b>I am > the rules!</b>\n"
925 "...since I make symbolic puns"
926 "]]>"
927 "</xmlElement>";
928 XMLDocument doc;
929 doc.Parse( str );
Dmitry-Me68578f42017-07-03 18:21:23 +0300930 XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800931 doc.Print();
932
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300933 XMLTest( "CDATA parse. [ tixml1:1480107 ]",
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800934 "<b>I am > the rules!</b>\n...since I make symbolic puns",
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300935 doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800936 false );
937 }
938
939 // InsertAfterChild causes crash.
940 {
941 // InsertBeforeChild and InsertAfterChild causes crash.
942 XMLDocument doc;
943 XMLElement* parent = doc.NewElement( "Parent" );
944 doc.InsertFirstChild( parent );
945
946 XMLElement* childText0 = doc.NewElement( "childText0" );
947 XMLElement* childText1 = doc.NewElement( "childText1" );
948
949 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
950 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
951
Dmitry-Me9832a5f2017-06-23 18:29:16 +0300952 XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800953 }
Lee Thomasond6277762012-02-22 16:00:12 -0800954
955 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800956 // Entities not being written correctly.
957 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800958
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800959 const char* passages =
960 "<?xml version=\"1.0\" standalone=\"no\" ?>"
961 "<passages count=\"006\" formatversion=\"20020620\">"
962 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
963 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
964 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800965
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800966 XMLDocument doc;
967 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +0300968 XMLTest( "Entity transformation parse round 1", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800969 XMLElement* psg = doc.RootElement()->FirstChildElement();
970 const char* context = psg->Attribute( "context" );
971 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 -0800972
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800973 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800974
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400975 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976 if ( textfile )
977 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800978 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800979 psg->Accept( &streamer );
980 fclose( textfile );
981 }
Thomas Roß0922b732012-09-23 16:31:22 +0200982
983 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800984 TIXMLASSERT( textfile );
985 if ( textfile )
986 {
987 char buf[ 1024 ];
988 fgets( buf, 1024, textfile );
989 XMLTest( "Entity transformation: write. ",
990 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
991 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
992 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700993 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800994 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800995 }
996
997 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800998 // Suppress entities.
999 const char* passages =
1000 "<?xml version=\"1.0\" standalone=\"no\" ?>"
1001 "<passages count=\"006\" formatversion=\"20020620\">"
1002 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
1003 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001004
Lee Thomason6f381b72012-03-02 12:59:39 -08001005 XMLDocument doc( false );
1006 doc.Parse( passages );
Dmitry-Me68578f42017-07-03 18:21:23 +03001007 XMLTest( "Entity transformation parse round 2", false, doc.Error() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001008
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001009 XMLTest( "No entity parsing.",
1010 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
1011 doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
1012 XMLTest( "No entity parsing.", "Crazy &ttk;",
1013 doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
Lee Thomason6f381b72012-03-02 12:59:39 -08001014 doc.Print();
1015 }
1016
1017 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001018 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001019
1020 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001021 doc.Parse( test );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001022 XMLTest( "dot in names", false, doc.Error() );
1023 XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
1024 XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001025 }
1026
1027 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001028 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001029
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001030 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001031 doc.Parse( test );
Dmitry-Me68578f42017-07-03 18:21:23 +03001032 XMLTest( "fin thickness", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001033
1034 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
1035 XMLTest( "Entity with one digit.",
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001036 "1.1 Start easy ignore fin thickness\n", text->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001037 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +04001038 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001039
1040 {
1041 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001042 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001043 const char* doctype =
1044 "<?xml version=\"1.0\" ?>"
1045 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
1046 "<!ELEMENT title (#PCDATA)>"
1047 "<!ELEMENT books (title,authors)>"
1048 "<element />";
1049
1050 XMLDocument doc;
1051 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001052 XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001053 doc.SaveFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001054 XMLTest( "PLAY SYSTEM save", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001055 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +04001056 doc.LoadFile( "resources/out/test7.xml" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001057 XMLTest( "PLAY SYSTEM load", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001058 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001059
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001060 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
1061 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
1062
1063 }
1064
1065 {
1066 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001067 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001068 "<!-- Somewhat<evil> -->";
1069 XMLDocument doc;
1070 doc.Parse( doctype );
Dmitry-Me68578f42017-07-03 18:21:23 +03001071 XMLTest( "Comment somewhat evil", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001072
1073 XMLComment* comment = doc.FirstChild()->ToComment();
1074
1075 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
1076 }
1077 {
1078 // Double attributes
1079 const char* doctype = "<element attr='red' attr='blue' />";
1080
1081 XMLDocument doc;
1082 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001083
Lee Thomason2fa81722012-11-09 12:37:46 -08001084 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 -08001085 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001086 }
1087
1088 {
1089 // Embedded null in stream.
1090 const char* doctype = "<element att\0r='red' attr='blue' />";
1091
1092 XMLDocument doc;
1093 doc.Parse( doctype );
1094 XMLTest( "Embedded null throws error.", true, doc.Error() );
1095 }
1096
1097 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001098 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001099 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001100 XMLDocument doc;
1101 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001102 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001103 }
1104
1105 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001106 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1107 const char* str = " ";
1108 XMLDocument doc;
1109 doc.Parse( str );
1110 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1111 }
1112
1113 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001114 // Low entities
1115 XMLDocument doc;
1116 doc.Parse( "<test>&#x0e;</test>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001117 XMLTest( "Hex values", false, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001118 const char result[] = { 0x0e, 0 };
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001119 XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001120 doc.Print();
1121 }
1122
1123 {
1124 // Attribute values with trailing quotes not handled correctly
1125 XMLDocument doc;
1126 doc.Parse( "<foo attribute=bar\" />" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001127 XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001128 }
1129
1130 {
1131 // [ 1663758 ] Failure to report error on bad XML
1132 XMLDocument xml;
1133 xml.Parse("<x>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001134 XMLTest("Missing end tag at end of input", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001135 xml.Parse("<x> ");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001136 XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001137 xml.Parse("<x></y>");
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001138 XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001139 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001140
1141
1142 {
1143 // [ 1475201 ] TinyXML parses entities in comments
1144 XMLDocument xml;
1145 xml.Parse("<!-- declarations for <head> & <body> -->"
1146 "<!-- far &amp; away -->" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001147 XMLTest( "Declarations for head and body", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001148
1149 XMLNode* e0 = xml.FirstChild();
1150 XMLNode* e1 = e0->NextSibling();
1151 XMLComment* c0 = e0->ToComment();
1152 XMLComment* c1 = e1->ToComment();
1153
1154 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1155 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1156 }
1157
1158 {
1159 XMLDocument xml;
1160 xml.Parse( "<Parent>"
1161 "<child1 att=''/>"
1162 "<!-- With this comment, child2 will not be parsed! -->"
1163 "<child2 att=''/>"
1164 "</Parent>" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001165 XMLTest( "Comments iteration", false, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001166 xml.Print();
1167
1168 int count = 0;
1169
1170 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1171 ele;
1172 ele = ele->NextSibling() )
1173 {
1174 ++count;
1175 }
1176
1177 XMLTest( "Comments iterate correctly.", 3, count );
1178 }
1179
1180 {
1181 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1182 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1183 buf[60] = 239;
1184 buf[61] = 0;
1185
1186 XMLDocument doc;
1187 doc.Parse( (const char*)buf);
Dmitry-Me68578f42017-07-03 18:21:23 +03001188 XMLTest( "Broken CDATA", true, doc.Error() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001189 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001190
1191
1192 {
1193 // bug 1827248 Error while parsing a little bit malformed file
1194 // Actually not malformed - should work.
1195 XMLDocument xml;
1196 xml.Parse( "<attributelist> </attributelist >" );
1197 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1198 }
1199
1200 {
1201 // This one must not result in an infinite loop
1202 XMLDocument xml;
1203 xml.Parse( "<infinite>loop" );
Dmitry-Me68578f42017-07-03 18:21:23 +03001204 XMLTest( "No closing element", true, xml.Error() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001205 XMLTest( "Infinite loop test.", true, true );
1206 }
1207#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001208 {
1209 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1210 XMLDocument doc;
1211 doc.Parse( pub );
Dmitry-Me68578f42017-07-03 18:21:23 +03001212 XMLTest( "Trailing DOCTYPE", false, doc.Error() );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001213
1214 XMLDocument clone;
1215 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1216 XMLNode* copy = node->ShallowClone( &clone );
1217 clone.InsertEndChild( copy );
1218 }
1219
1220 clone.Print();
1221
1222 int count=0;
1223 const XMLNode* a=clone.FirstChild();
1224 const XMLNode* b=doc.FirstChild();
1225 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1226 ++count;
1227 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1228 }
1229 XMLTest( "Clone and Equal", 4, count );
1230 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001231
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001232 {
Lee Thomason7085f002017-06-01 18:09:43 -07001233 // Deep Cloning of root element.
1234 XMLDocument doc2;
1235 XMLPrinter printer1;
1236 {
1237 // Make sure doc1 is deleted before we test doc2
1238 const char* xml =
1239 "<root>"
1240 " <child1 foo='bar'/>"
1241 " <!-- comment thing -->"
1242 " <child2 val='1'>Text</child2>"
1243 "</root>";
1244 XMLDocument doc;
1245 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001246 XMLTest( "Parse before deep cloning root element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001247
1248 doc.Print(&printer1);
1249 XMLNode* root = doc.RootElement()->DeepClone(&doc2);
1250 doc2.InsertFirstChild(root);
1251 }
1252 XMLPrinter printer2;
1253 doc2.Print(&printer2);
1254
1255 XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
1256 }
1257
1258 {
1259 // Deep Cloning of sub element.
1260 XMLDocument doc2;
1261 XMLPrinter printer1;
1262 {
1263 // Make sure doc1 is deleted before we test doc2
1264 const char* xml =
1265 "<?xml version ='1.0'?>"
1266 "<root>"
1267 " <child1 foo='bar'/>"
1268 " <!-- comment thing -->"
1269 " <child2 val='1'>Text</child2>"
1270 "</root>";
1271 XMLDocument doc;
1272 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001273 XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001274
1275 const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
1276 subElement->Accept(&printer1);
1277
1278 XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
1279 doc2.InsertFirstChild(clonedSubElement);
1280 }
1281 XMLPrinter printer2;
1282 doc2.Print(&printer2);
1283
1284 XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
1285 }
1286
1287 {
1288 // Deep cloning of document.
1289 XMLDocument doc2;
1290 XMLPrinter printer1;
1291 {
1292 // Make sure doc1 is deleted before we test doc2
1293 const char* xml =
1294 "<?xml version ='1.0'?>"
1295 "<!-- Top level comment. -->"
1296 "<root>"
1297 " <child1 foo='bar'/>"
1298 " <!-- comment thing -->"
1299 " <child2 val='1'>Text</child2>"
1300 "</root>";
1301 XMLDocument doc;
1302 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001303 XMLTest( "Parse before deep cloning document", false, doc.Error() );
Lee Thomason7085f002017-06-01 18:09:43 -07001304 doc.Print(&printer1);
1305
1306 doc.DeepCopy(&doc2);
1307 }
1308 XMLPrinter printer2;
1309 doc2.Print(&printer2);
1310
1311 XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
1312 }
1313
1314
1315 {
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001316 // This shouldn't crash.
1317 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001318 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001319 {
1320 doc.PrintError();
1321 }
1322 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1323 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001324
Lee Thomason5e3803c2012-04-16 08:57:05 -07001325 {
1326 // Attribute ordering.
1327 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1328 XMLDocument doc;
1329 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001330 XMLTest( "Parse for attribute ordering", false, doc.Error() );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001331 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001332
Lee Thomason5e3803c2012-04-16 08:57:05 -07001333 const XMLAttribute* a = ele->FirstAttribute();
1334 XMLTest( "Attribute order", "1", a->Value() );
1335 a = a->Next();
1336 XMLTest( "Attribute order", "2", a->Value() );
1337 a = a->Next();
1338 XMLTest( "Attribute order", "3", a->Value() );
1339 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001340
Lee Thomason5e3803c2012-04-16 08:57:05 -07001341 ele->DeleteAttribute( "attrib2" );
1342 a = ele->FirstAttribute();
1343 XMLTest( "Attribute order", "1", a->Value() );
1344 a = a->Next();
1345 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001346
Lee Thomason5e3803c2012-04-16 08:57:05 -07001347 ele->DeleteAttribute( "attrib1" );
1348 ele->DeleteAttribute( "attrib3" );
1349 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1350 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001351
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001352 {
1353 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001354 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1355 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1356 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1357 XMLDocument doc0;
1358 doc0.Parse( xml0 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001359 XMLTest( "Parse attribute with space 1", false, doc0.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001360 XMLDocument doc1;
1361 doc1.Parse( xml1 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001362 XMLTest( "Parse attribute with space 2", false, doc1.Error() );
Lee Thomason78a773d2012-07-02 10:10:19 -07001363 XMLDocument doc2;
1364 doc2.Parse( xml2 );
Dmitry-Me68578f42017-07-03 18:21:23 +03001365 XMLTest( "Parse attribute with space 3", false, doc2.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001366
Lee Thomason78a773d2012-07-02 10:10:19 -07001367 XMLElement* ele = 0;
1368 ele = doc0.FirstChildElement();
1369 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1370 ele = doc1.FirstChildElement();
1371 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1372 ele = doc2.FirstChildElement();
1373 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001374 }
1375
1376 {
1377 // Make sure we don't go into an infinite loop.
1378 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1379 XMLDocument doc;
1380 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001381 XMLTest( "Parse two elements with attribute", false, doc.Error() );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001382 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1383 XMLElement* ele1 = ele0->NextSiblingElement();
1384 bool equal = ele0->ShallowEqual( ele1 );
1385
1386 XMLTest( "Infinite loop in shallow equal.", true, equal );
1387 }
1388
Lee Thomason5708f812012-03-28 17:46:41 -07001389 // -------- Handles ------------
1390 {
1391 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1392 XMLDocument doc;
1393 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001394 XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
Lee Thomason5708f812012-03-28 17:46:41 -07001395
1396 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001397 XMLTest( "Handle, success, mutable", "sub", ele->Value() );
Lee Thomason5708f812012-03-28 17:46:41 -07001398
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001399 XMLHandle docH( doc );
1400 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001401 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001402 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001403
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001404 {
1405 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1406 XMLDocument doc;
1407 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001408 XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001409 XMLConstHandle docH( doc );
1410
1411 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1412 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1413
1414 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001415 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001416 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001417 {
1418 // Default Declaration & BOM
1419 XMLDocument doc;
1420 doc.InsertEndChild( doc.NewDeclaration() );
1421 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001422
Lee Thomasonf68c4382012-04-28 14:37:11 -07001423 XMLPrinter printer;
1424 doc.Print( &printer );
1425
1426 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001427 XMLTest( "BOM and default declaration", result, printer.CStr(), false );
1428 XMLTest( "CStrSize", 42, printer.CStrSize(), false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001429 }
Lee Thomason21be8822012-07-15 17:27:22 -07001430 {
1431 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1432 XMLDocument doc;
1433 doc.Parse( xml );
1434 XMLTest( "Ill formed XML", true, doc.Error() );
1435 }
1436
1437 // QueryXYZText
1438 {
1439 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1440 XMLDocument doc;
1441 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001442 XMLTest( "Parse points", false, doc.Error() );
Lee Thomason21be8822012-07-15 17:27:22 -07001443
1444 const XMLElement* pointElement = doc.RootElement();
1445
1446 int intValue = 0;
1447 unsigned unsignedValue = 0;
1448 float floatValue = 0;
1449 double doubleValue = 0;
1450 bool boolValue = false;
1451
1452 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1453 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1454 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1455 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1456 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1457
1458
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001459 XMLTest( "QueryIntText", 1, intValue, false );
1460 XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
1461 XMLTest( "QueryFloatText", 1.2f, floatValue, false );
1462 XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
1463 XMLTest( "QueryBoolText", true, boolValue, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001464 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001465
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001466 {
1467 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1468 XMLDocument doc;
1469 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001470 XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001471 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001472
1473 {
1474 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1475 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001476 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001477 XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001478 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001479
1480 {
1481 const char* xml = "<3lement></3lement>";
1482 XMLDocument doc;
1483 doc.Parse( xml );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001484 XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001485 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001486
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001487 {
1488 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1489 XMLDocument doc;
1490 doc.Parse( xml, 10 );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001491 XMLTest( "Set length of incoming data", false, doc.Error() );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001492 }
1493
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001494 {
1495 XMLDocument doc;
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001496 XMLTest( "Document is initially empty", true, doc.NoChildren() );
Dmitry-Me48b5df02015-04-06 18:20:25 +03001497 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001498 XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001499 doc.LoadFile( "resources/dream.xml" );
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001500 XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001501 doc.Clear();
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001502 XMLTest( "Document Clear()'s", true, doc.NoChildren() );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001503 }
1504
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001505 // ----------- Whitespace ------------
1506 {
1507 const char* xml = "<element>"
1508 "<a> This \nis &apos; text &apos; </a>"
1509 "<b> This is &apos; text &apos; \n</b>"
1510 "<c>This is &apos; \n\n text &apos;</c>"
1511 "</element>";
1512 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1513 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001514 XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001515
1516 const XMLElement* element = doc.FirstChildElement();
1517 for( const XMLElement* parent = element->FirstChildElement();
1518 parent;
1519 parent = parent->NextSiblingElement() )
1520 {
1521 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1522 }
1523 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001524
Lee Thomasonae9ab072012-10-24 10:17:53 -07001525#if 0
1526 {
1527 // Passes if assert doesn't fire.
1528 XMLDocument xmlDoc;
1529
1530 xmlDoc.NewDeclaration();
1531 xmlDoc.NewComment("Configuration file");
1532
1533 XMLElement *root = xmlDoc.NewElement("settings");
1534 root->SetAttribute("version", 2);
1535 }
1536#endif
1537
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001538 {
1539 const char* xml = "<element> </element>";
1540 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1541 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001542 XMLTest( "Parse with all whitespaces", false, doc.Error() );
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001543 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1544 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001545
Lee Thomason5b0a6772012-11-19 13:54:42 -08001546 {
1547 // An assert should not fire.
1548 const char* xml = "<element/>";
1549 XMLDocument doc;
1550 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001551 XMLTest( "Parse with self-closed element", false, doc.Error() );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001552 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1553 XMLTest( "Tracking unused elements", true, ele != 0, false );
1554 }
1555
Lee Thomasona6412ac2012-12-13 15:39:11 -08001556
1557 {
1558 const char* xml = "<parent><child>abc</child></parent>";
1559 XMLDocument doc;
1560 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001561 XMLTest( "Parse for printing of sub-element", false, doc.Error() );
Lee Thomasona6412ac2012-12-13 15:39:11 -08001562 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1563
1564 XMLPrinter printer;
1565 ele->Accept( &printer );
1566 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1567 }
1568
1569
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001570 {
1571 XMLDocument doc;
1572 XMLError error = doc.LoadFile( "resources/empty.xml" );
1573 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001574 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001575 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001576 }
1577
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001578 {
1579 // BOM preservation
1580 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1581 {
1582 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001583 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001584 XMLPrinter printer;
1585 doc.Print( &printer );
1586
1587 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1588 doc.SaveFile( "resources/bomtest.xml" );
1589 }
1590 {
1591 XMLDocument doc;
1592 doc.LoadFile( "resources/bomtest.xml" );
1593 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1594
1595 XMLPrinter printer;
1596 doc.Print( &printer );
1597 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1598 }
1599 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001600
Michael Daumlinged523282013-10-23 07:47:29 +02001601 {
1602 // Insertion with Removal
1603 const char* xml = "<?xml version=\"1.0\" ?>"
1604 "<root>"
1605 "<one>"
1606 "<subtree>"
1607 "<elem>element 1</elem>text<!-- comment -->"
1608 "</subtree>"
1609 "</one>"
1610 "<two/>"
1611 "</root>";
1612 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1613 "<root>"
1614 "<one/>"
1615 "<two>"
1616 "<subtree>"
1617 "<elem>element 1</elem>text<!-- comment -->"
1618 "</subtree>"
1619 "</two>"
1620 "</root>";
1621 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1622 "<root>"
1623 "<one/>"
1624 "<subtree>"
1625 "<elem>element 1</elem>text<!-- comment -->"
1626 "</subtree>"
1627 "<two/>"
1628 "</root>";
1629 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1630 "<root>"
1631 "<one/>"
1632 "<two/>"
1633 "<subtree>"
1634 "<elem>element 1</elem>text<!-- comment -->"
1635 "</subtree>"
1636 "</root>";
1637
1638 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001639 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001640 XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001641 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1642 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1643 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001644 XMLPrinter printer1(0, true);
1645 doc.Accept(&printer1);
1646 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001647
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001648 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001649 XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001650 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1651 two = doc.RootElement()->FirstChildElement("two");
1652 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001653 XMLPrinter printer2(0, true);
1654 doc.Accept(&printer2);
1655 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001656
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001657 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001658 XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001659 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1660 subtree = one->FirstChildElement("subtree");
1661 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001662 XMLPrinter printer3(0, true);
1663 doc.Accept(&printer3);
1664 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001665
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001666 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001667 XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
Michael Daumlinged523282013-10-23 07:47:29 +02001668 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1669 two = doc.RootElement()->FirstChildElement("two");
1670 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001671 XMLPrinter printer4(0, true);
1672 doc.Accept(&printer4);
1673 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001674 }
1675
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001676 {
1677 const char* xml = "<svg width = \"128\" height = \"128\">"
1678 " <text> </text>"
1679 "</svg>";
1680 XMLDocument doc;
1681 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001682 XMLTest( "Parse svg with text", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001683 doc.Print();
1684 }
1685
Lee Thomason92e521b2014-11-15 17:45:51 -08001686 {
1687 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001688 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1689 XMLDocument doc;
1690 doc.Parse(xml);
Dmitry-Me68578f42017-07-03 18:21:23 +03001691 XMLTest( "Parse root-sample-field0", true, doc.Error() );
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001692 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001693 }
1694
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001695#if 1
1696 // the question being explored is what kind of print to use:
1697 // https://github.com/leethomason/tinyxml2/issues/63
1698 {
1699 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1700 const char* xml = "<element/>";
1701 XMLDocument doc;
1702 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001703 XMLTest( "Parse self-closed empty element", false, doc.Error() );
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001704 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1705 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1706 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1707 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1708 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1709 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1710
1711 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1712 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1713 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1714 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1715 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1716 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1717
1718 doc.Print();
1719
1720 /* The result of this test is platform, compiler, and library version dependent. :("
1721 XMLPrinter printer;
1722 doc.Print( &printer );
1723 XMLTest( "Float and double formatting.",
1724 "<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",
1725 printer.CStr(),
1726 true );
1727 */
1728 }
1729#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001730
1731 {
1732 // Issue #184
1733 // If it doesn't assert, it passes. Caused by objects
1734 // getting created during parsing which are then
1735 // inaccessible in the memory pools.
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001736 const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
Lee Thomasonf07b9522014-10-30 13:25:12 -07001737 {
1738 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001739 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001740 XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001741 }
1742 {
1743 XMLDocument doc;
Dmitry-Me5d1aec12017-06-28 14:51:17 +03001744 doc.Parse(xmlText);
Dmitry-Me68578f42017-07-03 18:21:23 +03001745 XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
Lee Thomasonf07b9522014-10-30 13:25:12 -07001746 doc.Clear();
1747 }
1748 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001749
1750 {
1751 // If this doesn't assert in DEBUG, all is well.
1752 tinyxml2::XMLDocument doc;
1753 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1754 doc.DeleteNode(pRoot);
1755 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001756
Dmitry-Me8b67d742014-12-22 11:35:12 +03001757 {
1758 // Should not assert in DEBUG
1759 XMLPrinter printer;
1760 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001761
Dmitry-Me6f51c802015-03-14 13:25:03 +03001762 {
1763 // Issue 291. Should not crash
1764 const char* xml = "&#0</a>";
1765 XMLDocument doc;
1766 doc.Parse( xml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001767 XMLTest( "Parse hex with closing tag", false, doc.Error() );
Dmitry-Me6f51c802015-03-14 13:25:03 +03001768
1769 XMLPrinter printer;
1770 doc.Print( &printer );
1771 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001772 {
1773 // Issue 299. Can print elements that are not linked in.
1774 // Will crash if issue not fixed.
1775 XMLDocument doc;
1776 XMLElement* newElement = doc.NewElement( "printme" );
1777 XMLPrinter printer;
1778 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001779 // Delete the node to avoid possible memory leak report in debug output
1780 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001781 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001782 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001783 // Issue 302. Clear errors from LoadFile/SaveFile
1784 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001785 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001786 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001787 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001788 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001789 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001790 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001791
Dmitry-Med9852a52015-03-25 10:17:49 +03001792 {
1793 // If a document fails to load then subsequent
1794 // successful loads should clear the error
1795 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001796 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001797 doc.LoadFile( "resources/no-such-file.xml" );
1798 XMLTest( "No such file - should fail", true, doc.Error() );
1799
1800 doc.LoadFile( "resources/dream.xml" );
1801 XMLTest( "Error should be cleared", false, doc.Error() );
1802 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301803
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301804 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001805 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001806 const char* xml0 = "<?xml version=\"1.0\" ?>"
1807 " <!-- xml version=\"1.1\" -->"
1808 "<first />";
1809 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001810 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001811 "<first />";
1812 const char* xml2 = "<first />"
1813 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001814 const char* xml3 = "<first></first>"
1815 "<?xml version=\"1.0\" ?>";
1816
1817 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1818
Lee Thomason85492022015-05-22 11:07:45 -07001819 XMLDocument doc;
1820 doc.Parse(xml0);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001821 XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001822 doc.Parse(xml1);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001823 XMLTest("Test that the second declaration is allowed", false, doc.Error() );
Lee Thomason85492022015-05-22 11:07:45 -07001824 doc.Parse(xml2);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001825 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001826 doc.Parse(xml3);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001827 XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001828 doc.Parse(xml4);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001829 XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301830 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001831
Lee Thomason85492022015-05-22 11:07:45 -07001832 {
1833 // No matter - before or after successfully parsing a text -
1834 // calling XMLDocument::Value() causes an assert in debug.
1835 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1836 "<first />"
1837 "<second />";
1838 XMLDocument* doc = new XMLDocument();
1839 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1840 doc->Parse( validXml );
Dmitry-Me68578f42017-07-03 18:21:23 +03001841 XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
Lee Thomason85492022015-05-22 11:07:45 -07001842 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1843 delete doc;
1844 }
1845
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001846 {
1847 XMLDocument doc;
1848 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001849 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001850 doc.ErrorName();
1851 }
1852 }
1853
Lee Thomason816d3fa2017-06-05 14:35:55 -07001854 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001855 // Evil memory leaks.
1856 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1857 // and NOT added to the XMLDocument, what happens?
1858 //
1859 // Previously (buggy):
1860 // The memory would be free'd when the XMLDocument is
1861 // destructed. But the destructor wasn't called, so that
1862 // memory allocated by the XMLElement would not be free'd.
1863 // In practice this meant strings allocated by the XMLElement
1864 // would leak. An edge case, but annoying.
1865 // Now:
1866 // The destructor is called. But the list of unlinked nodes
1867 // has to be tracked. This has a minor performance impact
1868 // that can become significant if you have a lot. (But why
1869 // would you do that?)
1870 // The only way to see this bug is in a leak tracker. This
1871 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001872 {
1873 XMLDocument doc;
1874 doc.NewElement("LEAK 1");
1875 }
1876 {
1877 XMLDocument doc;
1878 XMLElement* ele = doc.NewElement("LEAK 2");
1879 doc.DeleteNode(ele);
1880 }
1881 }
1882
Lee Thomason224ef772017-06-16 09:45:26 -07001883 {
1884 // Crashing reported via email.
1885 const char* xml =
1886 "<playlist id='playlist1'>"
Lee Thomason82bb0742017-06-16 09:48:20 -07001887 "<property name='track_name'>voice</property>"
1888 "<property name='audio_track'>1</property>"
1889 "<entry out = '604' producer = '4_playlist1' in = '0' />"
1890 "<blank length = '1' />"
1891 "<entry out = '1625' producer = '3_playlist' in = '0' />"
1892 "<blank length = '2' />"
1893 "<entry out = '946' producer = '2_playlist1' in = '0' />"
1894 "<blank length = '1' />"
1895 "<entry out = '128' producer = '1_playlist1' in = '0' />"
Lee Thomason224ef772017-06-16 09:45:26 -07001896 "</playlist>";
Lee Thomason82bb0742017-06-16 09:48:20 -07001897
Lee Thomason224ef772017-06-16 09:45:26 -07001898 // It's not a good idea to delete elements as you walk the
1899 // list. I'm not sure this technically should work; but it's
1900 // an interesting test case.
1901 XMLDocument doc;
1902 XMLError err = doc.Parse(xml);
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001903 XMLTest("Crash bug parsing", XML_SUCCESS, err );
Dmitry-Meaea64c42017-06-20 18:20:15 +03001904
1905 XMLElement* playlist = doc.FirstChildElement("playlist");
Lee Thomason224ef772017-06-16 09:45:26 -07001906 XMLTest("Crash bug parsing", true, playlist != 0);
1907
1908 tinyxml2::XMLElement* entry = playlist->FirstChildElement("entry");
1909 XMLTest("Crash bug parsing", true, entry != 0);
1910 while (entry) {
1911 tinyxml2::XMLElement* todelete = entry;
1912 entry = entry->NextSiblingElement("entry");
1913 playlist->DeleteChild(todelete);
1914 };
1915 tinyxml2::XMLElement* blank = playlist->FirstChildElement("blank");
1916 while (blank) {
1917 tinyxml2::XMLElement* todelete = blank;
1918 blank = blank->NextSiblingElement("blank");
1919 playlist->DeleteChild(todelete);
1920 };
1921
1922 tinyxml2::XMLPrinter printer;
1923 playlist->Accept(&printer);
1924 printf("%s\n", printer.CStr());
1925
Lee Thomason82bb0742017-06-16 09:48:20 -07001926 // No test; it only need to not crash.
1927 // Still, wrap it up with a sanity check
1928 int nProperty = 0;
1929 for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
1930 nProperty++;
1931 }
Dmitry-Me9832a5f2017-06-23 18:29:16 +03001932 XMLTest("Crash bug parsing", 2, nProperty);
Lee Thomason224ef772017-06-16 09:45:26 -07001933 }
1934
kezenatorec694152016-11-26 17:21:43 +10001935 // ----------- Line Number Tracking --------------
1936 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001937 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001938 {
1939 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1940 {
1941 XMLDocument doc;
1942 XMLError err = doc.Parse(docStr);
1943
1944 XMLTest(testString, true, doc.Error());
1945 XMLTest(testString, expected_error, err);
1946 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1947 };
1948
1949 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1950 {
1951 XMLDocument doc;
1952 doc.Parse(docStr);
1953 XMLTest(testString, false, doc.Error());
1954 TestDocLines(testString, doc, expectedLines);
1955 }
1956
1957 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1958 {
1959 XMLDocument doc;
1960 doc.LoadFile(file_name);
1961 XMLTest(testString, false, doc.Error());
1962 TestDocLines(testString, doc, expectedLines);
1963 }
1964
1965 private:
1966 DynArray<char, 10> str;
1967
1968 void Push(char type, int lineNum)
1969 {
1970 str.Push(type);
1971 str.Push(char('0' + (lineNum / 10)));
1972 str.Push(char('0' + (lineNum % 10)));
1973 }
1974
1975 bool VisitEnter(const XMLDocument& doc)
1976 {
kezenator19d8ea82016-11-29 19:50:27 +10001977 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001978 return true;
1979 }
1980 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
1981 {
kezenator19d8ea82016-11-29 19:50:27 +10001982 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001983 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10001984 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001985 return true;
1986 }
1987 bool Visit(const XMLDeclaration& declaration)
1988 {
kezenator19d8ea82016-11-29 19:50:27 +10001989 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001990 return true;
1991 }
1992 bool Visit(const XMLText& text)
1993 {
kezenator19d8ea82016-11-29 19:50:27 +10001994 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001995 return true;
1996 }
1997 bool Visit(const XMLComment& comment)
1998 {
kezenator19d8ea82016-11-29 19:50:27 +10001999 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002000 return true;
2001 }
2002 bool Visit(const XMLUnknown& unknown)
2003 {
kezenator19d8ea82016-11-29 19:50:27 +10002004 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10002005 return true;
2006 }
2007
2008 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
2009 {
2010 str.Clear();
2011 doc.Accept(this);
2012 str.Push(0);
2013 XMLTest(testString, expectedLines, str.Mem());
2014 }
Lee Thomasone90e9012016-12-24 07:34:39 -08002015 } tester;
kezenatorec694152016-11-26 17:21:43 +10002016
Lee Thomasone90e9012016-12-24 07:34:39 -08002017 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
2018 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
2019 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
2020 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
2021 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
2022 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
2023 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
2024 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
2025 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
2026 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
2027 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10002028
Lee Thomasone90e9012016-12-24 07:34:39 -08002029 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002030 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08002031
2032 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
2033 "<root a='b' \n" // 2 Element Attribute
2034 "c='d'> d <blah/> \n" // 3 Attribute Text Element
2035 "newline in text \n" // 4 Text
2036 "and second <zxcv/><![CDATA[\n" // 5 Element Text
2037 " cdata test ]]><!-- comment -->\n" // 6 Comment
2038 "<! unknown></root>", // 7 Unknown
2039
kezenatorec694152016-11-26 17:21:43 +10002040 "D01L01E02A02A03T03E03T04E05T05C06U07");
2041
Lee Thomasone90e9012016-12-24 07:34:39 -08002042 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10002043 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08002044
2045 "\r\n" // 1 Doc (arguably should be line 2)
2046 "<?xml version=\"1.0\"?>\n" // 2 DecL
2047 "<root>\r\n" // 3 Element
2048 "\n" // 4
2049 "text contining new line \n" // 5 Text
2050 " and also containing crlf \r\n" // 6
2051 "<sub><![CDATA[\n" // 7 Element Text
2052 "cdata containing new line \n" // 8
2053 " and also containing cflr\r\n" // 9
2054 "]]></sub><sub2/></root>", // 10 Element
2055
kezenatorec694152016-11-26 17:21:43 +10002056 "D01L02E03T05E07T07E10");
2057
Lee Thomasone90e9012016-12-24 07:34:39 -08002058 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10002059 "LineNumbers-File",
2060 "resources/utf8test.xml",
2061 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
2062 }
2063
Lee Thomason85492022015-05-22 11:07:45 -07002064 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08002065 {
2066#if defined( _MSC_VER )
2067 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002068 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08002069#endif
2070
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002071 FILE* perfFP = fopen("resources/dream.xml", "r");
Dmitry-Med1b82822017-07-04 18:02:54 +03002072 XMLTest("Open dream.xml", true, perfFP != 0);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002073 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02002074 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002075 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08002076
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002077 char* mem = new char[size + 1];
Dmitry-Med1b82822017-07-04 18:02:54 +03002078 memset(mem, 0xfe, size);
Lee Thomasone4dc7212017-07-06 17:05:01 -07002079 size_t bytesRead = fread(mem, 1, size, perfFP);
2080 XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002081 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08002082 mem[size] = 0;
2083
2084#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002085 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08002086#else
2087 clock_t cstart = clock();
2088#endif
Dmitry-Me68578f42017-07-03 18:21:23 +03002089 bool parseDreamXmlFailed = false;
Lee Thomason6f381b72012-03-02 12:59:39 -08002090 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002091 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08002092 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002093 doc.Parse(mem);
Dmitry-Me68578f42017-07-03 18:21:23 +03002094 parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
Lee Thomason6f381b72012-03-02 12:59:39 -08002095 }
Dmitry-Me68578f42017-07-03 18:21:23 +03002096 XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
Lee Thomason6f381b72012-03-02 12:59:39 -08002097#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002098 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08002099#else
2100 clock_t cend = clock();
2101#endif
2102
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002103 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08002104
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002105 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08002106#ifdef DEBUG
2107 "DEBUG";
2108#else
2109 "Release";
2110#endif
2111
2112#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002113 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT));
Lee Thomason6f381b72012-03-02 12:59:39 -08002114#else
Lee Thomasondf4ffc02016-06-04 11:32:46 -07002115 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08002116#endif
2117 }
2118
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08002119 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002120 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08002121
2122 _CrtMemState diffMemState;
2123 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
2124 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03002125
2126 {
2127 int leaksBeforeExit = _CrtDumpMemoryLeaks();
2128 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
2129 }
Lee Thomason1ff38e02012-02-14 18:18:16 -08002130 #endif
2131
2132 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07002133
2134 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002135}