blob: a580756e469cd57f633f91140f4ac1be2e1e98b7 [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);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700295 #endif
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800296
Dmitry-Me4bcbf142014-12-25 19:05:18 +0300297 {
298 TIXMLASSERT( true );
299 }
300
Lee Thomason178e4cc2013-01-25 16:19:05 -0800301 if ( argc > 1 ) {
302 XMLDocument* doc = new XMLDocument();
303 clock_t startTime = clock();
304 doc->LoadFile( argv[1] );
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100305 clock_t loadTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800306 int errorID = doc->ErrorID();
307 delete doc; doc = 0;
Anton Indrawan8a0006c2014-11-20 18:27:07 +0100308 clock_t deleteTime = clock();
Lee Thomason178e4cc2013-01-25 16:19:05 -0800309
310 printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
311 if ( !errorID ) {
Lee Thomason (grinliz)d6bd7362013-05-11 20:23:13 -0700312 printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
313 printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
314 printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
Lee Thomason178e4cc2013-01-25 16:19:05 -0800315 }
316 exit(0);
317 }
318
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300319 FILE* fp = fopen( "resources/dream.xml", "r" );
Lee Thomason7f7b1622012-03-24 12:49:03 -0700320 if ( !fp ) {
321 printf( "Error opening test file 'dream.xml'.\n"
322 "Is your working directory the same as where \n"
323 "the xmltest.cpp and dream.xml file are?\n\n"
324 #if defined( _MSC_VER )
325 "In windows Visual Studio you may need to set\n"
326 "Properties->Debugging->Working Directory to '..'\n"
327 #endif
328 );
329 exit( 1 );
330 }
331 fclose( fp );
332
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -0700333 XMLTest( "Example-1", 0, example_1() );
334 XMLTest( "Example-2", 0, example_2() );
335 XMLTest( "Example-3", 0, example_3() );
Lee Thomason21be8822012-07-15 17:27:22 -0700336 XMLTest( "Example-4", true, example_4() );
Lee Thomason87e475a2012-03-20 11:55:29 -0700337
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700338 /* ------ Example 2: Lookup information. ---- */
Lee Thomason87e475a2012-03-20 11:55:29 -0700339
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800340 {
Lee Thomason43f59302012-02-06 18:18:11 -0800341 static const char* test[] = { "<element />",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400342 "<element></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800343 "<element><subelement/></element>",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400344 "<element><subelement></subelement></element>",
345 "<element><subelement><subsub/></subelement></element>",
346 "<!--comment beside elements--><element><subelement></subelement></element>",
347 "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
348 "<element attrib1='foo' attrib2=\"bar\" ></element>",
349 "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
Lee Thomason43f59302012-02-06 18:18:11 -0800350 "<element>Text inside element.</element>",
351 "<element><b></b></element>",
352 "<element>Text inside and <b>bolded</b> in the element.</element>",
353 "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
Lee Thomason8ee79892012-01-25 17:44:30 -0800354 "<element>This &amp; That.</element>",
Lee Thomason18d68bd2012-01-26 18:17:26 -0800355 "<element attrib='This&lt;That' />",
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800356 0
357 };
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800358 for( int i=0; test[i]; ++i ) {
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800359 XMLDocument doc;
Lee Thomason6ee99fc2012-01-21 18:45:16 -0800360 doc.Parse( test[i] );
Lee Thomason5cae8972012-01-24 18:03:07 -0800361 doc.Print();
Lee Thomasonec975ce2012-01-23 11:42:06 -0800362 printf( "----------------------------------------------\n" );
Lee Thomasondadcdfa2012-01-18 17:55:48 -0800363 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800364 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800365#if 1
Lee Thomasond6277762012-02-22 16:00:12 -0800366 {
367 static const char* test = "<!--hello world\n"
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400368 " line 2\r"
369 " line 3\r\n"
370 " line 4\n\r"
371 " line 5\r-->";
Lee Thomasond6277762012-02-22 16:00:12 -0800372
373 XMLDocument doc;
374 doc.Parse( test );
375 doc.Print();
376 }
377
Lee Thomason2c85a712012-01-31 08:24:24 -0800378 {
379 static const char* test = "<element>Text before.</element>";
380 XMLDocument doc;
381 doc.Parse( test );
382 XMLElement* root = doc.FirstChildElement();
383 XMLElement* newElement = doc.NewElement( "Subelement" );
384 root->InsertEndChild( newElement );
385 doc.Print();
386 }
Lee Thomasond1983222012-02-06 08:41:24 -0800387 {
388 XMLDocument* doc = new XMLDocument();
389 static const char* test = "<element><sub/></element>";
390 doc->Parse( test );
391 delete doc;
392 }
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800393 {
Lee Thomason1ff38e02012-02-14 18:18:16 -0800394 // Test: Programmatic DOM
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800395 // Build:
396 // <element>
397 // <!--comment-->
398 // <sub attrib="1" />
399 // <sub attrib="2" />
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800400 // <sub attrib="3" >& Text!</sub>
Lee Thomasonec5a7b42012-02-13 18:16:52 -0800401 // <element>
402
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800403 XMLDocument* doc = new XMLDocument();
Lee Thomason1ff38e02012-02-14 18:18:16 -0800404 XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
405
406 XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
407 for( int i=0; i<3; ++i ) {
408 sub[i]->SetAttribute( "attrib", i );
409 }
410 element->InsertEndChild( sub[2] );
411 XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
Lee Thomasonaf9bce12016-07-17 22:35:52 -0700412 comment->SetUserData((void*)2);
Lee Thomason1ff38e02012-02-14 18:18:16 -0800413 element->InsertAfterChild( comment, sub[0] );
414 element->InsertAfterChild( sub[0], sub[1] );
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800415 sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800416 doc->Print();
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800417 XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
418 XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
419 XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700420 XMLTest( "Programmatic DOM", "& Text!",
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800421 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
Lee Thomasonc9445462016-07-17 22:53:48 -0700422 XMLTest("User data", (void*)2 == comment->GetUserData(), true, false);
U-Stream\Leeae25a442012-02-17 17:48:16 -0800423
424 // And now deletion:
425 element->DeleteChild( sub[2] );
426 doc->DeleteNode( comment );
427
428 element->FirstChildElement()->SetAttribute( "attrib", true );
429 element->LastChildElement()->DeleteAttribute( "attrib" );
430
431 XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700432 int value1 = 10;
433 int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", 10 );
434 int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
Lee Thomason21be8822012-07-15 17:27:22 -0700435 XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700436 XMLTest( "Programmatic DOM", value1, 10 );
437 XMLTest( "Programmatic DOM", value2, 10 );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800438
439 doc->Print();
440
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700441 {
442 XMLPrinter streamer;
443 doc->Print( &streamer );
444 printf( "%s", streamer.CStr() );
445 }
446 {
447 XMLPrinter streamer( 0, true );
448 doc->Print( &streamer );
Doruk Turak1f212f32016-08-28 20:54:17 +0200449 XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
Lee Thomason7b1b86a2012-06-04 17:01:38 -0700450 }
Lee Thomason (grinliz)6b8b0122012-09-08 21:21:00 -0700451 doc->SaveFile( "./resources/out/pretty.xml" );
452 doc->SaveFile( "./resources/out/compact.xml", true );
Lee Thomasone9ecdab2012-02-13 18:11:20 -0800453 delete doc;
454 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800455 {
456 // Test: Dream
457 // XML1 : 1,187,569 bytes in 31,209 allocations
458 // XML2 : 469,073 bytes in 323 allocations
459 //int newStart = gNew;
460 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300461 doc.LoadFile( "resources/dream.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800462
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400463 doc.SaveFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800464 doc.PrintError();
465
466 XMLTest( "Dream", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400467 doc.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800468 XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
469 XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
470 doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
471 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400472 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800473 XMLTest( "Dream", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400474 doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800475
476 XMLDocument doc2;
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400477 doc2.LoadFile( "resources/out/dreamout.xml" );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800478 XMLTest( "Dream-out", "xml version=\"1.0\"",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400479 doc2.FirstChild()->ToDeclaration()->Value() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800480 XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
481 XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
482 doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
483 XMLTest( "Dream-out", "And Robin shall restore amends.",
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400484 doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -0800485
486 //gNewTotal = gNew - newStart;
487 }
Lee Thomason6f381b72012-03-02 12:59:39 -0800488
489
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800490 {
491 const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
492 "<passages count=\"006\" formatversion=\"20020620\">\n"
493 " <wrong error>\n"
494 "</passages>";
495
496 XMLDocument doc;
497 doc.Parse( error );
Lee Thomason2fa81722012-11-09 12:37:46 -0800498 XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800499 }
500
501 {
502 const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
503
504 XMLDocument doc;
505 doc.Parse( str );
506
507 XMLElement* ele = doc.FirstChildElement();
508
509 int iVal, result;
510 double dVal;
511
512 result = ele->QueryDoubleAttribute( "attr0", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700513 XMLTest( "Query attribute: int as double", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800514 XMLTest( "Query attribute: int as double", (int)dVal, 1 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700515 XMLTest( "Query attribute: int as double", (int)ele->DoubleAttribute("attr0"), 1);
516
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800517 result = ele->QueryDoubleAttribute( "attr1", &dVal );
Lee Thomason85536252016-06-04 19:10:53 -0700518 XMLTest( "Query attribute: double as double", result, (int)XML_SUCCESS);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700519 XMLTest( "Query attribute: double as double", dVal, 2.0 );
520 XMLTest( "Query attribute: double as double", ele->DoubleAttribute("attr1"), 2.0 );
521
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800522 result = ele->QueryIntAttribute( "attr1", &iVal );
Lee Thomason85536252016-06-04 19:10:53 -0700523 XMLTest( "Query attribute: double as int", result, (int)XML_SUCCESS);
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800524 XMLTest( "Query attribute: double as int", iVal, 2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700525
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800526 result = ele->QueryIntAttribute( "attr2", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700527 XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700528 XMLTest( "Query attribute: not a number", ele->DoubleAttribute("attr2", 4.0), 4.0 );
529
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800530 result = ele->QueryIntAttribute( "bar", &iVal );
Lee Thomason21be8822012-07-15 17:27:22 -0700531 XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700532 XMLTest( "Query attribute: does not exist", ele->BoolAttribute("bar", true), true );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800533 }
534
535 {
536 const char* str = "<doc/>";
537
538 XMLDocument doc;
539 doc.Parse( str );
540
541 XMLElement* ele = doc.FirstChildElement();
542
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800543 int iVal, iVal2;
544 double dVal, dVal2;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800545
546 ele->SetAttribute( "str", "strValue" );
547 ele->SetAttribute( "int", 1 );
548 ele->SetAttribute( "double", -1.0 );
549
550 const char* cStr = ele->Attribute( "str" );
551 ele->QueryIntAttribute( "int", &iVal );
552 ele->QueryDoubleAttribute( "double", &dVal );
553
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800554 ele->QueryAttribute( "int", &iVal2 );
555 ele->QueryAttribute( "double", &dVal2 );
556
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700557 XMLTest( "Attribute match test", ele->Attribute( "str", "strValue" ), "strValue" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800558 XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
559 XMLTest( "Attribute round trip. int.", 1, iVal );
560 XMLTest( "Attribute round trip. double.", -1, (int)dVal );
Lee Thomason (grinliz)5efaa5f2013-02-01 19:26:30 -0800561 XMLTest( "Alternate query", true, iVal == iVal2 );
562 XMLTest( "Alternate query", true, dVal == dVal2 );
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700563 XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
564 XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800565 }
566
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800567 {
568 XMLDocument doc;
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300569 doc.LoadFile( "resources/utf8test.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800570
571 // Get the attribute "value" from the "Russian" element and check it.
572 XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700573 const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800574 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
575
576 XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
577
578 const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
579 0xd1U, 0x81U, 0xd1U, 0x81U,
580 0xd0U, 0xbaU, 0xd0U, 0xb8U,
581 0xd0U, 0xb9U, 0 };
582 const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
583
584 XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
585 XMLTest( "UTF-8: Browsing russian element name.",
586 russianText,
587 text->Value() );
588
589 // Now try for a round trip.
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400590 doc.SaveFile( "resources/out/utf8testout.xml" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800591
592 // Check the round trip.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800593 int okay = 0;
594
Thomas Roßa6dd8c62012-07-26 20:42:18 +0200595 FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
Bruno Diasa2d4e6e2012-05-07 04:58:11 -0300596 FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800597
598 if ( saved && verify )
599 {
600 okay = 1;
PKEuSc28ba3a2012-07-16 03:08:47 -0700601 char verifyBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800602 while ( fgets( verifyBuf, 256, verify ) )
603 {
PKEuSc28ba3a2012-07-16 03:08:47 -0700604 char savedBuf[256];
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800605 fgets( savedBuf, 256, saved );
606 NullLineEndings( verifyBuf );
607 NullLineEndings( savedBuf );
608
609 if ( strcmp( verifyBuf, savedBuf ) )
610 {
611 printf( "verify:%s<\n", verifyBuf );
612 printf( "saved :%s<\n", savedBuf );
613 okay = 0;
614 break;
615 }
616 }
617 }
618 if ( saved )
619 fclose( saved );
620 if ( verify )
621 fclose( verify );
622 XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
623 }
624
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800625 // --------GetText()-----------
626 {
627 const char* str = "<foo>This is text</foo>";
628 XMLDocument doc;
629 doc.Parse( str );
630 const XMLElement* element = doc.RootElement();
631
632 XMLTest( "GetText() normal use.", "This is text", element->GetText() );
633
634 str = "<foo><b>This is text</b></foo>";
635 doc.Parse( str );
636 element = doc.RootElement();
637
638 XMLTest( "GetText() contained element.", element->GetText() == 0, true );
639 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800640
Lee Thomasond6277762012-02-22 16:00:12 -0800641
Uli Kusterer321072e2014-01-21 01:57:38 +0100642 // --------SetText()-----------
643 {
644 const char* str = "<foo></foo>";
645 XMLDocument doc;
646 doc.Parse( str );
647 XMLElement* element = doc.RootElement();
648
Lee Thomason9c0678a2014-01-24 10:18:27 -0800649 element->SetText("darkness.");
650 XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100651
Lee Thomason9c0678a2014-01-24 10:18:27 -0800652 element->SetText("blue flame.");
653 XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100654
655 str = "<foo/>";
656 doc.Parse( str );
657 element = doc.RootElement();
658
Lee Thomason9c0678a2014-01-24 10:18:27 -0800659 element->SetText("The driver");
660 XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100661
Lee Thomason9c0678a2014-01-24 10:18:27 -0800662 element->SetText("<b>horses</b>");
663 XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
664 //doc.Print();
Uli Kusterer321072e2014-01-21 01:57:38 +0100665
666 str = "<foo><bar>Text in nested element</bar></foo>";
667 doc.Parse( str );
668 element = doc.RootElement();
669
Lee Thomason9c0678a2014-01-24 10:18:27 -0800670 element->SetText("wolves");
671 XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800672
673 str = "<foo/>";
674 doc.Parse( str );
675 element = doc.RootElement();
676
677 element->SetText( "str" );
678 XMLTest( "SetText types", "str", element->GetText() );
679
680 element->SetText( 1 );
681 XMLTest( "SetText types", "1", element->GetText() );
682
683 element->SetText( 1U );
684 XMLTest( "SetText types", "1", element->GetText() );
685
686 element->SetText( true );
Doruk Turak1f212f32016-08-28 20:54:17 +0200687 XMLTest( "SetText types", "true", element->GetText() );
Lee Thomason5bb2d802014-01-24 10:42:57 -0800688
689 element->SetText( 1.5f );
690 XMLTest( "SetText types", "1.5", element->GetText() );
691
692 element->SetText( 1.5 );
693 XMLTest( "SetText types", "1.5", element->GetText() );
Uli Kusterer321072e2014-01-21 01:57:38 +0100694 }
695
Lee Thomason51c12712016-06-04 20:18:49 -0700696 // ---------- Attributes ---------
697 {
698 static const int64_t BIG = -123456789012345678;
699 XMLDocument doc;
700 XMLElement* element = doc.NewElement("element");
701 doc.InsertFirstChild(element);
702
703 {
704 element->SetAttribute("attrib", int(-100));
705 int v = 0;
706 element->QueryIntAttribute("attrib", &v);
707 XMLTest("Attribute: int", -100, v, true);
708 element->QueryAttribute("attrib", &v);
709 XMLTest("Attribute: int", -100, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700710 XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700711 }
712 {
713 element->SetAttribute("attrib", unsigned(100));
714 unsigned v = 0;
715 element->QueryUnsignedAttribute("attrib", &v);
716 XMLTest("Attribute: unsigned", unsigned(100), v, true);
717 element->QueryAttribute("attrib", &v);
718 XMLTest("Attribute: unsigned", unsigned(100), v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700719 XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700720 }
721 {
722 element->SetAttribute("attrib", BIG);
723 int64_t v = 0;
724 element->QueryInt64Attribute("attrib", &v);
725 XMLTest("Attribute: int64_t", BIG, v, true);
726 element->QueryAttribute("attrib", &v);
727 XMLTest("Attribute: int64_t", BIG, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700728 XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700729 }
730 {
731 element->SetAttribute("attrib", true);
732 bool v = false;
733 element->QueryBoolAttribute("attrib", &v);
734 XMLTest("Attribute: bool", true, v, true);
735 element->QueryAttribute("attrib", &v);
736 XMLTest("Attribute: bool", true, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700737 XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700738 }
739 {
Lee Thomasonce667c92016-12-26 16:45:30 -0800740 element->SetAttribute("attrib", true);
741 const char* result = element->Attribute("attrib");
742 XMLTest("Bool true is 'true'", "true", result);
743
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800744 XMLUtil::SetBoolSerialization("1", "0");
Lee Thomasonce667c92016-12-26 16:45:30 -0800745 element->SetAttribute("attrib", true);
746 result = element->Attribute("attrib");
747 XMLTest("Bool true is '1'", "1", result);
748
Lee Thomasonc5c99c22016-12-29 11:19:17 -0800749 XMLUtil::SetBoolSerialization(0, 0);
Lee Thomasonce667c92016-12-26 16:45:30 -0800750 }
751 {
Lee Thomason51c12712016-06-04 20:18:49 -0700752 element->SetAttribute("attrib", 100.0);
753 double v = 0;
754 element->QueryDoubleAttribute("attrib", &v);
755 XMLTest("Attribute: double", 100.0, v, true);
756 element->QueryAttribute("attrib", &v);
757 XMLTest("Attribute: double", 100.0, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700758 XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700759 }
760 {
761 element->SetAttribute("attrib", 100.0f);
762 float v = 0;
763 element->QueryFloatAttribute("attrib", &v);
764 XMLTest("Attribute: float", 100.0f, v, true);
765 element->QueryAttribute("attrib", &v);
766 XMLTest("Attribute: float", 100.0f, v, true);
Lee Thomason13cbc9a2016-10-27 14:55:07 -0700767 XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
Lee Thomason51c12712016-06-04 20:18:49 -0700768 }
769 {
770 element->SetText(BIG);
771 int64_t v = 0;
772 element->QueryInt64Text(&v);
773 XMLTest("Element: int64_t", BIG, v, true);
774 }
775 }
776
777 // ---------- XMLPrinter stream mode ------
778 {
779 {
780 FILE* printerfp = fopen("resources/printer.xml", "w");
781 XMLPrinter printer(printerfp);
782 printer.OpenElement("foo");
783 printer.PushAttribute("attrib-text", "text");
784 printer.PushAttribute("attrib-int", int(1));
785 printer.PushAttribute("attrib-unsigned", unsigned(2));
786 printer.PushAttribute("attrib-int64", int64_t(3));
787 printer.PushAttribute("attrib-bool", true);
788 printer.PushAttribute("attrib-double", 4.0);
789 printer.CloseElement();
790 fclose(printerfp);
791 }
792 {
793 XMLDocument doc;
794 doc.LoadFile("resources/printer.xml");
795 XMLTest("XMLPrinter Stream mode: load", doc.ErrorID(), XML_SUCCESS, true);
796
797 const XMLDocument& cdoc = doc;
798
799 const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
800 XMLTest("attrib-text", "text", attrib->Value(), true);
801 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
802 XMLTest("attrib-int", int(1), attrib->IntValue(), true);
803 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
804 XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
805 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
806 XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
807 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
808 XMLTest("attrib-bool", true, attrib->BoolValue(), true);
809 attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
810 XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
811 }
812
813 }
814
Uli Kusterer321072e2014-01-21 01:57:38 +0100815
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800816 // ---------- CDATA ---------------
817 {
818 const char* str = "<xmlElement>"
819 "<![CDATA["
820 "I am > the rules!\n"
821 "...since I make symbolic puns"
822 "]]>"
823 "</xmlElement>";
824 XMLDocument doc;
825 doc.Parse( str );
826 doc.Print();
Lee Thomasond6277762012-02-22 16:00:12 -0800827
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700828 XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800829 "I am > the rules!\n...since I make symbolic puns",
Lee Thomasond6277762012-02-22 16:00:12 -0800830 false );
831 }
832
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800833 // ----------- CDATA -------------
834 {
835 const char* str = "<xmlElement>"
836 "<![CDATA["
837 "<b>I am > the rules!</b>\n"
838 "...since I make symbolic puns"
839 "]]>"
840 "</xmlElement>";
841 XMLDocument doc;
842 doc.Parse( str );
843 doc.Print();
844
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700845 XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800846 "<b>I am > the rules!</b>\n...since I make symbolic puns",
847 false );
848 }
849
850 // InsertAfterChild causes crash.
851 {
852 // InsertBeforeChild and InsertAfterChild causes crash.
853 XMLDocument doc;
854 XMLElement* parent = doc.NewElement( "Parent" );
855 doc.InsertFirstChild( parent );
856
857 XMLElement* childText0 = doc.NewElement( "childText0" );
858 XMLElement* childText1 = doc.NewElement( "childText1" );
859
860 XMLNode* childNode0 = parent->InsertEndChild( childText0 );
861 XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
862
863 XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
864 }
Lee Thomasond6277762012-02-22 16:00:12 -0800865
866 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800867 // Entities not being written correctly.
868 // From Lynn Allen
Lee Thomasond6277762012-02-22 16:00:12 -0800869
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800870 const char* passages =
871 "<?xml version=\"1.0\" standalone=\"no\" ?>"
872 "<passages count=\"006\" formatversion=\"20020620\">"
873 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
874 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
875 "</passages>";
Lee Thomasond6277762012-02-22 16:00:12 -0800876
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800877 XMLDocument doc;
878 doc.Parse( passages );
879 XMLElement* psg = doc.RootElement()->FirstChildElement();
880 const char* context = psg->Attribute( "context" );
881 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 -0800882
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800883 XMLTest( "Entity transformation: read. ", expected, context, true );
Lee Thomasond6277762012-02-22 16:00:12 -0800884
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400885 FILE* textfile = fopen( "resources/out/textfile.txt", "w" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800886 if ( textfile )
887 {
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800888 XMLPrinter streamer( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800889 psg->Accept( &streamer );
890 fclose( textfile );
891 }
Thomas Roß0922b732012-09-23 16:31:22 +0200892
893 textfile = fopen( "resources/out/textfile.txt", "r" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800894 TIXMLASSERT( textfile );
895 if ( textfile )
896 {
897 char buf[ 1024 ];
898 fgets( buf, 1024, textfile );
899 XMLTest( "Entity transformation: write. ",
900 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
901 " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
902 buf, false );
PKEuSc28ba3a2012-07-16 03:08:47 -0700903 fclose( textfile );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800904 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800905 }
906
907 {
Lee Thomason6f381b72012-03-02 12:59:39 -0800908 // Suppress entities.
909 const char* passages =
910 "<?xml version=\"1.0\" standalone=\"no\" ?>"
911 "<passages count=\"006\" formatversion=\"20020620\">"
912 "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
913 "</passages>";
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700914
Lee Thomason6f381b72012-03-02 12:59:39 -0800915 XMLDocument doc( false );
916 doc.Parse( passages );
917
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700918 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ),
Lee Thomason6f381b72012-03-02 12:59:39 -0800919 "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;." );
920 XMLTest( "No entity parsing.", doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value(),
921 "Crazy &ttk;" );
922 doc.Print();
923 }
924
925 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400926 const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800927
928 XMLDocument doc;
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400929 doc.Parse( test );
930 XMLTest( "dot in names", doc.Error(), false );
931 XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
932 XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800933 }
934
935 {
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400936 const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800937
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400938 XMLDocument doc;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800939 doc.Parse( test );
940
941 XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
942 XMLTest( "Entity with one digit.",
943 text->Value(), "1.1 Start easy ignore fin thickness\n",
944 false );
Arkadiy Shapkinef1c69c2012-07-25 22:10:39 +0400945 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800946
947 {
948 // DOCTYPE not preserved (950171)
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700949 //
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800950 const char* doctype =
951 "<?xml version=\"1.0\" ?>"
952 "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
953 "<!ELEMENT title (#PCDATA)>"
954 "<!ELEMENT books (title,authors)>"
955 "<element />";
956
957 XMLDocument doc;
958 doc.Parse( doctype );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400959 doc.SaveFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800960 doc.DeleteChild( doc.RootElement() );
Arkadiy Shapkinff72d1f2012-07-24 00:24:07 +0400961 doc.LoadFile( "resources/out/test7.xml" );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800962 doc.Print();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700963
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800964 const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
965 XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
966
967 }
968
969 {
970 // Comments do not stream out correctly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700971 const char* doctype =
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800972 "<!-- Somewhat<evil> -->";
973 XMLDocument doc;
974 doc.Parse( doctype );
975
976 XMLComment* comment = doc.FirstChild()->ToComment();
977
978 XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
979 }
980 {
981 // Double attributes
982 const char* doctype = "<element attr='red' attr='blue' />";
983
984 XMLDocument doc;
985 doc.Parse( doctype );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700986
Lee Thomason2fa81722012-11-09 12:37:46 -0800987 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 -0800988 doc.PrintError();
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800989 }
990
991 {
992 // Embedded null in stream.
993 const char* doctype = "<element att\0r='red' attr='blue' />";
994
995 XMLDocument doc;
996 doc.Parse( doctype );
997 XMLTest( "Embedded null throws error.", true, doc.Error() );
998 }
999
1000 {
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -07001001 // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001002 const char* str = "";
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001003 XMLDocument doc;
1004 doc.Parse( str );
Lee Thomason2fa81722012-11-09 12:37:46 -08001005 XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001006 }
1007
1008 {
Dmitry-Me588bb8d2014-12-25 18:59:18 +03001009 // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
1010 const char* str = " ";
1011 XMLDocument doc;
1012 doc.Parse( str );
1013 XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
1014 }
1015
1016 {
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001017 // Low entities
1018 XMLDocument doc;
1019 doc.Parse( "<test>&#x0e;</test>" );
1020 const char result[] = { 0x0e, 0 };
1021 XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
1022 doc.Print();
1023 }
1024
1025 {
1026 // Attribute values with trailing quotes not handled correctly
1027 XMLDocument doc;
1028 doc.Parse( "<foo attribute=bar\" />" );
1029 XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
1030 }
1031
1032 {
1033 // [ 1663758 ] Failure to report error on bad XML
1034 XMLDocument xml;
1035 xml.Parse("<x>");
1036 XMLTest("Missing end tag at end of input", xml.Error(), true);
1037 xml.Parse("<x> ");
1038 XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
1039 xml.Parse("<x></y>");
Lee Thomason2fa81722012-11-09 12:37:46 -08001040 XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001041 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001042
1043
1044 {
1045 // [ 1475201 ] TinyXML parses entities in comments
1046 XMLDocument xml;
1047 xml.Parse("<!-- declarations for <head> & <body> -->"
1048 "<!-- far &amp; away -->" );
1049
1050 XMLNode* e0 = xml.FirstChild();
1051 XMLNode* e1 = e0->NextSibling();
1052 XMLComment* c0 = e0->ToComment();
1053 XMLComment* c1 = e1->ToComment();
1054
1055 XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
1056 XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
1057 }
1058
1059 {
1060 XMLDocument xml;
1061 xml.Parse( "<Parent>"
1062 "<child1 att=''/>"
1063 "<!-- With this comment, child2 will not be parsed! -->"
1064 "<child2 att=''/>"
1065 "</Parent>" );
1066 xml.Print();
1067
1068 int count = 0;
1069
1070 for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
1071 ele;
1072 ele = ele->NextSibling() )
1073 {
1074 ++count;
1075 }
1076
1077 XMLTest( "Comments iterate correctly.", 3, count );
1078 }
1079
1080 {
1081 // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
1082 unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
1083 buf[60] = 239;
1084 buf[61] = 0;
1085
1086 XMLDocument doc;
1087 doc.Parse( (const char*)buf);
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001088 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001089
1090
1091 {
1092 // bug 1827248 Error while parsing a little bit malformed file
1093 // Actually not malformed - should work.
1094 XMLDocument xml;
1095 xml.Parse( "<attributelist> </attributelist >" );
1096 XMLTest( "Handle end tag whitespace", false, xml.Error() );
1097 }
1098
1099 {
1100 // This one must not result in an infinite loop
1101 XMLDocument xml;
1102 xml.Parse( "<infinite>loop" );
1103 XMLTest( "Infinite loop test.", true, true );
1104 }
1105#endif
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001106 {
1107 const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
1108 XMLDocument doc;
1109 doc.Parse( pub );
1110
1111 XMLDocument clone;
1112 for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
1113 XMLNode* copy = node->ShallowClone( &clone );
1114 clone.InsertEndChild( copy );
1115 }
1116
1117 clone.Print();
1118
1119 int count=0;
1120 const XMLNode* a=clone.FirstChild();
1121 const XMLNode* b=doc.FirstChild();
1122 for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
1123 ++count;
1124 XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
1125 }
1126 XMLTest( "Clone and Equal", 4, count );
1127 }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001128
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001129 {
1130 // This shouldn't crash.
1131 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001132 if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001133 {
1134 doc.PrintError();
1135 }
1136 XMLTest( "Error in snprinf handling.", true, doc.Error() );
1137 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001138
Lee Thomason5e3803c2012-04-16 08:57:05 -07001139 {
1140 // Attribute ordering.
1141 static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
1142 XMLDocument doc;
1143 doc.Parse( xml );
1144 XMLElement* ele = doc.FirstChildElement();
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001145
Lee Thomason5e3803c2012-04-16 08:57:05 -07001146 const XMLAttribute* a = ele->FirstAttribute();
1147 XMLTest( "Attribute order", "1", a->Value() );
1148 a = a->Next();
1149 XMLTest( "Attribute order", "2", a->Value() );
1150 a = a->Next();
1151 XMLTest( "Attribute order", "3", a->Value() );
1152 XMLTest( "Attribute order", "attrib3", a->Name() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001153
Lee Thomason5e3803c2012-04-16 08:57:05 -07001154 ele->DeleteAttribute( "attrib2" );
1155 a = ele->FirstAttribute();
1156 XMLTest( "Attribute order", "1", a->Value() );
1157 a = a->Next();
1158 XMLTest( "Attribute order", "3", a->Value() );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001159
Lee Thomason5e3803c2012-04-16 08:57:05 -07001160 ele->DeleteAttribute( "attrib1" );
1161 ele->DeleteAttribute( "attrib3" );
1162 XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );
1163 }
Lee Thomason (grinliz)a4a36ba2012-04-06 21:24:29 -07001164
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001165 {
1166 // Make sure an attribute with a space in it succeeds.
Lee Thomason78a773d2012-07-02 10:10:19 -07001167 static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
1168 static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
1169 static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
1170 XMLDocument doc0;
1171 doc0.Parse( xml0 );
1172 XMLDocument doc1;
1173 doc1.Parse( xml1 );
1174 XMLDocument doc2;
1175 doc2.Parse( xml2 );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001176
Lee Thomason78a773d2012-07-02 10:10:19 -07001177 XMLElement* ele = 0;
1178 ele = doc0.FirstChildElement();
1179 XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
1180 ele = doc1.FirstChildElement();
1181 XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
1182 ele = doc2.FirstChildElement();
1183 XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -07001184 }
1185
1186 {
1187 // Make sure we don't go into an infinite loop.
1188 static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
1189 XMLDocument doc;
1190 doc.Parse( xml );
1191 XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
1192 XMLElement* ele1 = ele0->NextSiblingElement();
1193 bool equal = ele0->ShallowEqual( ele1 );
1194
1195 XMLTest( "Infinite loop in shallow equal.", true, equal );
1196 }
1197
Lee Thomason5708f812012-03-28 17:46:41 -07001198 // -------- Handles ------------
1199 {
1200 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1201 XMLDocument doc;
1202 doc.Parse( xml );
Lee Thomason5708f812012-03-28 17:46:41 -07001203
1204 XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
1205 XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
1206
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001207 XMLHandle docH( doc );
1208 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001209 XMLTest( "Handle, dne, mutable", false, ele != 0 );
Lee Thomason5708f812012-03-28 17:46:41 -07001210 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001211
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001212 {
1213 static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
1214 XMLDocument doc;
1215 doc.Parse( xml );
1216 XMLConstHandle docH( doc );
1217
1218 const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
1219 XMLTest( "Handle, success, const", ele->Value(), "sub" );
1220
1221 ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
Lee Thomasond0b19df2012-04-12 08:41:37 -07001222 XMLTest( "Handle, dne, const", false, ele != 0 );
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001223 }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001224 {
1225 // Default Declaration & BOM
1226 XMLDocument doc;
1227 doc.InsertEndChild( doc.NewDeclaration() );
1228 doc.SetBOM( true );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001229
Lee Thomasonf68c4382012-04-28 14:37:11 -07001230 XMLPrinter printer;
1231 doc.Print( &printer );
1232
1233 static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1234 XMLTest( "BOM and default declaration", printer.CStr(), result, false );
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001235 XMLTest( "CStrSize", printer.CStrSize(), 42, false );
Lee Thomasonf68c4382012-04-28 14:37:11 -07001236 }
Lee Thomason21be8822012-07-15 17:27:22 -07001237 {
1238 const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
1239 XMLDocument doc;
1240 doc.Parse( xml );
1241 XMLTest( "Ill formed XML", true, doc.Error() );
1242 }
1243
1244 // QueryXYZText
1245 {
1246 const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
1247 XMLDocument doc;
1248 doc.Parse( xml );
1249
1250 const XMLElement* pointElement = doc.RootElement();
1251
1252 int intValue = 0;
1253 unsigned unsignedValue = 0;
1254 float floatValue = 0;
1255 double doubleValue = 0;
1256 bool boolValue = false;
1257
1258 pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
1259 pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
1260 pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
1261 pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
1262 pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
1263
1264
1265 XMLTest( "QueryIntText", intValue, 1, false );
1266 XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1, false );
1267 XMLTest( "QueryFloatText", floatValue, 1.2f, false );
1268 XMLTest( "QueryDoubleText", doubleValue, 1.2, false );
1269 XMLTest( "QueryBoolText", boolValue, true, false );
1270 }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001271
Lee Thomason (grinliz)5fbacbe2012-09-08 21:40:53 -07001272 {
1273 const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
1274 XMLDocument doc;
1275 doc.Parse( xml );
1276 XMLTest( "Non-alpha element lead letter parses.", doc.Error(), false );
1277 }
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001278
1279 {
1280 const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
1281 XMLDocument doc;
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001282 doc.Parse( xml );
Martinsh Shaiters23e7ae62013-01-26 20:15:44 +02001283 XMLTest("Non-alpha attribute lead character parses.", doc.Error(), false);
1284 }
Martinsh Shaiters95b3e652013-01-26 23:08:10 +02001285
1286 {
1287 const char* xml = "<3lement></3lement>";
1288 XMLDocument doc;
1289 doc.Parse( xml );
1290 XMLTest("Element names with lead digit fail to parse.", doc.Error(), true);
1291 }
Lee Thomason (grinliz)62d1c5a2012-09-08 21:44:12 -07001292
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001293 {
1294 const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
1295 XMLDocument doc;
1296 doc.Parse( xml, 10 );
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001297 XMLTest( "Set length of incoming data", doc.Error(), false );
1298 }
1299
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001300 {
1301 XMLDocument doc;
Dmitry-Me48b5df02015-04-06 18:20:25 +03001302 XMLTest( "Document is initially empty", doc.NoChildren(), true );
1303 doc.Clear();
1304 XMLTest( "Empty is empty after Clear()", doc.NoChildren(), true );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001305 doc.LoadFile( "resources/dream.xml" );
Dmitry-Meaaa4cea2015-02-06 16:00:46 +03001306 XMLTest( "Document has something to Clear()", doc.NoChildren(), false );
Martinsh Shaiters53ab79a2013-01-30 11:21:36 +02001307 doc.Clear();
1308 XMLTest( "Document Clear()'s", doc.NoChildren(), true );
1309 }
1310
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001311 // ----------- Whitespace ------------
1312 {
1313 const char* xml = "<element>"
1314 "<a> This \nis &apos; text &apos; </a>"
1315 "<b> This is &apos; text &apos; \n</b>"
1316 "<c>This is &apos; \n\n text &apos;</c>"
1317 "</element>";
1318 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1319 doc.Parse( xml );
1320
1321 const XMLElement* element = doc.FirstChildElement();
1322 for( const XMLElement* parent = element->FirstChildElement();
1323 parent;
1324 parent = parent->NextSiblingElement() )
1325 {
1326 XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
1327 }
1328 }
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001329
Lee Thomasonae9ab072012-10-24 10:17:53 -07001330#if 0
1331 {
1332 // Passes if assert doesn't fire.
1333 XMLDocument xmlDoc;
1334
1335 xmlDoc.NewDeclaration();
1336 xmlDoc.NewComment("Configuration file");
1337
1338 XMLElement *root = xmlDoc.NewElement("settings");
1339 root->SetAttribute("version", 2);
1340 }
1341#endif
1342
Lee Thomason (grinliz)0fa82992012-09-08 21:53:47 -07001343 {
1344 const char* xml = "<element> </element>";
1345 XMLDocument doc( true, COLLAPSE_WHITESPACE );
1346 doc.Parse( xml );
1347 XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
1348 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001349
Lee Thomason5b0a6772012-11-19 13:54:42 -08001350 {
1351 // An assert should not fire.
1352 const char* xml = "<element/>";
1353 XMLDocument doc;
1354 doc.Parse( xml );
1355 XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
1356 XMLTest( "Tracking unused elements", true, ele != 0, false );
1357 }
1358
Lee Thomasona6412ac2012-12-13 15:39:11 -08001359
1360 {
1361 const char* xml = "<parent><child>abc</child></parent>";
1362 XMLDocument doc;
1363 doc.Parse( xml );
1364 XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
1365
1366 XMLPrinter printer;
1367 ele->Accept( &printer );
1368 XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
1369 }
1370
1371
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001372 {
1373 XMLDocument doc;
1374 XMLError error = doc.LoadFile( "resources/empty.xml" );
1375 XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
Lee Thomason331596e2014-09-11 14:56:43 -07001376 XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
Lee Thomasonc7556672014-09-14 12:39:42 -07001377 doc.PrintError();
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001378 }
1379
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001380 {
1381 // BOM preservation
1382 static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
1383 {
1384 XMLDocument doc;
Lee Thomason85536252016-06-04 19:10:53 -07001385 XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001386 XMLPrinter printer;
1387 doc.Print( &printer );
1388
1389 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1390 doc.SaveFile( "resources/bomtest.xml" );
1391 }
1392 {
1393 XMLDocument doc;
1394 doc.LoadFile( "resources/bomtest.xml" );
1395 XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
1396
1397 XMLPrinter printer;
1398 doc.Print( &printer );
1399 XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
1400 }
1401 }
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001402
Michael Daumlinged523282013-10-23 07:47:29 +02001403 {
1404 // Insertion with Removal
1405 const char* xml = "<?xml version=\"1.0\" ?>"
1406 "<root>"
1407 "<one>"
1408 "<subtree>"
1409 "<elem>element 1</elem>text<!-- comment -->"
1410 "</subtree>"
1411 "</one>"
1412 "<two/>"
1413 "</root>";
1414 const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
1415 "<root>"
1416 "<one/>"
1417 "<two>"
1418 "<subtree>"
1419 "<elem>element 1</elem>text<!-- comment -->"
1420 "</subtree>"
1421 "</two>"
1422 "</root>";
1423 const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
1424 "<root>"
1425 "<one/>"
1426 "<subtree>"
1427 "<elem>element 1</elem>text<!-- comment -->"
1428 "</subtree>"
1429 "<two/>"
1430 "</root>";
1431 const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
1432 "<root>"
1433 "<one/>"
1434 "<two/>"
1435 "<subtree>"
1436 "<elem>element 1</elem>text<!-- comment -->"
1437 "</subtree>"
1438 "</root>";
1439
1440 XMLDocument doc;
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001441 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001442 XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1443 XMLElement* two = doc.RootElement()->FirstChildElement("two");
1444 two->InsertFirstChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001445 XMLPrinter printer1(0, true);
1446 doc.Accept(&printer1);
1447 XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
Michael Daumlinged523282013-10-23 07:47:29 +02001448
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001449 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001450 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1451 two = doc.RootElement()->FirstChildElement("two");
1452 doc.RootElement()->InsertAfterChild(two, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001453 XMLPrinter printer2(0, true);
1454 doc.Accept(&printer2);
1455 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001456
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001457 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001458 XMLNode* one = doc.RootElement()->FirstChildElement("one");
1459 subtree = one->FirstChildElement("subtree");
1460 doc.RootElement()->InsertAfterChild(one, subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001461 XMLPrinter printer3(0, true);
1462 doc.Accept(&printer3);
1463 XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001464
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001465 doc.Parse(xml);
Michael Daumlinged523282013-10-23 07:47:29 +02001466 subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
1467 two = doc.RootElement()->FirstChildElement("two");
1468 doc.RootElement()->InsertEndChild(subtree);
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001469 XMLPrinter printer4(0, true);
1470 doc.Accept(&printer4);
1471 XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
Michael Daumlinged523282013-10-23 07:47:29 +02001472 }
1473
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001474 {
1475 const char* xml = "<svg width = \"128\" height = \"128\">"
1476 " <text> </text>"
1477 "</svg>";
1478 XMLDocument doc;
1479 doc.Parse(xml);
1480 doc.Print();
1481 }
1482
Lee Thomason92e521b2014-11-15 17:45:51 -08001483 {
1484 // Test that it doesn't crash.
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001485 const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
1486 XMLDocument doc;
1487 doc.Parse(xml);
1488 doc.PrintError();
Lee Thomason92e521b2014-11-15 17:45:51 -08001489 }
1490
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001491#if 1
1492 // the question being explored is what kind of print to use:
1493 // https://github.com/leethomason/tinyxml2/issues/63
1494 {
1495 //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
1496 const char* xml = "<element/>";
1497 XMLDocument doc;
1498 doc.Parse( xml );
1499 doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
1500 doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
1501 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
1502 doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
1503 doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
1504 doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
1505
1506 doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
1507 doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
1508 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
1509 doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
1510 doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
1511 doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
1512
1513 doc.Print();
1514
1515 /* The result of this test is platform, compiler, and library version dependent. :("
1516 XMLPrinter printer;
1517 doc.Print( &printer );
1518 XMLTest( "Float and double formatting.",
1519 "<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",
1520 printer.CStr(),
1521 true );
1522 */
1523 }
1524#endif
Lee Thomasonf07b9522014-10-30 13:25:12 -07001525
1526 {
1527 // Issue #184
1528 // If it doesn't assert, it passes. Caused by objects
1529 // getting created during parsing which are then
1530 // inaccessible in the memory pools.
1531 {
1532 XMLDocument doc;
1533 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1534 }
1535 {
1536 XMLDocument doc;
1537 doc.Parse("<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>");
1538 doc.Clear();
1539 }
1540 }
Lee Thomasoncd011bc2014-12-17 10:41:34 -08001541
1542 {
1543 // If this doesn't assert in DEBUG, all is well.
1544 tinyxml2::XMLDocument doc;
1545 tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
1546 doc.DeleteNode(pRoot);
1547 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001548
Dmitry-Me8b67d742014-12-22 11:35:12 +03001549 {
1550 // Should not assert in DEBUG
1551 XMLPrinter printer;
1552 }
Lee Thomasonc3708cc2014-01-14 12:30:03 -08001553
Dmitry-Me6f51c802015-03-14 13:25:03 +03001554 {
1555 // Issue 291. Should not crash
1556 const char* xml = "&#0</a>";
1557 XMLDocument doc;
1558 doc.Parse( xml );
1559
1560 XMLPrinter printer;
1561 doc.Print( &printer );
1562 }
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001563 {
1564 // Issue 299. Can print elements that are not linked in.
1565 // Will crash if issue not fixed.
1566 XMLDocument doc;
1567 XMLElement* newElement = doc.NewElement( "printme" );
1568 XMLPrinter printer;
1569 newElement->Accept( &printer );
Dmitry-Me5daa54c2015-04-08 17:45:07 +03001570 // Delete the node to avoid possible memory leak report in debug output
1571 doc.DeleteNode( newElement );
Ant Mitchell148cc1a2015-03-24 15:12:35 +00001572 }
Lee Thomasonf6577832015-03-26 11:18:21 -07001573 {
Ant Mitchell189198f2015-03-24 16:20:36 +00001574 // Issue 302. Clear errors from LoadFile/SaveFile
1575 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001576 XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001577 doc.SaveFile( "./no/such/path/pretty.xml" );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001578 XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001579 doc.SaveFile( "./resources/out/compact.xml", true );
Dmitry-Me32533ca2015-04-07 10:37:39 +03001580 XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
Ant Mitchell189198f2015-03-24 16:20:36 +00001581 }
Dmitry-Me6f51c802015-03-14 13:25:03 +03001582
Dmitry-Med9852a52015-03-25 10:17:49 +03001583 {
1584 // If a document fails to load then subsequent
1585 // successful loads should clear the error
1586 XMLDocument doc;
Dmitry-Me32533ca2015-04-07 10:37:39 +03001587 XMLTest( "Should be no error initially", false, doc.Error() );
Dmitry-Med9852a52015-03-25 10:17:49 +03001588 doc.LoadFile( "resources/no-such-file.xml" );
1589 XMLTest( "No such file - should fail", true, doc.Error() );
1590
1591 doc.LoadFile( "resources/dream.xml" );
1592 XMLTest( "Error should be cleared", false, doc.Error() );
1593 }
Sarat Addepalli8e85afa2015-05-19 09:07:03 +05301594
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301595 {
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001596 // Check that declarations are allowed only at beginning of document
Lee Thomason85492022015-05-22 11:07:45 -07001597 const char* xml0 = "<?xml version=\"1.0\" ?>"
1598 " <!-- xml version=\"1.1\" -->"
1599 "<first />";
1600 const char* xml1 = "<?xml version=\"1.0\" ?>"
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001601 "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
Lee Thomason85492022015-05-22 11:07:45 -07001602 "<first />";
1603 const char* xml2 = "<first />"
1604 "<?xml version=\"1.0\" ?>";
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001605 const char* xml3 = "<first></first>"
1606 "<?xml version=\"1.0\" ?>";
1607
1608 const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
1609
Lee Thomason85492022015-05-22 11:07:45 -07001610 XMLDocument doc;
1611 doc.Parse(xml0);
1612 XMLTest("Test that the code changes do not affect normal parsing", doc.Error(), false);
1613 doc.Parse(xml1);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001614 XMLTest("Test that the second declaration is allowed", doc.Error(), false);
Lee Thomason85492022015-05-22 11:07:45 -07001615 doc.Parse(xml2);
Dmitry-Me446c3bc2016-11-11 10:34:56 +03001616 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1617 doc.Parse(xml3);
1618 XMLTest("Test that declaration after a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
1619 doc.Parse(xml4);
1620 XMLTest("Test that declaration inside a child is not allowed", doc.ErrorID(), XML_ERROR_PARSING_DECLARATION);
Sarat Addepalli2bb6bb52015-05-18 09:16:34 +05301621 }
Dmitry-Med9852a52015-03-25 10:17:49 +03001622
Lee Thomason85492022015-05-22 11:07:45 -07001623 {
1624 // No matter - before or after successfully parsing a text -
1625 // calling XMLDocument::Value() causes an assert in debug.
1626 const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
1627 "<first />"
1628 "<second />";
1629 XMLDocument* doc = new XMLDocument();
1630 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1631 doc->Parse( validXml );
1632 XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
1633 delete doc;
1634 }
1635
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001636 {
1637 XMLDocument doc;
1638 for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
kezenatorec694152016-11-26 17:21:43 +10001639 doc.SetError( (XMLError)i, 0, 0, 0 );
Dmitry-Mea1beddf2015-05-26 16:19:21 +03001640 doc.ErrorName();
1641 }
1642 }
1643
Lee Thomason816d3fa2017-06-05 14:35:55 -07001644 {
1645 // Oh those memory leaks.
1646 // Only way to see these is in the (Windows) allocator tracking.
1647 {
1648 XMLDocument doc;
1649 doc.NewElement("LEAK 1");
1650 }
1651 {
1652 XMLDocument doc;
1653 XMLElement* ele = doc.NewElement("LEAK 2");
1654 doc.DeleteNode(ele);
1655 }
1656 }
1657
kezenatorec694152016-11-26 17:21:43 +10001658 // ----------- Line Number Tracking --------------
1659 {
Lee Thomasone90e9012016-12-24 07:34:39 -08001660 struct TestUtil: XMLVisitor
kezenatorec694152016-11-26 17:21:43 +10001661 {
1662 void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
1663 {
1664 XMLDocument doc;
1665 XMLError err = doc.Parse(docStr);
1666
1667 XMLTest(testString, true, doc.Error());
1668 XMLTest(testString, expected_error, err);
1669 XMLTest(testString, expectedLine, doc.GetErrorLineNum());
1670 };
1671
1672 void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
1673 {
1674 XMLDocument doc;
1675 doc.Parse(docStr);
1676 XMLTest(testString, false, doc.Error());
1677 TestDocLines(testString, doc, expectedLines);
1678 }
1679
1680 void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
1681 {
1682 XMLDocument doc;
1683 doc.LoadFile(file_name);
1684 XMLTest(testString, false, doc.Error());
1685 TestDocLines(testString, doc, expectedLines);
1686 }
1687
1688 private:
1689 DynArray<char, 10> str;
1690
1691 void Push(char type, int lineNum)
1692 {
1693 str.Push(type);
1694 str.Push(char('0' + (lineNum / 10)));
1695 str.Push(char('0' + (lineNum % 10)));
1696 }
1697
1698 bool VisitEnter(const XMLDocument& doc)
1699 {
kezenator19d8ea82016-11-29 19:50:27 +10001700 Push('D', doc.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001701 return true;
1702 }
1703 bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
1704 {
kezenator19d8ea82016-11-29 19:50:27 +10001705 Push('E', element.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001706 for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
kezenator19d8ea82016-11-29 19:50:27 +10001707 Push('A', attr->GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001708 return true;
1709 }
1710 bool Visit(const XMLDeclaration& declaration)
1711 {
kezenator19d8ea82016-11-29 19:50:27 +10001712 Push('L', declaration.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001713 return true;
1714 }
1715 bool Visit(const XMLText& text)
1716 {
kezenator19d8ea82016-11-29 19:50:27 +10001717 Push('T', text.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001718 return true;
1719 }
1720 bool Visit(const XMLComment& comment)
1721 {
kezenator19d8ea82016-11-29 19:50:27 +10001722 Push('C', comment.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001723 return true;
1724 }
1725 bool Visit(const XMLUnknown& unknown)
1726 {
kezenator19d8ea82016-11-29 19:50:27 +10001727 Push('U', unknown.GetLineNum());
kezenatorec694152016-11-26 17:21:43 +10001728 return true;
1729 }
1730
1731 void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
1732 {
1733 str.Clear();
1734 doc.Accept(this);
1735 str.Push(0);
1736 XMLTest(testString, expectedLines, str.Mem());
1737 }
Lee Thomasone90e9012016-12-24 07:34:39 -08001738 } tester;
kezenatorec694152016-11-26 17:21:43 +10001739
Lee Thomasone90e9012016-12-24 07:34:39 -08001740 tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
1741 tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
1742 tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
1743 tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
1744 tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
1745 tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
1746 tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
1747 tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
1748 tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
1749 tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
1750 tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
kezenatorec694152016-11-26 17:21:43 +10001751
Lee Thomasone90e9012016-12-24 07:34:39 -08001752 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001753 "LineNumbers-String",
Lee Thomasone90e9012016-12-24 07:34:39 -08001754
1755 "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
1756 "<root a='b' \n" // 2 Element Attribute
1757 "c='d'> d <blah/> \n" // 3 Attribute Text Element
1758 "newline in text \n" // 4 Text
1759 "and second <zxcv/><![CDATA[\n" // 5 Element Text
1760 " cdata test ]]><!-- comment -->\n" // 6 Comment
1761 "<! unknown></root>", // 7 Unknown
1762
kezenatorec694152016-11-26 17:21:43 +10001763 "D01L01E02A02A03T03E03T04E05T05C06U07");
1764
Lee Thomasone90e9012016-12-24 07:34:39 -08001765 tester.TestStringLines(
kezenatorec694152016-11-26 17:21:43 +10001766 "LineNumbers-CRLF",
Lee Thomasone90e9012016-12-24 07:34:39 -08001767
1768 "\r\n" // 1 Doc (arguably should be line 2)
1769 "<?xml version=\"1.0\"?>\n" // 2 DecL
1770 "<root>\r\n" // 3 Element
1771 "\n" // 4
1772 "text contining new line \n" // 5 Text
1773 " and also containing crlf \r\n" // 6
1774 "<sub><![CDATA[\n" // 7 Element Text
1775 "cdata containing new line \n" // 8
1776 " and also containing cflr\r\n" // 9
1777 "]]></sub><sub2/></root>", // 10 Element
1778
kezenatorec694152016-11-26 17:21:43 +10001779 "D01L02E03T05E07T07E10");
1780
Lee Thomasone90e9012016-12-24 07:34:39 -08001781 tester.TestFileLines(
kezenatorec694152016-11-26 17:21:43 +10001782 "LineNumbers-File",
1783 "resources/utf8test.xml",
1784 "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
1785 }
1786
Lee Thomason85492022015-05-22 11:07:45 -07001787 // ----------- Performance tracking --------------
Lee Thomason6f381b72012-03-02 12:59:39 -08001788 {
1789#if defined( _MSC_VER )
1790 __int64 start, end, freq;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001791 QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
Lee Thomason6f381b72012-03-02 12:59:39 -08001792#endif
1793
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001794 FILE* perfFP = fopen("resources/dream.xml", "r");
1795 fseek(perfFP, 0, SEEK_END);
Armagetron3c21d6f2016-10-13 13:31:23 +02001796 long size = ftell(perfFP);
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001797 fseek(perfFP, 0, SEEK_SET);
Lee Thomason6f381b72012-03-02 12:59:39 -08001798
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001799 char* mem = new char[size + 1];
1800 fread(mem, size, 1, perfFP);
1801 fclose(perfFP);
Lee Thomason6f381b72012-03-02 12:59:39 -08001802 mem[size] = 0;
1803
1804#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001805 QueryPerformanceCounter((LARGE_INTEGER*)&start);
Lee Thomason6f381b72012-03-02 12:59:39 -08001806#else
1807 clock_t cstart = clock();
1808#endif
1809 static const int COUNT = 10;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001810 for (int i = 0; i < COUNT; ++i) {
Lee Thomason6f381b72012-03-02 12:59:39 -08001811 XMLDocument doc;
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001812 doc.Parse(mem);
Lee Thomason6f381b72012-03-02 12:59:39 -08001813 }
1814#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001815 QueryPerformanceCounter((LARGE_INTEGER*)&end);
Lee Thomason6f381b72012-03-02 12:59:39 -08001816#else
1817 clock_t cend = clock();
1818#endif
1819
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001820 delete[] mem;
Lee Thomason6f381b72012-03-02 12:59:39 -08001821
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001822 static const char* note =
Lee Thomason6f381b72012-03-02 12:59:39 -08001823#ifdef DEBUG
1824 "DEBUG";
1825#else
1826 "Release";
1827#endif
1828
1829#if defined( _MSC_VER )
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001830 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 -08001831#else
Lee Thomasondf4ffc02016-06-04 11:32:46 -07001832 printf("\nParsing %s of dream.xml: %.3f milli-seconds\n", note, (double)(cend - cstart) / (double)COUNT);
Lee Thomason6f381b72012-03-02 12:59:39 -08001833#endif
1834 }
1835
Lee Thomason (grinliz)7ca55582012-03-07 21:54:57 -08001836 #if defined( _MSC_VER ) && defined( DEBUG )
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001837 _CrtMemCheckpoint( &endMemState );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001838
1839 _CrtMemState diffMemState;
1840 _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
1841 _CrtMemDumpStatistics( &diffMemState );
1842 #endif
1843
1844 printf ("\nPass %d, Fail %d\n", gPass, gFail);
Lee Thomason (grinliz)db304252013-07-31 12:24:52 -07001845
1846 return gFail;
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08001847}