xmltest.cpp 90 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743
  1. #if defined( _MSC_VER )
  2. #if !defined( _CRT_SECURE_NO_WARNINGS )
  3. #define _CRT_SECURE_NO_WARNINGS // This test file is not intended to be secure.
  4. #endif
  5. #endif
  6. #include "tinyxml2.h"
  7. #include <cerrno>
  8. #include <cstdlib>
  9. #include <cstring>
  10. #include <ctime>
  11. #if defined( _MSC_VER ) || defined (WIN32)
  12. #include <crtdbg.h>
  13. #define WIN32_LEAN_AND_MEAN
  14. #include <windows.h>
  15. _CrtMemState startMemState;
  16. _CrtMemState endMemState;
  17. #else
  18. #include <sys/stat.h>
  19. #include <sys/types.h>
  20. #endif
  21. using namespace tinyxml2;
  22. using namespace std;
  23. int gPass = 0;
  24. int gFail = 0;
  25. bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true, bool extraNL=false )
  26. {
  27. bool pass;
  28. if ( !expected && !found )
  29. pass = true;
  30. else if ( !expected || !found )
  31. pass = false;
  32. else
  33. pass = !strcmp( expected, found );
  34. if ( pass )
  35. printf ("[pass]");
  36. else
  37. printf ("[fail]");
  38. if ( !echo ) {
  39. printf (" %s\n", testString);
  40. }
  41. else {
  42. if ( extraNL ) {
  43. printf( " %s\n", testString );
  44. printf( "%s\n", expected );
  45. printf( "%s\n", found );
  46. }
  47. else {
  48. printf (" %s [%s][%s]\n", testString, expected, found);
  49. }
  50. }
  51. if ( pass )
  52. ++gPass;
  53. else
  54. ++gFail;
  55. return pass;
  56. }
  57. bool XMLTest(const char* testString, XMLError expected, XMLError found, bool echo = true, bool extraNL = false)
  58. {
  59. return XMLTest(testString, XMLDocument::ErrorIDToName(expected), XMLDocument::ErrorIDToName(found), echo, extraNL);
  60. }
  61. bool XMLTest(const char* testString, bool expected, bool found, bool echo = true, bool extraNL = false)
  62. {
  63. return XMLTest(testString, expected ? "true" : "false", found ? "true" : "false", echo, extraNL);
  64. }
  65. template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )
  66. {
  67. bool pass = ( expected == found );
  68. if ( pass )
  69. printf ("[pass]");
  70. else
  71. printf ("[fail]");
  72. if ( !echo )
  73. printf (" %s\n", testString);
  74. else {
  75. char expectedAsString[64];
  76. XMLUtil::ToStr(expected, expectedAsString, sizeof(expectedAsString));
  77. char foundAsString[64];
  78. XMLUtil::ToStr(found, foundAsString, sizeof(foundAsString));
  79. printf (" %s [%s][%s]\n", testString, expectedAsString, foundAsString );
  80. }
  81. if ( pass )
  82. ++gPass;
  83. else
  84. ++gFail;
  85. return pass;
  86. }
  87. void NullLineEndings( char* p )
  88. {
  89. while( p && *p ) {
  90. if ( *p == '\n' || *p == '\r' ) {
  91. *p = 0;
  92. return;
  93. }
  94. ++p;
  95. }
  96. }
  97. int example_1()
  98. {
  99. XMLDocument doc;
  100. doc.LoadFile( "resources/dream.xml" );
  101. return doc.ErrorID();
  102. }
  103. /** @page Example_1 Load an XML File
  104. * @dontinclude ./xmltest.cpp
  105. * Basic XML file loading.
  106. * The basic syntax to load an XML file from
  107. * disk and check for an error. (ErrorID()
  108. * will return 0 for no error.)
  109. * @skip example_1()
  110. * @until }
  111. */
  112. int example_2()
  113. {
  114. static const char* xml = "<element/>";
  115. XMLDocument doc;
  116. doc.Parse( xml );
  117. return doc.ErrorID();
  118. }
  119. /** @page Example_2 Parse an XML from char buffer
  120. * @dontinclude ./xmltest.cpp
  121. * Basic XML string parsing.
  122. * The basic syntax to parse an XML for
  123. * a char* and check for an error. (ErrorID()
  124. * will return 0 for no error.)
  125. * @skip example_2()
  126. * @until }
  127. */
  128. int example_3()
  129. {
  130. static const char* xml =
  131. "<?xml version=\"1.0\"?>"
  132. "<!DOCTYPE PLAY SYSTEM \"play.dtd\">"
  133. "<PLAY>"
  134. "<TITLE>A Midsummer Night's Dream</TITLE>"
  135. "</PLAY>";
  136. XMLDocument doc;
  137. doc.Parse( xml );
  138. XMLElement* titleElement = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" );
  139. const char* title = titleElement->GetText();
  140. printf( "Name of play (1): %s\n", title );
  141. XMLText* textNode = titleElement->FirstChild()->ToText();
  142. title = textNode->Value();
  143. printf( "Name of play (2): %s\n", title );
  144. return doc.ErrorID();
  145. }
  146. /** @page Example_3 Get information out of XML
  147. @dontinclude ./xmltest.cpp
  148. In this example, we navigate a simple XML
  149. file, and read some interesting text. Note
  150. that this example doesn't use error
  151. checking; working code should check for null
  152. pointers when walking an XML tree, or use
  153. XMLHandle.
  154. (The XML is an excerpt from "dream.xml").
  155. @skip example_3()
  156. @until </PLAY>";
  157. The structure of the XML file is:
  158. <ul>
  159. <li>(declaration)</li>
  160. <li>(dtd stuff)</li>
  161. <li>Element "PLAY"</li>
  162. <ul>
  163. <li>Element "TITLE"</li>
  164. <ul>
  165. <li>Text "A Midsummer Night's Dream"</li>
  166. </ul>
  167. </ul>
  168. </ul>
  169. For this example, we want to print out the
  170. title of the play. The text of the title (what
  171. we want) is child of the "TITLE" element which
  172. is a child of the "PLAY" element.
  173. We want to skip the declaration and dtd, so the
  174. method FirstChildElement() is a good choice. The
  175. FirstChildElement() of the Document is the "PLAY"
  176. Element, the FirstChildElement() of the "PLAY" Element
  177. is the "TITLE" Element.
  178. @until ( "TITLE" );
  179. We can then use the convenience function GetText()
  180. to get the title of the play.
  181. @until title );
  182. Text is just another Node in the XML DOM. And in
  183. fact you should be a little cautious with it, as
  184. text nodes can contain elements.
  185. @verbatim
  186. Consider: A Midsummer Night's <b>Dream</b>
  187. @endverbatim
  188. It is more correct to actually query the Text Node
  189. if in doubt:
  190. @until title );
  191. Noting that here we use FirstChild() since we are
  192. looking for XMLText, not an element, and ToText()
  193. is a cast from a Node to a XMLText.
  194. */
  195. bool example_4()
  196. {
  197. static const char* xml =
  198. "<information>"
  199. " <attributeApproach v='2' />"
  200. " <textApproach>"
  201. " <v>2</v>"
  202. " </textApproach>"
  203. "</information>";
  204. XMLDocument doc;
  205. doc.Parse( xml );
  206. int v0 = 0;
  207. int v1 = 0;
  208. XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );
  209. attributeApproachElement->QueryIntAttribute( "v", &v0 );
  210. XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );
  211. textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );
  212. printf( "Both values are the same: %d and %d\n", v0, v1 );
  213. return !doc.Error() && ( v0 == v1 );
  214. }
  215. /** @page Example_4 Read attributes and text information.
  216. @dontinclude ./xmltest.cpp
  217. There are fundamentally 2 ways of writing a key-value
  218. pair into an XML file. (Something that's always annoyed
  219. me about XML.) Either by using attributes, or by writing
  220. the key name into an element and the value into
  221. the text node wrapped by the element. Both approaches
  222. are illustrated in this example, which shows two ways
  223. to encode the value "2" into the key "v":
  224. @skip example_4()
  225. @until "</information>";
  226. TinyXML-2 has accessors for both approaches.
  227. When using an attribute, you navigate to the XMLElement
  228. with that attribute and use the QueryIntAttribute()
  229. group of methods. (Also QueryFloatAttribute(), etc.)
  230. @skip XMLElement* attributeApproachElement
  231. @until &v0 );
  232. When using the text approach, you need to navigate
  233. down one more step to the XMLElement that contains
  234. the text. Note the extra FirstChildElement( "v" )
  235. in the code below. The value of the text can then
  236. be safely queried with the QueryIntText() group
  237. of methods. (Also QueryFloatText(), etc.)
  238. @skip XMLElement* textApproachElement
  239. @until &v1 );
  240. */
  241. int main( int argc, const char ** argv )
  242. {
  243. #if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
  244. _CrtMemCheckpoint( &startMemState );
  245. // Enable MS Visual C++ debug heap memory leaks dump on exit
  246. _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
  247. {
  248. int leaksOnStart = _CrtDumpMemoryLeaks();
  249. XMLTest( "No leaks on start?", FALSE, leaksOnStart );
  250. }
  251. #endif
  252. {
  253. TIXMLASSERT( true );
  254. }
  255. if ( argc > 1 ) {
  256. XMLDocument* doc = new XMLDocument();
  257. clock_t startTime = clock();
  258. doc->LoadFile( argv[1] );
  259. clock_t loadTime = clock();
  260. int errorID = doc->ErrorID();
  261. delete doc; doc = 0;
  262. clock_t deleteTime = clock();
  263. printf( "Test file '%s' loaded. ErrorID=%d\n", argv[1], errorID );
  264. if ( !errorID ) {
  265. printf( "Load time=%u\n", (unsigned)(loadTime - startTime) );
  266. printf( "Delete time=%u\n", (unsigned)(deleteTime - loadTime) );
  267. printf( "Total time=%u\n", (unsigned)(deleteTime - startTime) );
  268. }
  269. exit(0);
  270. }
  271. FILE* fp = fopen( "resources/dream.xml", "r" );
  272. if ( !fp ) {
  273. printf( "Error opening test file 'dream.xml'.\n"
  274. "Is your working directory the same as where \n"
  275. "the xmltest.cpp and dream.xml file are?\n\n"
  276. #if defined( _MSC_VER )
  277. "In windows Visual Studio you may need to set\n"
  278. "Properties->Debugging->Working Directory to '..'\n"
  279. #endif
  280. );
  281. exit( 1 );
  282. }
  283. fclose( fp );
  284. XMLTest( "Example_1", 0, example_1() );
  285. XMLTest( "Example_2", 0, example_2() );
  286. XMLTest( "Example_3", 0, example_3() );
  287. XMLTest( "Example_4", true, example_4() );
  288. /* ------ Example 2: Lookup information. ---- */
  289. {
  290. static const char* test[] = { "<element />",
  291. "<element></element>",
  292. "<element><subelement/></element>",
  293. "<element><subelement></subelement></element>",
  294. "<element><subelement><subsub/></subelement></element>",
  295. "<!--comment beside elements--><element><subelement></subelement></element>",
  296. "<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
  297. "<element attrib1='foo' attrib2=\"bar\" ></element>",
  298. "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
  299. "<element>Text inside element.</element>",
  300. "<element><b></b></element>",
  301. "<element>Text inside and <b>bolded</b> in the element.</element>",
  302. "<outer><element>Text inside and <b>bolded</b> in the element.</element></outer>",
  303. "<element>This &amp; That.</element>",
  304. "<element attrib='This&lt;That' />",
  305. 0
  306. };
  307. for( int i=0; test[i]; ++i ) {
  308. XMLDocument doc;
  309. doc.Parse( test[i] );
  310. XMLTest( "Element test", false, doc.Error() );
  311. doc.Print();
  312. printf( "----------------------------------------------\n" );
  313. }
  314. }
  315. #if 1
  316. {
  317. static const char* test = "<!--hello world\n"
  318. " line 2\r"
  319. " line 3\r\n"
  320. " line 4\n\r"
  321. " line 5\r-->";
  322. XMLDocument doc;
  323. doc.Parse( test );
  324. XMLTest( "Hello world declaration", false, doc.Error() );
  325. doc.Print();
  326. }
  327. {
  328. // This test is pre-test for the next one
  329. // (where Element1 is inserted "after itself".
  330. // This code didn't use to crash.
  331. XMLDocument doc;
  332. XMLElement* element1 = doc.NewElement("Element1");
  333. XMLElement* element2 = doc.NewElement("Element2");
  334. doc.InsertEndChild(element1);
  335. doc.InsertEndChild(element2);
  336. doc.InsertAfterChild(element2, element2);
  337. doc.InsertAfterChild(element2, element2);
  338. }
  339. {
  340. XMLDocument doc;
  341. XMLElement* element1 = doc.NewElement("Element1");
  342. XMLElement* element2 = doc.NewElement("Element2");
  343. doc.InsertEndChild(element1);
  344. doc.InsertEndChild(element2);
  345. // This insertion "after itself"
  346. // used to cause invalid memory access and crash
  347. doc.InsertAfterChild(element1, element1);
  348. doc.InsertAfterChild(element1, element1);
  349. doc.InsertAfterChild(element2, element2);
  350. doc.InsertAfterChild(element2, element2);
  351. }
  352. {
  353. static const char* test = "<element>Text before.</element>";
  354. XMLDocument doc;
  355. doc.Parse( test );
  356. XMLTest( "Element text before", false, doc.Error() );
  357. XMLElement* root = doc.FirstChildElement();
  358. XMLElement* newElement = doc.NewElement( "Subelement" );
  359. root->InsertEndChild( newElement );
  360. doc.Print();
  361. }
  362. {
  363. XMLDocument* doc = new XMLDocument();
  364. static const char* test = "<element><sub/></element>";
  365. doc->Parse( test );
  366. XMLTest( "Element with sub element", false, doc->Error() );
  367. delete doc;
  368. }
  369. {
  370. // Test: Programmatic DOM nodes insertion return values
  371. XMLDocument doc;
  372. XMLNode* first = doc.NewElement( "firstElement" );
  373. XMLTest( "New element", true, first != 0 );
  374. XMLNode* firstAfterInsertion = doc.InsertFirstChild( first );
  375. XMLTest( "New element inserted first", true, firstAfterInsertion == first );
  376. XMLNode* last = doc.NewElement( "lastElement" );
  377. XMLTest( "New element", true, last != 0 );
  378. XMLNode* lastAfterInsertion = doc.InsertEndChild( last );
  379. XMLTest( "New element inserted last", true, lastAfterInsertion == last );
  380. XMLNode* middle = doc.NewElement( "middleElement" );
  381. XMLTest( "New element", true, middle != 0 );
  382. XMLNode* middleAfterInsertion = doc.InsertAfterChild( first, middle );
  383. XMLTest( "New element inserted middle", true, middleAfterInsertion == middle );
  384. }
  385. {
  386. // Test: Programmatic DOM
  387. // Build:
  388. // <element>
  389. // <!--comment-->
  390. // <sub attrib="0" />
  391. // <sub attrib="1" />
  392. // <sub attrib="2" >& Text!</sub>
  393. // <element>
  394. XMLDocument* doc = new XMLDocument();
  395. XMLNode* element = doc->InsertEndChild( doc->NewElement( "element" ) );
  396. XMLElement* sub[3] = { doc->NewElement( "sub" ), doc->NewElement( "sub" ), doc->NewElement( "sub" ) };
  397. for( int i=0; i<3; ++i ) {
  398. sub[i]->SetAttribute( "attrib", i );
  399. }
  400. element->InsertEndChild( sub[2] );
  401. const int dummyInitialValue = 1000;
  402. int dummyValue = dummyInitialValue;
  403. XMLNode* comment = element->InsertFirstChild( doc->NewComment( "comment" ) );
  404. comment->SetUserData(&dummyValue);
  405. element->InsertAfterChild( comment, sub[0] );
  406. element->InsertAfterChild( sub[0], sub[1] );
  407. sub[2]->InsertFirstChild( doc->NewText( "& Text!" ));
  408. doc->Print();
  409. XMLTest( "Programmatic DOM", "comment", doc->FirstChildElement( "element" )->FirstChild()->Value() );
  410. XMLTest( "Programmatic DOM", "0", doc->FirstChildElement( "element" )->FirstChildElement()->Attribute( "attrib" ) );
  411. XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
  412. XMLTest( "Programmatic DOM", "& Text!",
  413. doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );
  414. XMLTest("User data - pointer", true, &dummyValue == comment->GetUserData(), false);
  415. XMLTest("User data - value behind pointer", dummyInitialValue, dummyValue, false);
  416. // And now deletion:
  417. element->DeleteChild( sub[2] );
  418. doc->DeleteNode( comment );
  419. element->FirstChildElement()->SetAttribute( "attrib", true );
  420. element->LastChildElement()->DeleteAttribute( "attrib" );
  421. XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );
  422. const int defaultIntValue = 10;
  423. const int replacementIntValue = 20;
  424. int value1 = defaultIntValue;
  425. int value2 = doc->FirstChildElement()->LastChildElement()->IntAttribute( "attrib", replacementIntValue );
  426. XMLError result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value1 );
  427. XMLTest( "Programmatic DOM", XML_NO_ATTRIBUTE, result );
  428. XMLTest( "Programmatic DOM", defaultIntValue, value1 );
  429. XMLTest( "Programmatic DOM", replacementIntValue, value2 );
  430. doc->Print();
  431. {
  432. XMLPrinter streamer;
  433. doc->Print( &streamer );
  434. printf( "%s", streamer.CStr() );
  435. }
  436. {
  437. XMLPrinter streamer( 0, true );
  438. doc->Print( &streamer );
  439. XMLTest( "Compact mode", "<element><sub attrib=\"true\"/><sub/></element>", streamer.CStr(), false );
  440. }
  441. doc->SaveFile( "./resources/out/pretty.xml" );
  442. XMLTest( "Save pretty.xml", false, doc->Error() );
  443. doc->SaveFile( "./resources/out/compact.xml", true );
  444. XMLTest( "Save compact.xml", false, doc->Error() );
  445. delete doc;
  446. }
  447. {
  448. // Test: Dream
  449. // XML1 : 1,187,569 bytes in 31,209 allocations
  450. // XML2 : 469,073 bytes in 323 allocations
  451. //int newStart = gNew;
  452. XMLDocument doc;
  453. doc.LoadFile( "resources/dream.xml" );
  454. XMLTest( "Load dream.xml", false, doc.Error() );
  455. doc.SaveFile( "resources/out/dreamout.xml" );
  456. XMLTest( "Save dreamout.xml", false, doc.Error() );
  457. doc.PrintError();
  458. XMLTest( "Dream", "xml version=\"1.0\"",
  459. doc.FirstChild()->ToDeclaration()->Value() );
  460. XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() != 0 );
  461. XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
  462. doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
  463. XMLTest( "Dream", "And Robin shall restore amends.",
  464. doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
  465. XMLTest( "Dream", "And Robin shall restore amends.",
  466. doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
  467. XMLDocument doc2;
  468. doc2.LoadFile( "resources/out/dreamout.xml" );
  469. XMLTest( "Load dreamout.xml", false, doc2.Error() );
  470. XMLTest( "Dream-out", "xml version=\"1.0\"",
  471. doc2.FirstChild()->ToDeclaration()->Value() );
  472. XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() != 0 );
  473. XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
  474. doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
  475. XMLTest( "Dream-out", "And Robin shall restore amends.",
  476. doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
  477. //gNewTotal = gNew - newStart;
  478. }
  479. {
  480. const char* error = "<?xml version=\"1.0\" standalone=\"no\" ?>\n"
  481. "<passages count=\"006\" formatversion=\"20020620\">\n"
  482. " <wrong error>\n"
  483. "</passages>";
  484. XMLDocument doc;
  485. doc.Parse( error );
  486. XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
  487. const char* errorStr = doc.ErrorStr();
  488. XMLTest("Formatted error string",
  489. "Error=XML_ERROR_PARSING_ATTRIBUTE ErrorID=7 (0x7) Line number=3: XMLElement name=wrong",
  490. errorStr);
  491. }
  492. {
  493. const char* str = "<doc attr0='1' attr1='2.0' attr2='foo' />";
  494. XMLDocument doc;
  495. doc.Parse( str );
  496. XMLTest( "Top level attributes", false, doc.Error() );
  497. XMLElement* ele = doc.FirstChildElement();
  498. int iVal;
  499. XMLError result;
  500. double dVal;
  501. result = ele->QueryDoubleAttribute( "attr0", &dVal );
  502. XMLTest( "Query attribute: int as double", XML_SUCCESS, result);
  503. XMLTest( "Query attribute: int as double", 1, (int)dVal );
  504. XMLTest( "Query attribute: int as double", 1, (int)ele->DoubleAttribute("attr0"));
  505. result = ele->QueryDoubleAttribute( "attr1", &dVal );
  506. XMLTest( "Query attribute: double as double", XML_SUCCESS, result);
  507. XMLTest( "Query attribute: double as double", 2.0, dVal );
  508. XMLTest( "Query attribute: double as double", 2.0, ele->DoubleAttribute("attr1") );
  509. result = ele->QueryIntAttribute( "attr1", &iVal );
  510. XMLTest( "Query attribute: double as int", XML_SUCCESS, result);
  511. XMLTest( "Query attribute: double as int", 2, iVal );
  512. result = ele->QueryIntAttribute( "attr2", &iVal );
  513. XMLTest( "Query attribute: not a number", XML_WRONG_ATTRIBUTE_TYPE, result );
  514. XMLTest( "Query attribute: not a number", 4.0, ele->DoubleAttribute("attr2", 4.0) );
  515. result = ele->QueryIntAttribute( "bar", &iVal );
  516. XMLTest( "Query attribute: does not exist", XML_NO_ATTRIBUTE, result );
  517. XMLTest( "Query attribute: does not exist", true, ele->BoolAttribute("bar", true) );
  518. }
  519. {
  520. const char* str = "<doc/>";
  521. XMLDocument doc;
  522. doc.Parse( str );
  523. XMLTest( "Empty top element", false, doc.Error() );
  524. XMLElement* ele = doc.FirstChildElement();
  525. int iVal, iVal2;
  526. double dVal, dVal2;
  527. ele->SetAttribute( "str", "strValue" );
  528. ele->SetAttribute( "int", 1 );
  529. ele->SetAttribute( "double", -1.0 );
  530. const char* answer = 0;
  531. ele->QueryAttribute("str", &answer);
  532. XMLTest("Query char attribute", "strValue", answer);
  533. const char* cStr = ele->Attribute( "str" );
  534. {
  535. XMLError queryResult = ele->QueryIntAttribute( "int", &iVal );
  536. XMLTest( "Query int attribute", XML_SUCCESS, queryResult);
  537. }
  538. {
  539. XMLError queryResult = ele->QueryDoubleAttribute( "double", &dVal );
  540. XMLTest( "Query double attribute", XML_SUCCESS, queryResult);
  541. }
  542. {
  543. XMLError queryResult = ele->QueryAttribute( "int", &iVal2 );
  544. XMLTest( "Query int attribute generic", (int)XML_SUCCESS, queryResult);
  545. }
  546. {
  547. XMLError queryResult = ele->QueryAttribute( "double", &dVal2 );
  548. XMLTest( "Query double attribute generic", (int)XML_SUCCESS, queryResult);
  549. }
  550. XMLTest( "Attribute match test", "strValue", ele->Attribute( "str", "strValue" ) );
  551. XMLTest( "Attribute round trip. c-string.", "strValue", cStr );
  552. XMLTest( "Attribute round trip. int.", 1, iVal );
  553. XMLTest( "Attribute round trip. double.", -1, (int)dVal );
  554. XMLTest( "Alternate query", true, iVal == iVal2 );
  555. XMLTest( "Alternate query", true, dVal == dVal2 );
  556. XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
  557. XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
  558. }
  559. {
  560. XMLDocument doc;
  561. doc.LoadFile( "resources/utf8test.xml" );
  562. XMLTest( "Load utf8test.xml", false, doc.Error() );
  563. // Get the attribute "value" from the "Russian" element and check it.
  564. XMLElement* element = doc.FirstChildElement( "document" )->FirstChildElement( "Russian" );
  565. const unsigned char correctValue[] = { 0xd1U, 0x86U, 0xd0U, 0xb5U, 0xd0U, 0xbdU, 0xd0U, 0xbdU,
  566. 0xd0U, 0xbeU, 0xd1U, 0x81U, 0xd1U, 0x82U, 0xd1U, 0x8cU, 0 };
  567. XMLTest( "UTF-8: Russian value.", (const char*)correctValue, element->Attribute( "value" ) );
  568. const unsigned char russianElementName[] = { 0xd0U, 0xa0U, 0xd1U, 0x83U,
  569. 0xd1U, 0x81U, 0xd1U, 0x81U,
  570. 0xd0U, 0xbaU, 0xd0U, 0xb8U,
  571. 0xd0U, 0xb9U, 0 };
  572. const char russianText[] = "<\xD0\xB8\xD0\xBC\xD0\xB5\xD0\xB5\xD1\x82>";
  573. XMLText* text = doc.FirstChildElement( "document" )->FirstChildElement( (const char*) russianElementName )->FirstChild()->ToText();
  574. XMLTest( "UTF-8: Browsing russian element name.",
  575. russianText,
  576. text->Value() );
  577. // Now try for a round trip.
  578. doc.SaveFile( "resources/out/utf8testout.xml" );
  579. XMLTest( "UTF-8: Save testout.xml", false, doc.Error() );
  580. // Check the round trip.
  581. bool roundTripOkay = false;
  582. FILE* saved = fopen( "resources/out/utf8testout.xml", "r" );
  583. XMLTest( "UTF-8: Open utf8testout.xml", true, saved != 0 );
  584. FILE* verify = fopen( "resources/utf8testverify.xml", "r" );
  585. XMLTest( "UTF-8: Open utf8testverify.xml", true, verify != 0 );
  586. if ( saved && verify )
  587. {
  588. roundTripOkay = true;
  589. char verifyBuf[256];
  590. while ( fgets( verifyBuf, 256, verify ) )
  591. {
  592. char savedBuf[256];
  593. fgets( savedBuf, 256, saved );
  594. NullLineEndings( verifyBuf );
  595. NullLineEndings( savedBuf );
  596. if ( strcmp( verifyBuf, savedBuf ) )
  597. {
  598. printf( "verify:%s<\n", verifyBuf );
  599. printf( "saved :%s<\n", savedBuf );
  600. roundTripOkay = false;
  601. break;
  602. }
  603. }
  604. }
  605. if ( saved )
  606. fclose( saved );
  607. if ( verify )
  608. fclose( verify );
  609. XMLTest( "UTF-8: Verified multi-language round trip.", true, roundTripOkay );
  610. }
  611. // --------GetText()-----------
  612. {
  613. const char* str = "<foo>This is text</foo>";
  614. XMLDocument doc;
  615. doc.Parse( str );
  616. XMLTest( "Double whitespace", false, doc.Error() );
  617. const XMLElement* element = doc.RootElement();
  618. XMLTest( "GetText() normal use.", "This is text", element->GetText() );
  619. str = "<foo><b>This is text</b></foo>";
  620. doc.Parse( str );
  621. XMLTest( "Bold text simulation", false, doc.Error() );
  622. element = doc.RootElement();
  623. XMLTest( "GetText() contained element.", element->GetText() == 0, true );
  624. }
  625. // --------SetText()-----------
  626. {
  627. const char* str = "<foo></foo>";
  628. XMLDocument doc;
  629. doc.Parse( str );
  630. XMLTest( "Empty closed element", false, doc.Error() );
  631. XMLElement* element = doc.RootElement();
  632. element->SetText("darkness.");
  633. XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
  634. element->SetText("blue flame.");
  635. XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
  636. str = "<foo/>";
  637. doc.Parse( str );
  638. XMLTest( "Empty self-closed element", false, doc.Error() );
  639. element = doc.RootElement();
  640. element->SetText("The driver");
  641. XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
  642. element->SetText("<b>horses</b>");
  643. XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
  644. //doc.Print();
  645. str = "<foo><bar>Text in nested element</bar></foo>";
  646. doc.Parse( str );
  647. XMLTest( "Text in nested element", false, doc.Error() );
  648. element = doc.RootElement();
  649. element->SetText("wolves");
  650. XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
  651. str = "<foo/>";
  652. doc.Parse( str );
  653. XMLTest( "Empty self-closed element round 2", false, doc.Error() );
  654. element = doc.RootElement();
  655. element->SetText( "str" );
  656. XMLTest( "SetText types", "str", element->GetText() );
  657. element->SetText( 1 );
  658. XMLTest( "SetText types", "1", element->GetText() );
  659. element->SetText( 1U );
  660. XMLTest( "SetText types", "1", element->GetText() );
  661. element->SetText( true );
  662. XMLTest( "SetText types", "true", element->GetText() );
  663. element->SetText( 1.5f );
  664. XMLTest( "SetText types", "1.5", element->GetText() );
  665. element->SetText( 1.5 );
  666. XMLTest( "SetText types", "1.5", element->GetText() );
  667. }
  668. // ---------- Attributes ---------
  669. {
  670. static const int64_t BIG = -123456789012345678;
  671. static const uint64_t BIG_POS = 123456789012345678;
  672. XMLDocument doc;
  673. XMLElement* element = doc.NewElement("element");
  674. doc.InsertFirstChild(element);
  675. {
  676. element->SetAttribute("attrib", int(-100));
  677. {
  678. int v = 0;
  679. XMLError queryResult = element->QueryIntAttribute("attrib", &v);
  680. XMLTest("Attribute: int", XML_SUCCESS, queryResult, true);
  681. XMLTest("Attribute: int", -100, v, true);
  682. }
  683. {
  684. int v = 0;
  685. XMLError queryResult = element->QueryAttribute("attrib", &v);
  686. XMLTest("Attribute: int", (int)XML_SUCCESS, queryResult, true);
  687. XMLTest("Attribute: int", -100, v, true);
  688. }
  689. XMLTest("Attribute: int", -100, element->IntAttribute("attrib"), true);
  690. }
  691. {
  692. element->SetAttribute("attrib", unsigned(100));
  693. {
  694. unsigned v = 0;
  695. XMLError queryResult = element->QueryUnsignedAttribute("attrib", &v);
  696. XMLTest("Attribute: unsigned", XML_SUCCESS, queryResult, true);
  697. XMLTest("Attribute: unsigned", unsigned(100), v, true);
  698. }
  699. {
  700. unsigned v = 0;
  701. XMLError queryResult = element->QueryAttribute("attrib", &v);
  702. XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
  703. XMLTest("Attribute: unsigned", unsigned(100), v, true);
  704. }
  705. {
  706. const char* v = "failed";
  707. XMLError queryResult = element->QueryStringAttribute("not-attrib", &v);
  708. XMLTest("Attribute: string default", false, queryResult == XML_SUCCESS);
  709. queryResult = element->QueryStringAttribute("attrib", &v);
  710. XMLTest("Attribute: string", XML_SUCCESS, queryResult, true);
  711. XMLTest("Attribute: string", "100", v);
  712. }
  713. XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
  714. }
  715. {
  716. element->SetAttribute("attrib", BIG);
  717. {
  718. int64_t v = 0;
  719. XMLError queryResult = element->QueryInt64Attribute("attrib", &v);
  720. XMLTest("Attribute: int64_t", XML_SUCCESS, queryResult, true);
  721. XMLTest("Attribute: int64_t", BIG, v, true);
  722. }
  723. {
  724. int64_t v = 0;
  725. XMLError queryResult = element->QueryAttribute("attrib", &v);
  726. XMLTest("Attribute: int64_t", (int)XML_SUCCESS, queryResult, true);
  727. XMLTest("Attribute: int64_t", BIG, v, true);
  728. }
  729. XMLTest("Attribute: int64_t", BIG, element->Int64Attribute("attrib"), true);
  730. }
  731. {
  732. element->SetAttribute("attrib", BIG_POS);
  733. {
  734. uint64_t v = 0;
  735. XMLError queryResult = element->QueryUnsigned64Attribute("attrib", &v);
  736. XMLTest("Attribute: uint64_t", XML_SUCCESS, queryResult, true);
  737. XMLTest("Attribute: uint64_t", BIG_POS, v, true);
  738. }
  739. {
  740. uint64_t v = 0;
  741. XMLError queryResult = element->QueryAttribute("attrib", &v);
  742. XMLTest("Attribute: uint64_t", (int)XML_SUCCESS, queryResult, true);
  743. XMLTest("Attribute: uint64_t", BIG_POS, v, true);
  744. }
  745. XMLTest("Attribute: uint64_t", BIG_POS, element->Unsigned64Attribute("attrib"), true);
  746. }
  747. {
  748. element->SetAttribute("attrib", true);
  749. {
  750. bool v = false;
  751. XMLError queryResult = element->QueryBoolAttribute("attrib", &v);
  752. XMLTest("Attribute: bool", XML_SUCCESS, queryResult, true);
  753. XMLTest("Attribute: bool", true, v, true);
  754. }
  755. {
  756. bool v = false;
  757. XMLError queryResult = element->QueryAttribute("attrib", &v);
  758. XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
  759. XMLTest("Attribute: bool", true, v, true);
  760. }
  761. XMLTest("Attribute: bool", true, element->BoolAttribute("attrib"), true);
  762. }
  763. {
  764. element->SetAttribute("attrib", true);
  765. const char* result = element->Attribute("attrib");
  766. XMLTest("Bool true is 'true'", "true", result);
  767. XMLUtil::SetBoolSerialization("1", "0");
  768. element->SetAttribute("attrib", true);
  769. result = element->Attribute("attrib");
  770. XMLTest("Bool true is '1'", "1", result);
  771. XMLUtil::SetBoolSerialization(0, 0);
  772. }
  773. {
  774. element->SetAttribute("attrib", 100.0);
  775. {
  776. double v = 0;
  777. XMLError queryResult = element->QueryDoubleAttribute("attrib", &v);
  778. XMLTest("Attribute: double", XML_SUCCESS, queryResult, true);
  779. XMLTest("Attribute: double", 100.0, v, true);
  780. }
  781. {
  782. double v = 0;
  783. XMLError queryResult = element->QueryAttribute("attrib", &v);
  784. XMLTest("Attribute: bool", (int)XML_SUCCESS, queryResult, true);
  785. XMLTest("Attribute: double", 100.0, v, true);
  786. }
  787. XMLTest("Attribute: double", 100.0, element->DoubleAttribute("attrib"), true);
  788. }
  789. {
  790. element->SetAttribute("attrib", 100.0f);
  791. {
  792. float v = 0;
  793. XMLError queryResult = element->QueryFloatAttribute("attrib", &v);
  794. XMLTest("Attribute: float", XML_SUCCESS, queryResult, true);
  795. XMLTest("Attribute: float", 100.0f, v, true);
  796. }
  797. {
  798. float v = 0;
  799. XMLError queryResult = element->QueryAttribute("attrib", &v);
  800. XMLTest("Attribute: float", (int)XML_SUCCESS, queryResult, true);
  801. XMLTest("Attribute: float", 100.0f, v, true);
  802. }
  803. XMLTest("Attribute: float", 100.0f, element->FloatAttribute("attrib"), true);
  804. }
  805. {
  806. element->SetText(BIG);
  807. int64_t v = 0;
  808. XMLError queryResult = element->QueryInt64Text(&v);
  809. XMLTest("Element: int64_t", XML_SUCCESS, queryResult, true);
  810. XMLTest("Element: int64_t", BIG, v, true);
  811. }
  812. {
  813. element->SetText(BIG_POS);
  814. uint64_t v = 0;
  815. XMLError queryResult = element->QueryUnsigned64Text(&v);
  816. XMLTest("Element: uint64_t", XML_SUCCESS, queryResult, true);
  817. XMLTest("Element: uint64_t", BIG_POS, v, true);
  818. }
  819. }
  820. // ---------- XMLPrinter stream mode ------
  821. {
  822. {
  823. FILE* printerfp = fopen("resources/out/printer.xml", "w");
  824. XMLTest("Open printer.xml", true, printerfp != 0);
  825. XMLPrinter printer(printerfp);
  826. printer.OpenElement("foo");
  827. printer.PushAttribute("attrib-text", "text");
  828. printer.PushAttribute("attrib-int", int(1));
  829. printer.PushAttribute("attrib-unsigned", unsigned(2));
  830. printer.PushAttribute("attrib-int64", int64_t(3));
  831. printer.PushAttribute("attrib-uint64", uint64_t(37));
  832. printer.PushAttribute("attrib-bool", true);
  833. printer.PushAttribute("attrib-double", 4.0);
  834. printer.CloseElement();
  835. fclose(printerfp);
  836. }
  837. {
  838. XMLDocument doc;
  839. doc.LoadFile("resources/out/printer.xml");
  840. XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
  841. const XMLDocument& cdoc = doc;
  842. const XMLAttribute* attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-text");
  843. XMLTest("attrib-text", "text", attrib->Value(), true);
  844. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int");
  845. XMLTest("attrib-int", int(1), attrib->IntValue(), true);
  846. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-unsigned");
  847. XMLTest("attrib-unsigned", unsigned(2), attrib->UnsignedValue(), true);
  848. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-int64");
  849. XMLTest("attrib-int64", int64_t(3), attrib->Int64Value(), true);
  850. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-uint64");
  851. XMLTest("attrib-uint64", uint64_t(37), attrib->Unsigned64Value(), true);
  852. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-bool");
  853. XMLTest("attrib-bool", true, attrib->BoolValue(), true);
  854. attrib = cdoc.FirstChildElement("foo")->FindAttribute("attrib-double");
  855. XMLTest("attrib-double", 4.0, attrib->DoubleValue(), true);
  856. }
  857. // Add API_testcatse :PushDeclaration();PushText();PushComment()
  858. {
  859. FILE* fp1 = fopen("resources/out/printer_1.xml", "w");
  860. XMLPrinter printer(fp1);
  861. printer.PushDeclaration("version = '1.0' enconding = 'utf-8'");
  862. printer.OpenElement("foo");
  863. printer.PushAttribute("attrib-text", "text");
  864. printer.OpenElement("text");
  865. printer.PushText("Tinyxml2");
  866. printer.CloseElement();
  867. printer.OpenElement("int");
  868. printer.PushText(int(11));
  869. printer.CloseElement();
  870. printer.OpenElement("unsigned");
  871. printer.PushText(unsigned(12));
  872. printer.CloseElement();
  873. printer.OpenElement("int64_t");
  874. printer.PushText(int64_t(13));
  875. printer.CloseElement();
  876. printer.OpenElement("uint64_t");
  877. printer.PushText(uint64_t(14));
  878. printer.CloseElement();
  879. printer.OpenElement("bool");
  880. printer.PushText(true);
  881. printer.CloseElement();
  882. printer.OpenElement("float");
  883. printer.PushText("1.56");
  884. printer.CloseElement();
  885. printer.OpenElement("double");
  886. printer.PushText("12.12");
  887. printer.CloseElement();
  888. printer.OpenElement("comment");
  889. printer.PushComment("this is Tinyxml2");
  890. printer.CloseElement();
  891. printer.CloseElement();
  892. fclose(fp1);
  893. }
  894. {
  895. XMLDocument doc;
  896. doc.LoadFile("resources/out/printer_1.xml");
  897. XMLTest("XMLPrinter Stream mode: load", XML_SUCCESS, doc.ErrorID(), true);
  898. const XMLDocument& cdoc = doc;
  899. const XMLElement* root = cdoc.FirstChildElement("foo");
  900. const char* text_value;
  901. text_value = root->FirstChildElement("text")->GetText();
  902. XMLTest("PushText( const char* text, bool cdata=false ) test", "Tinyxml2", text_value);
  903. int int_value;
  904. int_value = root->FirstChildElement("int")->IntText();
  905. XMLTest("PushText( int value ) test", 11, int_value);
  906. unsigned unsigned_value;
  907. unsigned_value = root->FirstChildElement("unsigned")->UnsignedText();
  908. XMLTest("PushText( unsigned value ) test", (unsigned)12, unsigned_value);
  909. int64_t int64_t_value;
  910. int64_t_value = root->FirstChildElement("int64_t")->Int64Text();
  911. XMLTest("PushText( int64_t value ) test", (int64_t) 13, int64_t_value);
  912. uint64_t uint64_t_value;
  913. uint64_t_value = root->FirstChildElement("uint64_t")->Unsigned64Text();
  914. XMLTest("PushText( uint64_t value ) test", (uint64_t) 14, uint64_t_value);
  915. float float_value;
  916. float_value = root->FirstChildElement("float")->FloatText();
  917. XMLTest("PushText( float value ) test", 1.56f, float_value);
  918. double double_value;
  919. double_value = root->FirstChildElement("double")->DoubleText();
  920. XMLTest("PushText( double value ) test", 12.12, double_value);
  921. bool bool_value;
  922. bool_value = root->FirstChildElement("bool")->BoolText();
  923. XMLTest("PushText( bool value ) test", true, bool_value);
  924. const XMLComment* comment = root->FirstChildElement("comment")->FirstChild()->ToComment();
  925. const char* comment_value = comment->Value();
  926. XMLTest("PushComment() test", "this is Tinyxml2", comment_value);
  927. const XMLDeclaration* declaration = cdoc.FirstChild()->ToDeclaration();
  928. const char* declaration_value = declaration->Value();
  929. XMLTest("PushDeclaration() test", "version = '1.0' enconding = 'utf-8'", declaration_value);
  930. }
  931. }
  932. // ---------- CDATA ---------------
  933. {
  934. const char* str = "<xmlElement>"
  935. "<![CDATA["
  936. "I am > the rules!\n"
  937. "...since I make symbolic puns"
  938. "]]>"
  939. "</xmlElement>";
  940. XMLDocument doc;
  941. doc.Parse( str );
  942. XMLTest( "CDATA symbolic puns round 1", false, doc.Error() );
  943. doc.Print();
  944. XMLTest( "CDATA parse.", "I am > the rules!\n...since I make symbolic puns",
  945. doc.FirstChildElement()->FirstChild()->Value(),
  946. false );
  947. }
  948. // ----------- CDATA -------------
  949. {
  950. const char* str = "<xmlElement>"
  951. "<![CDATA["
  952. "<b>I am > the rules!</b>\n"
  953. "...since I make symbolic puns"
  954. "]]>"
  955. "</xmlElement>";
  956. XMLDocument doc;
  957. doc.Parse( str );
  958. XMLTest( "CDATA symbolic puns round 2", false, doc.Error() );
  959. doc.Print();
  960. XMLTest( "CDATA parse. [ tixml1:1480107 ]",
  961. "<b>I am > the rules!</b>\n...since I make symbolic puns",
  962. doc.FirstChildElement()->FirstChild()->Value(),
  963. false );
  964. }
  965. // InsertAfterChild causes crash.
  966. {
  967. // InsertBeforeChild and InsertAfterChild causes crash.
  968. XMLDocument doc;
  969. XMLElement* parent = doc.NewElement( "Parent" );
  970. doc.InsertFirstChild( parent );
  971. XMLElement* childText0 = doc.NewElement( "childText0" );
  972. XMLElement* childText1 = doc.NewElement( "childText1" );
  973. XMLNode* childNode0 = parent->InsertEndChild( childText0 );
  974. XMLTest( "InsertEndChild() return", true, childNode0 == childText0 );
  975. XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
  976. XMLTest( "InsertAfterChild() return", true, childNode1 == childText1 );
  977. XMLTest( "Test InsertAfterChild on empty node. ", true, ( childNode1 == parent->LastChild() ) );
  978. }
  979. {
  980. // Entities not being written correctly.
  981. // From Lynn Allen
  982. const char* passages =
  983. "<?xml version=\"1.0\" standalone=\"no\" ?>"
  984. "<passages count=\"006\" formatversion=\"20020620\">"
  985. "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
  986. " It also has &lt;, &gt;, and &amp;, as well as a fake copyright &#xA9;.\"> </psg>"
  987. "</passages>";
  988. XMLDocument doc;
  989. doc.Parse( passages );
  990. XMLTest( "Entity transformation parse round 1", false, doc.Error() );
  991. XMLElement* psg = doc.RootElement()->FirstChildElement();
  992. const char* context = psg->Attribute( "context" );
  993. const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9.";
  994. XMLTest( "Entity transformation: read. ", expected, context, true );
  995. const char* textFilePath = "resources/out/textfile.txt";
  996. FILE* textfile = fopen( textFilePath, "w" );
  997. XMLTest( "Entity transformation: open text file for writing", true, textfile != 0, true );
  998. if ( textfile )
  999. {
  1000. XMLPrinter streamer( textfile );
  1001. bool acceptResult = psg->Accept( &streamer );
  1002. fclose( textfile );
  1003. XMLTest( "Entity transformation: Accept", true, acceptResult );
  1004. }
  1005. textfile = fopen( textFilePath, "r" );
  1006. XMLTest( "Entity transformation: open text file for reading", true, textfile != 0, true );
  1007. if ( textfile )
  1008. {
  1009. char buf[ 1024 ];
  1010. fgets( buf, 1024, textfile );
  1011. XMLTest( "Entity transformation: write. ",
  1012. "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;."
  1013. " It also has &lt;, &gt;, and &amp;, as well as a fake copyright \xC2\xA9.\"/>\n",
  1014. buf, false );
  1015. fclose( textfile );
  1016. }
  1017. }
  1018. {
  1019. // Suppress entities.
  1020. const char* passages =
  1021. "<?xml version=\"1.0\" standalone=\"no\" ?>"
  1022. "<passages count=\"006\" formatversion=\"20020620\">"
  1023. "<psg context=\"Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.\">Crazy &ttk;</psg>"
  1024. "</passages>";
  1025. XMLDocument doc( false );
  1026. doc.Parse( passages );
  1027. XMLTest( "Entity transformation parse round 2", false, doc.Error() );
  1028. XMLTest( "No entity parsing.",
  1029. "Line 5 has &quot;quotation marks&quot; and &apos;apostrophe marks&apos;.",
  1030. doc.FirstChildElement()->FirstChildElement()->Attribute( "context" ) );
  1031. XMLTest( "No entity parsing.", "Crazy &ttk;",
  1032. doc.FirstChildElement()->FirstChildElement()->FirstChild()->Value() );
  1033. doc.Print();
  1034. }
  1035. {
  1036. const char* test = "<?xml version='1.0'?><a.elem xmi.version='2.0'/>";
  1037. XMLDocument doc;
  1038. doc.Parse( test );
  1039. XMLTest( "dot in names", false, doc.Error() );
  1040. XMLTest( "dot in names", "a.elem", doc.FirstChildElement()->Name() );
  1041. XMLTest( "dot in names", "2.0", doc.FirstChildElement()->Attribute( "xmi.version" ) );
  1042. }
  1043. {
  1044. const char* test = "<element><Name>1.1 Start easy ignore fin thickness&#xA;</Name></element>";
  1045. XMLDocument doc;
  1046. doc.Parse( test );
  1047. XMLTest( "fin thickness", false, doc.Error() );
  1048. XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
  1049. XMLTest( "Entity with one digit.",
  1050. "1.1 Start easy ignore fin thickness\n", text->Value(),
  1051. false );
  1052. }
  1053. {
  1054. // DOCTYPE not preserved (950171)
  1055. //
  1056. const char* doctype =
  1057. "<?xml version=\"1.0\" ?>"
  1058. "<!DOCTYPE PLAY SYSTEM 'play.dtd'>"
  1059. "<!ELEMENT title (#PCDATA)>"
  1060. "<!ELEMENT books (title,authors)>"
  1061. "<element />";
  1062. XMLDocument doc;
  1063. doc.Parse( doctype );
  1064. XMLTest( "PLAY SYSTEM parse", false, doc.Error() );
  1065. doc.SaveFile( "resources/out/test7.xml" );
  1066. XMLTest( "PLAY SYSTEM save", false, doc.Error() );
  1067. doc.DeleteChild( doc.RootElement() );
  1068. doc.LoadFile( "resources/out/test7.xml" );
  1069. XMLTest( "PLAY SYSTEM load", false, doc.Error() );
  1070. doc.Print();
  1071. const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
  1072. XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
  1073. }
  1074. {
  1075. // Comments do not stream out correctly.
  1076. const char* doctype =
  1077. "<!-- Somewhat<evil> -->";
  1078. XMLDocument doc;
  1079. doc.Parse( doctype );
  1080. XMLTest( "Comment somewhat evil", false, doc.Error() );
  1081. XMLComment* comment = doc.FirstChild()->ToComment();
  1082. XMLTest( "Comment formatting.", " Somewhat<evil> ", comment->Value() );
  1083. }
  1084. {
  1085. // Double attributes
  1086. const char* doctype = "<element attr='red' attr='blue' />";
  1087. XMLDocument doc;
  1088. doc.Parse( doctype );
  1089. XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues)
  1090. doc.PrintError();
  1091. }
  1092. {
  1093. // Embedded null in stream.
  1094. const char* doctype = "<element att\0r='red' attr='blue' />";
  1095. XMLDocument doc;
  1096. doc.Parse( doctype );
  1097. XMLTest( "Embedded null throws error.", true, doc.Error() );
  1098. }
  1099. {
  1100. // Empty documents should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
  1101. const char* str = "";
  1102. XMLDocument doc;
  1103. doc.Parse( str );
  1104. XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
  1105. // But be sure there is an error string!
  1106. const char* errorStr = doc.ErrorStr();
  1107. XMLTest("Error string should be set",
  1108. "Error=XML_ERROR_EMPTY_DOCUMENT ErrorID=13 (0xd) Line number=0",
  1109. errorStr);
  1110. }
  1111. {
  1112. // Documents with all whitespaces should return TIXML_XML_ERROR_PARSING_EMPTY, bug 1070717
  1113. const char* str = " ";
  1114. XMLDocument doc;
  1115. doc.Parse( str );
  1116. XMLTest( "All whitespaces document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
  1117. }
  1118. {
  1119. // Low entities
  1120. XMLDocument doc;
  1121. doc.Parse( "<test>&#x0e;</test>" );
  1122. XMLTest( "Hex values", false, doc.Error() );
  1123. const char result[] = { 0x0e, 0 };
  1124. XMLTest( "Low entities.", result, doc.FirstChildElement()->GetText() );
  1125. doc.Print();
  1126. }
  1127. {
  1128. // Attribute values with trailing quotes not handled correctly
  1129. XMLDocument doc;
  1130. doc.Parse( "<foo attribute=bar\" />" );
  1131. XMLTest( "Throw error with bad end quotes.", true, doc.Error() );
  1132. }
  1133. {
  1134. // [ 1663758 ] Failure to report error on bad XML
  1135. XMLDocument xml;
  1136. xml.Parse("<x>");
  1137. XMLTest("Missing end tag at end of input", true, xml.Error());
  1138. xml.Parse("<x> ");
  1139. XMLTest("Missing end tag with trailing whitespace", true, xml.Error());
  1140. xml.Parse("<x></y>");
  1141. XMLTest("Mismatched tags", XML_ERROR_MISMATCHED_ELEMENT, xml.ErrorID() );
  1142. }
  1143. {
  1144. // [ 1475201 ] TinyXML parses entities in comments
  1145. XMLDocument xml;
  1146. xml.Parse("<!-- declarations for <head> & <body> -->"
  1147. "<!-- far &amp; away -->" );
  1148. XMLTest( "Declarations for head and body", false, xml.Error() );
  1149. XMLNode* e0 = xml.FirstChild();
  1150. XMLNode* e1 = e0->NextSibling();
  1151. XMLComment* c0 = e0->ToComment();
  1152. XMLComment* c1 = e1->ToComment();
  1153. XMLTest( "Comments ignore entities.", " declarations for <head> & <body> ", c0->Value(), true );
  1154. XMLTest( "Comments ignore entities.", " far &amp; away ", c1->Value(), true );
  1155. }
  1156. {
  1157. XMLDocument xml;
  1158. xml.Parse( "<Parent>"
  1159. "<child1 att=''/>"
  1160. "<!-- With this comment, child2 will not be parsed! -->"
  1161. "<child2 att=''/>"
  1162. "</Parent>" );
  1163. XMLTest( "Comments iteration", false, xml.Error() );
  1164. xml.Print();
  1165. int count = 0;
  1166. for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
  1167. ele;
  1168. ele = ele->NextSibling() )
  1169. {
  1170. ++count;
  1171. }
  1172. XMLTest( "Comments iterate correctly.", 3, count );
  1173. }
  1174. {
  1175. // trying to repro [1874301]. If it doesn't go into an infinite loop, all is well.
  1176. unsigned char buf[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?><feed><![CDATA[Test XMLblablablalblbl";
  1177. buf[60] = 239;
  1178. buf[61] = 0;
  1179. XMLDocument doc;
  1180. doc.Parse( (const char*)buf);
  1181. XMLTest( "Broken CDATA", true, doc.Error() );
  1182. }
  1183. {
  1184. // bug 1827248 Error while parsing a little bit malformed file
  1185. // Actually not malformed - should work.
  1186. XMLDocument xml;
  1187. xml.Parse( "<attributelist> </attributelist >" );
  1188. XMLTest( "Handle end tag whitespace", false, xml.Error() );
  1189. }
  1190. {
  1191. // This one must not result in an infinite loop
  1192. XMLDocument xml;
  1193. xml.Parse( "<infinite>loop" );
  1194. XMLTest( "No closing element", true, xml.Error() );
  1195. XMLTest( "Infinite loop test.", true, true );
  1196. }
  1197. #endif
  1198. {
  1199. const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
  1200. XMLDocument doc;
  1201. doc.Parse( pub );
  1202. XMLTest( "Trailing DOCTYPE", false, doc.Error() );
  1203. XMLDocument clone;
  1204. for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
  1205. XMLNode* copy = node->ShallowClone( &clone );
  1206. clone.InsertEndChild( copy );
  1207. }
  1208. clone.Print();
  1209. int count=0;
  1210. const XMLNode* a=clone.FirstChild();
  1211. const XMLNode* b=doc.FirstChild();
  1212. for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
  1213. ++count;
  1214. XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
  1215. }
  1216. XMLTest( "Clone and Equal", 4, count );
  1217. }
  1218. {
  1219. // Deep Cloning of root element.
  1220. XMLDocument doc2;
  1221. XMLPrinter printer1;
  1222. {
  1223. // Make sure doc1 is deleted before we test doc2
  1224. const char* xml =
  1225. "<root>"
  1226. " <child1 foo='bar'/>"
  1227. " <!-- comment thing -->"
  1228. " <child2 val='1'>Text</child2>"
  1229. "</root>";
  1230. XMLDocument doc;
  1231. doc.Parse(xml);
  1232. XMLTest( "Parse before deep cloning root element", false, doc.Error() );
  1233. doc.Print(&printer1);
  1234. XMLNode* root = doc.RootElement()->DeepClone(&doc2);
  1235. doc2.InsertFirstChild(root);
  1236. }
  1237. XMLPrinter printer2;
  1238. doc2.Print(&printer2);
  1239. XMLTest("Deep clone of element.", printer1.CStr(), printer2.CStr(), true);
  1240. }
  1241. {
  1242. // Deep Cloning of sub element.
  1243. XMLDocument doc2;
  1244. XMLPrinter printer1;
  1245. {
  1246. // Make sure doc1 is deleted before we test doc2
  1247. const char* xml =
  1248. "<?xml version ='1.0'?>"
  1249. "<root>"
  1250. " <child1 foo='bar'/>"
  1251. " <!-- comment thing -->"
  1252. " <child2 val='1'>Text</child2>"
  1253. "</root>";
  1254. XMLDocument doc;
  1255. doc.Parse(xml);
  1256. XMLTest( "Parse before deep cloning sub element", false, doc.Error() );
  1257. const XMLElement* subElement = doc.FirstChildElement("root")->FirstChildElement("child2");
  1258. bool acceptResult = subElement->Accept(&printer1);
  1259. XMLTest( "Accept before deep cloning", true, acceptResult );
  1260. XMLNode* clonedSubElement = subElement->DeepClone(&doc2);
  1261. doc2.InsertFirstChild(clonedSubElement);
  1262. }
  1263. XMLPrinter printer2;
  1264. doc2.Print(&printer2);
  1265. XMLTest("Deep clone of sub-element.", printer1.CStr(), printer2.CStr(), true);
  1266. }
  1267. {
  1268. // Deep cloning of document.
  1269. XMLDocument doc2;
  1270. XMLPrinter printer1;
  1271. {
  1272. // Make sure doc1 is deleted before we test doc2
  1273. const char* xml =
  1274. "<?xml version ='1.0'?>"
  1275. "<!-- Top level comment. -->"
  1276. "<root>"
  1277. " <child1 foo='bar'/>"
  1278. " <!-- comment thing -->"
  1279. " <child2 val='1'>Text</child2>"
  1280. "</root>";
  1281. XMLDocument doc;
  1282. doc.Parse(xml);
  1283. XMLTest( "Parse before deep cloning document", false, doc.Error() );
  1284. doc.Print(&printer1);
  1285. doc.DeepCopy(&doc2);
  1286. }
  1287. XMLPrinter printer2;
  1288. doc2.Print(&printer2);
  1289. XMLTest("DeepCopy of document.", printer1.CStr(), printer2.CStr(), true);
  1290. }
  1291. {
  1292. // This shouldn't crash.
  1293. XMLDocument doc;
  1294. if(XML_SUCCESS != doc.LoadFile( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ))
  1295. {
  1296. doc.PrintError();
  1297. }
  1298. XMLTest( "Error in snprinf handling.", true, doc.Error() );
  1299. }
  1300. {
  1301. // Attribute ordering.
  1302. static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";
  1303. XMLDocument doc;
  1304. doc.Parse( xml );
  1305. XMLTest( "Parse for attribute ordering", false, doc.Error() );
  1306. XMLElement* ele = doc.FirstChildElement();
  1307. const XMLAttribute* a = ele->FirstAttribute();
  1308. XMLTest( "Attribute order", "1", a->Value() );
  1309. a = a->Next();
  1310. XMLTest( "Attribute order", "2", a->Value() );
  1311. a = a->Next();
  1312. XMLTest( "Attribute order", "3", a->Value() );
  1313. XMLTest( "Attribute order", "attrib3", a->Name() );
  1314. ele->DeleteAttribute( "attrib2" );
  1315. a = ele->FirstAttribute();
  1316. XMLTest( "Attribute order", "1", a->Value() );
  1317. a = a->Next();
  1318. XMLTest( "Attribute order", "3", a->Value() );
  1319. ele->DeleteAttribute( "attrib1" );
  1320. ele->DeleteAttribute( "attrib3" );
  1321. XMLTest( "Attribute order (empty)", true, ele->FirstAttribute() == 0 );
  1322. }
  1323. {
  1324. // Make sure an attribute with a space in it succeeds.
  1325. static const char* xml0 = "<element attribute1= \"Test Attribute\"/>";
  1326. static const char* xml1 = "<element attribute1 =\"Test Attribute\"/>";
  1327. static const char* xml2 = "<element attribute1 = \"Test Attribute\"/>";
  1328. XMLDocument doc0;
  1329. doc0.Parse( xml0 );
  1330. XMLTest( "Parse attribute with space 1", false, doc0.Error() );
  1331. XMLDocument doc1;
  1332. doc1.Parse( xml1 );
  1333. XMLTest( "Parse attribute with space 2", false, doc1.Error() );
  1334. XMLDocument doc2;
  1335. doc2.Parse( xml2 );
  1336. XMLTest( "Parse attribute with space 3", false, doc2.Error() );
  1337. XMLElement* ele = 0;
  1338. ele = doc0.FirstChildElement();
  1339. XMLTest( "Attribute with space #1", "Test Attribute", ele->Attribute( "attribute1" ) );
  1340. ele = doc1.FirstChildElement();
  1341. XMLTest( "Attribute with space #2", "Test Attribute", ele->Attribute( "attribute1" ) );
  1342. ele = doc2.FirstChildElement();
  1343. XMLTest( "Attribute with space #3", "Test Attribute", ele->Attribute( "attribute1" ) );
  1344. }
  1345. {
  1346. // Make sure we don't go into an infinite loop.
  1347. static const char* xml = "<doc><element attribute='attribute'/><element attribute='attribute'/></doc>";
  1348. XMLDocument doc;
  1349. doc.Parse( xml );
  1350. XMLTest( "Parse two elements with attribute", false, doc.Error() );
  1351. XMLElement* ele0 = doc.FirstChildElement()->FirstChildElement();
  1352. XMLElement* ele1 = ele0->NextSiblingElement();
  1353. bool equal = ele0->ShallowEqual( ele1 );
  1354. XMLTest( "Infinite loop in shallow equal.", true, equal );
  1355. }
  1356. // -------- Handles ------------
  1357. {
  1358. static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
  1359. XMLDocument doc;
  1360. doc.Parse( xml );
  1361. XMLTest( "Handle, parse element with attribute and nested element", false, doc.Error() );
  1362. {
  1363. XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
  1364. XMLTest( "Handle, non-const, element is found", true, ele != 0 );
  1365. XMLTest( "Handle, non-const, element name matches", "sub", ele->Value() );
  1366. }
  1367. {
  1368. XMLHandle docH( doc );
  1369. XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
  1370. XMLTest( "Handle, non-const, element not found", true, ele == 0 );
  1371. }
  1372. {
  1373. const XMLElement* ele = XMLConstHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
  1374. XMLTest( "Handle, const, element is found", true, ele != 0 );
  1375. XMLTest( "Handle, const, element name matches", "sub", ele->Value() );
  1376. }
  1377. {
  1378. XMLConstHandle docH( doc );
  1379. const XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
  1380. XMLTest( "Handle, const, element not found", true, ele == 0 );
  1381. }
  1382. }
  1383. {
  1384. // Default Declaration & BOM
  1385. XMLDocument doc;
  1386. doc.InsertEndChild( doc.NewDeclaration() );
  1387. doc.SetBOM( true );
  1388. XMLPrinter printer;
  1389. doc.Print( &printer );
  1390. static const char* result = "\xef\xbb\xbf<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
  1391. XMLTest( "BOM and default declaration", result, printer.CStr(), false );
  1392. XMLTest( "CStrSize", 42, printer.CStrSize(), false );
  1393. }
  1394. {
  1395. const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";
  1396. XMLDocument doc;
  1397. doc.Parse( xml );
  1398. XMLTest( "Ill formed XML", true, doc.Error() );
  1399. }
  1400. {
  1401. //API:IntText(),UnsignedText(),Int64Text(),DoubleText(),BoolText() and FloatText() test
  1402. const char* xml = "<point> <IntText>-24</IntText> <UnsignedText>42</UnsignedText> \
  1403. <Int64Text>38</Int64Text> <BoolText>true</BoolText> <DoubleText>2.35</DoubleText> </point>";
  1404. XMLDocument doc;
  1405. doc.Parse(xml);
  1406. const XMLElement* pointElement = doc.RootElement();
  1407. int test1 = pointElement->FirstChildElement("IntText")->IntText();
  1408. XMLTest("IntText() test", -24, test1);
  1409. unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
  1410. XMLTest("UnsignedText() test", static_cast<unsigned>(42), test2);
  1411. int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
  1412. XMLTest("Int64Text() test", static_cast<int64_t>(38), test3);
  1413. double test4 = pointElement->FirstChildElement("DoubleText")->DoubleText();
  1414. XMLTest("DoubleText() test", 2.35, test4);
  1415. float test5 = pointElement->FirstChildElement("DoubleText")->FloatText();
  1416. XMLTest("FloatText()) test", 2.35f, test5);
  1417. bool test6 = pointElement->FirstChildElement("BoolText")->BoolText();
  1418. XMLTest("FloatText()) test", true, test6);
  1419. }
  1420. {
  1421. // hex value test
  1422. const char* xml = "<point> <IntText> 0x2020</IntText> <UnsignedText>0X2020</UnsignedText> \
  1423. <Int64Text> 0x1234</Int64Text></point>";
  1424. XMLDocument doc;
  1425. doc.Parse(xml);
  1426. const XMLElement* pointElement = doc.RootElement();
  1427. int test1 = pointElement->FirstChildElement("IntText")->IntText();
  1428. XMLTest("IntText() hex value test", 0x2020, test1);
  1429. unsigned test2 = pointElement->FirstChildElement("UnsignedText")->UnsignedText();
  1430. XMLTest("UnsignedText() hex value test", static_cast<unsigned>(0x2020), test2);
  1431. int64_t test3 = pointElement->FirstChildElement("Int64Text")->Int64Text();
  1432. XMLTest("Int64Text() hex value test", static_cast<int64_t>(0x1234), test3);
  1433. }
  1434. {
  1435. //API:ShallowEqual() test
  1436. const char* xml = "<playlist id = 'playlist'>"
  1437. "<property name = 'track_name'>voice</property>"
  1438. "</playlist>";
  1439. XMLDocument doc;
  1440. doc.Parse( xml );
  1441. const XMLNode* PlaylistNode = doc.RootElement();
  1442. const XMLNode* PropertyNode = PlaylistNode->FirstChildElement();
  1443. bool result;
  1444. result = PlaylistNode->ShallowEqual(PropertyNode);
  1445. XMLTest("ShallowEqual() test",false,result);
  1446. result = PlaylistNode->ShallowEqual(PlaylistNode);
  1447. XMLTest("ShallowEqual() test",true,result);
  1448. }
  1449. {
  1450. //API: previousSiblingElement() and NextSiblingElement() test
  1451. const char* xml = "<playlist id = 'playlist'>"
  1452. "<property name = 'track_name'>voice</property>"
  1453. "<entry out = '946' producer = '2_playlist1' in = '0'/>"
  1454. "<blank length = '1'/>"
  1455. "</playlist>";
  1456. XMLDocument doc;
  1457. doc.Parse( xml );
  1458. XMLElement* ElementPlaylist = doc.FirstChildElement("playlist");
  1459. XMLTest("previousSiblingElement() test",true,ElementPlaylist != 0);
  1460. const XMLElement* pre = ElementPlaylist->PreviousSiblingElement();
  1461. XMLTest("previousSiblingElement() test",true,pre == 0);
  1462. const XMLElement* ElementBlank = ElementPlaylist->FirstChildElement("entry")->NextSiblingElement("blank");
  1463. XMLTest("NextSiblingElement() test",true,ElementBlank != 0);
  1464. const XMLElement* next = ElementBlank->NextSiblingElement();
  1465. XMLTest("NextSiblingElement() test",true,next == 0);
  1466. const XMLElement* ElementEntry = ElementBlank->PreviousSiblingElement("entry");
  1467. XMLTest("PreviousSiblingElement test",true,ElementEntry != 0);
  1468. }
  1469. // QueryXYZText
  1470. {
  1471. const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";
  1472. XMLDocument doc;
  1473. doc.Parse( xml );
  1474. XMLTest( "Parse points", false, doc.Error() );
  1475. const XMLElement* pointElement = doc.RootElement();
  1476. {
  1477. int intValue = 0;
  1478. XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );
  1479. XMLTest( "QueryIntText result", XML_SUCCESS, queryResult, false );
  1480. XMLTest( "QueryIntText", 1, intValue, false );
  1481. }
  1482. {
  1483. unsigned unsignedValue = 0;
  1484. XMLError queryResult = pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );
  1485. XMLTest( "QueryUnsignedText result", XML_SUCCESS, queryResult, false );
  1486. XMLTest( "QueryUnsignedText", (unsigned)1, unsignedValue, false );
  1487. }
  1488. {
  1489. float floatValue = 0;
  1490. XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );
  1491. XMLTest( "QueryFloatText result", XML_SUCCESS, queryResult, false );
  1492. XMLTest( "QueryFloatText", 1.2f, floatValue, false );
  1493. }
  1494. {
  1495. double doubleValue = 0;
  1496. XMLError queryResult = pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );
  1497. XMLTest( "QueryDoubleText result", XML_SUCCESS, queryResult, false );
  1498. XMLTest( "QueryDoubleText", 1.2, doubleValue, false );
  1499. }
  1500. {
  1501. bool boolValue = false;
  1502. XMLError queryResult = pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );
  1503. XMLTest( "QueryBoolText result", XML_SUCCESS, queryResult, false );
  1504. XMLTest( "QueryBoolText", true, boolValue, false );
  1505. }
  1506. }
  1507. {
  1508. const char* xml = "<element><_sub/><:sub/><sub:sub/><sub-sub/></element>";
  1509. XMLDocument doc;
  1510. doc.Parse( xml );
  1511. XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
  1512. }
  1513. {
  1514. const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
  1515. XMLDocument doc;
  1516. doc.Parse( xml );
  1517. XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
  1518. }
  1519. {
  1520. const char* xml = "<3lement></3lement>";
  1521. XMLDocument doc;
  1522. doc.Parse( xml );
  1523. XMLTest("Element names with lead digit fail to parse.", true, doc.Error());
  1524. }
  1525. {
  1526. const char* xml = "<element/>WOA THIS ISN'T GOING TO PARSE";
  1527. XMLDocument doc;
  1528. doc.Parse( xml, 10 );
  1529. XMLTest( "Set length of incoming data", false, doc.Error() );
  1530. }
  1531. {
  1532. XMLDocument doc;
  1533. XMLTest( "Document is initially empty", true, doc.NoChildren() );
  1534. doc.Clear();
  1535. XMLTest( "Empty is empty after Clear()", true, doc.NoChildren() );
  1536. doc.LoadFile( "resources/dream.xml" );
  1537. XMLTest( "Load dream.xml", false, doc.Error() );
  1538. XMLTest( "Document has something to Clear()", false, doc.NoChildren() );
  1539. doc.Clear();
  1540. XMLTest( "Document Clear()'s", true, doc.NoChildren() );
  1541. }
  1542. {
  1543. XMLDocument doc;
  1544. XMLTest( "No error initially", false, doc.Error() );
  1545. XMLError error = doc.Parse( "This is not XML" );
  1546. XMLTest( "Error after invalid XML", true, doc.Error() );
  1547. XMLTest( "Error after invalid XML", error, doc.ErrorID() );
  1548. doc.Clear();
  1549. XMLTest( "No error after Clear()", false, doc.Error() );
  1550. }
  1551. // ----------- Whitespace ------------
  1552. {
  1553. const char* xml = "<element>"
  1554. "<a> This \nis &apos; text &apos; </a>"
  1555. "<b> This is &apos; text &apos; \n</b>"
  1556. "<c>This is &apos; \n\n text &apos;</c>"
  1557. "</element>";
  1558. XMLDocument doc( true, COLLAPSE_WHITESPACE );
  1559. doc.Parse( xml );
  1560. XMLTest( "Parse with whitespace collapsing and &apos", false, doc.Error() );
  1561. const XMLElement* element = doc.FirstChildElement();
  1562. for( const XMLElement* parent = element->FirstChildElement();
  1563. parent;
  1564. parent = parent->NextSiblingElement() )
  1565. {
  1566. XMLTest( "Whitespace collapse", "This is ' text '", parent->GetText() );
  1567. }
  1568. }
  1569. #if 0
  1570. {
  1571. // Passes if assert doesn't fire.
  1572. XMLDocument xmlDoc;
  1573. xmlDoc.NewDeclaration();
  1574. xmlDoc.NewComment("Configuration file");
  1575. XMLElement *root = xmlDoc.NewElement("settings");
  1576. root->SetAttribute("version", 2);
  1577. }
  1578. #endif
  1579. {
  1580. const char* xml = "<element> </element>";
  1581. XMLDocument doc( true, COLLAPSE_WHITESPACE );
  1582. doc.Parse( xml );
  1583. XMLTest( "Parse with all whitespaces", false, doc.Error() );
  1584. XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
  1585. }
  1586. // ----------- Preserve Whitespace ------------
  1587. {
  1588. const char* xml = "<element>This is &apos; \n\n text &apos;</element>";
  1589. XMLDocument doc(true, PRESERVE_WHITESPACE);
  1590. doc.Parse(xml);
  1591. XMLTest("Parse with whitespace preserved", false, doc.Error());
  1592. XMLTest("Whitespace preserved", "This is ' \n\n text '", doc.FirstChildElement()->GetText());
  1593. }
  1594. {
  1595. const char* xml = "<element> This \nis &apos; text &apos; </element>";
  1596. XMLDocument doc(true, PRESERVE_WHITESPACE);
  1597. doc.Parse(xml);
  1598. XMLTest("Parse with whitespace preserved", false, doc.Error());
  1599. XMLTest("Whitespace preserved", " This \nis ' text ' ", doc.FirstChildElement()->GetText());
  1600. }
  1601. {
  1602. const char* xml = "<element> \n This is &apos; text &apos; \n</element>";
  1603. XMLDocument doc(true, PRESERVE_WHITESPACE);
  1604. doc.Parse(xml);
  1605. XMLTest("Parse with whitespace preserved", false, doc.Error());
  1606. XMLTest("Whitespace preserved", " \n This is ' text ' \n", doc.FirstChildElement()->GetText());
  1607. }
  1608. // Following cases are for text that is all whitespace which are not preserved intentionally
  1609. {
  1610. const char* xml = "<element> </element>";
  1611. XMLDocument doc(true, PRESERVE_WHITESPACE);
  1612. doc.Parse(xml);
  1613. XMLTest("Parse with whitespace preserved", false, doc.Error());
  1614. XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
  1615. }
  1616. {
  1617. const char* xml = "<element> </element>";
  1618. XMLDocument doc(true, PRESERVE_WHITESPACE);
  1619. doc.Parse(xml);
  1620. XMLTest("Parse with whitespace preserved", false, doc.Error());
  1621. XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
  1622. }
  1623. {
  1624. const char* xml = "<element>\n\n</element>";
  1625. XMLDocument doc(true, PRESERVE_WHITESPACE);
  1626. doc.Parse(xml);
  1627. XMLTest("Parse with whitespace preserved", false, doc.Error());
  1628. XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
  1629. }
  1630. {
  1631. const char* xml = "<element> \n</element>";
  1632. XMLDocument doc(true, PRESERVE_WHITESPACE);
  1633. doc.Parse(xml);
  1634. XMLTest("Parse with whitespace preserved", false, doc.Error());
  1635. XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
  1636. }
  1637. {
  1638. const char* xml = "<element> \n \n </element>";
  1639. XMLDocument doc(true, PRESERVE_WHITESPACE);
  1640. doc.Parse(xml);
  1641. XMLTest("Parse with whitespace preserved", false, doc.Error());
  1642. XMLTest("Whitespace preserved", true, 0 == doc.FirstChildElement()->GetText());
  1643. }
  1644. // ----------- Pedantic Whitespace ------------
  1645. {
  1646. const char* xml = "<element>This is &apos; \n\n text &apos;</element>";
  1647. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1648. doc.Parse(xml);
  1649. XMLTest("Parse with pedantic whitespace", false, doc.Error());
  1650. XMLTest("Pedantic whitespace", "This is ' \n\n text '", doc.FirstChildElement()->GetText());
  1651. }
  1652. {
  1653. const char* xml = "<element> This \nis &apos; text &apos; </element>";
  1654. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1655. doc.Parse(xml);
  1656. XMLTest("Parse with pedantic whitespace", false, doc.Error());
  1657. XMLTest("Pedantic whitespace", " This \nis ' text ' ", doc.FirstChildElement()->GetText());
  1658. }
  1659. {
  1660. const char* xml = "<element> \n This is &apos; text &apos; \n</element>";
  1661. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1662. doc.Parse(xml);
  1663. XMLTest("Parse with pedantic whitespace", false, doc.Error());
  1664. XMLTest("Pedantic whitespace", " \n This is ' text ' \n", doc.FirstChildElement()->GetText());
  1665. }
  1666. // Following cases are for text that is all whitespace which is preserved with pedantic mode
  1667. {
  1668. const char* xml = "<element> </element>";
  1669. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1670. doc.Parse(xml);
  1671. XMLTest("Parse with pedantic whitespace", false, doc.Error());
  1672. XMLTest("Pedantic whitespace", " ", doc.FirstChildElement()->GetText());
  1673. }
  1674. {
  1675. const char* xml = "<element> </element>";
  1676. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1677. doc.Parse(xml);
  1678. XMLTest("Parse with pedantic whitespace", false, doc.Error());
  1679. XMLTest("Pedantic whitespace", " ", doc.FirstChildElement()->GetText());
  1680. }
  1681. {
  1682. const char* xml = "<element>\n\n</element>\n";
  1683. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1684. doc.Parse(xml);
  1685. XMLTest("Parse with pedantic whitespace", false, doc.Error());
  1686. XMLTest("Pedantic whitespace", "\n\n", doc.FirstChildElement()->GetText());
  1687. }
  1688. {
  1689. const char* xml = "<element> \n</element> \n ";
  1690. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1691. doc.Parse(xml);
  1692. XMLTest("Parse with pedantic whitespace", false, doc.Error());
  1693. XMLTest("Pedantic whitespace", " \n", doc.FirstChildElement()->GetText());
  1694. }
  1695. {
  1696. const char* xml = "<element> \n \n </element> ";
  1697. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1698. doc.Parse(xml);
  1699. XMLTest("Parse with pedantic whitespace", false, doc.Error());
  1700. XMLTest("Pedantic whitespace", " \n \n ", doc.FirstChildElement()->GetText());
  1701. }
  1702. // Following cases are for checking nested elements are still parsed with pedantic whitespace
  1703. {
  1704. const char* xml = "<element>\n\t<a> This is nested text </a>\n</element> ";
  1705. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1706. doc.Parse(xml);
  1707. XMLTest("Parse nested elements with pedantic whitespace", false, doc.Error());
  1708. XMLTest("Pedantic whitespace", " This is nested text ", doc.RootElement()->FirstChildElement()->GetText());
  1709. }
  1710. {
  1711. const char* xml = "<element> <b> </b> </element>\n";
  1712. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1713. doc.Parse(xml);
  1714. XMLTest("Parse nested elements with pedantic whitespace", false, doc.Error());
  1715. XMLTest("Pedantic whitespace", " ", doc.RootElement()->FirstChildElement()->GetText());
  1716. }
  1717. {
  1718. const char* xml = "<element> <c attribute=\"test\"/> </element>\n ";
  1719. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1720. doc.Parse(xml);
  1721. XMLTest("Parse nested elements with pedantic whitespace", false, doc.Error());
  1722. XMLTest("Pedantic whitespace", true, 0 == doc.RootElement()->FirstChildElement()->GetText());
  1723. }
  1724. // Check sample xml can be parsed with pedantic mode
  1725. {
  1726. XMLDocument doc(true, PEDANTIC_WHITESPACE);
  1727. doc.LoadFile("resources/dream.xml");
  1728. XMLTest("Load dream.xml with pedantic whitespace mode", false, doc.Error());
  1729. XMLTest("Dream", "xml version=\"1.0\"",
  1730. doc.FirstChild()->ToDeclaration()->Value());
  1731. XMLTest("Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() != 0);
  1732. XMLTest("Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
  1733. doc.FirstChild()->NextSibling()->ToUnknown()->Value());
  1734. XMLTest("Dream", "And Robin shall restore amends.",
  1735. doc.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText());
  1736. }
  1737. {
  1738. // An assert should not fire.
  1739. const char* xml = "<element/>";
  1740. XMLDocument doc;
  1741. doc.Parse( xml );
  1742. XMLTest( "Parse with self-closed element", false, doc.Error() );
  1743. XMLElement* ele = doc.NewElement( "unused" ); // This will get cleaned up with the 'doc' going out of scope.
  1744. XMLTest( "Tracking unused elements", true, ele != 0, false );
  1745. }
  1746. {
  1747. const char* xml = "<parent><child>abc</child></parent>";
  1748. XMLDocument doc;
  1749. doc.Parse( xml );
  1750. XMLTest( "Parse for printing of sub-element", false, doc.Error() );
  1751. XMLElement* ele = doc.FirstChildElement( "parent")->FirstChildElement( "child");
  1752. XMLPrinter printer;
  1753. bool acceptResult = ele->Accept( &printer );
  1754. XMLTest( "Accept of sub-element", true, acceptResult );
  1755. XMLTest( "Printing of sub-element", "<child>abc</child>\n", printer.CStr(), false );
  1756. }
  1757. {
  1758. XMLDocument doc;
  1759. XMLError error = doc.LoadFile( "resources/empty.xml" );
  1760. XMLTest( "Loading an empty file", XML_ERROR_EMPTY_DOCUMENT, error );
  1761. XMLTest( "Loading an empty file and ErrorName as string", "XML_ERROR_EMPTY_DOCUMENT", doc.ErrorName() );
  1762. doc.PrintError();
  1763. }
  1764. {
  1765. // BOM preservation
  1766. static const char* xml_bom_preservation = "\xef\xbb\xbf<element/>\n";
  1767. {
  1768. XMLDocument doc;
  1769. XMLTest( "BOM preservation (parse)", XML_SUCCESS, doc.Parse( xml_bom_preservation ), false );
  1770. XMLPrinter printer;
  1771. doc.Print( &printer );
  1772. XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
  1773. doc.SaveFile( "resources/out/bomtest.xml" );
  1774. XMLTest( "Save bomtest.xml", false, doc.Error() );
  1775. }
  1776. {
  1777. XMLDocument doc;
  1778. doc.LoadFile( "resources/out/bomtest.xml" );
  1779. XMLTest( "Load bomtest.xml", false, doc.Error() );
  1780. XMLTest( "BOM preservation (load)", true, doc.HasBOM(), false );
  1781. XMLPrinter printer;
  1782. doc.Print( &printer );
  1783. XMLTest( "BOM preservation (compare)", xml_bom_preservation, printer.CStr(), false, true );
  1784. }
  1785. }
  1786. {
  1787. // Insertion with Removal
  1788. const char* xml = "<?xml version=\"1.0\" ?>"
  1789. "<root>"
  1790. "<one>"
  1791. "<subtree>"
  1792. "<elem>element 1</elem>text<!-- comment -->"
  1793. "</subtree>"
  1794. "</one>"
  1795. "<two/>"
  1796. "</root>";
  1797. const char* xmlInsideTwo = "<?xml version=\"1.0\" ?>"
  1798. "<root>"
  1799. "<one/>"
  1800. "<two>"
  1801. "<subtree>"
  1802. "<elem>element 1</elem>text<!-- comment -->"
  1803. "</subtree>"
  1804. "</two>"
  1805. "</root>";
  1806. const char* xmlAfterOne = "<?xml version=\"1.0\" ?>"
  1807. "<root>"
  1808. "<one/>"
  1809. "<subtree>"
  1810. "<elem>element 1</elem>text<!-- comment -->"
  1811. "</subtree>"
  1812. "<two/>"
  1813. "</root>";
  1814. const char* xmlAfterTwo = "<?xml version=\"1.0\" ?>"
  1815. "<root>"
  1816. "<one/>"
  1817. "<two/>"
  1818. "<subtree>"
  1819. "<elem>element 1</elem>text<!-- comment -->"
  1820. "</subtree>"
  1821. "</root>";
  1822. XMLDocument doc;
  1823. doc.Parse(xml);
  1824. XMLTest( "Insertion with removal parse round 1", false, doc.Error() );
  1825. XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
  1826. XMLElement* two = doc.RootElement()->FirstChildElement("two");
  1827. two->InsertFirstChild(subtree);
  1828. XMLPrinter printer1(0, true);
  1829. bool acceptResult = doc.Accept(&printer1);
  1830. XMLTest("Move node from within <one> to <two> - Accept()", true, acceptResult);
  1831. XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
  1832. doc.Parse(xml);
  1833. XMLTest( "Insertion with removal parse round 2", false, doc.Error() );
  1834. subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
  1835. two = doc.RootElement()->FirstChildElement("two");
  1836. doc.RootElement()->InsertAfterChild(two, subtree);
  1837. XMLPrinter printer2(0, true);
  1838. acceptResult = doc.Accept(&printer2);
  1839. XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
  1840. XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
  1841. doc.Parse(xml);
  1842. XMLTest( "Insertion with removal parse round 3", false, doc.Error() );
  1843. XMLNode* one = doc.RootElement()->FirstChildElement("one");
  1844. subtree = one->FirstChildElement("subtree");
  1845. doc.RootElement()->InsertAfterChild(one, subtree);
  1846. XMLPrinter printer3(0, true);
  1847. acceptResult = doc.Accept(&printer3);
  1848. XMLTest("Move node from within <one> after <one> - Accept()", true, acceptResult);
  1849. XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
  1850. doc.Parse(xml);
  1851. XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
  1852. subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
  1853. two = doc.RootElement()->FirstChildElement("two");
  1854. XMLTest("<two> is the last child at root level", true, two == doc.RootElement()->LastChildElement());
  1855. doc.RootElement()->InsertEndChild(subtree);
  1856. XMLPrinter printer4(0, true);
  1857. acceptResult = doc.Accept(&printer4);
  1858. XMLTest("Move node from within <one> after <two> - Accept()", true, acceptResult);
  1859. XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
  1860. }
  1861. {
  1862. const char* xml = "<svg width = \"128\" height = \"128\">"
  1863. " <text> </text>"
  1864. "</svg>";
  1865. XMLDocument doc;
  1866. doc.Parse(xml);
  1867. XMLTest( "Parse svg with text", false, doc.Error() );
  1868. doc.Print();
  1869. }
  1870. {
  1871. // Test that it doesn't crash.
  1872. const char* xml = "<?xml version=\"1.0\"?><root><sample><field0><1</field0><field1>2</field1></sample></root>";
  1873. XMLDocument doc;
  1874. doc.Parse(xml);
  1875. XMLTest( "Parse root-sample-field0", true, doc.Error() );
  1876. doc.PrintError();
  1877. }
  1878. #if 1
  1879. // the question being explored is what kind of print to use:
  1880. // https://github.com/leethomason/tinyxml2/issues/63
  1881. {
  1882. //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
  1883. const char* xml = "<element/>";
  1884. XMLDocument doc;
  1885. doc.Parse( xml );
  1886. XMLTest( "Parse self-closed empty element", false, doc.Error() );
  1887. doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
  1888. doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
  1889. doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
  1890. doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
  1891. doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
  1892. doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
  1893. doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
  1894. doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
  1895. doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
  1896. doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
  1897. doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
  1898. doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
  1899. doc.Print();
  1900. /* The result of this test is platform, compiler, and library version dependent. :("
  1901. XMLPrinter printer;
  1902. doc.Print( &printer );
  1903. XMLTest( "Float and double formatting.",
  1904. "<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",
  1905. printer.CStr(),
  1906. true );
  1907. */
  1908. }
  1909. #endif
  1910. {
  1911. // Issue #184
  1912. // If it doesn't assert, it passes. Caused by objects
  1913. // getting created during parsing which are then
  1914. // inaccessible in the memory pools.
  1915. const char* xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test>";
  1916. {
  1917. XMLDocument doc;
  1918. doc.Parse(xmlText);
  1919. XMLTest( "Parse hex no closing tag round 1", true, doc.Error() );
  1920. }
  1921. {
  1922. XMLDocument doc;
  1923. doc.Parse(xmlText);
  1924. XMLTest( "Parse hex no closing tag round 2", true, doc.Error() );
  1925. doc.Clear();
  1926. }
  1927. }
  1928. {
  1929. // If this doesn't assert in TINYXML2_DEBUG, all is well.
  1930. tinyxml2::XMLDocument doc;
  1931. tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
  1932. doc.DeleteNode(pRoot);
  1933. }
  1934. {
  1935. XMLDocument doc;
  1936. XMLElement* root = doc.NewElement( "Root" );
  1937. XMLTest( "Node document before insertion", true, &doc == root->GetDocument() );
  1938. doc.InsertEndChild( root );
  1939. XMLTest( "Node document after insertion", true, &doc == root->GetDocument() );
  1940. }
  1941. {
  1942. // If this doesn't assert in TINYXML2_DEBUG, all is well.
  1943. XMLDocument doc;
  1944. XMLElement* unlinkedRoot = doc.NewElement( "Root" );
  1945. XMLElement* linkedRoot = doc.NewElement( "Root" );
  1946. doc.InsertFirstChild( linkedRoot );
  1947. unlinkedRoot->GetDocument()->DeleteNode( linkedRoot );
  1948. unlinkedRoot->GetDocument()->DeleteNode( unlinkedRoot );
  1949. }
  1950. {
  1951. // Should not assert in TINYXML2_DEBUG
  1952. XMLPrinter printer;
  1953. }
  1954. {
  1955. // Issue 291. Should not crash
  1956. const char* xml = "&#0</a>";
  1957. XMLDocument doc;
  1958. doc.Parse( xml );
  1959. XMLTest( "Parse hex with closing tag", false, doc.Error() );
  1960. XMLPrinter printer;
  1961. doc.Print( &printer );
  1962. }
  1963. {
  1964. // Issue 299. Can print elements that are not linked in.
  1965. // Will crash if issue not fixed.
  1966. XMLDocument doc;
  1967. XMLElement* newElement = doc.NewElement( "printme" );
  1968. XMLPrinter printer;
  1969. bool acceptResult = newElement->Accept( &printer );
  1970. XMLTest( "printme - Accept()", true, acceptResult );
  1971. // Delete the node to avoid possible memory leak report in debug output
  1972. doc.DeleteNode( newElement );
  1973. }
  1974. {
  1975. // Issue 302. Clear errors from LoadFile/SaveFile
  1976. XMLDocument doc;
  1977. XMLTest( "Issue 302. Should be no error initially", "XML_SUCCESS", doc.ErrorName() );
  1978. doc.SaveFile( "./no/such/path/pretty.xml" );
  1979. XMLTest( "Issue 302. Fail to save", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", doc.ErrorName() );
  1980. doc.SaveFile( "./resources/out/compact.xml", true );
  1981. XMLTest( "Issue 302. Subsequent success in saving", "XML_SUCCESS", doc.ErrorName() );
  1982. }
  1983. {
  1984. // If a document fails to load then subsequent
  1985. // successful loads should clear the error
  1986. XMLDocument doc;
  1987. XMLTest( "Should be no error initially", false, doc.Error() );
  1988. doc.LoadFile( "resources/no-such-file.xml" );
  1989. XMLTest( "No such file - should fail", true, doc.Error() );
  1990. doc.LoadFile("resources/dream.xml");
  1991. XMLTest("Error should be cleared", false, doc.Error());
  1992. doc.LoadFile( "resources/xmltest-5330.xml" );
  1993. XMLTest( "parse errors occur - should fail", true, doc.Error() );
  1994. doc.LoadFile( "resources/dream.xml" );
  1995. XMLTest( "Error should be cleared", false, doc.Error() );
  1996. }
  1997. {
  1998. // Check that declarations are allowed only at beginning of document
  1999. const char* xml0 = "<?xml version=\"1.0\" ?>"
  2000. " <!-- xml version=\"1.1\" -->"
  2001. "<first />";
  2002. const char* xml1 = "<?xml version=\"1.0\" ?>"
  2003. "<?xml-stylesheet type=\"text/xsl\" href=\"Anything.xsl\"?>"
  2004. "<first />";
  2005. const char* xml2 = "<first />"
  2006. "<?xml version=\"1.0\" ?>";
  2007. const char* xml3 = "<first></first>"
  2008. "<?xml version=\"1.0\" ?>";
  2009. const char* xml4 = "<first><?xml version=\"1.0\" ?></first>";
  2010. XMLDocument doc;
  2011. doc.Parse(xml0);
  2012. XMLTest("Test that the code changes do not affect normal parsing", false, doc.Error() );
  2013. doc.Parse(xml1);
  2014. XMLTest("Test that the second declaration is allowed", false, doc.Error() );
  2015. doc.Parse(xml2);
  2016. XMLTest("Test that declaration after self-closed child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
  2017. doc.Parse(xml3);
  2018. XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
  2019. doc.Parse(xml4);
  2020. XMLTest("Test that declaration inside a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
  2021. }
  2022. {
  2023. // No matter - before or after successfully parsing a text -
  2024. // calling XMLDocument::Value() used to cause an assert in debug.
  2025. // Null must be returned.
  2026. const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
  2027. "<first />"
  2028. "<second />";
  2029. XMLDocument* doc = new XMLDocument();
  2030. XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
  2031. doc->Parse( validXml );
  2032. XMLTest( "Parse to test XMLDocument::Value()", false, doc->Error());
  2033. XMLTest( "XMLDocument::Value() returns null?", NULL, doc->Value() );
  2034. delete doc;
  2035. }
  2036. {
  2037. XMLDocument doc;
  2038. for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
  2039. const XMLError error = static_cast<XMLError>(i);
  2040. const char* name = XMLDocument::ErrorIDToName(error);
  2041. XMLTest( "ErrorName() not null after ClearError()", true, name != 0 );
  2042. if( name == 0 ) {
  2043. // passing null pointer into strlen() is undefined behavior, so
  2044. // compiler is allowed to optimise away the null test above if it's
  2045. // as reachable as the strlen() call
  2046. continue;
  2047. }
  2048. XMLTest( "ErrorName() not empty after ClearError()", true, strlen(name) > 0 );
  2049. }
  2050. }
  2051. {
  2052. const char* html("<!DOCTYPE html><html><body><p>test</p><p><br/></p></body></html>");
  2053. XMLDocument doc(false);
  2054. doc.Parse(html);
  2055. XMLPrinter printer(0, true);
  2056. doc.Print(&printer);
  2057. XMLTest(html, html, printer.CStr());
  2058. }
  2059. {
  2060. // Evil memory leaks.
  2061. // If an XMLElement (etc) is allocated via NewElement() (etc.)
  2062. // and NOT added to the XMLDocument, what happens?
  2063. //
  2064. // Previously (buggy):
  2065. // The memory would be free'd when the XMLDocument is
  2066. // destructed. But the XMLElement destructor wasn't called, so
  2067. // memory allocated for the XMLElement text would not be free'd.
  2068. // In practice this meant strings allocated for the XMLElement
  2069. // text would be leaked. An edge case, but annoying.
  2070. // Now:
  2071. // The XMLElement destructor is called. But the unlinked nodes
  2072. // have to be tracked using a list. This has a minor performance
  2073. // impact that can become significant if you have a lot of
  2074. // unlinked nodes. (But why would you do that?)
  2075. // The only way to see this bug was in a Visual C++ runtime debug heap
  2076. // leak tracker. This is compiled in by default on Windows Debug and
  2077. // enabled with _CRTDBG_LEAK_CHECK_DF parameter passed to _CrtSetDbgFlag().
  2078. {
  2079. XMLDocument doc;
  2080. doc.NewElement("LEAK 1");
  2081. }
  2082. {
  2083. XMLDocument doc;
  2084. XMLElement* ele = doc.NewElement("LEAK 2");
  2085. doc.DeleteNode(ele);
  2086. }
  2087. }
  2088. {
  2089. // Bad bad crash. Parsing error results in stack overflow, if uncaught.
  2090. const char* TESTS[] = {
  2091. "./resources/xmltest-5330.xml",
  2092. "./resources/xmltest-4636783552757760.xml",
  2093. "./resources/xmltest-5720541257269248.xml",
  2094. 0
  2095. };
  2096. for (int i=0; TESTS[i]; ++i) {
  2097. XMLDocument doc;
  2098. doc.LoadFile(TESTS[i]);
  2099. XMLTest("Stack overflow prevented.", XML_ELEMENT_DEPTH_EXCEEDED, doc.ErrorID());
  2100. }
  2101. }
  2102. {
  2103. const char* TESTS[] = {
  2104. "./resources/xmltest-5662204197076992.xml", // Security-level performance issue.
  2105. 0
  2106. };
  2107. for (int i = 0; TESTS[i]; ++i) {
  2108. XMLDocument doc;
  2109. doc.LoadFile(TESTS[i]);
  2110. // Need only not crash / lock up.
  2111. XMLTest("Fuzz attack prevented.", true, true);
  2112. }
  2113. }
  2114. {
  2115. // Crashing reported via email.
  2116. const char* xml =
  2117. "<playlist id='playlist1'>"
  2118. "<property name='track_name'>voice</property>"
  2119. "<property name='audio_track'>1</property>"
  2120. "<entry out = '604' producer = '4_playlist1' in = '0' />"
  2121. "<blank length = '1' />"
  2122. "<entry out = '1625' producer = '3_playlist' in = '0' />"
  2123. "<blank length = '2' />"
  2124. "<entry out = '946' producer = '2_playlist1' in = '0' />"
  2125. "<blank length = '1' />"
  2126. "<entry out = '128' producer = '1_playlist1' in = '0' />"
  2127. "</playlist>";
  2128. // It's not a good idea to delete elements as you walk the
  2129. // list. I'm not sure this technically should work; but it's
  2130. // an interesting test case.
  2131. XMLDocument doc;
  2132. XMLError err = doc.Parse(xml);
  2133. XMLTest("Crash bug parsing", XML_SUCCESS, err );
  2134. XMLElement* playlist = doc.FirstChildElement("playlist");
  2135. XMLTest("Crash bug parsing", true, playlist != 0);
  2136. {
  2137. const char* elementName = "entry";
  2138. XMLElement* entry = playlist->FirstChildElement(elementName);
  2139. XMLTest("Crash bug parsing", true, entry != 0);
  2140. while (entry) {
  2141. XMLElement* todelete = entry;
  2142. entry = entry->NextSiblingElement(elementName);
  2143. playlist->DeleteChild(todelete);
  2144. }
  2145. entry = playlist->FirstChildElement(elementName);
  2146. XMLTest("Crash bug parsing", true, entry == 0);
  2147. }
  2148. {
  2149. const char* elementName = "blank";
  2150. XMLElement* blank = playlist->FirstChildElement(elementName);
  2151. XMLTest("Crash bug parsing", true, blank != 0);
  2152. while (blank) {
  2153. XMLElement* todelete = blank;
  2154. blank = blank->NextSiblingElement(elementName);
  2155. playlist->DeleteChild(todelete);
  2156. }
  2157. XMLTest("Crash bug parsing", true, blank == 0);
  2158. }
  2159. tinyxml2::XMLPrinter printer;
  2160. const bool acceptResult = playlist->Accept(&printer);
  2161. XMLTest("Crash bug parsing - Accept()", true, acceptResult);
  2162. printf("%s\n", printer.CStr());
  2163. // No test; it only need to not crash.
  2164. // Still, wrap it up with a sanity check
  2165. int nProperty = 0;
  2166. for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
  2167. nProperty++;
  2168. }
  2169. XMLTest("Crash bug parsing", 2, nProperty);
  2170. }
  2171. // ----------- Line Number Tracking --------------
  2172. {
  2173. struct TestUtil: XMLVisitor
  2174. {
  2175. TestUtil() : str() {}
  2176. void TestParseError(const char *testString, const char *docStr, XMLError expected_error, int expectedLine)
  2177. {
  2178. XMLDocument doc;
  2179. const XMLError parseError = doc.Parse(docStr);
  2180. XMLTest(testString, parseError, doc.ErrorID());
  2181. XMLTest(testString, true, doc.Error());
  2182. XMLTest(testString, expected_error, parseError);
  2183. XMLTest(testString, expectedLine, doc.ErrorLineNum());
  2184. };
  2185. void TestStringLines(const char *testString, const char *docStr, const char *expectedLines)
  2186. {
  2187. XMLDocument doc;
  2188. doc.Parse(docStr);
  2189. XMLTest(testString, false, doc.Error());
  2190. TestDocLines(testString, doc, expectedLines);
  2191. }
  2192. void TestFileLines(const char *testString, const char *file_name, const char *expectedLines)
  2193. {
  2194. XMLDocument doc;
  2195. doc.LoadFile(file_name);
  2196. XMLTest(testString, false, doc.Error());
  2197. TestDocLines(testString, doc, expectedLines);
  2198. }
  2199. private:
  2200. DynArray<char, 10> str;
  2201. void Push(char type, int lineNum)
  2202. {
  2203. str.Push(type);
  2204. str.Push(char('0' + (lineNum / 10)));
  2205. str.Push(char('0' + (lineNum % 10)));
  2206. }
  2207. bool VisitEnter(const XMLDocument& doc)
  2208. {
  2209. Push('D', doc.GetLineNum());
  2210. return true;
  2211. }
  2212. bool VisitEnter(const XMLElement& element, const XMLAttribute* firstAttribute)
  2213. {
  2214. Push('E', element.GetLineNum());
  2215. for (const XMLAttribute *attr = firstAttribute; attr != 0; attr = attr->Next())
  2216. Push('A', attr->GetLineNum());
  2217. return true;
  2218. }
  2219. bool Visit(const XMLDeclaration& declaration)
  2220. {
  2221. Push('L', declaration.GetLineNum());
  2222. return true;
  2223. }
  2224. bool Visit(const XMLText& text)
  2225. {
  2226. Push('T', text.GetLineNum());
  2227. return true;
  2228. }
  2229. bool Visit(const XMLComment& comment)
  2230. {
  2231. Push('C', comment.GetLineNum());
  2232. return true;
  2233. }
  2234. bool Visit(const XMLUnknown& unknown)
  2235. {
  2236. Push('U', unknown.GetLineNum());
  2237. return true;
  2238. }
  2239. void TestDocLines(const char *testString, XMLDocument &doc, const char *expectedLines)
  2240. {
  2241. str.Clear();
  2242. const bool acceptResult = doc.Accept(this);
  2243. XMLTest(testString, true, acceptResult);
  2244. str.Push(0);
  2245. XMLTest(testString, expectedLines, str.Mem());
  2246. }
  2247. } tester;
  2248. tester.TestParseError("ErrorLine-Parsing", "\n<root>\n foo \n<unclosed/>", XML_ERROR_PARSING, 2);
  2249. tester.TestParseError("ErrorLine-Declaration", "<root>\n<?xml version=\"1.0\"?>", XML_ERROR_PARSING_DECLARATION, 2);
  2250. tester.TestParseError("ErrorLine-Mismatch", "\n<root>\n</mismatch>", XML_ERROR_MISMATCHED_ELEMENT, 2);
  2251. tester.TestParseError("ErrorLine-CData", "\n<root><![CDATA[ \n foo bar \n", XML_ERROR_PARSING_CDATA, 2);
  2252. tester.TestParseError("ErrorLine-Text", "\n<root>\n foo bar \n", XML_ERROR_PARSING_TEXT, 3);
  2253. tester.TestParseError("ErrorLine-Comment", "\n<root>\n<!-- >\n", XML_ERROR_PARSING_COMMENT, 3);
  2254. tester.TestParseError("ErrorLine-Declaration", "\n<root>\n<? >\n", XML_ERROR_PARSING_DECLARATION, 3);
  2255. tester.TestParseError("ErrorLine-Unknown", "\n<root>\n<! \n", XML_ERROR_PARSING_UNKNOWN, 3);
  2256. tester.TestParseError("ErrorLine-Element", "\n<root>\n<unclosed \n", XML_ERROR_PARSING_ELEMENT, 3);
  2257. tester.TestParseError("ErrorLine-Attribute", "\n<root>\n<unclosed \n att\n", XML_ERROR_PARSING_ATTRIBUTE, 4);
  2258. tester.TestParseError("ErrorLine-ElementClose", "\n<root>\n<unclosed \n/unexpected", XML_ERROR_PARSING_ELEMENT, 3);
  2259. tester.TestStringLines(
  2260. "LineNumbers-String",
  2261. "<?xml version=\"1.0\"?>\n" // 1 Doc, DecL
  2262. "<root a='b' \n" // 2 Element Attribute
  2263. "c='d'> d <blah/> \n" // 3 Attribute Text Element
  2264. "newline in text \n" // 4 Text
  2265. "and second <zxcv/><![CDATA[\n" // 5 Element Text
  2266. " cdata test ]]><!-- comment -->\n" // 6 Comment
  2267. "<! unknown></root>", // 7 Unknown
  2268. "D01L01E02A02A03T03E03T04E05T05C06U07");
  2269. tester.TestStringLines(
  2270. "LineNumbers-CRLF",
  2271. "\r\n" // 1 Doc (arguably should be line 2)
  2272. "<?xml version=\"1.0\"?>\n" // 2 DecL
  2273. "<root>\r\n" // 3 Element
  2274. "\n" // 4
  2275. "text contining new line \n" // 5 Text
  2276. " and also containing crlf \r\n" // 6
  2277. "<sub><![CDATA[\n" // 7 Element Text
  2278. "cdata containing new line \n" // 8
  2279. " and also containing cflr\r\n" // 9
  2280. "]]></sub><sub2/></root>", // 10 Element
  2281. "D01L02E03T05E07T07E10");
  2282. tester.TestFileLines(
  2283. "LineNumbers-File",
  2284. "resources/utf8test.xml",
  2285. "D01L01E02E03A03A03T03E04A04A04T04E05A05A05T05E06A06A06T06E07A07A07T07E08A08A08T08E09T09E10T10");
  2286. }
  2287. {
  2288. const char* xml = "<Hello>Text</Error>";
  2289. XMLDocument doc;
  2290. doc.Parse(xml);
  2291. XMLTest("Test mismatched elements.", true, doc.Error());
  2292. XMLTest("Test mismatched elements.", XML_ERROR_MISMATCHED_ELEMENT, doc.ErrorID());
  2293. // For now just make sure calls work & doesn't crash.
  2294. // May solidify the error output in the future.
  2295. printf("%s\n", doc.ErrorStr());
  2296. doc.PrintError();
  2297. }
  2298. // ----------- Performance tracking --------------
  2299. {
  2300. #if defined( _MSC_VER )
  2301. __int64 start, end, freq;
  2302. QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
  2303. #endif
  2304. FILE* perfFP = fopen("resources/dream.xml", "r");
  2305. XMLTest("Open dream.xml", true, perfFP != 0);
  2306. fseek(perfFP, 0, SEEK_END);
  2307. long size = ftell(perfFP);
  2308. fseek(perfFP, 0, SEEK_SET);
  2309. char* mem = new char[size + 1];
  2310. memset(mem, 0xfe, size);
  2311. size_t bytesRead = fread(mem, 1, size, perfFP);
  2312. XMLTest("Read dream.xml", true, uint32_t(size) >= uint32_t(bytesRead));
  2313. fclose(perfFP);
  2314. mem[size] = 0;
  2315. #if defined( _MSC_VER )
  2316. QueryPerformanceCounter((LARGE_INTEGER*)&start);
  2317. #else
  2318. clock_t cstart = clock();
  2319. #endif
  2320. bool parseDreamXmlFailed = false;
  2321. static const int COUNT = 10;
  2322. for (int i = 0; i < COUNT; ++i) {
  2323. XMLDocument doc;
  2324. doc.Parse(mem);
  2325. parseDreamXmlFailed = parseDreamXmlFailed || doc.Error();
  2326. }
  2327. #if defined( _MSC_VER )
  2328. QueryPerformanceCounter((LARGE_INTEGER*)&end);
  2329. #else
  2330. clock_t cend = clock();
  2331. #endif
  2332. XMLTest( "Parse dream.xml", false, parseDreamXmlFailed );
  2333. delete[] mem;
  2334. static const char* note =
  2335. #ifdef TINYXML2_DEBUG
  2336. "DEBUG";
  2337. #else
  2338. "Release";
  2339. #endif
  2340. #if defined( _MSC_VER )
  2341. const double duration = 1000.0 * (double)(end - start) / ((double)freq * (double)COUNT);
  2342. #else
  2343. const double duration = (double)(cend - cstart) / (double)COUNT;
  2344. #endif
  2345. printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
  2346. }
  2347. #if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
  2348. {
  2349. _CrtMemCheckpoint( &endMemState );
  2350. _CrtMemState diffMemState;
  2351. _CrtMemDifference( &diffMemState, &startMemState, &endMemState );
  2352. _CrtMemDumpStatistics( &diffMemState );
  2353. {
  2354. int leaksBeforeExit = _CrtDumpMemoryLeaks();
  2355. XMLTest( "No leaks before exit?", FALSE, leaksBeforeExit );
  2356. }
  2357. }
  2358. #endif
  2359. printf ("\nPass %d, Fail %d\n", gPass, gFail);
  2360. return gFail;
  2361. }