xmltest.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: tests/xml/xmltest.cpp
  3. // Purpose: XML classes unit test
  4. // Author: Vaclav Slavik
  5. // Created: 2008-03-29
  6. // Copyright: (c) 2008 Vaclav Slavik
  7. ///////////////////////////////////////////////////////////////////////////////
  8. // ----------------------------------------------------------------------------
  9. // headers
  10. // ----------------------------------------------------------------------------
  11. #include "testprec.h"
  12. #ifdef __BORLANDC__
  13. #pragma hdrstop
  14. #endif
  15. #ifndef WX_PRECOMP
  16. #include "wx/wx.h"
  17. #endif // WX_PRECOMP
  18. #include "wx/xml/xml.h"
  19. #include "wx/scopedptr.h"
  20. #include "wx/sstream.h"
  21. #include <stdarg.h>
  22. // ----------------------------------------------------------------------------
  23. // helpers for testing XML tree
  24. // ----------------------------------------------------------------------------
  25. namespace
  26. {
  27. void CheckXml(const wxXmlNode *n, ...)
  28. {
  29. va_list args;
  30. va_start(args, n);
  31. wxXmlNode *child = n->GetChildren();
  32. for (;;)
  33. {
  34. const char *childName = va_arg(args, char*);
  35. if ( childName == NULL )
  36. break;
  37. CPPUNIT_ASSERT( child );
  38. CPPUNIT_ASSERT_EQUAL( childName, child->GetName() );
  39. CPPUNIT_ASSERT( child->GetChildren() == NULL );
  40. CPPUNIT_ASSERT( child->GetParent() == n );
  41. child = child->GetNext();
  42. }
  43. va_end(args);
  44. CPPUNIT_ASSERT( child == NULL ); // no more children
  45. }
  46. } // anon namespace
  47. // ----------------------------------------------------------------------------
  48. // test class
  49. // ----------------------------------------------------------------------------
  50. class XmlTestCase : public CppUnit::TestCase
  51. {
  52. public:
  53. XmlTestCase() {}
  54. private:
  55. CPPUNIT_TEST_SUITE( XmlTestCase );
  56. CPPUNIT_TEST( InsertChild );
  57. CPPUNIT_TEST( InsertChildAfter );
  58. CPPUNIT_TEST( LoadSave );
  59. CPPUNIT_TEST( CDATA );
  60. CPPUNIT_TEST( PI );
  61. CPPUNIT_TEST( Escaping );
  62. CPPUNIT_TEST( DetachRoot );
  63. CPPUNIT_TEST( AppendToProlog );
  64. CPPUNIT_TEST( SetRoot );
  65. CPPUNIT_TEST( CopyNode );
  66. CPPUNIT_TEST_SUITE_END();
  67. void InsertChild();
  68. void InsertChildAfter();
  69. void LoadSave();
  70. void CDATA();
  71. void PI();
  72. void Escaping();
  73. void DetachRoot();
  74. void AppendToProlog();
  75. void SetRoot();
  76. void CopyNode();
  77. DECLARE_NO_COPY_CLASS(XmlTestCase)
  78. };
  79. // register in the unnamed registry so that these tests are run by default
  80. CPPUNIT_TEST_SUITE_REGISTRATION( XmlTestCase );
  81. // also include in its own registry so that these tests can be run alone
  82. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( XmlTestCase, "XmlTestCase" );
  83. void XmlTestCase::InsertChild()
  84. {
  85. wxScopedPtr<wxXmlNode> root(new wxXmlNode(wxXML_ELEMENT_NODE, "root"));
  86. root->AddChild(new wxXmlNode(wxXML_ELEMENT_NODE, "1"));
  87. wxXmlNode *two = new wxXmlNode(wxXML_ELEMENT_NODE, "2");
  88. root->AddChild(two);
  89. root->AddChild(new wxXmlNode(wxXML_ELEMENT_NODE, "3"));
  90. CheckXml(root.get(), "1", "2", "3", NULL);
  91. // check inserting in front:
  92. root->InsertChild(new wxXmlNode(wxXML_ELEMENT_NODE, "A"), NULL);
  93. CheckXml(root.get(), "A", "1", "2", "3", NULL);
  94. root->InsertChild(new wxXmlNode(wxXML_ELEMENT_NODE, "B"), root->GetChildren());
  95. CheckXml(root.get(), "B", "A", "1", "2", "3", NULL);
  96. // and in the middle:
  97. root->InsertChild(new wxXmlNode(wxXML_ELEMENT_NODE, "C"), two);
  98. CheckXml(root.get(), "B", "A", "1", "C", "2", "3", NULL);
  99. }
  100. void XmlTestCase::InsertChildAfter()
  101. {
  102. wxScopedPtr<wxXmlNode> root(new wxXmlNode(wxXML_ELEMENT_NODE, "root"));
  103. root->InsertChildAfter(new wxXmlNode(wxXML_ELEMENT_NODE, "1"), NULL);
  104. CheckXml(root.get(), "1", NULL);
  105. wxXmlNode *two = new wxXmlNode(wxXML_ELEMENT_NODE, "2");
  106. root->AddChild(two);
  107. wxXmlNode *three = new wxXmlNode(wxXML_ELEMENT_NODE, "3");
  108. root->AddChild(three);
  109. CheckXml(root.get(), "1", "2", "3", NULL);
  110. // check inserting in the middle:
  111. root->InsertChildAfter(new wxXmlNode(wxXML_ELEMENT_NODE, "A"), root->GetChildren());
  112. CheckXml(root.get(), "1", "A", "2", "3", NULL);
  113. root->InsertChildAfter(new wxXmlNode(wxXML_ELEMENT_NODE, "B"), two);
  114. CheckXml(root.get(), "1", "A", "2", "B", "3", NULL);
  115. // and at the end:
  116. root->InsertChildAfter(new wxXmlNode(wxXML_ELEMENT_NODE, "C"), three);
  117. CheckXml(root.get(), "1", "A", "2", "B", "3", "C", NULL);
  118. }
  119. void XmlTestCase::LoadSave()
  120. {
  121. // NB: this is not real XRC but rather some XRC-like XML fragment which
  122. // exercises different XML constructs to check that they're saved back
  123. // correctly
  124. //
  125. // Also note that there should be no blank lines here as they disappear
  126. // after saving.
  127. const char *xmlText =
  128. "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
  129. "<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
  130. " <!-- Test comment -->\n"
  131. " <object class=\"wxDialog\" name=\"my_dialog\">\n"
  132. " <children>\n"
  133. " <grandchild id=\"1\"/>\n"
  134. " </children>\n"
  135. " <subobject/>\n"
  136. " </object>\n"
  137. "</resource>\n"
  138. ;
  139. wxStringInputStream sis(xmlText);
  140. wxXmlDocument doc;
  141. CPPUNIT_ASSERT( doc.Load(sis) );
  142. wxStringOutputStream sos;
  143. CPPUNIT_ASSERT( doc.Save(sos) );
  144. CPPUNIT_ASSERT_EQUAL( xmlText, sos.GetString() );
  145. #if wxUSE_UNICODE
  146. const char *utf8xmlText =
  147. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  148. "<word>\n"
  149. " <lang name=\"fr\">\xc3\xa9t\xc3\xa9</lang>\n"
  150. " <lang name=\"ru\">\xd0\xbb\xd0\xb5\xd1\x82\xd0\xbe</lang>\n"
  151. "</word>\n"
  152. ;
  153. wxStringInputStream sis8(wxString::FromUTF8(utf8xmlText));
  154. CPPUNIT_ASSERT( doc.Load(sis8) );
  155. // this contents can't be represented in Latin-1 as it contains Cyrillic
  156. // letters
  157. doc.SetFileEncoding("ISO-8859-1");
  158. CPPUNIT_ASSERT( !doc.Save(sos) );
  159. // but it should work in UTF-8
  160. wxStringOutputStream sos8;
  161. doc.SetFileEncoding("UTF-8");
  162. CPPUNIT_ASSERT( doc.Save(sos8) );
  163. CPPUNIT_ASSERT_EQUAL( wxString(utf8xmlText),
  164. wxString(sos8.GetString().ToUTF8()) );
  165. #endif // wxUSE_UNICODE
  166. const char *xmlTextProlog =
  167. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  168. "<!-- Prolog comment -->\n"
  169. "<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
  170. "<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
  171. " <!-- Test comment -->\n"
  172. " <object class=\"wxDialog\" name=\"my_dialog\">\n"
  173. " <children>\n"
  174. " <grandchild id=\"1\"/>\n"
  175. " </children>\n"
  176. " <subobject/>\n"
  177. " </object>\n"
  178. "</resource>\n"
  179. "<!-- Trailing comment -->\n"
  180. ;
  181. wxStringInputStream sisp(xmlTextProlog);
  182. CPPUNIT_ASSERT( doc.Load(sisp, "UTF-8") );
  183. wxStringOutputStream sosp;
  184. CPPUNIT_ASSERT( doc.Save(sosp) );
  185. CPPUNIT_ASSERT_EQUAL( xmlTextProlog, sosp.GetString() );
  186. }
  187. void XmlTestCase::CDATA()
  188. {
  189. const char *xmlText =
  190. "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
  191. "<name>\n"
  192. " <![CDATA[Giovanni Mittone]]>\n"
  193. "</name>\n"
  194. ;
  195. wxStringInputStream sis(xmlText);
  196. wxXmlDocument doc;
  197. CPPUNIT_ASSERT( doc.Load(sis) );
  198. wxXmlNode *n = doc.GetRoot();
  199. CPPUNIT_ASSERT( n );
  200. n = n->GetChildren();
  201. CPPUNIT_ASSERT( n );
  202. // check that both leading (" ") and trailing white space is not part of
  203. // the node contents when CDATA is used and wxXMLDOC_KEEP_WHITESPACE_NODES
  204. // is not
  205. CPPUNIT_ASSERT_EQUAL( "Giovanni Mittone", n->GetContent() );
  206. }
  207. void XmlTestCase::PI()
  208. {
  209. const char *xmlText =
  210. "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
  211. "<root>\n"
  212. " <?robot index=\"no\" follow=\"no\"?>\n"
  213. "</root>\n"
  214. ;
  215. wxStringInputStream sis(xmlText);
  216. wxXmlDocument doc;
  217. CPPUNIT_ASSERT( doc.Load(sis) );
  218. wxXmlNode *n = doc.GetRoot();
  219. CPPUNIT_ASSERT( n );
  220. n = n->GetChildren();
  221. CPPUNIT_ASSERT( n );
  222. CPPUNIT_ASSERT_EQUAL( "index=\"no\" follow=\"no\"", n->GetContent() );
  223. }
  224. void XmlTestCase::Escaping()
  225. {
  226. // Verify that attribute values are escaped correctly, see
  227. // http://trac.wxwidgets.org/ticket/12275
  228. const char *xmlText =
  229. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  230. "<root text=\"hello&#xD;&#xA;this is a new line\">\n"
  231. " <x/>\n"
  232. "</root>\n"
  233. ;
  234. wxStringInputStream sis(xmlText);
  235. wxXmlDocument doc;
  236. CPPUNIT_ASSERT( doc.Load(sis) );
  237. wxStringOutputStream sos;
  238. CPPUNIT_ASSERT( doc.Save(sos) );
  239. CPPUNIT_ASSERT_EQUAL( xmlText, sos.GetString() );
  240. }
  241. void XmlTestCase::DetachRoot()
  242. {
  243. const char *xmlTextProlog =
  244. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  245. "<!-- Prolog comment -->\n"
  246. "<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
  247. "<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
  248. " <!-- Test comment -->\n"
  249. " <object class=\"wxDialog\" name=\"my_dialog\">\n"
  250. " <children>\n"
  251. " <grandchild id=\"1\"/>\n"
  252. " </children>\n"
  253. " <subobject/>\n"
  254. " </object>\n"
  255. "</resource>\n"
  256. "<!-- Trailing comment -->\n"
  257. ;
  258. const char *xmlTextHtm =
  259. "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
  260. "<html>\n"
  261. " <head>\n"
  262. " <title>Testing wxXml</title>\n"
  263. " </head>\n"
  264. " <body>\n"
  265. " <p>Some body text</p>\n"
  266. " </body>\n"
  267. "</html>\n"
  268. ;
  269. wxXmlDocument doc;
  270. wxStringInputStream sish(xmlTextHtm);
  271. CPPUNIT_ASSERT( doc.Load(sish) );
  272. wxXmlNode *root = doc.DetachRoot();
  273. wxStringInputStream sisp(xmlTextProlog);
  274. CPPUNIT_ASSERT( doc.Load(sisp) );
  275. doc.SetRoot(root);
  276. wxStringOutputStream sos;
  277. CPPUNIT_ASSERT( doc.Save(sos) );
  278. const char *xmlTextResult1 =
  279. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  280. "<!-- Prolog comment -->\n"
  281. "<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
  282. "<html>\n"
  283. " <head>\n"
  284. " <title>Testing wxXml</title>\n"
  285. " </head>\n"
  286. " <body>\n"
  287. " <p>Some body text</p>\n"
  288. " </body>\n"
  289. "</html>\n"
  290. "<!-- Trailing comment -->\n"
  291. ;
  292. CPPUNIT_ASSERT_EQUAL( xmlTextResult1, sos.GetString() );
  293. wxStringInputStream sisp2(xmlTextProlog);
  294. CPPUNIT_ASSERT( doc.Load(sisp2) );
  295. root = doc.DetachRoot();
  296. wxStringInputStream sish2(xmlTextHtm);
  297. CPPUNIT_ASSERT( doc.Load(sish2) );
  298. doc.SetRoot(root);
  299. wxStringOutputStream sos2;
  300. CPPUNIT_ASSERT( doc.Save(sos2) );
  301. const char *xmlTextResult2 =
  302. "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
  303. "<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
  304. " <!-- Test comment -->\n"
  305. " <object class=\"wxDialog\" name=\"my_dialog\">\n"
  306. " <children>\n"
  307. " <grandchild id=\"1\"/>\n"
  308. " </children>\n"
  309. " <subobject/>\n"
  310. " </object>\n"
  311. "</resource>\n"
  312. ;
  313. CPPUNIT_ASSERT_EQUAL( xmlTextResult2, sos2.GetString() );
  314. }
  315. void XmlTestCase::AppendToProlog()
  316. {
  317. const char *xmlText =
  318. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  319. "<root>\n"
  320. " <p>Some text</p>\n"
  321. "</root>\n"
  322. ;
  323. wxXmlDocument rootdoc;
  324. wxStringInputStream sis(xmlText);
  325. CPPUNIT_ASSERT( rootdoc.Load(sis) );
  326. wxXmlNode *root = rootdoc.DetachRoot();
  327. wxXmlNode *comment1 = new wxXmlNode(wxXML_COMMENT_NODE, "comment",
  328. " 1st prolog entry ");
  329. wxXmlNode *pi = new wxXmlNode(wxXML_PI_NODE, "xml-stylesheet",
  330. "href=\"style.css\" type=\"text/css\"");
  331. wxXmlNode *comment2 = new wxXmlNode(wxXML_COMMENT_NODE, "comment",
  332. " 3rd prolog entry ");
  333. wxXmlDocument doc;
  334. doc.AppendToProlog( comment1 );
  335. doc.AppendToProlog( pi );
  336. doc.SetRoot( root );
  337. doc.AppendToProlog( comment2 );
  338. wxStringOutputStream sos;
  339. CPPUNIT_ASSERT( doc.Save(sos) );
  340. const char *xmlTextResult =
  341. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  342. "<!-- 1st prolog entry -->\n"
  343. "<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
  344. "<!-- 3rd prolog entry -->\n"
  345. "<root>\n"
  346. " <p>Some text</p>\n"
  347. "</root>\n"
  348. ;
  349. CPPUNIT_ASSERT_EQUAL( xmlTextResult, sos.GetString() );
  350. }
  351. void XmlTestCase::SetRoot()
  352. {
  353. wxXmlDocument doc;
  354. CPPUNIT_ASSERT( !doc.IsOk() );
  355. wxXmlNode *root = new wxXmlNode(wxXML_ELEMENT_NODE, "root");
  356. // Test for the problem of http://trac.wxwidgets.org/ticket/13135
  357. doc.SetRoot( root );
  358. wxXmlNode *docNode = doc.GetDocumentNode();
  359. CPPUNIT_ASSERT( docNode && root == docNode->GetChildren() );
  360. CPPUNIT_ASSERT( doc.IsOk() );
  361. // Other tests.
  362. CPPUNIT_ASSERT( docNode == root->GetParent() );
  363. doc.SetRoot(NULL); // Removes from doc but dosn't free mem, doc node left.
  364. CPPUNIT_ASSERT( !doc.IsOk() );
  365. wxXmlNode *comment = new wxXmlNode(wxXML_COMMENT_NODE, "comment", "Prolog Comment");
  366. wxXmlNode *pi = new wxXmlNode(wxXML_PI_NODE, "target", "PI instructions");
  367. doc.AppendToProlog(comment);
  368. doc.SetRoot( root );
  369. doc.AppendToProlog(pi);
  370. CPPUNIT_ASSERT( doc.IsOk() );
  371. wxXmlNode *node = docNode->GetChildren();
  372. CPPUNIT_ASSERT( node );
  373. CPPUNIT_ASSERT( node->GetType() == wxXML_COMMENT_NODE );
  374. CPPUNIT_ASSERT( node->GetParent() == docNode );
  375. node = node->GetNext();
  376. CPPUNIT_ASSERT( node );
  377. CPPUNIT_ASSERT( node->GetType() == wxXML_PI_NODE );
  378. CPPUNIT_ASSERT( node->GetParent() == docNode );
  379. node = node->GetNext();
  380. CPPUNIT_ASSERT( node );
  381. CPPUNIT_ASSERT( node->GetType() == wxXML_ELEMENT_NODE );
  382. CPPUNIT_ASSERT( node->GetParent() == docNode );
  383. node = node->GetNext();
  384. CPPUNIT_ASSERT( !node );
  385. doc.SetRoot(NULL);
  386. CPPUNIT_ASSERT( !doc.IsOk() );
  387. doc.SetRoot(root);
  388. CPPUNIT_ASSERT( doc.IsOk() );
  389. }
  390. void XmlTestCase::CopyNode()
  391. {
  392. const char *xmlText =
  393. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  394. "<root>\n"
  395. " <first><sub1/><sub2/><sub3/></first>\n"
  396. " <second/>\n"
  397. "</root>\n"
  398. ;
  399. wxXmlDocument doc;
  400. wxStringInputStream sis(xmlText);
  401. CPPUNIT_ASSERT( doc.Load(sis) );
  402. wxXmlNode* const root = doc.GetRoot();
  403. CPPUNIT_ASSERT( root );
  404. wxXmlNode* const first = root->GetChildren();
  405. CPPUNIT_ASSERT( first );
  406. wxXmlNode* const second = first->GetNext();
  407. CPPUNIT_ASSERT( second );
  408. *first = *second;
  409. wxStringOutputStream sos;
  410. CPPUNIT_ASSERT( doc.Save(sos) );
  411. const char *xmlTextResult =
  412. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  413. "<root>\n"
  414. " <second/>\n"
  415. " <second/>\n"
  416. "</root>\n"
  417. ;
  418. CPPUNIT_ASSERT_EQUAL( xmlTextResult, sos.GetString() );
  419. }