added more unit tests and did some refactoring of xml parser code

This commit is contained in:
Mark Vejvoda 2013-05-03 20:18:01 +00:00
parent e43b9c3176
commit 1b344808ff
3 changed files with 228 additions and 47 deletions

View File

@ -59,16 +59,21 @@ class XmlAttribute;
/// Wrapper for Xerces C++
// =====================================================
class XmlIo{
class XmlIo {
private:
static bool initialized;
XERCES_CPP_NAMESPACE::DOMImplementation *implementation;
private:
XmlIo();
void init();
#if XERCES_VERSION_MAJOR < 3
XERCES_CPP_NAMESPACE::DOMBuilder *parser;
#else
XERCES_CPP_NAMESPACE::DOMLSParser *parser;
#endif
protected:
XmlIo();
virtual ~XmlIo();
void init();
#if XERCES_VERSION_MAJOR < 3
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * getRootDOMDocument(const string &path, DOMBuilder *parser, bool noValidation);
@ -76,14 +81,16 @@ protected:
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * getRootDOMDocument(const string &path, DOMLSParser *parser, bool noValidation);
#endif
DOMNode *loadDOMNode(const string &path, bool noValidation=false);
virtual void releaseDOMParser();
public:
static XmlIo &getInstance();
~XmlIo();
void cleanup();
static bool isInitialized();
void cleanup();
XmlNode *load(const string &path, const std::map<string,string> &mapTagReplacementValues,bool noValidation=false, bool skipStackCheck=false);
XmlNode *load(const string &path, const std::map<string,string> &mapTagReplacementValues,bool noValidation=false);
void save(const string &path, const XmlNode *node);
};
@ -99,9 +106,9 @@ private:
public:
static XmlIoRapid &getInstance();
~XmlIoRapid();
void cleanup();
static bool isInitialized();
void cleanup();
XmlNode *load(const string &path, const std::map<string,string> &mapTagReplacementValues,bool noValidation=false,bool skipStackCheck=false);
void save(const string &path, const XmlNode *node);
@ -149,6 +156,9 @@ private:
XmlNode(XmlNode&);
void operator =(XmlNode&);
string getTreeString() const;
bool hasChildNoSuper(const string& childName) const;
public:
XmlNode(XERCES_CPP_NAMESPACE::DOMNode *node, const std::map<string,string> &mapTagReplacementValues);
XmlNode(xml_node<> *node, const std::map<string,string> &mapTagReplacementValues);
@ -172,18 +182,13 @@ public:
bool hasChildAtIndex(const string &childName, int childIndex=0) const;
bool hasChild(const string &childName) const;
int clearChild(const string &childName);
XmlNode *getParent() const;
XmlNode *addChild(const string &name);
XmlNode *addChild(const string &name, const string text = "");
XmlAttribute *addAttribute(const string &name, const string &value, const std::map<string,string> &mapTagReplacementValues);
XERCES_CPP_NAMESPACE::DOMElement *buildElement(XERCES_CPP_NAMESPACE::DOMDocument *document) const;
xml_node<>* buildElement(xml_document<> *document) const;
private:
string getTreeString() const;
bool hasChildNoSuper(const string& childName) const;
};
// =====================================================

View File

@ -64,10 +64,14 @@ public:
bool XmlIo::initialized = false;
bool XmlIoRapid::initialized= false;
XmlIo::XmlIo() {
XmlIo::XmlIo() : parser(NULL) {
init();
}
XmlIo::~XmlIo() {
cleanup();
}
bool XmlIo::isInitialized() {
return XmlIo::initialized;
}
@ -105,6 +109,7 @@ XmlIo &XmlIo::getInstance() {
}
void XmlIo::cleanup() {
releaseDOMParser();
if(XmlIo::initialized == true) {
XmlIo::initialized= false;
//printf("XmlIo cleanup\n");
@ -112,10 +117,6 @@ void XmlIo::cleanup() {
}
}
XmlIo::~XmlIo() {
cleanup();
}
#if XERCES_VERSION_MAJOR < 3
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * XmlIo::getRootDOMDocument(const string &path, DOMBuilder *parser, bool noValidation) {
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *document= parser->parseURI(path.c_str());
@ -128,7 +129,14 @@ XmlIo::~XmlIo() {
}
#endif
XmlNode *XmlIo::load(const string &path, const std::map<string,string> &mapTagReplacementValues,bool noValidation,bool skipStackCheck) {
void XmlIo::releaseDOMParser() {
if(parser != NULL) {
parser->release();
parser = NULL;
}
}
DOMNode *XmlIo::loadDOMNode(const string &path, bool noValidation) {
//printf("Load file using Xerces engine [%s]\n",path.c_str());
try {
@ -136,15 +144,15 @@ XmlNode *XmlIo::load(const string &path, const std::map<string,string> &mapTagRe
ErrorHandler errorHandler;
#if XERCES_VERSION_MAJOR < 3
DOMBuilder *parser= (static_cast<DOMImplementationLS*>(implementation))->createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
parser->setErrorHandler(&errorHandler);
if(noValidation == false) {
parser= (static_cast<DOMImplementationLS*>(implementation))->createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
parser->setErrorHandler(&errorHandler);
if(noValidation == false) {
parser->setFeature(XMLUni::fgXercesSchema, true);
parser->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
//parser->setFeature(XMLUni::fgDOMValidateIfSchema, true);
parser->setFeature(XMLUni::fgDOMValidation, true);
}
else {
}
else {
//parser->setFeature(XMLUni::fgSAX2CoreValidation, false);
//parser->setFeature(XMLUni::fgXercesDynamic, true);
@ -153,30 +161,30 @@ XmlNode *XmlIo::load(const string &path, const std::map<string,string> &mapTagRe
//parser->setFeature(XMLUni::fgDOMValidateIfSchema, true);
//parser->setFeature(XMLUni::fgDOMValidation, false);
parser->setFeature(XMLUni::fgXercesSchemaFullChecking, false);
parser->setFeature(XMLUni::fgXercesLoadExternalDTD, false);
parser->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
}
parser->setFeature(XMLUni::fgXercesSchemaFullChecking, false);
parser->setFeature(XMLUni::fgXercesLoadExternalDTD, false);
parser->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
}
#else
DOMLSParser *parser = (static_cast<DOMImplementationLS*>(implementation))->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
DOMConfiguration *config = parser->getDomConfig();
if(noValidation == false) {
parser = (static_cast<DOMImplementationLS*>(implementation))->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, 0);
DOMConfiguration *config = parser->getDomConfig();
if(noValidation == false) {
config->setParameter(XMLUni::fgXercesSchema, true);
config->setParameter(XMLUni::fgXercesSchemaFullChecking, true);
//config->setParameter(XMLUni::fgDOMValidateIfSchema, true);
config->setParameter(XMLUni::fgDOMValidate, true);
}
else {
}
else {
config->setParameter(XMLUni::fgXercesSchema, false);
config->setParameter(XMLUni::fgXercesSchemaFullChecking, false);
config->setParameter(XMLUni::fgXercesLoadExternalDTD, false);
config->setParameter(XMLUni::fgXercesCacheGrammarFromParse, true);
config->setParameter(XMLUni::fgXercesUseCachedGrammarInParse, true);
}
}
#endif
//XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *document= parser->parseURI(path.c_str());
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *document = getRootDOMDocument(path, parser, noValidation);
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *document = getRootDOMDocument(path, parser, noValidation);
#ifdef WIN32
if(document == NULL) {
@ -187,8 +195,29 @@ XmlNode *XmlIo::load(const string &path, const std::map<string,string> &mapTagRe
throw megaglest_runtime_error("Can not parse URL: " + path);
}
XmlNode *rootNode= new XmlNode(document->getDocumentElement(),mapTagReplacementValues);
parser->release();
DOMNode *rootNode = document->getDocumentElement();
return rootNode;
}
catch(const DOMException &ex) {
char szBuf[8096]="";
snprintf(szBuf,8096,"In [%s::%s Line: %d] Exception while loading: [%s], msg:\n%s",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,path.c_str(),XMLString::transcode(ex.msg));
SystemFlags::OutputDebug(SystemFlags::debugError,"%s\n",szBuf);
throw megaglest_runtime_error(szBuf);
}
return NULL;
}
XmlNode *XmlIo::load(const string &path, const std::map<string,string> &mapTagReplacementValues,bool noValidation) {
//printf("Load file using Xerces engine [%s]\n",path.c_str());
try {
if(SystemFlags::VERBOSE_MODE_ENABLED) printf("XERCES_FULLVERSIONDOT [%s]\nnoValidation = %d\npath [%s]\n",XERCES_FULLVERSIONDOT,noValidation,path.c_str());
DOMNode *domNode = loadDOMNode(path, noValidation);
XmlNode *rootNode= new XmlNode(domNode,mapTagReplacementValues);
releaseDOMParser();
return rootNode;
}
catch(const DOMException &ex) {
@ -512,7 +541,7 @@ void XmlTree::load(const string &path, const std::map<string,string> &mapTagRepl
loadPath = path;
if(this->engine_type == XML_XERCES_ENGINE) {
this->rootNode= XmlIo::getInstance().load(path, mapTagReplacementValues, noValidation,this->skipStackCheck);
this->rootNode= XmlIo::getInstance().load(path, mapTagReplacementValues, noValidation);
}
else {
this->rootNode= XmlIoRapid::getInstance().load(path, mapTagReplacementValues, noValidation,this->skipStackCheck);
@ -745,6 +774,7 @@ bool XmlNode::hasChildAtIndex(const string &childName, int i) const {
return superNode->hasChildAtIndex(childName,i);
int count= 0;
for(unsigned int j = 0; j < children.size(); ++j) {
//printf("Looking for [%s] at index: %d found [%s] index = %d\n",childName.c_str(),i,children[j]->getName().c_str(),j);
if(children[j]->getName()==childName) {
if(count == i) {
return true;
@ -770,9 +800,10 @@ bool XmlNode::hasChildNoSuper(const string &childName) const {
return false;
}
XmlNode *XmlNode::addChild(const string &name){
XmlNode *XmlNode::addChild(const string &name, const string text) {
assert(!superNode);
XmlNode *node= new XmlNode(name);
node->text = text;
children.push_back(node);
return node;
}

View File

@ -15,6 +15,10 @@
#include "xml_parser.h"
#include "platform_util.h"
#include <xercesc/dom/DOM.hpp>
//#include <xercesc/util/PlatformUtils.hpp>
//#include <xercesc/framework/LocalFileFormatTarget.hpp>
#ifdef WIN32
#include <io.h>
#else
@ -37,7 +41,7 @@ bool removeTestFile(string file) {
void createValidXMLTestFile(const string& test_filename) {
std::ofstream xmlFile(test_filename.c_str());
xmlFile << "<?xml version=\"1.0\"?>" << std::endl
<< "<menu>" << std::endl
<< "<menu mytest-attribute=\"true\">" << std::endl
<< "<menu-background-model value=\"data/core/menu/main_model/menu_main1.g3d\"/>" << std::endl
<< "</menu>" << std::endl;
xmlFile.close();
@ -103,7 +107,7 @@ public:
XmlNode *rootNode = XmlIo::getInstance().load(test_filename, std::map<string,string>());
CPPUNIT_ASSERT( rootNode != NULL );
CPPUNIT_ASSERT( rootNode->getName() == "menu" );
CPPUNIT_ASSERT_EQUAL( string("menu"), rootNode->getName() );
}
void test_load_file_malformed_content() {
const string test_filename = "xml_test_malformed.xml";
@ -170,7 +174,7 @@ public:
XmlNode *rootNode = XmlIoRapid::getInstance().load(test_filename, std::map<string,string>());
CPPUNIT_ASSERT( rootNode != NULL );
CPPUNIT_ASSERT( rootNode->getName() == "menu" );
CPPUNIT_ASSERT_EQUAL( string("menu"), rootNode->getName() );
}
void test_load_file_malformed_content() {
const string test_filename = "xml_test_malformed.xml";
@ -233,11 +237,11 @@ public:
XmlTree xmlInstance;
xmlInstance.init("");
CPPUNIT_ASSERT( xmlInstance.getRootNode() != NULL );
CPPUNIT_ASSERT( xmlInstance.getRootNode()->getName() == "" );
CPPUNIT_ASSERT_EQUAL( string(""), xmlInstance.getRootNode()->getName() );
xmlInstance.init("testRoot");
CPPUNIT_ASSERT( xmlInstance.getRootNode() != NULL );
CPPUNIT_ASSERT( xmlInstance.getRootNode()->getName() == "testRoot" );
CPPUNIT_ASSERT_EQUAL( string("testRoot"), xmlInstance.getRootNode()->getName() );
}
void test_load_simultaneously_same_file() {
const string test_filename = "xml_test_valid.xml";
@ -264,7 +268,148 @@ public:
}
};
class XmlNodeTest : public CppUnit::TestFixture {
// Register the suite of tests for this fixture
CPPUNIT_TEST_SUITE( XmlNodeTest );
CPPUNIT_TEST_EXCEPTION( test_null_xerces_node, megaglest_runtime_error );
CPPUNIT_TEST_EXCEPTION( test_null_rapidxml_node, megaglest_runtime_error );
CPPUNIT_TEST( test_valid_xerces_node );
CPPUNIT_TEST( test_valid_named_node );
CPPUNIT_TEST( test_child_nodes );
CPPUNIT_TEST( test_node_attributes );
CPPUNIT_TEST_SUITE_END();
// End of Fixture registration
private:
class XmlIoMock : public XmlIo {
protected:
virtual void releaseDOMParser() { }
public:
XmlIoMock() : XmlIo() { }
DOMNode *loadDOMNode(const string &path, bool noValidation=false) {
return XmlIo::loadDOMNode(path, noValidation);
}
void manualParserRelease() {
XmlIo::releaseDOMParser();
}
};
public:
void test_null_xerces_node() {
XERCES_CPP_NAMESPACE::DOMNode *node = NULL;
const std::map<string,string> mapTagReplacementValues;
XmlNode(node, mapTagReplacementValues);
}
void test_null_rapidxml_node() {
xml_node<> *node = NULL;
const std::map<string,string> mapTagReplacementValues;
XmlNode(node, mapTagReplacementValues);
}
void test_valid_xerces_node() {
const string test_filename = "xml_test_valid.xml";
createValidXMLTestFile(test_filename);
SafeRemoveTestFile deleteFile(test_filename);
XmlIoMock xml;
XERCES_CPP_NAMESPACE::DOMNode *domNode = xml.loadDOMNode(test_filename);
CPPUNIT_ASSERT( domNode != NULL );
const std::map<string,string> mapTagReplacementValues;
XmlNode node(domNode, mapTagReplacementValues);
xml.manualParserRelease();
CPPUNIT_ASSERT_EQUAL( string("menu"), node.getName() );
CPPUNIT_ASSERT( node.hasAttribute("mytest-attribute") == true );
CPPUNIT_ASSERT( node.hasChild("menu-background-model") == true );
}
void test_valid_named_node() {
XmlNode node("testNode");
CPPUNIT_ASSERT_EQUAL( string("testNode"), node.getName() );
}
void test_child_nodes() {
XmlNode node("testNode");
CPPUNIT_ASSERT( node.getName() == "testNode" );
CPPUNIT_ASSERT_EQUAL( (size_t)0,node.getChildCount() );
XmlNode *childNode1 = node.addChild("child1");
CPPUNIT_ASSERT_EQUAL( (size_t)1,node.getChildCount() );
CPPUNIT_ASSERT_EQUAL( string(""), childNode1->getText() );
XmlNode *childChildNode1 = childNode1->addChild("childchild1", "testValue");
CPPUNIT_ASSERT_EQUAL( (size_t)1,childNode1->getChildCount() );
CPPUNIT_ASSERT_EQUAL( string("testValue"), childChildNode1->getText() );
XmlNode *childChildNode2 = childNode1->addChild("childchild2", "testValue2");
CPPUNIT_ASSERT_EQUAL( (size_t)2, childNode1->getChildCount() );
CPPUNIT_ASSERT_EQUAL( string("testValue2"), childChildNode2->getText() );
XmlNode *childChildNode3 = childNode1->addChild("childchild2", "testValue3");
CPPUNIT_ASSERT_EQUAL( (size_t)3, childNode1->getChildCount() );
CPPUNIT_ASSERT_EQUAL( string("testValue3"), childChildNode3->getText() );
CPPUNIT_ASSERT( childNode1->hasChildAtIndex("childchild2",1) == true);
XmlNode *childNode2 = node.addChild("child2","child2Value");
CPPUNIT_ASSERT_EQUAL( (size_t)2,node.getChildCount() );
CPPUNIT_ASSERT_EQUAL( string("child2Value"), childNode2->getText() );
CPPUNIT_ASSERT_EQUAL( string("child2"), node.getChild(1)->getName() );
CPPUNIT_ASSERT_EQUAL( string("child2"), node.getChild("child2")->getName() );
CPPUNIT_ASSERT_EQUAL( string("child1"), node.getChild("child1")->getName() );
XmlNode *childNode2x = node.addChild("child2","child2xValue");
CPPUNIT_ASSERT_EQUAL( (size_t)3, node.getChildCount() );
CPPUNIT_ASSERT_EQUAL( string("child2xValue"), childNode2x->getText() );
CPPUNIT_ASSERT_EQUAL( string("child2xValue"), node.getChild("child2",1)->getText() );
XmlNode *childNode3 = node.addChild("child3","child3Value");
CPPUNIT_ASSERT_EQUAL( (size_t)4, node.getChildCount() );
vector<XmlNode *> child2List = node.getChildList("child2");
CPPUNIT_ASSERT_EQUAL( (size_t)2, child2List.size() );
CPPUNIT_ASSERT_EQUAL( string("child2Value"), child2List[0]->getText() );
CPPUNIT_ASSERT_EQUAL( string("child2xValue"), child2List[1]->getText() );
//printf("%d\n",__LINE__);
CPPUNIT_ASSERT( childNode3->hasChild("child2") == false);
CPPUNIT_ASSERT_EQUAL( 2, node.clearChild("child2"));
CPPUNIT_ASSERT_EQUAL( (size_t)2,node.getChildCount() );
}
void test_node_attributes() {
XmlNode node("testNode");
CPPUNIT_ASSERT( node.getName() == "testNode" );
CPPUNIT_ASSERT_EQUAL( (size_t)0,node.getAttributeCount() );
CPPUNIT_ASSERT_EQUAL( (XmlAttribute *)NULL, node.getAttribute("some-attribute",false) );
CPPUNIT_ASSERT_EQUAL( false, node.hasAttribute("some-attribute") );
std::map<string,string> mapTagReplacementValues;
XmlAttribute *attribute1 = node.addAttribute("some-attribute", "some-value", mapTagReplacementValues);
CPPUNIT_ASSERT_EQUAL( (size_t)1,node.getAttributeCount() );
CPPUNIT_ASSERT_EQUAL( attribute1, node.getAttribute("some-attribute") );
CPPUNIT_ASSERT_EQUAL( string("some-attribute"), node.getAttribute(0)->getName() );
CPPUNIT_ASSERT_EQUAL( true, node.hasAttribute("some-attribute") );
}
};
// Suite Registrations
CPPUNIT_TEST_SUITE_REGISTRATION( XmlIoTest );
CPPUNIT_TEST_SUITE_REGISTRATION( XmlIoRapidTest );
CPPUNIT_TEST_SUITE_REGISTRATION( XmlTreeTest );
CPPUNIT_TEST_SUITE_REGISTRATION( XmlNodeTest );