1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/xml/xmltest.cpp
3 // Purpose: XML classes unit test
4 // Author: Vaclav Slavik
7 // Copyright: (c) 2008 Vaclav Slavik
8 ///////////////////////////////////////////////////////////////////////////////
10 // ----------------------------------------------------------------------------
12 // ----------------------------------------------------------------------------
24 #include "wx/xml/xml.h"
25 #include "wx/scopedptr.h"
26 #include "wx/sstream.h"
30 // ----------------------------------------------------------------------------
31 // helpers for testing XML tree
32 // ----------------------------------------------------------------------------
37 void CheckXml(const wxXmlNode
*n
, ...)
42 wxXmlNode
*child
= n
->GetChildren();
46 const char *childName
= va_arg(args
, char*);
47 if ( childName
== NULL
)
50 CPPUNIT_ASSERT( child
);
51 CPPUNIT_ASSERT_EQUAL( childName
, child
->GetName() );
52 CPPUNIT_ASSERT( child
->GetChildren() == NULL
);
53 CPPUNIT_ASSERT( child
->GetParent() == n
);
55 child
= child
->GetNext();
60 CPPUNIT_ASSERT( child
== NULL
); // no more children
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
69 class XmlTestCase
: public CppUnit::TestCase
75 CPPUNIT_TEST_SUITE( XmlTestCase
);
76 CPPUNIT_TEST( InsertChild
);
77 CPPUNIT_TEST( InsertChildAfter
);
78 CPPUNIT_TEST( LoadSave
);
79 CPPUNIT_TEST( CDATA
);
81 CPPUNIT_TEST( Escaping
);
82 CPPUNIT_TEST( DetachRoot
);
83 CPPUNIT_TEST( AppendToProlog
);
84 CPPUNIT_TEST( SetRoot
);
85 CPPUNIT_TEST_SUITE_END();
88 void InsertChildAfter();
94 void AppendToProlog();
97 DECLARE_NO_COPY_CLASS(XmlTestCase
)
100 // register in the unnamed registry so that these tests are run by default
101 CPPUNIT_TEST_SUITE_REGISTRATION( XmlTestCase
);
103 // also include in its own registry so that these tests can be run alone
104 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( XmlTestCase
, "XmlTestCase" );
106 void XmlTestCase::InsertChild()
108 wxScopedPtr
<wxXmlNode
> root(new wxXmlNode(wxXML_ELEMENT_NODE
, "root"));
109 root
->AddChild(new wxXmlNode(wxXML_ELEMENT_NODE
, "1"));
110 wxXmlNode
*two
= new wxXmlNode(wxXML_ELEMENT_NODE
, "2");
112 root
->AddChild(new wxXmlNode(wxXML_ELEMENT_NODE
, "3"));
113 CheckXml(root
.get(), "1", "2", "3", NULL
);
115 // check inserting in front:
116 root
->InsertChild(new wxXmlNode(wxXML_ELEMENT_NODE
, "A"), NULL
);
117 CheckXml(root
.get(), "A", "1", "2", "3", NULL
);
118 root
->InsertChild(new wxXmlNode(wxXML_ELEMENT_NODE
, "B"), root
->GetChildren());
119 CheckXml(root
.get(), "B", "A", "1", "2", "3", NULL
);
121 // and in the middle:
122 root
->InsertChild(new wxXmlNode(wxXML_ELEMENT_NODE
, "C"), two
);
123 CheckXml(root
.get(), "B", "A", "1", "C", "2", "3", NULL
);
126 void XmlTestCase::InsertChildAfter()
128 wxScopedPtr
<wxXmlNode
> root(new wxXmlNode(wxXML_ELEMENT_NODE
, "root"));
130 root
->InsertChildAfter(new wxXmlNode(wxXML_ELEMENT_NODE
, "1"), NULL
);
131 CheckXml(root
.get(), "1", NULL
);
133 wxXmlNode
*two
= new wxXmlNode(wxXML_ELEMENT_NODE
, "2");
135 wxXmlNode
*three
= new wxXmlNode(wxXML_ELEMENT_NODE
, "3");
136 root
->AddChild(three
);
137 CheckXml(root
.get(), "1", "2", "3", NULL
);
139 // check inserting in the middle:
140 root
->InsertChildAfter(new wxXmlNode(wxXML_ELEMENT_NODE
, "A"), root
->GetChildren());
141 CheckXml(root
.get(), "1", "A", "2", "3", NULL
);
142 root
->InsertChildAfter(new wxXmlNode(wxXML_ELEMENT_NODE
, "B"), two
);
143 CheckXml(root
.get(), "1", "A", "2", "B", "3", NULL
);
146 root
->InsertChildAfter(new wxXmlNode(wxXML_ELEMENT_NODE
, "C"), three
);
147 CheckXml(root
.get(), "1", "A", "2", "B", "3", "C", NULL
);
150 void XmlTestCase::LoadSave()
152 // NB: this is not real XRC but rather some XRC-like XML fragment which
153 // exercises different XML constructs to check that they're saved back
156 // Also note that there should be no blank lines here as they disappear
158 const char *xmlText
=
159 "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
160 "<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
161 " <!-- Test comment -->\n"
162 " <object class=\"wxDialog\" name=\"my_dialog\">\n"
164 " <grandchild id=\"1\"/>\n"
171 wxStringInputStream
sis(xmlText
);
174 CPPUNIT_ASSERT( doc
.Load(sis
) );
176 wxStringOutputStream sos
;
177 CPPUNIT_ASSERT( doc
.Save(sos
) );
179 CPPUNIT_ASSERT_EQUAL( xmlText
, sos
.GetString() );
183 const char *utf8xmlText
=
184 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
186 " <lang name=\"fr\">\xc3\xa9t\xc3\xa9</lang>\n"
187 " <lang name=\"ru\">\xd0\xbb\xd0\xb5\xd1\x82\xd0\xbe</lang>\n"
191 wxStringInputStream
sis8(wxString::FromUTF8(utf8xmlText
));
192 CPPUNIT_ASSERT( doc
.Load(sis8
) );
194 // this contents can't be represented in Latin-1 as it contains Cyrillic
196 doc
.SetFileEncoding("ISO-8859-1");
197 CPPUNIT_ASSERT( !doc
.Save(sos
) );
199 // but it should work in UTF-8
200 wxStringOutputStream sos8
;
201 doc
.SetFileEncoding("UTF-8");
202 CPPUNIT_ASSERT( doc
.Save(sos8
) );
203 CPPUNIT_ASSERT_EQUAL( wxString(utf8xmlText
),
204 wxString(sos8
.GetString().ToUTF8()) );
205 #endif // wxUSE_UNICODE
207 const char *xmlTextProlog
=
208 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
209 "<!-- Prolog comment -->\n"
210 "<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
211 "<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
212 " <!-- Test comment -->\n"
213 " <object class=\"wxDialog\" name=\"my_dialog\">\n"
215 " <grandchild id=\"1\"/>\n"
220 "<!-- Trailing comment -->\n"
223 wxStringInputStream
sisp(xmlTextProlog
);
224 CPPUNIT_ASSERT( doc
.Load(sisp
, "UTF-8") );
226 wxStringOutputStream sosp
;
227 CPPUNIT_ASSERT( doc
.Save(sosp
) );
229 CPPUNIT_ASSERT_EQUAL( xmlTextProlog
, sosp
.GetString() );
232 void XmlTestCase::CDATA()
234 const char *xmlText
=
235 "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
237 " <![CDATA[Giovanni Mittone]]>\n"
241 wxStringInputStream
sis(xmlText
);
243 CPPUNIT_ASSERT( doc
.Load(sis
) );
245 wxXmlNode
*n
= doc
.GetRoot();
248 n
= n
->GetChildren();
251 // check that both leading (" ") and trailing white space is not part of
252 // the node contents when CDATA is used and wxXMLDOC_KEEP_WHITESPACE_NODES
254 CPPUNIT_ASSERT_EQUAL( "Giovanni Mittone", n
->GetContent() );
257 void XmlTestCase::PI()
259 const char *xmlText
=
260 "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
262 " <?robot index=\"no\" follow=\"no\"?>\n"
266 wxStringInputStream
sis(xmlText
);
268 CPPUNIT_ASSERT( doc
.Load(sis
) );
270 wxXmlNode
*n
= doc
.GetRoot();
273 n
= n
->GetChildren();
276 CPPUNIT_ASSERT_EQUAL( "index=\"no\" follow=\"no\"", n
->GetContent() );
279 void XmlTestCase::Escaping()
281 // Verify that attribute values are escaped correctly, see
282 // http://trac.wxwidgets.org/ticket/12275
284 const char *xmlText
=
285 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
286 "<root text=\"hello
this is a new line\">\n"
291 wxStringInputStream
sis(xmlText
);
294 CPPUNIT_ASSERT( doc
.Load(sis
) );
296 wxStringOutputStream sos
;
297 CPPUNIT_ASSERT( doc
.Save(sos
) );
299 CPPUNIT_ASSERT_EQUAL( xmlText
, sos
.GetString() );
302 void XmlTestCase::DetachRoot()
304 const char *xmlTextProlog
=
305 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
306 "<!-- Prolog comment -->\n"
307 "<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
308 "<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
309 " <!-- Test comment -->\n"
310 " <object class=\"wxDialog\" name=\"my_dialog\">\n"
312 " <grandchild id=\"1\"/>\n"
317 "<!-- Trailing comment -->\n"
319 const char *xmlTextHtm
=
320 "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
323 " <title>Testing wxXml</title>\n"
326 " <p>Some body text</p>\n"
332 wxStringInputStream
sish(xmlTextHtm
);
333 CPPUNIT_ASSERT( doc
.Load(sish
) );
335 wxXmlNode
*root
= doc
.DetachRoot();
337 wxStringInputStream
sisp(xmlTextProlog
);
338 CPPUNIT_ASSERT( doc
.Load(sisp
) );
342 wxStringOutputStream sos
;
343 CPPUNIT_ASSERT( doc
.Save(sos
) );
345 const char *xmlTextResult1
=
346 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
347 "<!-- Prolog comment -->\n"
348 "<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
351 " <title>Testing wxXml</title>\n"
354 " <p>Some body text</p>\n"
357 "<!-- Trailing comment -->\n"
359 CPPUNIT_ASSERT_EQUAL( xmlTextResult1
, sos
.GetString() );
361 wxStringInputStream
sisp2(xmlTextProlog
);
362 CPPUNIT_ASSERT( doc
.Load(sisp2
) );
364 root
= doc
.DetachRoot();
366 wxStringInputStream
sish2(xmlTextHtm
);
367 CPPUNIT_ASSERT( doc
.Load(sish2
) );
371 wxStringOutputStream sos2
;
372 CPPUNIT_ASSERT( doc
.Save(sos2
) );
374 const char *xmlTextResult2
=
375 "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n"
376 "<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.3.0.1\">\n"
377 " <!-- Test comment -->\n"
378 " <object class=\"wxDialog\" name=\"my_dialog\">\n"
380 " <grandchild id=\"1\"/>\n"
386 CPPUNIT_ASSERT_EQUAL( xmlTextResult2
, sos2
.GetString() );
389 void XmlTestCase::AppendToProlog()
391 const char *xmlText
=
392 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
394 " <p>Some text</p>\n"
397 wxXmlDocument rootdoc
;
398 wxStringInputStream
sis(xmlText
);
399 CPPUNIT_ASSERT( rootdoc
.Load(sis
) );
400 wxXmlNode
*root
= rootdoc
.DetachRoot();
402 wxXmlNode
*comment1
= new wxXmlNode(wxXML_COMMENT_NODE
, "comment",
403 " 1st prolog entry ");
404 wxXmlNode
*pi
= new wxXmlNode(wxXML_PI_NODE
, "xml-stylesheet",
405 "href=\"style.css\" type=\"text/css\"");
406 wxXmlNode
*comment2
= new wxXmlNode(wxXML_COMMENT_NODE
, "comment",
407 " 3rd prolog entry ");
410 doc
.AppendToProlog( comment1
);
411 doc
.AppendToProlog( pi
);
413 doc
.AppendToProlog( comment2
);
415 wxStringOutputStream sos
;
416 CPPUNIT_ASSERT( doc
.Save(sos
) );
418 const char *xmlTextResult
=
419 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
420 "<!-- 1st prolog entry -->\n"
421 "<?xml-stylesheet href=\"style.css\" type=\"text/css\"?>\n"
422 "<!-- 3rd prolog entry -->\n"
424 " <p>Some text</p>\n"
427 CPPUNIT_ASSERT_EQUAL( xmlTextResult
, sos
.GetString() );
430 void XmlTestCase::SetRoot()
433 CPPUNIT_ASSERT( !doc
.IsOk() );
434 wxXmlNode
*root
= new wxXmlNode(wxXML_ELEMENT_NODE
, "root");
436 // Test for the problem of http://trac.wxwidgets.org/ticket/13135
438 wxXmlNode
*docNode
= doc
.GetDocumentNode();
439 CPPUNIT_ASSERT( docNode
&& root
== docNode
->GetChildren() );
440 CPPUNIT_ASSERT( doc
.IsOk() );
443 CPPUNIT_ASSERT( docNode
== root
->GetParent() );
444 doc
.SetRoot(NULL
); // Removes from doc but dosn't free mem, doc node left.
445 CPPUNIT_ASSERT( !doc
.IsOk() );
447 wxXmlNode
*comment
= new wxXmlNode(wxXML_COMMENT_NODE
, "comment", "Prolog Comment");
448 wxXmlNode
*pi
= new wxXmlNode(wxXML_PI_NODE
, "target", "PI instructions");
449 doc
.AppendToProlog(comment
);
451 doc
.AppendToProlog(pi
);
452 CPPUNIT_ASSERT( doc
.IsOk() );
453 wxXmlNode
*node
= docNode
->GetChildren();
454 CPPUNIT_ASSERT( node
);
455 CPPUNIT_ASSERT( node
->GetType() == wxXML_COMMENT_NODE
);
456 CPPUNIT_ASSERT( node
->GetParent() == docNode
);
457 node
= node
->GetNext();
458 CPPUNIT_ASSERT( node
);
459 CPPUNIT_ASSERT( node
->GetType() == wxXML_PI_NODE
);
460 CPPUNIT_ASSERT( node
->GetParent() == docNode
);
461 node
= node
->GetNext();
462 CPPUNIT_ASSERT( node
);
463 CPPUNIT_ASSERT( node
->GetType() == wxXML_ELEMENT_NODE
);
464 CPPUNIT_ASSERT( node
->GetParent() == docNode
);
465 node
= node
->GetNext();
466 CPPUNIT_ASSERT( !node
);
468 CPPUNIT_ASSERT( !doc
.IsOk() );
470 CPPUNIT_ASSERT( doc
.IsOk() );