Files
libreoffice/sw/qa/extras/inc/swmodeltestbase.hxx
Luboš Luňák e1036f0fae add messages to utility test functions
So that e.g. parseDump() in case of an incorrect xpath does not just
plain give an equality assertion failure, which on its own is confusing.

Change-Id: Ib9fc2b4f6720b5c472773afbe8dc18cd8961465c
2014-03-18 20:57:03 +01:00

691 lines
28 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <com/sun/star/container/XContentEnumerationAccess.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/style/XAutoStylesSupplier.hpp>
#include <com/sun/star/style/XAutoStyleFamily.hpp>
#include <com/sun/star/text/XPageCursor.hpp>
#include <com/sun/star/text/XTextDocument.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <com/sun/star/text/XTextTable.hpp>
#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
#include <com/sun/star/table/XCell.hpp>
#include <com/sun/star/table/BorderLine2.hpp>
#include <test/bootstrapfixture.hxx>
#include <unotest/macros_test.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <comphelper/processfactory.hxx>
#include <unotools/tempfile.hxx>
#include <unotxdoc.hxx>
#include <docsh.hxx>
#include <doc.hxx>
#include <rootfrm.hxx>
#include <libxml/xmlwriter.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/parserInternals.h>
using namespace com::sun::star;
#define DEFAULT_STYLE "Default Style"
#define EMU_TO_MM100(EMU) (EMU / 360)
/**
* Macro to declare a new test (with full round-trip. To test
* import only use the DECLARE_SW_IMPORT_TEST macro instead).
* In order to add a new test, one only needs to use this macro
* and then specify the test content, like this:
*
* DECLARE_SW_ROUNDTRIP_TEST(MyTest, "myfilename.docx", Test)
* {
* CPPUNIT_ASSERT_EQUAL(blabla);
* }
*
*/
#define DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, BaseClass) \
class TestName : public BaseClass { \
public:\
CPPUNIT_TEST_SUITE(TestName); \
CPPUNIT_TEST(Import); \
CPPUNIT_TEST(Import_Export_Import); \
CPPUNIT_TEST_SUITE_END(); \
\
void Import() { \
executeImportTest(filename);\
}\
void Import_Export_Import() {\
executeImportExportImportTest(filename);\
}\
void verify();\
}; \
CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
void TestName::verify()
#define DECLARE_SW_IMPORT_TEST(TestName, filename, BaseClass) \
class TestName : public BaseClass { \
public:\
CPPUNIT_TEST_SUITE(TestName); \
CPPUNIT_TEST(Import); \
CPPUNIT_TEST_SUITE_END(); \
\
void Import() { \
executeImportTest(filename);\
}\
void verify();\
}; \
CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
void TestName::verify()
/// Base class for filter tests loading or roundtriping a document, then asserting the document model.
class SwModelTestBase : public test::BootstrapFixture, public unotest::MacrosTest
{
public:
SwModelTestBase(const char* pTestDocumentPath = "", const char* pFilter = "")
: mpXmlBuffer(0),
mpTestDocumentPath(pTestDocumentPath),
mpFilter(pFilter),
m_nStartTime(0),
m_bExported(false)
{
}
~SwModelTestBase()
{
}
virtual void setUp()
{
test::BootstrapFixture::setUp();
mxDesktop.set( com::sun::star::frame::Desktop::create(comphelper::getComponentContext(getMultiServiceFactory())) );
}
virtual void tearDown()
{
if (mxComponent.is())
mxComponent->dispose();
test::BootstrapFixture::tearDown();
}
protected:
/**
* Helper func used by each unit test to test the 'import' code.
* (Loads the requested file and then calls 'verify' method)
*/
void executeImportTest(const char* filename)
{
// If the testcase is stored in some other format, it's pointless to test.
if (mustTestImportOf(filename))
{
header();
preTest(filename);
load(mpTestDocumentPath, filename);
postTest(filename);
verify();
finish();
}
}
/**
* Helper func used by each unit test to test the 'export' code.
* (Loads the requested file, save it to temp file, load the
* temp file and then calls 'verify' method)
*/
void executeImportExportImportTest(const char* filename)
{
header();
preTest(filename);
load(mpTestDocumentPath, filename);
reload(mpFilter, filename);
postTest(filename);
verify();
finish();
}
/**
* Function overloaded by unit test. See DECLARE_SW_*_TEST macros
*/
virtual void verify()
{
CPPUNIT_FAIL( "verify method must be overridden" );
}
/**
* Override this function if interested in skipping import test for this file
*/
virtual bool mustTestImportOf(const char* /* filename */) const
{
return true;
}
/**
* Override this function if some special filename-specific setup is needed
*/
virtual void preTest(const char* /*filename*/)
{
}
/**
* Override this function if some special filename-specific teardown is needed
*/
virtual void postTest(const char* /*filename*/)
{
}
/**
* Override this function if not calcing layout is needed
*/
virtual bool mustCalcLayoutOf(const char* /*filename*/)
{
return true;
}
private:
void dumpLayout()
{
// create the xml writer
mpXmlBuffer = xmlBufferCreate();
xmlTextWriterPtr pXmlWriter = xmlNewTextWriterMemory(mpXmlBuffer, 0);
xmlTextWriterStartDocument(pXmlWriter, NULL, NULL, NULL);
// create the dump
SwXTextDocument* pTxtDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
SwDoc* pDoc = pTxtDoc->GetDocShell()->GetDoc();
SwRootFrm* pLayout = pDoc->GetCurrentLayout();
pLayout->dumpAsXml(pXmlWriter);
// delete xml writer
xmlTextWriterEndDocument(pXmlWriter);
xmlFreeTextWriter(pXmlWriter);
}
void calcLayout()
{
SwXTextDocument* pTxtDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
SwDoc* pDoc = pTxtDoc->GetDocShell()->GetDoc();
pDoc->GetCurrentViewShell()->CalcLayout();
}
protected:
/// Get the length of the whole document.
int getLength()
{
uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(), uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
OUStringBuffer aBuf;
while (xParaEnum->hasMoreElements())
{
uno::Reference<container::XEnumerationAccess> xRangeEnumAccess(xParaEnum->nextElement(), uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xRangeEnum = xRangeEnumAccess->createEnumeration();
while (xRangeEnum->hasMoreElements())
{
uno::Reference<text::XTextRange> xRange(xRangeEnum->nextElement(), uno::UNO_QUERY);
aBuf.append(xRange->getString());
}
}
return aBuf.getLength();
}
/// Get a family of styles, see com.sun.star.style.StyleFamilies for possible values.
uno::Reference<container::XNameAccess> getStyles(const OUString& aFamily)
{
uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XNameAccess> xStyleFamilies(xStyleFamiliesSupplier->getStyleFamilies(), uno::UNO_QUERY);
uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName(aFamily), uno::UNO_QUERY);
return xStyleFamily;
}
/// Get a family of auto styles, see com.sun.star.style.StyleFamilies for possible values.
uno::Reference<style::XAutoStyleFamily> getAutoStyles(const OUString& aFamily)
{
uno::Reference< style::XAutoStylesSupplier > xAutoStylesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference< style::XAutoStyles > xAutoStyles(xAutoStylesSupplier->getAutoStyles());
uno::Reference< style::XAutoStyleFamily > xAutoStyleFamily(xAutoStyles->getByName(aFamily), uno::UNO_QUERY);
return xAutoStyleFamily;
}
/**
* Extract a value from the layout dump using an XPath expression and an attribute name.
*
* If the attribute is omitted, the text of the node is returned.
*/
OUString parseDump(const OString& aXPath, const OString& aAttribute = OString())
{
if (!mpXmlBuffer)
dumpLayout();
xmlDocPtr pXmlDoc = xmlParseMemory((const char*)xmlBufferContent(mpXmlBuffer), xmlBufferLength(mpXmlBuffer));;
xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pXmlDoc);
xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(aXPath.getStr()), pXmlXpathCtx);
xmlNodeSetPtr pXmlNodes = pXmlXpathObj->nodesetval;
CPPUNIT_ASSERT_EQUAL_MESSAGE("parsing dump failed", 1, xmlXPathNodeSetGetLength(pXmlNodes));
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
OUString aRet;
if (aAttribute.getLength())
aRet = OUString::createFromAscii((const char*)xmlGetProp(pXmlNode, BAD_CAST(aAttribute.getStr())));
else
aRet = OUString::createFromAscii((const char*)XML_GET_CONTENT(pXmlNode));
xmlFreeDoc(pXmlDoc);
return aRet;
}
template< typename T >
T getProperty( const uno::Any& obj, const OUString& name ) const
{
uno::Reference< beans::XPropertySet > properties( obj, uno::UNO_QUERY_THROW );
T data = T();
properties->getPropertyValue( name ) >>= data;
return data;
}
template< typename T >
T getProperty( const uno::Reference< uno::XInterface >& obj, const OUString& name ) const
{
uno::Reference< beans::XPropertySet > properties( obj, uno::UNO_QUERY_THROW );
T data = T();
properties->getPropertyValue( name ) >>= data;
return data;
}
bool hasProperty(const uno::Reference<uno::XInterface>& obj, const OUString& name) const
{
uno::Reference<beans::XPropertySet> properties(obj, uno::UNO_QUERY_THROW);
return properties->getPropertySetInfo()->hasPropertyByName(name);
}
/// Get number of paragraphs of the document.
int getParagraphs()
{
uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(), uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
int nRet = 0;
while (xParaEnum->hasMoreElements())
{
xParaEnum->nextElement();
nRet++;
}
return nRet;
}
uno::Reference<text::XTextContent> getParagraphOrTable(int number, uno::Reference<text::XText> xText = uno::Reference<text::XText>()) const
{
uno::Reference<container::XEnumerationAccess> paraEnumAccess;
if (xText.is())
paraEnumAccess.set(xText, uno::UNO_QUERY);
else
{
uno::Reference<text::XTextDocument> textDocument(mxComponent, uno::UNO_QUERY);
paraEnumAccess.set(textDocument->getText(), uno::UNO_QUERY);
}
uno::Reference<container::XEnumeration> paraEnum = paraEnumAccess->createEnumeration();
for( int i = 1;
i < number;
++i )
paraEnum->nextElement();
uno::Reference< text::XTextContent> const xElem(paraEnum->nextElement(),
uno::UNO_QUERY_THROW);
return xElem;
}
// Get paragraph (counted from 1), optionally check it contains the given text.
uno::Reference< text::XTextRange > getParagraph( int number, const OUString& content = OUString() ) const
{
uno::Reference<text::XTextRange> const xParagraph(
getParagraphOrTable(number), uno::UNO_QUERY_THROW);
if( !content.isEmpty())
CPPUNIT_ASSERT_EQUAL_MESSAGE( "paragraph does not have expected content", content, xParagraph->getString());
return xParagraph;
}
uno::Reference<text::XTextRange> getParagraphOfText(int number, uno::Reference<text::XText> xText, const OUString& content = OUString()) const
{
uno::Reference<text::XTextRange> const xParagraph(getParagraphOrTable(number, xText), uno::UNO_QUERY_THROW);
if (!content.isEmpty())
CPPUNIT_ASSERT_EQUAL_MESSAGE( "paragraph does not contain expected content", content, xParagraph->getString());
return xParagraph;
}
/// Get run (counted from 1) of a paragraph, optionally check it contains the given text.
uno::Reference<text::XTextRange> getRun(uno::Reference<text::XTextRange> xParagraph, int number, const OUString& content = OUString()) const
{
uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph, uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
for (int i = 1; i < number; ++i)
xRunEnum->nextElement();
uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
if( !content.isEmpty())
CPPUNIT_ASSERT_EQUAL_MESSAGE( "run does not contain expected content", content, xRun->getString());
return xRun;
}
/// Get math formula string of a run.
OUString getFormula(uno::Reference<text::XTextRange> xRun) const
{
uno::Reference<container::XContentEnumerationAccess> xContentEnumAccess(xRun, uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xContentEnum(xContentEnumAccess->createContentEnumeration(""), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xFormula(xContentEnum->nextElement(), uno::UNO_QUERY);
return getProperty<OUString>(getProperty< uno::Reference<beans::XPropertySet> >(xFormula, "Model"), "Formula");
}
/// get cell of a table; table can be retrieved with getParagraphOrTable
uno::Reference<table::XCell> getCell(
uno::Reference<uno::XInterface> const& xTableIfc,
OUString const& rCell, OUString const& rContent = OUString())
{
uno::Reference<text::XTextTable> const xTable(xTableIfc,
uno::UNO_QUERY_THROW);
uno::Reference<table::XCell> const xCell(
xTable->getCellByName(rCell), uno::UNO_SET_THROW);
if (!rContent.isEmpty())
{
uno::Reference<text::XText> const xCellText(xCell,
uno::UNO_QUERY_THROW);
CPPUNIT_ASSERT_EQUAL_MESSAGE("cell does not contain expected content", rContent, xCellText->getString());
}
return xCell;
}
/// Get shape (counted from 1)
uno::Reference<drawing::XShape> getShape(int number)
{
uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(number - 1), uno::UNO_QUERY);
return xShape;
}
/// Get TextFrame by name
uno::Reference<drawing::XShape> getTextFrameByName(const OUString& aName)
{
uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<container::XNameAccess> xNameAccess(xTextFramesSupplier->getTextFrames(), uno::UNO_QUERY);
uno::Reference<drawing::XShape> xShape(xNameAccess->getByName(aName), uno::UNO_QUERY);
return xShape;
}
void header()
{
std::cout << "File tested,Execution Time (ms)" << std::endl;
}
void load(const char* pDir, const char* pName)
{
if (mxComponent.is())
mxComponent->dispose();
// Output name early, so in the case of a hang, the name of the hanging input file is visible.
std::cout << pName << ",";
m_nStartTime = osl_getGlobalTimer();
mxComponent = loadFromDesktop(getURLFromSrc(pDir) + OUString::createFromAscii(pName), "com.sun.star.text.TextDocument");
if (mustCalcLayoutOf(pName))
calcLayout();
}
void reload(const char* pFilter, const char* filename)
{
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
uno::Sequence<beans::PropertyValue> aArgs(1);
aArgs[0].Name = "FilterName";
OUString aFilterName = OUString::createFromAscii(pFilter);
aArgs[0].Value <<= aFilterName;
m_aTempFile.EnableKillingFile();
xStorable->storeToURL(m_aTempFile.GetURL(), aArgs);
uno::Reference<lang::XComponent> xComponent(xStorable, uno::UNO_QUERY);
xComponent->dispose();
m_bExported = true;
mxComponent = loadFromDesktop(m_aTempFile.GetURL(), "com.sun.star.text.TextDocument");
if(aFilterName == "Office Open XML Text")
{
// too many validation errors right now
// validate(m_aTempFile.GetFileName(), test::OOXML);
}
else if(aFilterName == "writer8")
{
// still a few validation errors
// validate(m_aTempFile.GetFileName(), test::ODF);
}
if (mpXmlBuffer)
{
xmlBufferFree(mpXmlBuffer);
mpXmlBuffer = 0;
}
if (mustCalcLayoutOf(filename))
calcLayout();
}
/// Save the loaded document to a tempfile. Can be used to check the resulting docx/odt directly as a ZIP file.
void save(const OUString& aFilter, utl::TempFile& rTempFile)
{
rTempFile.EnableKillingFile();
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
uno::Sequence<beans::PropertyValue> aFilterArgs(1);
aFilterArgs[0].Name = "FilterName";
aFilterArgs[0].Value <<= aFilter;
xStorable->storeToURL(rTempFile.GetURL(), aFilterArgs);
}
void finish()
{
sal_uInt32 nEndTime = osl_getGlobalTimer();
std::cout << (nEndTime - m_nStartTime) << std::endl;
if (mpXmlBuffer)
{
xmlBufferFree(mpXmlBuffer);
mpXmlBuffer = 0;
}
}
/// Get page count.
int getPages()
{
uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(xModel->getCurrentController(), uno::UNO_QUERY);
uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(), uno::UNO_QUERY);
xCursor->jumpToLastPage();
return xCursor->getPage();
}
/**
* Given that some problem doesn't affect the result in the importer, we
* test the resulting file directly, by opening the zip file, parsing an
* xml stream, and asserting an XPath expression. This method returns the
* xml stream, so that you can do the asserting.
*/
xmlDocPtr parseExport(const OUString& rStreamName = OUString("word/document.xml"))
{
if (!m_bExported)
return 0;
// Read the XML stream we're interested in.
uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), m_aTempFile.GetURL());
uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName(rStreamName), uno::UNO_QUERY);
boost::shared_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
pStream->Seek(STREAM_SEEK_TO_END);
sal_Size nSize = pStream->Tell();
pStream->Seek(0);
OStringBuffer aDocument(nSize);
char ch;
for (sal_Size i = 0; i < nSize; ++i)
{
pStream->ReadChar( ch );
aDocument.append(ch);
}
// Parse the XML.
return xmlParseMemory((const char*)aDocument.getStr(), aDocument.getLength());
}
/**
* Helper method to return nodes represented by rXPath.
*/
xmlNodeSetPtr getXPathNode(xmlDocPtr pXmlDoc, const OString& rXPath)
{
xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pXmlDoc);
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("w"), BAD_CAST("http://schemas.openxmlformats.org/wordprocessingml/2006/main"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("v"), BAD_CAST("urn:schemas-microsoft-com:vml"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("mc"), BAD_CAST("http://schemas.openxmlformats.org/markup-compatibility/2006"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("wps"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingShape"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("wpg"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("wp"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("wp14"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("a"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/main"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("pic"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/picture"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("rels"), BAD_CAST("http://schemas.openxmlformats.org/package/2006/relationships"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("w14"), BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordml"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("m"), BAD_CAST("http://schemas.openxmlformats.org/officeDocument/2006/math"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("ContentType"), BAD_CAST("http://schemas.openxmlformats.org/package/2006/content-types"));
xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("lc"), BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"));
xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(rXPath.getStr()), pXmlXpathCtx);
return pXmlXpathObj->nodesetval;
}
/**
* Same as the assertXPath(), but don't assert: return the string instead.
*/
OUString getXPath(xmlDocPtr pXmlDoc, const OString& rXPath, const OString& rAttribute)
{
xmlNodeSetPtr pXmlNodes = getXPathNode(pXmlDoc, rXPath);
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString("XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
1, xmlXPathNodeSetGetLength(pXmlNodes));
if (rAttribute.isEmpty())
return OUString();
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
return OUString::createFromAscii((const char*)xmlGetProp(pXmlNode, BAD_CAST(rAttribute.getStr())));
}
/**
* Assert that rXPath exists, and returns exactly one node.
* In case rAttribute is provided, the rXPath's attribute's value must
* equal to the rExpected value.
*/
void assertXPath(xmlDocPtr pXmlDoc, const OString& rXPath, const OString& rAttribute = OString(), const OUString& rExpectedValue = OUString())
{
OUString aValue = getXPath(pXmlDoc, rXPath, rAttribute);
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString("Attribute '" + rAttribute + "' of '" + rXPath + "' incorrect value.").getStr(),
rExpectedValue, aValue);
}
/**
* Assert that rXPath exists, and returns exactly nNumberOfNodes nodes.
* Useful for checking that we do _not_ export some node (nNumberOfNodes == 0).
*/
void assertXPath(xmlDocPtr pXmlDoc, const OString& rXPath, int nNumberOfNodes)
{
xmlNodeSetPtr pXmlNodes = getXPathNode(pXmlDoc, rXPath);
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString("XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
nNumberOfNodes, xmlXPathNodeSetGetLength(pXmlNodes));
}
/**
* Assert that rXPath exists, and its content equals rContent.
*/
void assertXPathContent(xmlDocPtr pXmlDoc, const OString& rXPath, const OUString& rContent)
{
xmlNodeSetPtr pXmlNodes = getXPathNode(pXmlDoc, rXPath);
CPPUNIT_ASSERT_MESSAGE(OString("XPath '" + rXPath + "' not found").getStr(),
xmlXPathNodeSetGetLength(pXmlNodes) > 0);
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
CPPUNIT_ASSERT_EQUAL_MESSAGE("XPath contents of child does not match", rContent,
OUString::createFromAscii((const char*)((pXmlNode->children[0]).content)));
}
/**
* Assert that rXPath exists, and has exactly nNumberOfChildNodes child nodes.
* Useful for checking that we do have a no child nodes to a specific node (nNumberOfChildNodes == 0).
*/
void assertXPathChildren(xmlDocPtr pXmlDoc, const OString& rXPath, int nNumberOfChildNodes)
{
xmlNodeSetPtr pXmlNodes = getXPathNode(pXmlDoc, rXPath);
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString("XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
1, xmlXPathNodeSetGetLength(pXmlNodes));
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString("XPath '" + rXPath + "' number of child-nodes is incorrect").getStr(),
nNumberOfChildNodes, (int)xmlChildElementCount(pXmlNode));
}
/**
* Get the position of the child named rName of the parent node specified by rXPath.
* Useful for checking relative order of elements.
*/
int getXPathPosition(xmlDocPtr pXmlDoc, const OString& rXPath, const OUString& rChildName)
{
xmlNodeSetPtr pXmlNodes = getXPathNode(pXmlDoc, rXPath);
CPPUNIT_ASSERT_EQUAL_MESSAGE(OString("XPath '" + rXPath + "' number of nodes is incorrect").getStr(),
1,
xmlXPathNodeSetGetLength(pXmlNodes));
xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
int nRet = 0;
for (xmlNodePtr pChild = pXmlNode->children; pChild; pChild = pChild->next)
{
if (OUString::createFromAscii((const char*)pChild->name) == rChildName)
break;
++nRet;
}
return nRet;
}
uno::Reference<lang::XComponent> mxComponent;
xmlBufferPtr mpXmlBuffer;
const char* mpTestDocumentPath;
const char* mpFilter;
template< typename T >
struct MethodEntry
{
const char* pName;
void (T::*pMethod)();
};
sal_uInt32 m_nStartTime;
utl::TempFile m_aTempFile;
bool m_bExported; ///< Does m_aTempFile already contain something useful?
};
/**
* Test whether the expected and actual borderline parameters are equal
* and assert if not.
*
* @param[in] rExpected expected borderline object
* @param[in] rActual actual borderline object
* @param[in] rSourceLine line from where the assertion is called
* Note: This method is the implementatition of CPPUNIT_ASSERT_BORDER_EQUAL, so
* use that macro instead.
**/
inline void assertBorderEqual(
const table::BorderLine2& rExpected, const table::BorderLine2& rActual,
const CppUnit::SourceLine& rSourceLine )
{
CPPUNIT_NS::assertEquals<util::Color>( rExpected.Color, rActual.Color, rSourceLine, "different Color" );
CPPUNIT_NS::assertEquals<sal_Int16>( rExpected.InnerLineWidth, rActual.InnerLineWidth, rSourceLine, "different InnerLineWidth" );
CPPUNIT_NS::assertEquals<sal_Int16>( rExpected.OuterLineWidth, rActual.OuterLineWidth, rSourceLine, "different OuterLineWidth" );
CPPUNIT_NS::assertEquals<sal_Int16>( rExpected.LineDistance, rActual.LineDistance, rSourceLine, "different LineDistance" );
CPPUNIT_NS::assertEquals<sal_Int16>( rExpected.LineStyle, rActual.LineStyle, rSourceLine, "different LineStyle" );
CPPUNIT_NS::assertEquals<sal_Int32>( rExpected.LineWidth, rActual.LineWidth, rSourceLine, "different LineWidth" );
}
#define CPPUNIT_ASSERT_BORDER_EQUAL(aExpected, aActual) \
assertBorderEqual( aExpected, aActual, CPPUNIT_SOURCELINE() ) \
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */