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