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