/* * Version: MPL 1.1 / GPLv3+ / LGPLv3+ * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Initial Developer of the Original Code is * Miklos Vajna <vmiklos@suse.cz> (SUSE, Inc.) * Portions created by the Initial Developer are Copyright (C) 2012 the * Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 3 or later (the "GPLv3+"), or * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable * instead of those above. */ #include <com/sun/star/container/XContentEnumerationAccess.hpp> #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> #include <com/sun/star/text/XTextDocument.hpp> #include <com/sun/star/text/XTextRange.hpp> #include <test/bootstrapfixture.hxx> #include <unotest/macros_test.hxx> #include <rtl/ustrbuf.hxx> #include <unotxdoc.hxx> #include <docsh.hxx> #include <doc.hxx> #include <rootfrm.hxx> #include <libxml/xmlwriter.h> #include <libxml/xpath.h> using namespace com::sun::star; /// 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() : mpXmlBuffer(0) { } ~SwModelTestBase() { if (mpXmlBuffer) xmlBufferFree(mpXmlBuffer); } virtual void setUp() { test::BootstrapFixture::setUp(); mxDesktop.set(getMultiServiceFactory()->createInstance("com.sun.star.frame.Desktop"), uno::UNO_QUERY); CPPUNIT_ASSERT(mxDesktop.is()); } virtual void tearDown() { if (mxComponent.is()) mxComponent->dispose(); test::BootstrapFixture::tearDown(); } 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); } 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(); rtl::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(rtl::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; } /** * 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. */ rtl::OUString parseDump(rtl::OString aXPath, rtl::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(1, xmlXPathNodeSetGetLength(pXmlNodes)); xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0]; rtl::OUString aRet; if (aAttribute.getLength()) aRet = rtl::OUString::createFromAscii((const char*)xmlGetProp(pXmlNode, BAD_CAST(aAttribute.getStr()))); else aRet = rtl::OUString::createFromAscii((const char*)XML_GET_CONTENT(pXmlNode)); xmlFreeDoc(pXmlDoc); return aRet; } template< typename T > T getProperty( uno::Any obj, const rtl::OUString& name ) const { uno::Reference< beans::XPropertySet > properties( obj, uno::UNO_QUERY ); T data = T(); properties->getPropertyValue( name ) >>= data; return data; } template< typename T > T getProperty( uno::Reference< uno::XInterface > obj, const rtl::OUString& name ) const { uno::Reference< beans::XPropertySet > properties( obj, uno::UNO_QUERY ); T data = T(); properties->getPropertyValue( name ) >>= data; return data; } /// 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; } // Get paragraph (counted from 1), optionally check it contains the given text. uno::Reference< text::XTextRange > getParagraph( int number, OUString content = OUString() ) const { uno::Reference<text::XTextDocument> textDocument(mxComponent, uno::UNO_QUERY); uno::Reference<container::XEnumerationAccess> paraEnumAccess(textDocument->getText(), uno::UNO_QUERY); uno::Reference<container::XEnumeration> paraEnum = paraEnumAccess->createEnumeration(); for( int i = 1; i < number; ++i ) paraEnum->nextElement(); uno::Reference< text::XTextRange > paragraph( paraEnum->nextElement(), uno::UNO_QUERY ); if( !content.isEmpty()) CPPUNIT_ASSERT_EQUAL( content, paragraph->getString()); return paragraph; } /// 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, 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( 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"); } uno::Reference<lang::XComponent> mxComponent; xmlBufferPtr mpXmlBuffer; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */