summaryrefslogtreecommitdiffstats
path: root/sw/qa/inc/swmodeltestbase.hxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sw/qa/inc/swmodeltestbase.hxx430
1 files changed, 430 insertions, 0 deletions
diff --git a/sw/qa/inc/swmodeltestbase.hxx b/sw/qa/inc/swmodeltestbase.hxx
new file mode 100644
index 000000000..ed7beefbb
--- /dev/null
+++ b/sw/qa/inc/swmodeltestbase.hxx
@@ -0,0 +1,430 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_SW_QA_INC_SWMODELTESTBASE_HXX
+#define INCLUDED_SW_QA_INC_SWMODELTESTBASE_HXX
+
+#include <memory>
+#include <string_view>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/style/XAutoStyleFamily.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/table/XCell.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/xml/AttributeData.hpp>
+
+#include "swqahelperdllapi.h"
+#include <test/bootstrapfixture.hxx>
+#include <test/xmltesttools.hxx>
+#include <test/testinteractionhandler.hxx>
+#include <unotest/macros_test.hxx>
+#include <unotools/tempfile.hxx>
+
+#include <doc.hxx>
+
+/**
+ * Macro to declare a new test (with full round-trip. To test
+ * import only use the CPPUNIT_TEST_FIXTURE macro directly).
+ * 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, password, BaseClass) \
+ class TestName : public BaseClass { \
+ protected:\
+ virtual OUString getTestName() override { return #TestName; } \
+ public:\
+ CPPUNIT_TEST_SUITE(TestName); \
+ CPPUNIT_TEST(Load_Verify_Reload_Verify); \
+ CPPUNIT_TEST_SUITE_END(); \
+ \
+ void Load_Verify_Reload_Verify() {\
+ executeLoadVerifyReloadVerify(filename, password);\
+ }\
+ void verify() override;\
+ }; \
+ CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
+ void TestName::verify()
+
+#define DECLARE_OOXMLEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, Test)
+#define DECLARE_RTFEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, Test)
+#define DECLARE_ODFEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, Test)
+#define DECLARE_FODFEXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, Test)
+#define DECLARE_WW8EXPORT_TEST(TestName, filename) DECLARE_SW_ROUNDTRIP_TEST(TestName, filename, nullptr, Test)
+
+#define DECLARE_SW_EXPORT_TEST(TestName, filename, password, BaseClass) \
+ class TestName : public BaseClass { \
+ protected:\
+ virtual OUString getTestName() override { return #TestName; } \
+ public:\
+ CPPUNIT_TEST_SUITE(TestName); \
+ CPPUNIT_TEST(Import_Export); \
+ CPPUNIT_TEST_SUITE_END(); \
+ \
+ void Import_Export() {\
+ executeImportExport(filename, password);\
+ }\
+ void verify() override;\
+ }; \
+ CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
+ void TestName::verify()
+
+/// Base class for filter tests loading or roundtripping a document, then asserting the document model.
+class SWQAHELPER_DLLPUBLIC SwModelTestBase : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
+{
+private:
+ OUString maFilterOptions;
+ OUString maImportFilterOptions;
+ OUString maImportFilterName;
+
+protected:
+ css::uno::Reference< css::lang::XComponent > mxComponent;
+
+ rtl::Reference<TestInteractionHandler> xInteractionHandler;
+
+ xmlBufferPtr mpXmlBuffer;
+ const OUString mpTestDocumentPath;
+ const char* mpFilter;
+
+ sal_uInt32 mnStartTime;
+ utl::TempFile maTempFile;
+ bool mbExported; ///< Does maTempFile already contain something useful?
+ bool mbFontNameWYSIWYG;
+
+protected:
+
+ virtual OUString getTestName() { return OUString(); }
+
+ /// Copy&paste helper.
+ void paste(std::u16string_view aFilename, css::uno::Reference<css::text::XTextRange> const& xTextRange);
+
+public:
+ void setFilterOptions(const OUString &rFilterOptions)
+ {
+ maFilterOptions = rFilterOptions;
+ }
+
+ void setImportFilterOptions(const OUString &rFilterOptions)
+ {
+ maImportFilterOptions = rFilterOptions;
+ }
+
+ void setImportFilterName(const OUString &rFilterName)
+ {
+ maImportFilterName = rFilterName;
+ }
+
+ SwModelTestBase(const OUString& pTestDocumentPath = OUString(), const char* pFilter = "");
+
+ void setUp() override;
+
+ void tearDown() override;
+
+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, const char* pPassword = nullptr);
+
+ /**
+ * Helper func used by each unit test to test the 'export' code.
+ * (Loads the requested file, calls 'verify' function, save it to temp file, load the
+ * temp file and then calls 'verify' function again)
+ */
+ void executeLoadVerifyReloadVerify(const char* filename, const char* pPassword = nullptr);
+
+ /**
+ * 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 executeLoadReloadVerify(const char* filename, const char* pPassword = nullptr);
+
+ /**
+ * Helper func used by each unit test to test the 'export' code.
+ * (Loads the requested file for document base (this represents
+ * the initial document condition), exports with the desired
+ * export filter and then calls 'verify' method)
+ */
+ void executeImportExport(const char* filename, const char* pPassword);
+
+ /**
+ * Function overridden 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 std::unique_ptr<Resetter> preTest(const char* /*filename*/)
+ {
+ return nullptr;
+ }
+
+ /// Override this function if some special file-specific setup is needed during export test: after load, but before save.
+ virtual void postLoad(const char* /*pFilename*/)
+ {
+ }
+
+ /**
+ * Override this function if calc layout is not needed
+ */
+ virtual bool mustCalcLayoutOf(const char* /*filename*/)
+ {
+ return true;
+ }
+
+ /**
+ * Override this function if validation is wanted
+ */
+ virtual bool mustValidate(const char* /*filename*/) const
+ {
+ return false;
+ }
+
+protected:
+ void dumpLayout(const css::uno::Reference< css::lang::XComponent > & rComponent);
+
+ void discardDumpedLayout();
+
+ void calcLayout();
+
+ /// Get the length of the whole document. @deprecated why use this?
+ int getLength() const;
+ /// Get the body text of the whole document.
+ OUString getBodyText() const;
+
+ /// Get a family of styles, see com.sun.star.style.StyleFamilies for possible values.
+ css::uno::Reference<css::container::XNameAccess> getStyles(const OUString& aFamily);
+
+ /// Get a family of auto styles, see com.sun.star.style.StyleFamilies for possible values.
+ css::uno::Reference<css::style::XAutoStyleFamily> getAutoStyles(const OUString& aFamily);
+
+ /// Similar to parseExport(), but this gives the xmlDocPtr of the layout dump.
+ xmlDocUniquePtr parseLayoutDump();
+
+ /**
+ * 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());
+
+ template< typename T >
+ T getProperty( const css::uno::Any& obj, const OUString& name ) const
+ {
+ css::uno::Reference< css::beans::XPropertySet > properties( obj, uno::UNO_QUERY_THROW );
+ T data;
+ if (!css::uno::fromAny(properties->getPropertyValue(name), &data))
+ {
+ OString const msg("the property is of unexpected type or void: "
+ + OUStringToOString(name, RTL_TEXTENCODING_UTF8));
+ CPPUNIT_FAIL(msg.getStr());
+ }
+ return data;
+ }
+
+ template< typename T >
+ T getProperty( const css::uno::Reference< css::uno::XInterface >& obj, const OUString& name ) const
+ {
+ css::uno::Reference< css::beans::XPropertySet > properties( obj, uno::UNO_QUERY_THROW );
+ T data = T();
+ if (!(properties->getPropertyValue(name) >>= data))
+ {
+ OString const msg("the property is of unexpected type or void: "
+ + OUStringToOString(name, RTL_TEXTENCODING_UTF8));
+ CPPUNIT_FAIL(msg.getStr());
+ }
+ return data;
+ }
+
+ bool hasProperty(const css::uno::Reference<css::uno::XInterface>& obj, const OUString& name) const;
+
+ css::xml::AttributeData getUserDefineAttribute(const css::uno::Any& obj, const OUString& name, const OUString& rValue) const;
+
+ int getParagraphs( css::uno::Reference<text::XText> const & xText );
+
+ /// Get number of paragraphs of the document.
+ int getParagraphs();
+
+ css::uno::Reference<css::text::XTextContent> getParagraphOrTable(int number, css::uno::Reference<css::text::XText> const & xText = css::uno::Reference<css::text::XText>()) const;
+
+ // Get paragraph (counted from 1), optionally check it contains the given text.
+ css::uno::Reference< css::text::XTextRange > getParagraph( int number, const OUString& content = OUString() ) const;
+
+ sal_Int16 getNumberingTypeOfParagraph(int nPara);
+
+ css::uno::Reference<css::text::XTextRange> getParagraphOfText(int number, css::uno::Reference<css::text::XText> const & xText, const OUString& content = OUString()) const;
+
+ /// get nth object/fly that is anchored AT paragraph
+ css::uno::Reference<css::beans::XPropertySet> getParagraphAnchoredObject(
+ int const index, css::uno::Reference<css::text::XTextRange> const & xPara) const;
+
+ /// Get run (counted from 1) of a paragraph, optionally check it contains the given text.
+ css::uno::Reference<css::text::XTextRange> getRun(uno::Reference<css::text::XTextRange> const & xParagraph, int number, const OUString& content = OUString()) const;
+
+ /// Get math formula string of a run.
+ OUString getFormula(css::uno::Reference<css::text::XTextRange> const & xRun) const;
+
+ /// get cell of a table; table can be retrieved with getParagraphOrTable
+ css::uno::Reference<css::table::XCell> getCell(
+ css::uno::Reference<css::uno::XInterface> const& xTableIfc,
+ OUString const& rCell, OUString const& rContent = OUString());
+
+ /// Get shape (counted from 1)
+ css::uno::Reference<css::drawing::XShape> getShape(int number);
+
+ /// Get shape by name
+ css::uno::Reference<css::drawing::XShape> getShapeByName(std::u16string_view aName);
+
+ /// Get TextFrame by name
+ css::uno::Reference<css::drawing::XShape> getTextFrameByName(const OUString& aName);
+
+ void header();
+
+ void load(std::u16string_view pDir, const char* pName, const char* pPassword = nullptr)
+ {
+ return loadURLWithComponent(m_directories.getURLFromSrc(pDir) + OUString::createFromAscii(pName),
+ "com.sun.star.text.TextDocument", pName, pPassword);
+ }
+
+ void load_web(std::u16string_view pDir, const char* pName, const char* pPassword = nullptr)
+ {
+ return loadURLWithComponent(m_directories.getURLFromSrc(pDir) + OUString::createFromAscii(pName),
+ "com.sun.star.text.WebDocument", pName, pPassword);
+ }
+
+ void setTestInteractionHandler(const char* pPassword, std::vector<beans::PropertyValue>& rFilterOptions);
+
+ void loadURLWithComponent(OUString const& rURL, OUString const& rComponent, const char* pName, const char* pPassword);
+
+ void loadURL(OUString const& rURL, const char* pName, const char* pPassword = nullptr);
+
+ void reload(const char* pFilter, const char* filename, const char* pPassword = nullptr);
+
+ /// 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& aFilterName, utl::TempFile& rTempFile);
+
+ /// Combines load() and save().
+ void loadAndSave(const char* pName);
+
+ /// Combines load() and reload().
+ void loadAndReload(const char* pName);
+
+ void finish();
+
+ /// Get page count.
+ int getPages() const;
+
+ /// Get shape count.
+ int getShapes() const;
+
+ /**
+ * 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.
+ */
+ xmlDocUniquePtr parseExport(const OUString& rStreamName = OUString("word/document.xml"));
+
+ /**
+ * Returns an xml stream of an exported file.
+ * To be used when the exporter doesn't create zip archives, but single files
+ * (like Flat ODF Export)
+ */
+ xmlDocUniquePtr parseExportedFile();
+
+ std::unique_ptr<SvStream> parseExportStream(const OUString& url, const OUString& rStreamName);
+
+ xmlDocUniquePtr parseExportInternal(const OUString& url, const OUString& rStreamName);
+
+ /**
+ * Helper method to return nodes represented by rXPath.
+ */
+ void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
+
+ /**
+ * Creates a new document to be used with the internal sw/ API.
+ *
+ * Examples:
+ * SwDoc* pDoc = createSwDoc();
+ * SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "test.fodt");
+ */
+ SwDoc* createSwDoc(
+ std::u16string_view rDataDirectory = std::u16string_view(), const char* pName = nullptr);
+
+ /**
+ * As createSwDoc except a Web Document in Browse Mode
+ */
+ SwDoc* createSwWebDoc(
+ std::u16string_view rDataDirectory = std::u16string_view(), const char* pName = nullptr);
+
+ /**
+ * Wraps a reqif-xhtml fragment into an XHTML file, so an XML parser can
+ * parse it.
+ */
+ void WrapReqifFromTempFile(SvMemoryStream& rStream);
+};
+
+/**
+ * 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 implementation of CPPUNIT_ASSERT_BORDER_EQUAL, so
+ * use that macro instead.
+**/
+inline void assertBorderEqual(
+ const css::table::BorderLine2& rExpected, const css::table::BorderLine2& rActual,
+ const CppUnit::SourceLine& rSourceLine )
+{
+ CPPUNIT_NS::assertEquals<css::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() ) \
+
+inline std::ostream& operator<<(std::ostream& rStrm, const Color& rColor)
+{
+ rStrm << "Color: R:" << static_cast<int>(rColor.GetRed())
+ << " G:" << static_cast<int>(rColor.GetGreen())
+ << " B:" << static_cast<int>(rColor.GetBlue())
+ << " A:" << static_cast<int>(255 - rColor.GetAlpha());
+ return rStrm;
+}
+
+#endif // INCLUDED_SW_QA_INC_SWMODELTESTBASE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */