CPPUnit Tests for this library. Binary should be installed as sp-gxmlcpp-test.
/* * (C) Copyright 2002, Schlund+Partner AG * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // Local configuration #include "config.h" // C++ Libraries #include <cppunit/TestCase.h> #include <cppunit/TestSuite.h> #include <cppunit/TestCaller.h> #include <cppunit/TextTestRunner.h> #include <sp-gxmlcpp/XMLTree.hpp> #include <sp-gxmlcpp/XMLDump.hpp> #include <sp-gxmlcpp/XSLTrans.hpp> #include <sp-gxmlcpp/XMLNode.hpp> #include <sp-gxmlcpp/XMLNodeSet.hpp> #include <sp-gxmlcpp/XMLException.hpp> namespace SP { namespace GXML { // // XMLTree (&& XMLDump) // class TestXMLTreeOld: public CppUnit::TestCase { public: TestXMLTreeOld() {} void testRun() { // ^^ Note: dump will always use " (not ') to quote, so we must do this here too for string compare const std::string xmlString( "<?xml version=\"1.0\"?>\n" "<req>\n" " <uid>5</uid>\n" " <home>/home/absurd</home>\n" " <key>AAAABBBBCCCCDDDD</key>\n" "\n" " <a>\n" " <b>\n" " <c>Wert1</c>\n" " </b>\n" " <b>\n" " <c> Wert 2</c>\n" " </b>\n" " </a>\n" "\n" " <X>5</X>\n" "\n" " <int>-42</int>\n" " <int>17</int>\n" " <bool>0</bool>\n" " <string> abc def </string>\n" "\n" " <X>13</X>\n" "\n" "<tags>\n" " <subtag>EINS</subtag>\n" "</tags>\n" "\n" " <tags>\n" " <subtag>ZWEI</subtag>\n" " </tags>\n" "\n" " <X>17</X>\n" "\n" "</req>\n"); // ^^ Note: dump will always add a \n to the last line (in a full ("/") dump, that is), so our string should have this too for string compare // Note2: It's a bit dumb to literally compare dumps here, as the default way of producing dumps might change... §STS§ // Partial Tree && Dump XMLTree xmlTree1(xmlString.c_str(), xmlString.size()); std::string dump1 = XMLDump(&xmlTree1, "/req/tags").get(); CPPUNIT_ASSERT(dump1 == "<tags>\n" " <subtag>EINS</subtag>\n" "</tags>"); // Full Tree && Dump XMLTree xmlTree(xmlString.c_str(), xmlString.size()); std::string dump = XMLDump(&xmlTree, "/").get(); // §STS§ This does not work anymore with default encoding added in XMLDump //CPPUNIT_ASSERT(dump == xmlString); // XMLTree methods CPPUNIT_ASSERT(xmlTree.getValue("/req/string") == " abc def "); CPPUNIT_ASSERT(xmlTree.getCount("/req/int") == 2); CPPUNIT_ASSERT(xmlTree.getValue("/req/int") == "-42"); CPPUNIT_ASSERT(xmlTree.getValue("/req/int[position()=2]") == "17"); CPPUNIT_ASSERT(xmlTree.getCount("/req/tags/subtag") == 2); CPPUNIT_ASSERT(xmlTree.getValue("/req/tags/subtag") == "EINS"); CPPUNIT_ASSERT(xmlTree.getCount("/req/nonexisting") == 0); CPPUNIT_ASSERT(xmlTree.getCount("/nonexisting/tag") == 0); CPPUNIT_ASSERT(xmlTree.getValue("/nonexisting/tag") == ""); xmlTree.delTag("/req/int"); CPPUNIT_ASSERT(xmlTree.getCount("/req/int") == 1); xmlTree.addTag("/req", "newtag", "contents of new tag"); CPPUNIT_ASSERT(xmlTree.getValue("/req/newtag") == "contents of new tag"); } }; // XSLTrans Test // class TestXSLTrans : public CppUnit::TestCase { public: TestXSLTrans() {} void testRun() { std::string xmlString( "<?xml version=\"1.0\"?>\n" "<!DOCTYPE guestbook>\n" "\n" "<guestbook>\n" " <record>\n" " <name>kurt</name>\n" " <date>2.3.01</date>\n" " <text>\n" " find ich total klasse, koennte aber noch besser sein\n" " </text>\n" " </record>\n" " <record>\n" " <name>kurt</name>\n" " <date>2.3.01</date>\n" " <text>\n" " find ich total klasse, koennte aber noch besser sein\n" " </text>\n" " </record>\n" "</guestbook>\n"); std::string xslString( "<?xml version=\"1.0\"?>\n" "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" "<!-- Basic stylesheet for GUESTBOOK -->\n" "<xsl:output indent=\"yes\" />\n" "<xsl:template match=\"guestbook\">\n" " <html>\n" " <head>\n" " <title>Gaestebuch</title>\n" " </head> \n" " <body bgcolor=\"FFFFFF\">\n" " <h1>Mein Gaestebuch</h1>\n" " <center>\n" " <table cellspacing=\"2\" cellpadding=\"3\" border=\"0\">\n" " \n" " <xsl:apply-templates/>\n" " \n" " </table>\n" " </center>\n" " </body>\n" " </html>\n" "</xsl:template>\n" "\n" "<xsl:template match=\"record\">\n" " \n" " <tr> \n" " <td bgcolor=\"336699\"><font face=\"Arial,helvitica\" size=\"-1\" color=\"FFFFFF\">Name</font></td>\n" " <td bgcolor=\"336699\"><font face=\"Arial,helvitica\" size=\"-1\" color=\"FFFFFF\"><xsl:value-of select=\"name\"/></font></td>\n" " </tr>\n" " <tr>\n" " <td bgcolor=\"336699\"><font face=\"Arial,helvitica\" size=\"-1\" color=\"FFFFFF\">Datum</font></td>\n" " <td bgcolor=\"336699\"><font face=\"Arial,helvitica\" size=\"-1\" color=\"FFFFFF\"><xsl:value-of select=\"date\"/></font></td>\n" " </tr>\n" " <tr>\n" " <td bgcolor=\"336699\"><font face=\"Arial,helvitica\" size=\"-1\" color=\"FFFFFF\">Text</font></td>\n" " <td bgcolor=\"336699\"><font face=\"Arial,helvitica\" size=\"-1\" color=\"FFFFFF\"><xsl:value-of select=\"text\"/></font></td>\n" " </tr>\n" " <tr >\n" " <td colspan=\"2\"><hr height=\"1\"/></td>\n" " </tr>\n" " \n" "</xsl:template>\n" "</xsl:stylesheet>\n"); XMLTree xmlTree(xmlString); XSLTrans xslTrans(xslString); std::auto_ptr<XMLTree> resultTree = xslTrans.transToXMLTree(xmlTree.getDocPtr()); CPPUNIT_ASSERT(resultTree.get()->getValue("/html/head/title") == "Gaestebuch"); CPPUNIT_ASSERT(resultTree.get()->getValue("/html/body/h1") == "Mein Gaestebuch"); CPPUNIT_ASSERT(resultTree.get()->getCount("/html/body/center/table") == 1); } }; // TestXMLTree // class TestXMLTree : public CppUnit::TestCase { public: TestXMLTree() :tree_(NULL) { // test XMLTree's following functions: // getString // getBool (XSLT-functions: boolean, false, true, not) // getFloat // getNodeSet // getXML // getTree xmlTree_ = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<test>\n" " <string>StringValue</string>\n" " <string>\n" " Also a string value\n" " </string>\n" " <boolean>1</boolean>\n" " <boolean>0</boolean>\n" " <boolean>-1</boolean>\n" " <float>3.5</float>\n" " <float>1.6</float>\n" " <float>-123.2</float>\n" "</test>"; tree_ = new XMLTree( xmlTree_.c_str() ); } ~TestXMLTree() { delete tree_; } void testRun() { CPPUNIT_ASSERT( tree_ ); testGetString(); testGetBool(); testGetFloat(); testGetNodeSet(); testGetXML(); testGetTree(); } void testGetString() { // test getString // string( xpath ) returns content of first xpath-node // string( invalid_xpath ) returns "" CPPUNIT_ASSERT( tree_->getString( "string( /test/string )" ) == "StringValue" ); CPPUNIT_ASSERT( tree_->getString( "string( /test/string[position() = 2] )" ) == "\n\t\tAlso a string value\n\t" ); CPPUNIT_ASSERT( tree_->getString( "string( /test/something )" ) == "" ); try { // xpath won't return a string tree_->getString( "/test/string" ); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( GXML::XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLTREE_NO_STRING_FROM_PATH ); } try { // xpath won't return a string tree_->getString( "/test/something" ); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLTREE_NO_STRING_FROM_PATH ); } } void testGetBool() { // test getBool // 0 = false else true, "" = false else true CPPUNIT_ASSERT( tree_->getBool( "boolean( number( /test/boolean ) )" ) ); CPPUNIT_ASSERT( ! tree_->getBool( "boolean( number( /test/boolean[position() = 2] ) )" ) ); CPPUNIT_ASSERT( tree_->getBool( "boolean( number( /test/boolean[position() = 3] ) )" ) ); CPPUNIT_ASSERT( tree_->getBool( "true()" ) ); CPPUNIT_ASSERT( ! tree_->getBool( "false()" ) ); CPPUNIT_ASSERT( tree_->getBool( "not( /test/something )" ) ); CPPUNIT_ASSERT( ! tree_->getBool( "not( /test/string )" ) ); CPPUNIT_ASSERT( tree_->getBool( "boolean( /test/string )" ) ); CPPUNIT_ASSERT( ! tree_->getBool( "boolean( /test/something )" ) ); CPPUNIT_ASSERT( tree_->getBool( "boolean( 'anything' )" ) ); CPPUNIT_ASSERT( ! tree_->getBool( "boolean( '' )" ) ); try { // xpath won't return a boolean tree_->getBool( "/test/string" ); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLTREE_NO_BOOL_FROM_PATH ); } } void testGetFloat() { // test getFloat CPPUNIT_ASSERT_DOUBLES_EQUAL( double(-118.1), tree_->getFloat( "sum( /test/float )" ), 1E-10 ); CPPUNIT_ASSERT_DOUBLES_EQUAL( double(-123.2), tree_->getFloat( "number( /test/float[position() = 3 ])" ), 1E-10 ); CPPUNIT_ASSERT( tree_->getFloat( "count( /test/boolean )" ) == 3 ); try { // xpath won't return a number tree_->getFloat( "/test/string" ); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLTREE_NO_FLOAT_FROM_PATH ); } } void testGetNodeSet() { std::auto_ptr<XMLNodeSet> set = tree_->getNodeSet( "/test/*" ); CPPUNIT_ASSERT( set->size() == 8 ); try { // xpath will return an empty set std::auto_ptr<XMLNodeSet> set = tree_->getNodeSet( "/something" ); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLNODESET_NO_MATCH ); } try { // xpath won't return a set std::auto_ptr<XMLNodeSet> set = tree_->getNodeSet( "true()" ); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLNODESET_NO_SET ); } } void testGetXML() { CPPUNIT_ASSERT( xmlTree_+"\n" == tree_->getXML( "/" ) ); } void testGetTree() { CPPUNIT_ASSERT( tree_->getXML() == tree_->getTree()->getXML() ); } private: std::string xmlTree_; XMLTree *tree_; }; // TestXMLNode // class TestXMLNode : public CppUnit::TestCase { public: TestXMLNode() { // test XMLNode's following functions: // getNext // getPrev // getParent // getLast // getChild // getName // getContent // getAttribute( name ) xmlTree_ = "<?xml version=\"1.0\"?>\n" "<test><node>node1</node><node name=\"node2\">node2<child>child of node 2</child></node><node>last node</node></test>"; tree_ = new XMLTree( xmlTree_.c_str() ); } void testRun() { XMLNode node1 = XMLNode(); XMLNode node2 = XMLNode(); XMLNode node3 = XMLNode(); std::auto_ptr<XMLNodeSet> set = tree_->getNodeSet( "/test/node" ); for ( XMLNodeSet::Iterator iter = set->begin(); iter != set->end(); ++iter ) { switch ( iter.getPosition() ) { case 0: node1 = *iter; break; case 1: node2 = *iter; break; case 2: node3 = *iter; break; default: CPPUNIT_ASSERT( false ); //should never get here. } } CPPUNIT_ASSERT( node1.getName() == "node" ); CPPUNIT_ASSERT( node1.getContent() == "node1" ); CPPUNIT_ASSERT( node1.getNext().getContent() == node2.getContent() ); // CPPUNIT_ASSERT( node1.getLast().getContent() == node3.getContent() ); CPPUNIT_ASSERT( node2.getContent() == "node2" ); CPPUNIT_ASSERT( node2.getNext().getContent() == node3.getContent() ); CPPUNIT_ASSERT( node2.getAttribute( "name" ) == "node2" ); // first child of node2 is its content text-node, therefore take child->next CPPUNIT_ASSERT( node2.getChild().getNext().getContent() == "child of node 2" ); CPPUNIT_ASSERT( node3.getPrev().getContent() == node2.getContent() ); CPPUNIT_ASSERT( node3.getParent().getName() == node2.getParent().getName() ); CPPUNIT_ASSERT( node3.getParent().getChild().getContent() == node1.getContent() ); CPPUNIT_ASSERT( node3.getParent().getLast().getContent() == node3.getContent() ); // first child of node with content is a text-node CPPUNIT_ASSERT( node3.getChild().getName() == "text" ); // test for exceptions try { node3 = node3.getNext(); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLNODE_LAST_NODE ); } try { node1 = node1.getPrev(); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLNODE_FIRST_NODE ); } try { // parent of parent is document node, which has no parent node1 = node1.getParent().getParent().getParent(); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLNODE_NO_PARENT ); } try { node1 = node1.getPrev(); CPPUNIT_ASSERT( ! "Exception expected!!!" ); } catch ( XMLException & e ) { CPPUNIT_ASSERT( e.getException() == XMLException::XMLNODE_FIRST_NODE ); } } private: std::string xmlTree_; XMLTree *tree_; }; // XMLNodeSet Test // class TestXMLNodeSet : public CppUnit::TestCase { public: TestXMLNodeSet() {}; void testRun() {} }; // Master Class for all tests // class UnitTests: public CppUnit::TestSuite { public: UnitTests() { addTest(new CppUnit::TestCaller<TestXMLTreeOld>("Testing XMLTree (old)", &TestXMLTreeOld::testRun)); addTest(new CppUnit::TestCaller<TestXMLTree> ("Testing XMLTree", &TestXMLTree::testRun)); addTest(new CppUnit::TestCaller<TestXSLTrans> ("Testing XSLTrans", &TestXSLTrans::testRun)); addTest(new CppUnit::TestCaller<TestXMLNode> ("Testing XMLNode", &TestXMLNode::testRun)); addTest(new CppUnit::TestCaller<TestXMLNodeSet>("Testing XMLNodeSet", &TestXMLNodeSet::testRun)); } }; }} // create binary that tests the XML* stuff int main(int argc, char **argv) { CppUnit::TextTestRunner runner; // This must be an object, and must be created with new, as it is deleted by runner (this is braindead, but well). SP::GXML::UnitTests * unitTests = new SP::GXML::UnitTests(); runner.addTest(unitTests); if (runner.run()) return(0); else return(1); }