# More XML stuff

Added some tests for Xeromyces. Refactored it a bit to make it testable.

This was SVN commit r6768.
This commit is contained in:
Ykkrosh 2009-03-23 21:53:17 +00:00
parent 2bc48fc1e7
commit fd20cda5b6
5 changed files with 121 additions and 19 deletions

View File

@ -14,7 +14,7 @@ const char* UnfinishedHeaderMagicStr = "XMBu";
bool XMBFile::Initialise(const char* FileData)
{
m_Pointer = FileData;
char Header[5];
char Header[5] = { 0 };
strncpy_s(Header, 5, m_Pointer, 4);
m_Pointer += 4;
// (c.f. @return documentation of this function)

View File

@ -165,8 +165,8 @@ PSRETURN CXeromyces::Load(const VfsPath& filename)
// zeroed because zip files only have 2 second resolution.
const int suffixLength = 22;
char suffix[suffixLength+1];
int ret = sprintf(suffix, "_%08x%08xB.xmb", (int)(fileInfo.MTime() & ~1), (int)fileInfo.Size());
debug_assert(ret == suffixLength);
int printed = sprintf(suffix, "_%08x%08xB.xmb", (int)(fileInfo.MTime() & ~1), (int)fileInfo.Size());
debug_assert(printed == suffixLength);
VfsPath xmbFilename = change_extension(filename, suffix);
VfsPath xmbPath;
@ -199,12 +199,35 @@ PSRETURN CXeromyces::Load(const VfsPath& filename)
return PSRETURN_Xeromyces_XMLOpenFailed;
}
WriteBuffer writeBuffer;
PSRETURN ret = ConvertXMLtoXMB(filename.string().c_str(), source, writeBuffer);
if (ret)
{
if (ret == PSRETURN_Xeromyces_XMLParseError)
LOG(CLogger::Error, LOG_CATEGORY, "CXeromyces: Errors in XML file '%s'", filename.string().c_str());
return ret;
}
// Save the file to disk, so it can be loaded quickly next time
g_VFS->CreateFile(xmbPath, writeBuffer.Data(), writeBuffer.Size());
XMBBuffer = writeBuffer.Data(); // add a reference
// Set up the XMBFile
const bool ok = Initialise((const char*)XMBBuffer.get());
debug_assert(ok);
return PSRETURN_OK;
}
// Reads from source, returns output in writeBuffer
PSRETURN CXeromyces::ConvertXMLtoXMB(const char* filename, InputSource& source, WriteBuffer& writeBuffer)
{
// Set up the Xerces parser
SAX2XMLReader* Parser = XMLReaderFactory::createXMLReader();
// Enable validation
Parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
Parser->setFeature(XMLUni::fgXercesDynamic, true);
// Disable DTDs
Parser->setFeature(XMLUni::fgXercesLoadExternalDTD, false);
XeroHandler handler;
Parser->setContentHandler(&handler);
@ -212,7 +235,7 @@ PSRETURN CXeromyces::Load(const VfsPath& filename)
CXercesErrorHandler errorHandler;
Parser->setErrorHandler(&errorHandler);
CVFSEntityResolver entityResolver(filename.string().c_str());
CVFSEntityResolver entityResolver(filename);
Parser->setEntityResolver(&entityResolver);
// Build a tree inside handler
@ -227,24 +250,14 @@ PSRETURN CXeromyces::Load(const VfsPath& filename)
delete Parser;
if (errorHandler.GetSawErrors())
{
LOG(CLogger::Error, LOG_CATEGORY, "CXeromyces: Errors in XML file '%s'", filename.string().c_str());
return PSRETURN_Xeromyces_XMLParseError;
// The internal tree of the XeroHandler will be cleaned up automatically
}
// Convert the data structures into the XMB format
handler.CreateXMB();
// Save the file to disk, so it can be loaded quickly next time
WriteBuffer& writeBuffer = handler.writeBuffer;
g_VFS->CreateFile(xmbPath, writeBuffer.Data(), writeBuffer.Size());
XMBBuffer = writeBuffer.Data(); // add a reference
// Set up the XMBFile
const bool ok = Initialise((const char*)XMBBuffer.get());
debug_assert(ok);
// Copy the (refcounted) buffer into the output parameter
writeBuffer = handler.writeBuffer;
return PSRETURN_OK;
}

View File

@ -15,9 +15,12 @@ ERROR_TYPE(Xeromyces, XMLParseError);
#include "XeroXMB.h"
#include "ps/Filesystem.h"
#include "XML.h" // XXX remove this
class CXeromyces : public XMBFile
{
friend class TestXeromyces;
friend class TestXeroXMB;
public:
CXeromyces();
~CXeromyces();
@ -35,6 +38,8 @@ private:
bool ReadXMBFile(const VfsPath& filename);
static PSRETURN ConvertXMLtoXMB(const char* filename, InputSource& source, WriteBuffer& writeBuffer); // XXX remove filename
shared_ptr<u8> XMBBuffer;
static int XercesLoaded; // for once-only initialisation

View File

@ -0,0 +1,76 @@
#include "lib/self_test.h"
#include "ps/XML/Xeromyces.h"
#include <xercesc/framework/MemBufInputSource.hpp>
XERCES_CPP_NAMESPACE_USE
class TestXeroXMB : public CxxTest::TestSuite
{
private:
shared_ptr<u8> m_Buffer;
XMBFile parse(const char* doc)
{
XMLPlatformUtils::Initialize();
MemBufInputSource source((const XMLByte*)doc, strlen(doc), "null");
WriteBuffer buffer;
PSRETURN ret = CXeromyces::ConvertXMLtoXMB("/dev/null", source, buffer);
TS_ASSERT_EQUALS(ret, PSRETURN_OK);
XMBFile xmb;
m_Buffer = buffer.Data(); // hold a reference
TS_ASSERT(xmb.Initialise((const char*)m_Buffer.get()));
return xmb;
}
public:
void test_basic()
{
XMBFile xmb (parse("<test>\n<foo x=' y '> bar </foo>\n</test>"));
TS_ASSERT_DIFFERS(xmb.GetElementID("test"), -1);
TS_ASSERT_DIFFERS(xmb.GetElementID("foo"), -1);
TS_ASSERT_EQUALS(xmb.GetElementID("bar"), -1);
TS_ASSERT_DIFFERS(xmb.GetAttributeID("x"), -1);
TS_ASSERT_EQUALS(xmb.GetAttributeID("y"), -1);
TS_ASSERT_EQUALS(xmb.GetAttributeID("test"), -1);
int el_test = xmb.GetElementID("test");
int el_foo = xmb.GetElementID("foo");
int at_x = xmb.GetAttributeID("x");
XMBElement root = xmb.GetRoot();
TS_ASSERT_EQUALS(root.GetNodeName(), el_test);
// TS_ASSERT_EQUALS(root.GetLineNumber(), 1);
TS_ASSERT_EQUALS(CStr(root.GetText()), "");
TS_ASSERT_EQUALS(root.GetChildNodes().Count, 1);
XMBElement child = root.GetChildNodes().Item(0);
TS_ASSERT_EQUALS(child.GetNodeName(), el_foo);
// TS_ASSERT_EQUALS(child.GetLineNumber(), 2);
TS_ASSERT_EQUALS(child.GetChildNodes().Count, 0);
TS_ASSERT_EQUALS(CStr(child.GetText()), "bar");
TS_ASSERT_EQUALS(child.GetAttributes().Count, 1);
XMBAttribute attr = child.GetAttributes().Item(0);
TS_ASSERT_EQUALS(attr.Name, at_x);
TS_ASSERT_EQUALS(CStr(attr.Value), " y ");
}
void test_doctype_ignored()
{
XMBFile xmb (parse("<!DOCTYPE foo SYSTEM \"file:///dev/urandom\"><foo/>"));
TS_ASSERT_DIFFERS(xmb.GetElementID("foo"), -1);
}
void test_complex_parse()
{
XMBFile xmb (parse("<test>\t\n \tx &lt;>&amp;&quot;&apos;<![CDATA[foo]]>bar\n<x/>\nbaz<?cheese?>qux</test>"));
TS_ASSERT_EQUALS(CStr(xmb.GetRoot().GetText()), "x <>&\"'foobar\n\nbazqux");
}
};

View File

@ -93,6 +93,14 @@ public:
"<foo>abcde&amp;f&lt;g&gt;h\"i'j</foo>\n"
);
}
void test_parse_doctype()
{
try_parse_save(
"<!DOCTYPE foo SYSTEM \"file:///dev/urandom\"><foo/>",
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<foo/>\n"
);
}
void test_parse_ignored()
{
try_parse_save(