blob: d892a9e6b2e394fe9d780dc3385b0170aa7b82b0 [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"
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07008#include <cstdlib>
9#include <cstring>
10#include <ctime>
U-Lama\Leee13c3e62011-12-28 14:36:55 -080011
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080012#if defined( _MSC_VER )
Lee Thomason1ff38e02012-02-14 18:18:16 -080013 #include <crtdbg.h>
Lee Thomason6f381b72012-03-02 12:59:39 -080014 #define WIN32_LEAN_AND_MEAN
15 #include <windows.h>
Lee Thomason1ff38e02012-02-14 18:18:16 -080016 _CrtMemState startMemState;
Lee Thomason53858b42017-06-01 19:09:16 -070017 _CrtMemState endMemState;
Lee Thomason1ff38e02012-02-14 18:18:16 -080018#endif
Lee Thomasone9ecdab2012-02-13 18:11:20 -080019
U-Lama\Leee13c3e62011-12-28 14:36:55 -080020using namespace tinyxml2;
Anton Indrawan8a0006c2014-11-20 18:27:07 +010021using namespace std;
Lee Thomasonec5a7b42012-02-13 18:16:52 -080022int gPass = 0;
23int gFail = 0;
24
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -080025
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070026bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
Lee Thomason1ff38e02012-02-14 18:18:16 -080027{
Sarat Addepalli13b2d732015-05-19 12:44:57 +053028 bool pass;
29 if ( !expected && !found )
30 pass = true;
31 else if ( !expected || !found )
32 pass = false;
Sarat Addepallid608c562015-05-20 10:19:00 +053033 else
34 pass = !strcmp( expected, found );
Lee Thomason1ff38e02012-02-14 18:18:16 -080035 if ( pass )
36 printf ("[pass]");
37 else
38 printf ("[fail]");
39
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070040 if ( !echo ) {
Lee Thomason1ff38e02012-02-14 18:18:16 -080041 printf (" %s\n", testString);
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -070042 }
43 else {
44 if ( extraNL ) {
45 printf( " %s\n", testString );
46 printf( "%s\n", expected );
47 printf( "%s\n", found );
48 }
49 else {
50 printf (" %s [%s][%s]\n", testString, expected, found);
51 }
52 }
Lee Thomason1ff38e02012-02-14 18:18:16 -080053
54 if ( pass )
55 ++gPass;
56 else
57 ++gFail;
58 return pass;
59}
60
kezenator5a700712016-11-26 13:54:42 +100061bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
62{
Lee Thomasone90e9012016-12-24 07:34:39 -080063 return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
kezenator5a700712016-11-26 13:54:42 +100064}
65
66bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
67{
68 return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
69}
Lee Thomason1ff38e02012-02-14 18:18:16 -080070
Lee Thomason21be8822012-07-15 17:27:22 -070071template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
Lee Thomason1ff38e02012-02-14 18:18:16 -080072{
73 bool pass = ( expected == found );
74 if ( pass )
75 printf ("[pass]");
76 else
77 printf ("[fail]");
78
U-Stream\Lee09a11c52012-02-17 08:31:16 -080079 if ( !echo )
Lee Thomason1ff38e02012-02-14 18:18:16 -080080 printf (" %s\n", testString);
81 else
Lee Thomasonc8312792012-07-16 12:44:41 -070082 printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
Lee Thomason1ff38e02012-02-14 18:18:16 -080083
84 if ( pass )
85 ++gPass;
86 else
87 ++gFail;
88 return pass;
89}
Lee Thomasonec5a7b42012-02-13 18:16:52 -080090
U-Lama\Leee13c3e62011-12-28 14:36:55 -080091
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080092void NullLineEndings( char* p )
93{
94 while( p && *p ) {
95 if ( *p == '\n' || *p == '\r' ) {
96 *p = 0;
97 return;
98 }
99 ++p;
100 }
101}
102
103
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700104int example_1()
105{
106 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300107 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700108
109 return doc.ErrorID();
110}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200111/** @page Example-1 Load an XML File
112 * @dontinclude ./xmltest.cpp
113 * Basic XML file loading.
114 * The basic syntax to load an XML file from
115 * disk and check for an error. (ErrorID()
116 * will return 0 for no error.)
117 * @skip example_1()
118 * @until }
119 */
120
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700121
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700122int example_2()
123{
124 static const char* xml = "<element/>";
125 XMLDocument doc;
126 doc.Parse( xml );
127
128 return doc.ErrorID();
129}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200130/** @page Example-2 Parse an XML from char buffer
131 * @dontinclude ./xmltest.cpp
132 * Basic XML string parsing.
133 * The basic syntax to parse an XML for
134 * a char* and check for an error. (ErrorID()
135 * will return 0 for no error.)
136 * @skip example_2()
137 * @until }
138 */
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700139
140
141int example_3()
142{
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700143 static const char* xml =
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -0700144 "<?xml version=\"1.0\"?>"
145 "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
146 "<PLAY>"
147 "<TITLE>A Midsummer Night's Dream</TITLE>"
148 "</PLAY>";
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700149
150 XMLDocument doc;
151 doc.Parse( xml );
152
153 XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
154 const char* title = titleElement->GetText();
155 printf( "Name of play (1): %s\n", title );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700156
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700157 XMLText* textNode = titleElement->FirstChild()->ToText();
158 title = textNode->Value();
159 printf( "Name of play (2): %s\n", title );
160
161 return doc.ErrorID();
162}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200163/** @page Example-3 Get information out of XML
164 @dontinclude ./xmltest.cpp
165 In this example, we navigate a simple XML
166 file, and read some interesting text. Note
Andrew C. Martin0fd87462013-03-09 20:09:45 -0700167 that this example doesn't use error
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200168 checking; working code should check for null
169 pointers when walking an XML tree, or use
170 XMLHandle.
171
172 (The XML is an excerpt from "dream.xml").
173
174 @skip example_3()
175 @until </PLAY>";
176
177 The structure of the XML file is:
178
179 <ul>
180 <li>(declaration)</li>
181 <li>(dtd stuff)</li>
182 <li>Element "PLAY"</li>
183 <ul>
184 <li>Element "TITLE"</li>
185 <ul>
186 <li>Text "A Midsummer Night's Dream"</li>
187 </ul>
188 </ul>
189 </ul>
190
191 For this example, we want to print out the
192 title of the play. The text of the title (what
193 we want) is child of the "TITLE" element which
194 is a child of the "PLAY" element.
195
196 We want to skip the declaration and dtd, so the
197 method FirstChildElement() is a good choice. The
198 FirstChildElement() of the Document is the "PLAY"
199 Element, the FirstChildElement() of the "PLAY" Element
200 is the "TITLE" Element.
201
202 @until ( "TITLE" );
203
204 We can then use the convenience function GetText()
205 to get the title of the play.
206
207 @until title );
208
209 Text is just another Node in the XML DOM. And in
210 fact you should be a little cautious with it, as
211 text nodes can contain elements.
212
213 @verbatim
214 Consider: A Midsummer Night's <b>Dream</b>
215 @endverbatim
216
217 It is more correct to actually query the Text Node
218 if in doubt:
219
220 @until title );
221
222 Noting that here we use FirstChild() since we are
223 looking for XMLText, not an element, and ToText()
224 is a cast from a Node to a XMLText.
225*/
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700226
227
Lee Thomason21be8822012-07-15 17:27:22 -0700228bool example_4()
229{
230 static const char* xml =
231 "<information>"
232 " <attributeApproach v='2' />"
233 " <textApproach>"
234 " <v>2</v>"
235 " </textApproach>"
236 "</information>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700237
Lee Thomason21be8822012-07-15 17:27:22 -0700238 XMLDocument doc;
239 doc.Parse( xml );
240
241 int v0 = 0;
242 int v1 = 0;
243
244 XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
245 attributeApproachElement->QueryIntAttribute( "v", &v0 );
246
247 XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
248 textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
249
250 printf( "Both values are the same: %d and %d\n", v0, v1 );
251
252 return !doc.Error() && ( v0 == v1 );
253}
Martinsh Shaitersc9c8b772013-01-16 02:08:19 +0200254/** @page Example-4 Read attributes and text information.
255 @dontinclude ./xmltest.cpp
256
257 There are fundamentally 2 ways of writing a key-value
258 pair into an XML file. (Something that's always annoyed
259 me about XML.) Either by using attributes, or by writing
260 the key name into an element and the value into
261 the text node wrapped by the element. Both approaches
262 are illustrated in this example, which shows two ways
263 to encode the value "2" into the key "v":
264
265 @skip example_4()
266 @until "</information>";
267
268 TinyXML-2 has accessors for both approaches.
269
270 When using an attribute, you navigate to the XMLElement
271 with that attribute and use the QueryIntAttribute()
272 group of methods. (Also QueryFloatAttribute(), etc.)
273
274 @skip XMLElement* attributeApproachElement
275 @until &v0 );
276
277 When using the text approach, you need to navigate
278 down one more step to the XMLElement that contains
279 the text. Note the extra FirstChildElement( "v" )
280 in the code below. The value of the text can then
281 be safely queried with the QueryIntText() group
282 of methods. (Also QueryFloatText(), etc.)
283
284 @skip XMLElement* textApproachElement
285 @until &v1 );
286*/
Lee Thomason21be8822012-07-15 17:27:22 -0700287
288
Lee Thomason178e4cc2013-01-25 16:19:05 -0800289int main( int argc, const char ** argv )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800290{
Lee Thomason (grinliz)0a4df402012-02-27 20:50:52 -0800291 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason1ff38e02012-02-14 18:18:16 -0800292 _CrtMemCheckpoint( &startMemState );
Dmitry-Me99916592014-10-23 11:37:03 +0400293 // Enable MS Visual C++ debug heap memory leaks dump on exit
294 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
Dmitry-Meed785702017-06-15 13:39:53 +0300295 {
296 int leaksOnStart = _CrtDumpMemoryLeaks();
297 XMLTest( "No leaks on start?", FALSE, leaksOnStart );
298 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700299 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800300
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300301 {
302 TIXMLASSERT( true );
303 }
304
Lee Thomason178e4cc2013-01-25 16:19:05 -0800305 if ( argc > 1 ) {
306 XMLDocument* doc = new XMLDocument();
307 clock_t startTime = clock();
308 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100309 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800310 int errorID = doc->ErrorID();
311 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100312 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800313
314 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
315 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700316 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
317 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
318 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800319 }
320 exit(0);
321 }
322
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300323 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700324 if ( !fp ) {
325 printf( "Error opening test file 'dream.xml'.\n"
326 "Is your working directory the same as where \n"
327 "the xmltest.cpp and dream.xml file are?\n\n"
328 #if defined( _MSC_VER )
329 "In windows Visual Studio you may need to set\n"
330 "Properties->Debugging->Working Directory to '..'\n"
331 #endif
332 );
333 exit( 1 );
334 }
335 fclose( fp );
336
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700337 XMLTest( "Example-1", 0, example_1() );
338 XMLTest( "Example-2", 0, example_2() );
339 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700340 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700341
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700342 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700343
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800344 {
Lee Thomason43f59302012-02-06 18:18:11 -0800345 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400346 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800347 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400348 "<element><subelement></subelement></element>",
349 "<element><subelement><subsub/></subelement></element>",
350 "<!--comment beside elements--><element><subelement></subelement></element>",
351 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
352 "<element attrib1='foo' attrib2=\"bar\" ></element>",
353 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800354 "<element>Text inside element.</element>",
355 "<element><b></b></element>",
356 "<element>Text inside and <b>bolded</b> in the element.</element>",
357 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800358 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800359 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800360 0
361 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800362 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800363 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800364 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800365 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800366 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800367 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800368 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800369#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800370 {
371 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400372 " line 2\r"
373 " line 3\r\n"
374 " line 4\n\r"
375 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800376
377 XMLDocument doc;
378 doc.Parse( test );
379 doc.Print();
380 }
381
Lee Thomason2c85a712012-01-31 08:24:24 -0800382 {
383 static const char* test = "<element>Text before.</element>";
384 XMLDocument doc;
385 doc.Parse( test );
386 XMLElement* root = doc.FirstChildElement();
387 XMLElement* newElement = doc.NewElement( "Subelement" );
388 root->InsertEndChild( newElement );
389 doc.Print();
390 }
Lee Thomasond1983222012-02-06 08:41:24 -0800391 {
392 XMLDocument* doc = new XMLDocument();
393 static const char* test = "<element><sub/></element>";
394 doc->Parse( test );
395 delete doc;
396 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800397 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800398 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800399 // Build:
400 // <element>
401 // <!--comment-->
402 // <sub attrib="1" />
403 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800404 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800405 // <element>
406
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800407 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800408 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
409
410 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
411 for( int i=0; i<3; ++i ) {
412 sub[i]->SetAttribute( "attrib", i );
413 }
414 element->InsertEndChild( sub[2] );
415 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700416 comment->SetUserData((void*)2);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800417 element->InsertAfterChild( comment, sub[0] );
418 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800419 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800420 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800421 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
422 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
423 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700424 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800425 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Lee Thomasonc9445462016-07-17 22:53:48 -0700426 XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800427
428 // And now deletion:
429 element->DeleteChild( sub[2] );
430 doc->DeleteNode( comment );
431
432 element->FirstChildElement()->SetAttribute( "attrib", true );
433 element->LastChildElement()->DeleteAttribute( "attrib" );
434
435 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700436 int value1 = 10;
437 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", 10 );
438 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
Lee Thomason21be8822012-07-15 17:27:22 -0700439 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700440 XMLTest( "Programmatic DOM", value1, 10 );
441 XMLTest( "Programmatic DOM", value2, 10 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800442
443 doc->Print();
444
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700445 {
446 XMLPrinter streamer;
447 doc->Print( &streamer );
448 printf( "%s", streamer.CStr() );
449 }
450 {
451 XMLPrinter streamer( 0, true );
452 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200453 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700454 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700455 doc->SaveFile( "./resources/out/pretty.xml" );
456 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800457 delete doc;
458 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800459 {
460 // Test: Dream
461 // XML1 : 1,187,569 bytes in 31,209 allocations
462 // XML2 : 469,073 bytes in 323 allocations
463 //int newStart = gNew;
464 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300465 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800466
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400467 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800468 doc.PrintError();
469
470 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400471 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800472 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
473 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
474 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
475 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400476 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800477 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400478 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800479
480 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400481 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800482 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400483 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800484 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
485 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
486 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
487 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400488 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800489
490 //gNewTotal = gNew - newStart;
491 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800492
493
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800494 {
495 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
496 "<passages count=\"006\" formatversion=\"20020620\">\n"
497 " <wrong error>\n"
498 "</passages>";
499
500 XMLDocument doc;
501 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800502 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800503 }
504
505 {
506 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
507
508 XMLDocument doc;
509 doc.Parse( str );
510
511 XMLElement* ele = doc.FirstChildElement();
512
513 int iVal, result;
514 double dVal;
515
516 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700517 XMLTest( "Query attribute: int as double", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800518 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700519 XMLTest( "Query attribute: int as double", (int)ele->DoubleAttribute("attr0"), 1);
520
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800521 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700522 XMLTest( "Query attribute: double as double", result, (int)XML_SUCCESS);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700523 XMLTest( "Query attribute: double as double", dVal, 2.0 );
524 XMLTest( "Query attribute: double as double", ele->DoubleAttribute("attr1"), 2.0 );
525
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800526 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason85536252016-06-04 19:10:53 -0700527 XMLTest( "Query attribute: double as int", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800528 XMLTest( "Query attribute: double as int", iVal, 2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700529
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800530 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700531 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700532 XMLTest( "Query attribute: not a number", ele->DoubleAttribute("attr2", 4.0), 4.0 );
533
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800534 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700535 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700536 XMLTest( "Query attribute: does not exist", ele->BoolAttribute("bar", true), true );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800537 }
538
539 {
540 const char* str = "<doc/>";
541
542 XMLDocument doc;
543 doc.Parse( str );
544
545 XMLElement* ele = doc.FirstChildElement();
546
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800547 int iVal, iVal2;
548 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800549
550 ele->SetAttribute( "str", "strValue" );
551 ele->SetAttribute( "int", 1 );
552 ele->SetAttribute( "double", -1.0 );
553
554 const char* cStr = ele->Attribute( "str" );
555 ele->QueryIntAttribute( "int", &iVal );
556 ele->QueryDoubleAttribute( "double", &dVal );
557
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800558 ele->QueryAttribute( "int", &iVal2 );
559 ele->QueryAttribute( "double", &dVal2 );
560
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700561 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800562 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
563 XMLTest( "Attribute round trip. int.", 1, iVal );
564 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800565 XMLTest( "Alternate query", true, iVal == iVal2 );
566 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700567 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
568 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800569 }
570
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800571 {
572 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300573 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800574
575 // Get the attribute "value" from the "Russian" element and check it.
576 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700577 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800578 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
579
580 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
581
582 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
583 0xd1U, 0x81U, 0xd1U, 0x81U,
584 0xd0U, 0xbaU, 0xd0U, 0xb8U,
585 0xd0U, 0xb9U, 0 };
586 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
587
588 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
589 XMLTest( "UTF-8: Browsing russian element name.",
590 russianText,
591 text->Value() );
592
593 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400594 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800595
596 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800597 int okay = 0;
598
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200599 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300600 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800601
602 if ( saved && verify )
603 {
604 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700605 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800606 while ( fgets( verifyBuf, 256, verify ) )
607 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700608 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800609 fgets( savedBuf, 256, saved );
610 NullLineEndings( verifyBuf );
611 NullLineEndings( savedBuf );
612
613 if ( strcmp( verifyBuf, savedBuf ) )
614 {
615 printf( "verify:%s<\n", verifyBuf );
616 printf( "saved :%s<\n", savedBuf );
617 okay = 0;
618 break;
619 }
620 }
621 }
622 if ( saved )
623 fclose( saved );
624 if ( verify )
625 fclose( verify );
626 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
627 }
628
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800629 // --------GetText()-----------
630 {
631 const char* str = "<foo>This is text</foo>";
632 XMLDocument doc;
633 doc.Parse( str );
634 const XMLElement* element = doc.RootElement();
635
636 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
637
638 str = "<foo><b>This is text</b></foo>";
639 doc.Parse( str );
640 element = doc.RootElement();
641
642 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
643 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800644
Lee Thomasond6277762012-02-22 16:00:12 -0800645
Uli Kusterer321072e2014-01-21 01:57:38 +0100646 // --------SetText()-----------
647 {
648 const char* str = "<foo></foo>";
649 XMLDocument doc;
650 doc.Parse( str );
651 XMLElement* element = doc.RootElement();
652
Lee Thomason9c0678a2014-01-24 10:18:27 -0800653 element->SetText("darkness.");
654 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100655
Lee Thomason9c0678a2014-01-24 10:18:27 -0800656 element->SetText("blue flame.");
657 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100658
659 str = "<foo/>";
660 doc.Parse( str );
661 element = doc.RootElement();
662
Lee Thomason9c0678a2014-01-24 10:18:27 -0800663 element->SetText("The driver");
664 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100665
Lee Thomason9c0678a2014-01-24 10:18:27 -0800666 element->SetText("<b>horses</b>");
667 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
668 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100669
670 str = "<foo><bar>Text in nested element</bar></foo>";
671 doc.Parse( str );
672 element = doc.RootElement();
673
Lee Thomason9c0678a2014-01-24 10:18:27 -0800674 element->SetText("wolves");
675 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800676
677 str = "<foo/>";
678 doc.Parse( str );
679 element = doc.RootElement();
680
681 element->SetText( "str" );
682 XMLTest( "SetText types", "str", element->GetText() );
683
684 element->SetText( 1 );
685 XMLTest( "SetText types", "1", element->GetText() );
686
687 element->SetText( 1U );
688 XMLTest( "SetText types", "1", element->GetText() );
689
690 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200691 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800692
693 element->SetText( 1.5f );
694 XMLTest( "SetText types", "1.5", element->GetText() );
695
696 element->SetText( 1.5 );
697 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100698 }
699
Lee Thomason51c12712016-06-04 20:18:49 -0700700 // ---------- Attributes ---------
701 {
702 static const int64_t BIG = -123456789012345678;
703 XMLDocument doc;
704 XMLElement* element = doc.NewElement("element");
705 doc.InsertFirstChild(element);
706
707 {
708 element->SetAttribute("attrib", int(-100));
709 int v = 0;
710 element->QueryIntAttribute("attrib", &v);
711 XMLTest("Attribute: int", -100, v, true);
712 element->QueryAttribute("attrib", &v);
713 XMLTest("Attribute: int", -100, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700714 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700715 }
716 {
717 element->SetAttribute("attrib", unsigned(100));
718 unsigned v = 0;
719 element->QueryUnsignedAttribute("attrib", &v);
720 XMLTest("Attribute: unsigned", unsigned(100), v, true);
721 element->QueryAttribute("attrib", &v);
722 XMLTest("Attribute: unsigned", unsigned(100), v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700723 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700724 }
725 {
726 element->SetAttribute("attrib", BIG);
727 int64_t v = 0;
728 element->QueryInt64Attribute("attrib", &v);
729 XMLTest("Attribute: int64_t", BIG, v, true);
730 element->QueryAttribute("attrib", &v);
731 XMLTest("Attribute: int64_t", BIG, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700732 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700733 }
734 {
735 element->SetAttribute("attrib", true);
736 bool v = false;
737 element->QueryBoolAttribute("attrib", &v);
738 XMLTest("Attribute: bool", true, v, true);
739 element->QueryAttribute("attrib", &v);
740 XMLTest("Attribute: bool", true, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700741 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700742 }
743 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800744 element->SetAttribute("attrib", true);
745 const char* result = element->Attribute("attrib");
746 XMLTest("Bool true is 'true'", "true", result);
747
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800748 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800749 element->SetAttribute("attrib", true);
750 result = element->Attribute("attrib");
751 XMLTest("Bool true is '1'", "1", result);
752
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800753 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800754 }
755 {
Lee Thomason51c12712016-06-04 20:18:49 -0700756 element->SetAttribute("attrib", 100.0);
757 double v = 0;
758 element->QueryDoubleAttribute("attrib", &v);
759 XMLTest("Attribute: double", 100.0, v, true);
760 element->QueryAttribute("attrib", &v);
761 XMLTest("Attribute: double", 100.0, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700762 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700763 }
764 {
765 element->SetAttribute("attrib", 100.0f);
766 float v = 0;
767 element->QueryFloatAttribute("attrib", &v);
768 XMLTest("Attribute: float", 100.0f, v, true);
769 element->QueryAttribute("attrib", &v);
770 XMLTest("Attribute: float", 100.0f, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700771 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700772 }
773 {
774 element->SetText(BIG);
775 int64_t v = 0;
776 element->QueryInt64Text(&v);
777 XMLTest("Element: int64_t", BIG, v, true);
778 }
779 }
780
781 // ---------- XMLPrinter stream mode ------
782 {
783 {
784 FILE* printerfp = fopen("resources/printer.xml", "w");
785 XMLPrinter printer(printerfp);
786 printer.OpenElement("foo");
787 printer.PushAttribute("attrib-text", "text");
788 printer.PushAttribute("attrib-int", int(1));
789 printer.PushAttribute("attrib-unsigned", unsigned(2));
790 printer.PushAttribute("attrib-int64", int64_t(3));
791 printer.PushAttribute("attrib-bool", true);
792 printer.PushAttribute("attrib-double", 4.0);
793 printer.CloseElement();
794 fclose(printerfp);
795 }
796 {
797 XMLDocument doc;
798 doc.LoadFile("resources/printer.xml");
799 XMLTest("XMLPrinter Stream mode: load", doc.ErrorID(), XML_SUCCESS, true);
800
801 const XMLDocument& cdoc = doc;
802
803 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
804 XMLTest("attrib-text", "text", attrib->Value(), true);
805 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
806 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
807 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
808 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
809 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
810 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
811 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
812 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
813 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
814 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
815 }
816
817 }
818
Uli Kusterer321072e2014-01-21 01:57:38 +0100819
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800820 // ---------- CDATA ---------------
821 {
822 const char* str = "<xmlElement>"
823 "<![CDATA["
824 "I am > the rules!\n"
825 "...since I make symbolic puns"
826 "]]>"
827 "</xmlElement>";
828 XMLDocument doc;
829 doc.Parse( str );
830 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800831
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700832 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800833 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800834 false );
835 }
836
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800837 // ----------- CDATA -------------
838 {
839 const char* str = "<xmlElement>"
840 "<![CDATA["
841 "<b>I am > the rules!</b>\n"
842 "...since I make symbolic puns"
843 "]]>"
844 "</xmlElement>";
845 XMLDocument doc;
846 doc.Parse( str );
847 doc.Print();
848
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700849 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800850 "<b>I am > the rules!</b>\n...since I make symbolic puns",
851 false );
852 }
853
854 // InsertAfterChild causes crash.
855 {
856 // InsertBeforeChild and InsertAfterChild causes crash.
857 XMLDocument doc;
858 XMLElement* parent = doc.NewElement( "Parent" );
859 doc.InsertFirstChild( parent );
860
861 XMLElement* childText0 = doc.NewElement( "childText0" );
862 XMLElement* childText1 = doc.NewElement( "childText1" );
863
864 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
865 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
866
867 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
868 }
Lee Thomasond6277762012-02-22 16:00:12 -0800869
870 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800871 // Entities not being written correctly.
872 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800873
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800874 const char* passages =
875 "<?xml version=\"1.0\" standalone=\"no\" ?>"
876 "<passages count=\"006\" formatversion=\"20020620\">"
877 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
878 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
879 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800880
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800881 XMLDocument doc;
882 doc.Parse( passages );
883 XMLElement* psg = doc.RootElement()->FirstChildElement();
884 const char* context = psg->Attribute( "context" );
885 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 -0800886
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800887 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800888
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400889 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800890 if ( textfile )
891 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800892 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800893 psg->Accept( &streamer );
894 fclose( textfile );
895 }
Thomas Roß0922b732012-09-23 16:31:22 +0200896
897 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800898 TIXMLASSERT( textfile );
899 if ( textfile )
900 {
901 char buf[ 1024 ];
902 fgets( buf, 1024, textfile );
903 XMLTest( "Entity transformation: write. ",
904 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
905 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
906 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700907 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800908 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800909 }
910
911 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800912 // Suppress entities.
913 const char* passages =
914 "<?xml version=\"1.0\" standalone=\"no\" ?>"
915 "<passages count=\"006\" formatversion=\"20020620\">"
916 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
917 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700918
Lee Thomason6f381b72012-03-02 12:59:39 -0800919 XMLDocument doc( false );
920 doc.Parse( passages );
921
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700922 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800923 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
924 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
925 "Crazy &ttk;" );
926 doc.Print();
927 }
928
929 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400930 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800931
932 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400933 doc.Parse( test );
934 XMLTest( "dot in names", doc.Error(), false );
935 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
936 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800937 }
938
939 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400940 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800941
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400942 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800943 doc.Parse( test );
944
945 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
946 XMLTest( "Entity with one digit.",
947 text->Value(), "1.1 Start easy ignore fin thickness\n",
948 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400949 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800950
951 {
952 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700953 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800954 const char* doctype =
955 "<?xml version=\"1.0\" ?>"
956 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
957 "<!ELEMENT title (#PCDATA)>"
958 "<!ELEMENT books (title,authors)>"
959 "<element />";
960
961 XMLDocument doc;
962 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400963 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800964 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400965 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800966 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700967
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800968 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
969 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
970
971 }
972
973 {
974 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700975 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800976 "<!-- Somewhat<evil> -->";
977 XMLDocument doc;
978 doc.Parse( doctype );
979
980 XMLComment* comment = doc.FirstChild()->ToComment();
981
982 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
983 }
984 {
985 // Double attributes
986 const char* doctype = "<element attr='red' attr='blue' />";
987
988 XMLDocument doc;
989 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700990
Lee Thomason2fa81722012-11-09 12:37:46 -0800991 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 -0800992 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800993 }
994
995 {
996 // Embedded null in stream.
997 const char* doctype = "<element att\0r='red' attr='blue' />";
998
999 XMLDocument doc;
1000 doc.Parse( doctype );
1001 XMLTest( "Embedded null throws error.", true, doc.Error() );
1002 }
1003
1004 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001005 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001006 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001007 XMLDocument doc;
1008 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001009 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001010 }
1011
1012 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001013 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1014 const char* str = " ";
1015 XMLDocument doc;
1016 doc.Parse( str );
1017 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1018 }
1019
1020 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001021 // Low entities
1022 XMLDocument doc;
1023 doc.Parse( "<test>&#x0e;</test>" );
1024 const char result[] = { 0x0e, 0 };
1025 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
1026 doc.Print();
1027 }
1028
1029 {
1030 // Attribute values with trailing quotes not handled correctly
1031 XMLDocument doc;
1032 doc.Parse( "<foo attribute=bar\" />" );
1033 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
1034 }
1035
1036 {
1037 // [ 1663758 ] Failure to report error on bad XML
1038 XMLDocument xml;
1039 xml.Parse("<x>");
1040 XMLTest("Missing end tag at end of input", xml.Error(), true);
1041 xml.Parse("<x> ");
1042 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
1043 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -08001044 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001045 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001046
1047
1048 {
1049 // [ 1475201 ] TinyXML parses entities in comments
1050 XMLDocument xml;
1051 xml.Parse("<!-- declarations for <head> & <body> -->"
1052 "<!-- far &amp; away -->" );
1053
1054 XMLNode* e0 = xml.FirstChild();
1055 XMLNode* e1 = e0->NextSibling();
1056 XMLComment* c0 = e0->ToComment();
1057 XMLComment* c1 = e1->ToComment();
1058
1059 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1060 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1061 }
1062
1063 {
1064 XMLDocument xml;
1065 xml.Parse( "<Parent>"
1066 "<child1 att=''/>"
1067 "<!-- With this comment, child2 will not be parsed! -->"
1068 "<child2 att=''/>"
1069 "</Parent>" );
1070 xml.Print();
1071
1072 int count = 0;
1073
1074 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1075 ele;
1076 ele = ele->NextSibling() )
1077 {
1078 ++count;
1079 }
1080
1081 XMLTest( "Comments iterate correctly.", 3, count );
1082 }
1083
1084 {
1085 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1086 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1087 buf[60] = 239;
1088 buf[61] = 0;
1089
1090 XMLDocument doc;
1091 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001092 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001093
1094
1095 {
1096 // bug 1827248 Error while parsing a little bit malformed file
1097 // Actually not malformed - should work.
1098 XMLDocument xml;
1099 xml.Parse( "<attributelist> </attributelist >" );
1100 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1101 }
1102
1103 {
1104 // This one must not result in an infinite loop
1105 XMLDocument xml;
1106 xml.Parse( "<infinite>loop" );
1107 XMLTest( "Infinite loop test.", true, true );
1108 }
1109#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001110 {
1111 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1112 XMLDocument doc;
1113 doc.Parse( pub );
1114
1115 XMLDocument clone;
1116 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1117 XMLNode* copy = node->ShallowClone( &clone );
1118 clone.InsertEndChild( copy );
1119 }
1120
1121 clone.Print();
1122
1123 int count=0;
1124 const XMLNode* a=clone.FirstChild();
1125 const XMLNode* b=doc.FirstChild();
1126 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1127 ++count;
1128 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1129 }
1130 XMLTest( "Clone and Equal", 4, count );
1131 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001132
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001133 {
1134 // This shouldn't crash.
1135 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001136 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001137 {
1138 doc.PrintError();
1139 }
1140 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1141 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001142
Lee Thomason5e3803c2012-04-16 08:57:05 -07001143 {
1144 // Attribute ordering.
1145 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1146 XMLDocument doc;
1147 doc.Parse( xml );
1148 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001149
Lee Thomason5e3803c2012-04-16 08:57:05 -07001150 const XMLAttribute* a = ele->FirstAttribute();
1151 XMLTest( "Attribute order", "1", a->Value() );
1152 a = a->Next();
1153 XMLTest( "Attribute order", "2", a->Value() );
1154 a = a->Next();
1155 XMLTest( "Attribute order", "3", a->Value() );
1156 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001157
Lee Thomason5e3803c2012-04-16 08:57:05 -07001158 ele->DeleteAttribute( "attrib2" );
1159 a = ele->FirstAttribute();
1160 XMLTest( "Attribute order", "1", a->Value() );
1161 a = a->Next();
1162 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001163
Lee Thomason5e3803c2012-04-16 08:57:05 -07001164 ele->DeleteAttribute( "attrib1" );
1165 ele->DeleteAttribute( "attrib3" );
1166 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1167 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001168
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001169 {
1170 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001171 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1172 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1173 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1174 XMLDocument doc0;
1175 doc0.Parse( xml0 );
1176 XMLDocument doc1;
1177 doc1.Parse( xml1 );
1178 XMLDocument doc2;
1179 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001180
Lee Thomason78a773d2012-07-02 10:10:19 -07001181 XMLElement* ele = 0;
1182 ele = doc0.FirstChildElement();
1183 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1184 ele = doc1.FirstChildElement();
1185 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1186 ele = doc2.FirstChildElement();
1187 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001188 }
1189
1190 {
1191 // Make sure we don't go into an infinite loop.
1192 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1193 XMLDocument doc;
1194 doc.Parse( xml );
1195 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1196 XMLElement* ele1 = ele0->NextSiblingElement();
1197 bool equal = ele0->ShallowEqual( ele1 );
1198
1199 XMLTest( "Infinite loop in shallow equal.", true, equal );
1200 }
1201
Lee Thomason5708f812012-03-28 17:46:41 -07001202 // -------- Handles ------------
1203 {
1204 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1205 XMLDocument doc;
1206 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -07001207
1208 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1209 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
1210
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001211 XMLHandle docH( doc );
1212 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001213 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001214 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001215
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001216 {
1217 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1218 XMLDocument doc;
1219 doc.Parse( xml );
1220 XMLConstHandle docH( doc );
1221
1222 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1223 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1224
1225 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001226 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001227 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001228 {
1229 // Default Declaration & BOM
1230 XMLDocument doc;
1231 doc.InsertEndChild( doc.NewDeclaration() );
1232 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001233
Lee Thomasonf68c4382012-04-28 14:37:11 -07001234 XMLPrinter printer;
1235 doc.Print( &printer );
1236
1237 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1238 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001239 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001240 }
Lee Thomason21be8822012-07-15 17:27:22 -07001241 {
1242 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1243 XMLDocument doc;
1244 doc.Parse( xml );
1245 XMLTest( "Ill formed XML", true, doc.Error() );
1246 }
1247
1248 // QueryXYZText
1249 {
1250 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1251 XMLDocument doc;
1252 doc.Parse( xml );
1253
1254 const XMLElement* pointElement = doc.RootElement();
1255
1256 int intValue = 0;
1257 unsigned unsignedValue = 0;
1258 float floatValue = 0;
1259 double doubleValue = 0;
1260 bool boolValue = false;
1261
1262 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1263 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1264 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1265 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1266 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1267
1268
1269 XMLTest( "QueryIntText", intValue, 1, false );
1270 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1271 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1272 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1273 XMLTest( "QueryBoolText", boolValue, true, false );
1274 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001275
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001276 {
1277 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1278 XMLDocument doc;
1279 doc.Parse( xml );
1280 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1281 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001282
1283 {
1284 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1285 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001286 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001287 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1288 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001289
1290 {
1291 const char* xml = "<3lement></3lement>";
1292 XMLDocument doc;
1293 doc.Parse( xml );
1294 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1295 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001296
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001297 {
1298 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1299 XMLDocument doc;
1300 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001301 XMLTest( "Set length of incoming data", doc.Error(), false );
1302 }
1303
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001304 {
1305 XMLDocument doc;
Dmitry-Me48b5df02015-04-06 18:20:25 +03001306 XMLTest( "Document is initially empty", doc.NoChildren(), true );
1307 doc.Clear();
1308 XMLTest( "Empty is empty after Clear()", doc.NoChildren(), true );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001309 doc.LoadFile( "resources/dream.xml" );
Dmitry-Meaaa4cea2015-02-06 16:00:46 +03001310 XMLTest( "Document has something to Clear()", doc.NoChildren(), false );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001311 doc.Clear();
1312 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1313 }
1314
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001315 // ----------- Whitespace ------------
1316 {
1317 const char* xml = "<element>"
1318 "<a> This \nis &apos; text &apos; </a>"
1319 "<b> This is &apos; text &apos; \n</b>"
1320 "<c>This is &apos; \n\n text &apos;</c>"
1321 "</element>";
1322 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1323 doc.Parse( xml );
1324
1325 const XMLElement* element = doc.FirstChildElement();
1326 for( const XMLElement* parent = element->FirstChildElement();
1327 parent;
1328 parent = parent->NextSiblingElement() )
1329 {
1330 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1331 }
1332 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001333
Lee Thomasonae9ab072012-10-24 10:17:53 -07001334#if 0
1335 {
1336 // Passes if assert doesn't fire.
1337 XMLDocument xmlDoc;
1338
1339 xmlDoc.NewDeclaration();
1340 xmlDoc.NewComment("Configuration file");
1341
1342 XMLElement *root = xmlDoc.NewElement("settings");
1343 root->SetAttribute("version", 2);
1344 }
1345#endif
1346
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001347 {
1348 const char* xml = "<element> </element>";
1349 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1350 doc.Parse( xml );
1351 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1352 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001353
Lee Thomason5b0a6772012-11-19 13:54:42 -08001354 {
1355 // An assert should not fire.
1356 const char* xml = "<element/>";
1357 XMLDocument doc;
1358 doc.Parse( xml );
1359 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1360 XMLTest( "Tracking unused elements", true, ele != 0, false );
1361 }
1362
Lee Thomasona6412ac2012-12-13 15:39:11 -08001363
1364 {
1365 const char* xml = "<parent><child>abc</child></parent>";
1366 XMLDocument doc;
1367 doc.Parse( xml );
1368 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1369
1370 XMLPrinter printer;
1371 ele->Accept( &printer );
1372 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1373 }
1374
1375
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001376 {
1377 XMLDocument doc;
1378 XMLError error = doc.LoadFile( "resources/empty.xml" );
1379 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001380 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001381 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001382 }
1383
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001384 {
1385 // BOM preservation
1386 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1387 {
1388 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001389 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001390 XMLPrinter printer;
1391 doc.Print( &printer );
1392
1393 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1394 doc.SaveFile( "resources/bomtest.xml" );
1395 }
1396 {
1397 XMLDocument doc;
1398 doc.LoadFile( "resources/bomtest.xml" );
1399 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1400
1401 XMLPrinter printer;
1402 doc.Print( &printer );
1403 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1404 }
1405 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001406
Michael Daumlinged523282013-10-23 07:47:29 +02001407 {
1408 // Insertion with Removal
1409 const char* xml = "<?xml version=\"1.0\" ?>"
1410 "<root>"
1411 "<one>"
1412 "<subtree>"
1413 "<elem>element 1</elem>text<!-- comment -->"
1414 "</subtree>"
1415 "</one>"
1416 "<two/>"
1417 "</root>";
1418 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1419 "<root>"
1420 "<one/>"
1421 "<two>"
1422 "<subtree>"
1423 "<elem>element 1</elem>text<!-- comment -->"
1424 "</subtree>"
1425 "</two>"
1426 "</root>";
1427 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1428 "<root>"
1429 "<one/>"
1430 "<subtree>"
1431 "<elem>element 1</elem>text<!-- comment -->"
1432 "</subtree>"
1433 "<two/>"
1434 "</root>";
1435 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1436 "<root>"
1437 "<one/>"
1438 "<two/>"
1439 "<subtree>"
1440 "<elem>element 1</elem>text<!-- comment -->"
1441 "</subtree>"
1442 "</root>";
1443
1444 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001445 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001446 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1447 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1448 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001449 XMLPrinter printer1(0, true);
1450 doc.Accept(&printer1);
1451 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001452
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001453 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001454 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1455 two = doc.RootElement()->FirstChildElement("two");
1456 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001457 XMLPrinter printer2(0, true);
1458 doc.Accept(&printer2);
1459 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001460
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001461 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001462 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1463 subtree = one->FirstChildElement("subtree");
1464 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001465 XMLPrinter printer3(0, true);
1466 doc.Accept(&printer3);
1467 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001468
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001469 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001470 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1471 two = doc.RootElement()->FirstChildElement("two");
1472 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001473 XMLPrinter printer4(0, true);
1474 doc.Accept(&printer4);
1475 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001476 }
1477
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001478 {
1479 const char* xml = "<svg width = \"128\" height = \"128\">"
1480 " <text> </text>"
1481 "</svg>";
1482 XMLDocument doc;
1483 doc.Parse(xml);
1484 doc.Print();
1485 }
1486
Lee Thomason92e521b2014-11-15 17:45:51 -08001487 {
1488 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001489 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1490 XMLDocument doc;
1491 doc.Parse(xml);
1492 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001493 }
1494
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001495#if 1
1496 // the question being explored is what kind of print to use:
1497 // https://github.com/leethomason/tinyxml2/issues/63
1498 {
1499 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1500 const char* xml = "<element/>";
1501 XMLDocument doc;
1502 doc.Parse( xml );
1503 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1504 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1505 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1506 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1507 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1508 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1509
1510 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1511 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1512 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1513 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1514 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1515 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1516
1517 doc.Print();
1518
1519 /* The result of this test is platform, compiler, and library version dependent. :("
1520 XMLPrinter printer;
1521 doc.Print( &printer );
1522 XMLTest( "Float and double formatting.",
1523 "<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",
1524 printer.CStr(),
1525 true );
1526 */
1527 }
1528#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001529
1530 {
1531 // Issue #184
1532 // If it doesn't assert, it passes. Caused by objects
1533 // getting created during parsing which are then
1534 // inaccessible in the memory pools.
1535 {
1536 XMLDocument doc;
1537 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1538 }
1539 {
1540 XMLDocument doc;
1541 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1542 doc.Clear();
1543 }
1544 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001545
1546 {
1547 // If this doesn't assert in DEBUG, all is well.
1548 tinyxml2::XMLDocument doc;
1549 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1550 doc.DeleteNode(pRoot);
1551 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001552
Dmitry-Me8b67d742014-12-22 11:35:12 +03001553 {
1554 // Should not assert in DEBUG
1555 XMLPrinter printer;
1556 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001557
Dmitry-Me6f51c802015-03-14 13:25:03 +03001558 {
1559 // Issue 291. Should not crash
1560 const char* xml = "&#0</a>";
1561 XMLDocument doc;
1562 doc.Parse( xml );
1563
1564 XMLPrinter printer;
1565 doc.Print( &printer );
1566 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001567 {
1568 // Issue 299. Can print elements that are not linked in.
1569 // Will crash if issue not fixed.
1570 XMLDocument doc;
1571 XMLElement* newElement = doc.NewElement( "printme" );
1572 XMLPrinter printer;
1573 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001574 // Delete the node to avoid possible memory leak report in debug output
1575 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001576 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001577 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001578 // Issue 302. Clear errors from LoadFile/SaveFile
1579 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001580 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001581 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001582 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001583 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001584 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001585 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001586
Dmitry-Med9852a52015-03-25 10:17:49 +03001587 {
1588 // If a document fails to load then subsequent
1589 // successful loads should clear the error
1590 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001591 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001592 doc.LoadFile( "resources/no-such-file.xml" );
1593 XMLTest( "No such file - should fail", true, doc.Error() );
1594
1595 doc.LoadFile( "resources/dream.xml" );
1596 XMLTest( "Error should be cleared", false, doc.Error() );
1597 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301598
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301599 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001600 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001601 const char* xml0 = "<?xml version=\"1.0\" ?>"
1602 " <!-- xml version=\"1.1\" -->"
1603 "<first />";
1604 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001605 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001606 "<first />";
1607 const char* xml2 = "<first />"
1608 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001609 const char* xml3 = "<first></first>"
1610 "<?xml version=\"1.0\" ?>";
1611
1612 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1613
Lee Thomason85492022015-05-22 11:07:45 -07001614 XMLDocument doc;
1615 doc.Parse(xml0);
1616 XMLTest("Test that the code changes do not affect normal parsing", doc.Error(), false);
1617 doc.Parse(xml1);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001618 XMLTest("Test that the second declaration is allowed", doc.Error(), false);
Lee Thomason85492022015-05-22 11:07:45 -07001619 doc.Parse(xml2);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001620 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1621 doc.Parse(xml3);
1622 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1623 doc.Parse(xml4);
1624 XMLTest("Test that declaration inside a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301625 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001626
Lee Thomason85492022015-05-22 11:07:45 -07001627 {
1628 // No matter - before or after successfully parsing a text -
1629 // calling XMLDocument::Value() causes an assert in debug.
1630 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1631 "<first />"
1632 "<second />";
1633 XMLDocument* doc = new XMLDocument();
1634 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1635 doc->Parse( validXml );
1636 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1637 delete doc;
1638 }
1639
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001640 {
1641 XMLDocument doc;
1642 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001643 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001644 doc.ErrorName();
1645 }
1646 }
1647
Lee Thomason816d3fa2017-06-05 14:35:55 -07001648 {
Lee Thomasonb754ddf2017-06-14 15:02:38 -07001649 // Evil memory leaks.
1650 // If an XMLElement (etc) is allocated via NewElement() (etc.)
1651 // and NOT added to the XMLDocument, what happens?
1652 //
1653 // Previously (buggy):
1654 // The memory would be free'd when the XMLDocument is
1655 // destructed. But the destructor wasn't called, so that
1656 // memory allocated by the XMLElement would not be free'd.
1657 // In practice this meant strings allocated by the XMLElement
1658 // would leak. An edge case, but annoying.
1659 // Now:
1660 // The destructor is called. But the list of unlinked nodes
1661 // has to be tracked. This has a minor performance impact
1662 // that can become significant if you have a lot. (But why
1663 // would you do that?)
1664 // The only way to see this bug is in a leak tracker. This
1665 // is compiled in by default on Windows Debug.
Lee Thomason816d3fa2017-06-05 14:35:55 -07001666 {
1667 XMLDocument doc;
1668 doc.NewElement("LEAK 1");
1669 }
1670 {
1671 XMLDocument doc;
1672 XMLElement* ele = doc.NewElement("LEAK 2");
1673 doc.DeleteNode(ele);
1674 }
1675 }
1676
kezenatorec694152016-11-26 17:21:43 +10001677 // ----------- Line Number Tracking --------------
1678 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001679 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001680 {
1681 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1682 {
1683 XMLDocument doc;
1684 XMLError err = doc.Parse(docStr);
1685
1686 XMLTest(testString, true, doc.Error());
1687 XMLTest(testString, expected_error, err);
1688 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1689 };
1690
1691 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1692 {
1693 XMLDocument doc;
1694 doc.Parse(docStr);
1695 XMLTest(testString, false, doc.Error());
1696 TestDocLines(testString, doc, expectedLines);
1697 }
1698
1699 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1700 {
1701 XMLDocument doc;
1702 doc.LoadFile(file_name);
1703 XMLTest(testString, false, doc.Error());
1704 TestDocLines(testString, doc, expectedLines);
1705 }
1706
1707 private:
1708 DynArray<char, 10> str;
1709
1710 void Push(char type, int lineNum)
1711 {
1712 str.Push(type);
1713 str.Push(char('0' + (lineNum / 10)));
1714 str.Push(char('0' + (lineNum % 10)));
1715 }
1716
1717 bool VisitEnter(const XMLDocument& doc)
1718 {
kezenator19d8ea82016-11-29 19:50:27 +10001719 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001720 return true;
1721 }
1722 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
1723 {
kezenator19d8ea82016-11-29 19:50:27 +10001724 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001725 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10001726 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001727 return true;
1728 }
1729 bool Visit(const XMLDeclaration& declaration)
1730 {
kezenator19d8ea82016-11-29 19:50:27 +10001731 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001732 return true;
1733 }
1734 bool Visit(const XMLText& text)
1735 {
kezenator19d8ea82016-11-29 19:50:27 +10001736 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001737 return true;
1738 }
1739 bool Visit(const XMLComment& comment)
1740 {
kezenator19d8ea82016-11-29 19:50:27 +10001741 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001742 return true;
1743 }
1744 bool Visit(const XMLUnknown& unknown)
1745 {
kezenator19d8ea82016-11-29 19:50:27 +10001746 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001747 return true;
1748 }
1749
1750 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
1751 {
1752 str.Clear();
1753 doc.Accept(this);
1754 str.Push(0);
1755 XMLTest(testString, expectedLines, str.Mem());
1756 }
Lee Thomasone90e9012016-12-24 07:34:39 -08001757 } tester;
kezenatorec694152016-11-26 17:21:43 +10001758
Lee Thomasone90e9012016-12-24 07:34:39 -08001759 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
1760 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
1761 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
1762 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
1763 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
1764 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
1765 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
1766 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
1767 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
1768 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
1769 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10001770
Lee Thomasone90e9012016-12-24 07:34:39 -08001771 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001772 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08001773
1774 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
1775 "<root a='b' \n" // 2 Element Attribute
1776 "c='d'> d <blah/> \n" // 3 Attribute Text Element
1777 "newline in text \n" // 4 Text
1778 "and second <zxcv/><![CDATA[\n" // 5 Element Text
1779 " cdata test ]]><!-- comment -->\n" // 6 Comment
1780 "<! unknown></root>", // 7 Unknown
1781
kezenatorec694152016-11-26 17:21:43 +10001782 "D01L01E02A02A03T03E03T04E05T05C06U07");
1783
Lee Thomasone90e9012016-12-24 07:34:39 -08001784 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001785 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08001786
1787 "\r\n" // 1 Doc (arguably should be line 2)
1788 "<?xml version=\"1.0\"?>\n" // 2 DecL
1789 "<root>\r\n" // 3 Element
1790 "\n" // 4
1791 "text contining new line \n" // 5 Text
1792 " and also containing crlf \r\n" // 6
1793 "<sub><![CDATA[\n" // 7 Element Text
1794 "cdata containing new line \n" // 8
1795 " and also containing cflr\r\n" // 9
1796 "]]></sub><sub2/></root>", // 10 Element
1797
kezenatorec694152016-11-26 17:21:43 +10001798 "D01L02E03T05E07T07E10");
1799
Lee Thomasone90e9012016-12-24 07:34:39 -08001800 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10001801 "LineNumbers-File",
1802 "resources/utf8test.xml",
1803 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
1804 }
1805
Lee Thomason85492022015-05-22 11:07:45 -07001806 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08001807 {
1808#if defined( _MSC_VER )
1809 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001810 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08001811#endif
1812
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001813 FILE* perfFP = fopen("resources/dream.xml", "r");
1814 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02001815 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001816 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08001817
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001818 char* mem = new char[size + 1];
1819 fread(mem, size, 1, perfFP);
1820 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08001821 mem[size] = 0;
1822
1823#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001824 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08001825#else
1826 clock_t cstart = clock();
1827#endif
1828 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001829 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001830 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001831 doc.Parse(mem);
Lee Thomason6f381b72012-03-02 12:59:39 -08001832 }
1833#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001834 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08001835#else
1836 clock_t cend = clock();
1837#endif
1838
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001839 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08001840
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001841 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001842#ifdef DEBUG
1843 "DEBUG";
1844#else
1845 "Release";
1846#endif
1847
1848#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001849 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 -08001850#else
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001851 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08001852#endif
1853 }
1854
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001855 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001856 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001857
1858 _CrtMemState diffMemState;
1859 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1860 _CrtMemDumpStatistics( &diffMemState );
Dmitry-Meed785702017-06-15 13:39:53 +03001861
1862 {
1863 int leaksBeforeExit = _CrtDumpMemoryLeaks();
1864 XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
1865 }
Lee Thomason1ff38e02012-02-14 18:18:16 -08001866 #endif
1867
1868 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07001869
1870 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001871}