summaryrefslogtreecommitdiffstats
path: root/sw/qa/unit
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sw/qa/unit/data/sw-dialogs-test.txt207
-rw-r--r--sw/qa/unit/data/sw-dialogs-test_2.txt76
-rw-r--r--sw/qa/unit/sw-dialogs-test.cxx103
-rw-r--r--sw/qa/unit/sw-dialogs-test_2.cxx94
-rw-r--r--sw/qa/unit/swmodeltestbase.cxx768
-rw-r--r--sw/qa/unit/uibase.cxx44
6 files changed, 1292 insertions, 0 deletions
diff --git a/sw/qa/unit/data/sw-dialogs-test.txt b/sw/qa/unit/data/sw-dialogs-test.txt
new file mode 100644
index 000000000..93fb6911b
--- /dev/null
+++ b/sw/qa/unit/data/sw-dialogs-test.txt
@@ -0,0 +1,207 @@
+# -*- 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/.
+#
+
+# This file contains all dialogs that the unit tests in the module
+# will work on if it is in script mode. It will read one-by-one,
+# try to open it and create a screenshot that will be saved in
+# workdir/screenshots using the pattern of the ui-file name.
+#
+# Syntax:
+# - empty lines are allowed
+# - lines starting with '#' are treated as comment
+# - all other lines should contain a *.ui filename in the same
+# notation as in the dialog constructors (see code)
+
+#
+# The 'known' dialogs which have a hard-coded representation
+# in registerKnownDialogsByID/createDialogByID
+#
+
+# No known dialogs in writer for now
+
+#
+# Dialogs without a hard-coded representation. These will
+# be visualized using a fallback based on weld::Builder
+#
+
+# currently deactivated, leads to problems and the test to not work
+# This is typically a hint that these should be hard-coded in the
+# test case since they need some document and model data to work
+#
+# modules/swriter/ui/templatedialog(nRegion).ui
+# modules/swriter/ui/autoformattable.ui
+# modules/swriter/ui/endnotepage.ui
+# modules/swriter/ui/footnotesendnotestabpage.ui
+# modules/swriter/ui/linenumbering.ui
+# modules/swriter/ui/footnotepage.ui
+# modules/swriter/ui/outlinenumberingpage.ui
+# modules/swriter/ui/picturepage.ui <- problems under Linux
+#
+# Problems under ASan/UBSan, SwEnvPreview needs SwEnvDlg as parent:
+# modules/swriter/ui/envaddresspage.ui
+# modules/swriter/ui/envformatpage.ui
+# modules/swriter/ui/envprinterpage.ui
+
+modules/swriter/ui/abstractdialog.ui
+modules/swriter/ui/addentrydialog.ui
+modules/swriter/ui/addressblockdialog.ui
+modules/swriter/ui/alreadyexistsdialog.ui
+modules/swriter/ui/asciifilterdialog.ui
+modules/swriter/ui/asksearchdialog.ui
+modules/swriter/ui/assignfieldsdialog.ui
+modules/swriter/ui/assignstylesdialog.ui
+modules/swriter/ui/attachnamedialog.ui
+modules/swriter/ui/authenticationsettingsdialog.ui
+modules/swriter/ui/autotext.ui
+modules/swriter/ui/bibliographyentry.ui
+modules/swriter/ui/bulletsandnumbering.ui
+modules/swriter/ui/businessdatapage.ui
+modules/swriter/ui/cannotsavelabeldialog.ui
+modules/swriter/ui/captiondialog.ui
+modules/swriter/ui/captionoptions.ui
+modules/swriter/ui/cardmediumpage.ui
+modules/swriter/ui/ccdialog.ui
+modules/swriter/ui/characterproperties.ui
+modules/swriter/ui/charurlpage.ui
+modules/swriter/ui/columndialog.ui
+modules/swriter/ui/columnpage.ui
+modules/swriter/ui/columnwidth.ui
+modules/swriter/ui/conditionpage.ui
+modules/swriter/ui/converttexttable.ui
+modules/swriter/ui/createaddresslist.ui
+modules/swriter/ui/createauthorentry.ui
+modules/swriter/ui/createautomarkdialog.ui
+modules/swriter/ui/customizeaddrlistdialog.ui
+modules/swriter/ui/datasourcesunavailabledialog.ui
+modules/swriter/ui/dropcapspage.ui
+modules/swriter/ui/dropdownfielddialog.ui
+modules/swriter/ui/editcategories.ui
+modules/swriter/ui/editfielddialog.ui
+modules/swriter/ui/editsectiondialog.ui
+modules/swriter/ui/envdialog.ui
+modules/swriter/ui/exchangedatabases.ui
+modules/swriter/ui/fielddialog.ui
+modules/swriter/ui/findentrydialog.ui
+modules/swriter/ui/flddbpage.ui
+modules/swriter/ui/flddocinfopage.ui
+modules/swriter/ui/flddocumentpage.ui
+modules/swriter/ui/fldfuncpage.ui
+modules/swriter/ui/fldrefpage.ui
+modules/swriter/ui/fldvarpage.ui
+modules/swriter/ui/floatingsync.ui
+modules/swriter/ui/footendnotedialog.ui
+modules/swriter/ui/footnoteareapage.ui
+modules/swriter/ui/formatsectiondialog.ui
+modules/swriter/ui/formattablepage.ui
+modules/swriter/ui/frmaddpage.ui
+modules/swriter/ui/frmtypepage.ui
+modules/swriter/ui/frmurlpage.ui
+modules/swriter/ui/indentpage.ui
+modules/swriter/ui/indexentry.ui
+modules/swriter/ui/infonotfounddialog.ui
+modules/swriter/ui/inforeadonlydialog.ui
+modules/swriter/ui/inputfielddialog.ui
+modules/swriter/ui/insertautotextdialog.ui
+modules/swriter/ui/insertbookmark.ui
+modules/swriter/ui/insertbreak.ui
+modules/swriter/ui/insertcaption.ui
+modules/swriter/ui/insertdbcolumnsdialog.ui
+modules/swriter/ui/insertfootnote.ui
+modules/swriter/ui/insertscript.ui
+modules/swriter/ui/insertsectiondialog.ui
+modules/swriter/ui/inserttable.ui
+modules/swriter/ui/labeldialog.ui
+modules/swriter/ui/labelformatpage.ui
+modules/swriter/ui/labeloptionspage.ui
+modules/swriter/ui/mailconfigpage.ui
+modules/swriter/ui/mailmerge.ui
+modules/swriter/ui/mailmergedialog.ui
+modules/swriter/ui/managechangessidebar.ui
+modules/swriter/ui/mergeconnectdialog.ui
+modules/swriter/ui/mergetabledialog.ui
+modules/swriter/ui/mmaddressblockpage.ui
+modules/swriter/ui/mmcreatingdialog.ui
+modules/swriter/ui/mmlayoutpage.ui
+modules/swriter/ui/mmmailbody.ui
+modules/swriter/ui/mmoutputtypepage.ui
+modules/swriter/ui/mmresultemaildialog.ui
+modules/swriter/ui/mmresultprintdialog.ui
+modules/swriter/ui/mmresultsavedialog.ui
+modules/swriter/ui/mmsalutationpage.ui
+modules/swriter/ui/mmselectpage.ui
+modules/swriter/ui/mmsendmails.ui
+modules/swriter/ui/newuserindexdialog.ui
+modules/swriter/ui/notebookbar.ui
+modules/swriter/ui/numberingnamedialog.ui
+modules/swriter/ui/numparapage.ui
+modules/swriter/ui/optcaptionpage.ui
+modules/swriter/ui/optcomparison.ui
+modules/swriter/ui/optcompatpage.ui
+modules/swriter/ui/optfonttabpage.ui
+modules/swriter/ui/optformataidspage.ui
+modules/swriter/ui/optgeneralpage.ui
+modules/swriter/ui/optredlinepage.ui
+modules/swriter/ui/opttablepage.ui
+modules/swriter/ui/opttestpage.ui
+modules/swriter/ui/outlinenumbering.ui
+modules/swriter/ui/outlinepositionpage.ui
+modules/swriter/ui/paradialog.ui
+modules/swriter/ui/previewzoomdialog.ui
+modules/swriter/ui/printeroptions.ui
+modules/swriter/ui/printmergedialog.ui
+modules/swriter/ui/printmonitordialog.ui
+modules/swriter/ui/printoptionspage.ui
+modules/swriter/ui/privateuserpage.ui
+modules/swriter/ui/querycontinuebegindialog.ui
+modules/swriter/ui/querycontinueenddialog.ui
+modules/swriter/ui/querydefaultcompatdialog.ui
+modules/swriter/ui/querysavelabeldialog.ui
+modules/swriter/ui/renameautotextdialog.ui
+modules/swriter/ui/renameentrydialog.ui
+modules/swriter/ui/renameobjectdialog.ui
+modules/swriter/ui/rowheight.ui
+modules/swriter/ui/saveashtmldialog.ui
+modules/swriter/ui/savelabeldialog.ui
+modules/swriter/ui/sectionpage.ui
+modules/swriter/ui/selectaddressdialog.ui
+modules/swriter/ui/selectautotextdialog.ui
+modules/swriter/ui/selectblockdialog.ui
+modules/swriter/ui/selectindexdialog.ui
+modules/swriter/ui/selecttabledialog.ui
+modules/swriter/ui/sidebarstylepresets.ui
+modules/swriter/ui/sidebartheme.ui
+modules/swriter/ui/sidebarwrap.ui
+modules/swriter/ui/sortdialog.ui
+modules/swriter/ui/splittable.ui
+modules/swriter/ui/statisticsinfopage.ui
+modules/swriter/ui/stringinput.ui
+modules/swriter/ui/subjectdialog.ui
+modules/swriter/ui/tablecolumnpage.ui
+modules/swriter/ui/tablepreviewdialog.ui
+modules/swriter/ui/tableproperties.ui
+modules/swriter/ui/tabletextflowpage.ui
+modules/swriter/ui/testmailsettings.ui
+modules/swriter/ui/textgridpage.ui
+modules/swriter/ui/titlepage.ui
+modules/swriter/ui/tocdialog.ui
+modules/swriter/ui/tocentriespage.ui
+modules/swriter/ui/tocindexpage.ui
+modules/swriter/ui/tocstylespage.ui
+modules/swriter/ui/tokenwidget.ui
+modules/swriter/ui/viewoptionspage.ui
+modules/swriter/ui/warndatasourcedialog.ui
+modules/swriter/ui/warnemaildialog.ui
+modules/swriter/ui/wordcount.ui
+modules/swriter/ui/wrapdialog.ui
+modules/swriter/ui/wrappage.ui
+modules/swriter/ui/indexentry.ui
+modules/swriter/ui/bibliographyentry.ui
+modules/swriter/ui/inforeadonlydialog.ui
+modules/swriter/ui/inforeadonlydialog.ui
+modules/swriter/ui/inforeadonlydialog.ui
diff --git a/sw/qa/unit/data/sw-dialogs-test_2.txt b/sw/qa/unit/data/sw-dialogs-test_2.txt
new file mode 100644
index 000000000..9ddde7617
--- /dev/null
+++ b/sw/qa/unit/data/sw-dialogs-test_2.txt
@@ -0,0 +1,76 @@
+# -*- 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/.
+#
+
+# see sw-dialogs-test.txt
+
+modules/swriter/ui/optcaptionpage.ui
+modules/swriter/ui/optcomparison.ui
+modules/swriter/ui/optcompatpage.ui
+modules/swriter/ui/optfonttabpage.ui
+modules/swriter/ui/optformataidspage.ui
+modules/swriter/ui/optgeneralpage.ui
+modules/swriter/ui/optredlinepage.ui
+modules/swriter/ui/opttablepage.ui
+modules/swriter/ui/opttestpage.ui
+modules/swriter/ui/outlinenumbering.ui
+modules/swriter/ui/outlinepositionpage.ui
+modules/swriter/ui/paradialog.ui
+modules/swriter/ui/previewzoomdialog.ui
+modules/swriter/ui/printeroptions.ui
+modules/swriter/ui/printmergedialog.ui
+modules/swriter/ui/printmonitordialog.ui
+modules/swriter/ui/printoptionspage.ui
+modules/swriter/ui/privateuserpage.ui
+modules/swriter/ui/querycontinuebegindialog.ui
+modules/swriter/ui/querycontinueenddialog.ui
+modules/swriter/ui/querydefaultcompatdialog.ui
+modules/swriter/ui/querysavelabeldialog.ui
+modules/swriter/ui/renameautotextdialog.ui
+modules/swriter/ui/renameentrydialog.ui
+modules/swriter/ui/renameobjectdialog.ui
+modules/swriter/ui/rowheight.ui
+modules/swriter/ui/saveashtmldialog.ui
+modules/swriter/ui/savelabeldialog.ui
+modules/swriter/ui/sectionpage.ui
+modules/swriter/ui/selectaddressdialog.ui
+modules/swriter/ui/selectautotextdialog.ui
+modules/swriter/ui/selectblockdialog.ui
+modules/swriter/ui/selectindexdialog.ui
+modules/swriter/ui/selecttabledialog.ui
+modules/swriter/ui/sidebarstylepresets.ui
+modules/swriter/ui/sidebartheme.ui
+modules/swriter/ui/sidebarwrap.ui
+modules/swriter/ui/sortdialog.ui
+modules/swriter/ui/splittable.ui
+modules/swriter/ui/statisticsinfopage.ui
+modules/swriter/ui/stringinput.ui
+modules/swriter/ui/subjectdialog.ui
+modules/swriter/ui/tablecolumnpage.ui
+modules/swriter/ui/tablepreviewdialog.ui
+modules/swriter/ui/tableproperties.ui
+modules/swriter/ui/tabletextflowpage.ui
+modules/swriter/ui/testmailsettings.ui
+modules/swriter/ui/textgridpage.ui
+modules/swriter/ui/titlepage.ui
+modules/swriter/ui/tocdialog.ui
+modules/swriter/ui/tocentriespage.ui
+modules/swriter/ui/tocindexpage.ui
+modules/swriter/ui/tocstylespage.ui
+modules/swriter/ui/tokenwidget.ui
+modules/swriter/ui/viewoptionspage.ui
+modules/swriter/ui/warndatasourcedialog.ui
+modules/swriter/ui/warnemaildialog.ui
+modules/swriter/ui/wordcount.ui
+modules/swriter/ui/wrapdialog.ui
+modules/swriter/ui/wrappage.ui
+modules/swriter/ui/indexentry.ui
+modules/swriter/ui/bibliographyentry.ui
+modules/swriter/ui/inforeadonlydialog.ui
+modules/swriter/ui/inforeadonlydialog.ui
+modules/swriter/ui/inforeadonlydialog.ui
diff --git a/sw/qa/unit/sw-dialogs-test.cxx b/sw/qa/unit/sw-dialogs-test.cxx
new file mode 100644
index 000000000..48652ca1d
--- /dev/null
+++ b/sw/qa/unit/sw-dialogs-test.cxx
@@ -0,0 +1,103 @@
+/* -*- 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 <sal/config.h>
+#include <test/screenshot_test.hxx>
+#include <rtl/bootstrap.hxx>
+#include <osl/module.hxx>
+#include <tools/svlibrary.h>
+#include <vcl/abstdlg.hxx>
+
+class SwAbstractDialogFactory;
+
+using namespace ::com::sun::star;
+
+extern "C" { using Fn = SwAbstractDialogFactory * (*)(); }
+ // sw/source/ui/dialog/swuiexp.cxx
+
+/// Test opening a dialog in sw
+class SwDialogsTest : public ScreenshotTest
+{
+private:
+ css::uno::Reference<css::lang::XComponent> component_;
+ osl::Module libSwui_;
+
+ /// helper method to populate KnownDialogs, called in setUp(). Needs to be
+ /// written and has to add entries to KnownDialogs
+ virtual void registerKnownDialogsByID(mapType& rKnownDialogs) override;
+
+ /// dialog creation for known dialogs by ID. Has to be implemented for
+ /// each registered known dialog
+ virtual VclPtr<VclAbstractDialog> createDialogByID(sal_uInt32 nID) override;
+
+public:
+ SwDialogsTest();
+
+ void setUp() override;
+
+ void tearDown() override;
+
+ // try to open a dialog
+ void openAnyDialog();
+
+ CPPUNIT_TEST_SUITE(SwDialogsTest);
+ CPPUNIT_TEST(openAnyDialog);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+SwDialogsTest::SwDialogsTest()
+{
+}
+
+void SwDialogsTest::setUp()
+{
+ ScreenshotTest::setUp();
+ // Make sure the sw library's global pSwResMgr is initialized:
+ component_ = loadFromDesktop(
+ "private:factory/swriter", "com.sun.star.text.TextDocument");
+ // Make sure the swui library's global pSwResMgr is initialized
+ // (alternatively to dynamically loading the library, SwCreateDialogFactory
+ // could be declared in an include file and this CppunitTest link against
+ // the swui library):
+ OUString url("${LO_LIB_DIR}/" SVLIBRARY("swui"));
+ rtl::Bootstrap::expandMacros(url); //TODO: detect failure
+ CPPUNIT_ASSERT(libSwui_.load(url, SAL_LOADMODULE_GLOBAL));
+ auto fn = reinterpret_cast<Fn>(
+ libSwui_.getFunctionSymbol("SwCreateDialogFactory"));
+ CPPUNIT_ASSERT(fn != nullptr);
+ (*fn)();
+}
+
+void SwDialogsTest::tearDown()
+{
+ component_->dispose();
+ ScreenshotTest::tearDown();
+}
+
+void SwDialogsTest::registerKnownDialogsByID(mapType& /*rKnownDialogs*/)
+{
+ // fill map of known dialogs
+}
+
+VclPtr<VclAbstractDialog> SwDialogsTest::createDialogByID(sal_uInt32 /*nID*/)
+{
+ return nullptr;
+}
+
+void SwDialogsTest::openAnyDialog()
+{
+ /// process input file containing the UXMLDescriptions of the dialogs to dump
+ processDialogBatchFile(u"sw/qa/unit/data/sw-dialogs-test.txt");
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SwDialogsTest);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/unit/sw-dialogs-test_2.cxx b/sw/qa/unit/sw-dialogs-test_2.cxx
new file mode 100644
index 000000000..42e8d4b78
--- /dev/null
+++ b/sw/qa/unit/sw-dialogs-test_2.cxx
@@ -0,0 +1,94 @@
+/* -*- 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 <sal/config.h>
+#include <test/screenshot_test.hxx>
+#include <rtl/bootstrap.hxx>
+#include <osl/module.hxx>
+#include <tools/svlibrary.h>
+#include <vcl/abstdlg.hxx>
+
+#include <swdll.hxx>
+
+class SwAbstractDialogFactory;
+
+using namespace ::com::sun::star;
+
+extern "C" { using Fn = SwAbstractDialogFactory * (*)(); }
+ // sw/source/ui/dialog/swuiexp.cxx
+
+/// Test opening a dialog in sw
+class SwDialogsTest2 : public ScreenshotTest
+{
+private:
+ osl::Module libSwui_;
+
+ /// helper method to populate KnownDialogs, called in setUp(). Needs to be
+ /// written and has to add entries to KnownDialogs
+ virtual void registerKnownDialogsByID(mapType& rKnownDialogs) override;
+
+ /// dialog creation for known dialogs by ID. Has to be implemented for
+ /// each registered known dialog
+ virtual VclPtr<VclAbstractDialog> createDialogByID(sal_uInt32 nID) override;
+
+public:
+ SwDialogsTest2();
+
+ void setUp() override;
+
+ // try to open a dialog
+ void openAnyDialog();
+
+ CPPUNIT_TEST_SUITE(SwDialogsTest2);
+ CPPUNIT_TEST(openAnyDialog);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+SwDialogsTest2::SwDialogsTest2()
+{
+}
+
+void SwDialogsTest2::setUp()
+{
+ ScreenshotTest::setUp();
+ SwGlobals::ensure();
+ // Make sure the swui library's global pSwResMgr is initialized
+ // (alternatively to dynamically loading the library, SwCreateDialogFactory
+ // could be declared in an include file and this CppunitTest link against
+ // the swui library):
+ OUString url("${LO_LIB_DIR}/" SVLIBRARY("swui"));
+ rtl::Bootstrap::expandMacros(url); //TODO: detect failure
+ CPPUNIT_ASSERT(libSwui_.load(url, SAL_LOADMODULE_GLOBAL));
+ auto fn = reinterpret_cast<Fn>(
+ libSwui_.getFunctionSymbol("SwCreateDialogFactory"));
+ CPPUNIT_ASSERT(fn != nullptr);
+ (*fn)();
+}
+
+void SwDialogsTest2::registerKnownDialogsByID(mapType& /*rKnownDialogs*/)
+{
+ // fill map of known dialogs
+}
+
+VclPtr<VclAbstractDialog> SwDialogsTest2::createDialogByID(sal_uInt32 /*nID*/)
+{
+ return nullptr;
+}
+
+void SwDialogsTest2::openAnyDialog()
+{
+ /// process input file containing the UXMLDescriptions of the dialogs to dump
+ processDialogBatchFile(u"sw/qa/unit/data/sw-dialogs-test_2.txt");
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SwDialogsTest2);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/unit/swmodeltestbase.cxx b/sw/qa/unit/swmodeltestbase.cxx
new file mode 100644
index 000000000..707d306ce
--- /dev/null
+++ b/sw/qa/unit/swmodeltestbase.cxx
@@ -0,0 +1,768 @@
+/* -*- 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 <swmodeltestbase.hxx>
+
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
+#include <com/sun/star/text/XPageCursor.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sfx2/app.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+#include <IDocumentLayoutAccess.hxx>
+#include <docsh.hxx>
+#include <rootfrm.hxx>
+#include <unotxdoc.hxx>
+#include <viewsh.hxx>
+
+using namespace css;
+
+void SwModelTestBase::paste(std::u16string_view aFilename,
+ uno::Reference<text::XTextRange> const& xTextRange)
+{
+ uno::Reference<document::XFilter> xFilter(
+ m_xSFactory->createInstance("com.sun.star.comp.Writer.RtfFilter"), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XImporter> xImporter(xFilter, uno::UNO_QUERY_THROW);
+ xImporter->setTargetDocument(mxComponent);
+ std::unique_ptr<SvStream> pStream = utl::UcbStreamHelper::CreateStream(
+ m_directories.getURLFromSrc(u"/sw/qa/extras/") + aFilename, StreamMode::STD_READ);
+ CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, pStream->GetError());
+ uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(std::move(pStream)));
+ uno::Sequence aDescriptor{ comphelper::makePropertyValue("InputStream", xStream),
+ comphelper::makePropertyValue("InsertMode", true),
+ comphelper::makePropertyValue("TextInsertModeRange", xTextRange) };
+ CPPUNIT_ASSERT(xFilter->filter(aDescriptor));
+}
+
+SwModelTestBase::SwModelTestBase(const OUString& pTestDocumentPath, const char* pFilter)
+ : mpXmlBuffer(nullptr)
+ , mpTestDocumentPath(pTestDocumentPath)
+ , mpFilter(pFilter)
+ , mnStartTime(0)
+ , mbExported(false)
+ , mbFontNameWYSIWYG(officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::get())
+{
+ maTempFile.EnableKillingFile();
+}
+
+void SwModelTestBase::setUp()
+{
+ test::BootstrapFixture::setUp();
+ mxDesktop.set(
+ css::frame::Desktop::create(comphelper::getComponentContext(getMultiServiceFactory())));
+ SfxApplication::GetOrCreate();
+ std::shared_ptr<comphelper::ConfigurationChanges> xChanges(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::set(false, xChanges);
+ xChanges->commit();
+}
+
+void SwModelTestBase::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+ std::shared_ptr<comphelper::ConfigurationChanges> xChanges(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::set(mbFontNameWYSIWYG, xChanges);
+ xChanges->commit();
+ test::BootstrapFixture::tearDown();
+}
+
+void SwModelTestBase::executeImportTest(const char* filename, const char* pPassword)
+{
+ // If the testcase is stored in some other format, it's pointless to test.
+ if (mustTestImportOf(filename))
+ {
+ maTempFile.EnableKillingFile(false);
+ header();
+ std::unique_ptr<Resetter> const pChanges(preTest(filename));
+ load(mpTestDocumentPath, filename, pPassword);
+ verify();
+ finish();
+ maTempFile.EnableKillingFile();
+ }
+}
+
+void SwModelTestBase::executeLoadVerifyReloadVerify(const char* filename, const char* pPassword)
+{
+ maTempFile.EnableKillingFile(false);
+ header();
+ std::unique_ptr<Resetter> const pChanges(preTest(filename));
+ load(mpTestDocumentPath, filename, pPassword);
+ if (mustTestImportOf(filename))
+ {
+ verify();
+ }
+ postLoad(filename);
+ reload(mpFilter, filename, pPassword);
+ verify();
+ finish();
+ maTempFile.EnableKillingFile();
+}
+
+void SwModelTestBase::executeLoadReloadVerify(const char* filename, const char* pPassword)
+{
+ maTempFile.EnableKillingFile(false);
+ header();
+ std::unique_ptr<Resetter> const pChanges(preTest(filename));
+ load(mpTestDocumentPath, filename, pPassword);
+ postLoad(filename);
+ reload(mpFilter, filename, pPassword);
+ verify();
+ finish();
+ maTempFile.EnableKillingFile();
+}
+
+void SwModelTestBase::executeImportExport(const char* filename, const char* pPassword)
+{
+ maTempFile.EnableKillingFile(false);
+ header();
+ std::unique_ptr<Resetter> const pChanges(preTest(filename));
+ load(mpTestDocumentPath, filename, pPassword);
+ save(OUString::createFromAscii(mpFilter), maTempFile);
+ maTempFile.EnableKillingFile(false);
+ verify();
+ finish();
+ maTempFile.EnableKillingFile();
+}
+
+void SwModelTestBase::dumpLayout(const uno::Reference<lang::XComponent>& rComponent)
+{
+ // create the xml writer
+ mpXmlBuffer = xmlBufferCreate();
+ xmlTextWriterPtr pXmlWriter = xmlNewTextWriterMemory(mpXmlBuffer, 0);
+ (void)xmlTextWriterStartDocument(pXmlWriter, nullptr, nullptr, nullptr);
+
+ // create the dump
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(rComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
+ SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+ pLayout->dumpAsXml(pXmlWriter);
+
+ // delete xml writer
+ (void)xmlTextWriterEndDocument(pXmlWriter);
+ xmlFreeTextWriter(pXmlWriter);
+}
+
+void SwModelTestBase::discardDumpedLayout()
+{
+ if (mpXmlBuffer)
+ {
+ xmlBufferFree(mpXmlBuffer);
+ mpXmlBuffer = nullptr;
+ }
+}
+
+void SwModelTestBase::calcLayout()
+{
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
+ pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
+}
+
+int SwModelTestBase::getLength() const { return getBodyText().getLength(); }
+
+OUString SwModelTestBase::getBodyText() const
+{
+ 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.makeStringAndClear();
+}
+
+uno::Reference<container::XNameAccess> SwModelTestBase::getStyles(const OUString& aFamily)
+{
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(mxComponent,
+ uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName(aFamily),
+ uno::UNO_QUERY);
+ return xStyleFamily;
+}
+
+uno::Reference<style::XAutoStyleFamily> SwModelTestBase::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;
+}
+
+xmlDocUniquePtr SwModelTestBase::parseLayoutDump()
+{
+ if (!mpXmlBuffer)
+ dumpLayout(mxComponent);
+
+ auto pBuffer = reinterpret_cast<const char*>(xmlBufferContent(mpXmlBuffer));
+ SAL_INFO("sw", "SwModelTestBase::parseLayoutDump: pBuffer is '" << pBuffer << "'");
+ return xmlDocUniquePtr(xmlParseMemory(pBuffer, xmlBufferLength(mpXmlBuffer)));
+}
+
+OUString SwModelTestBase::parseDump(const OString& aXPath, const OString& aAttribute)
+{
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+ xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pXmlDoc.get());
+ xmlXPathObjectPtr pXmlXpathObj
+ = xmlXPathEvalExpression(BAD_CAST(aXPath.getStr()), pXmlXpathCtx);
+ CPPUNIT_ASSERT_MESSAGE("xpath evaluation failed", pXmlXpathObj);
+ xmlChar* pXpathStrResult;
+ if (pXmlXpathObj->type == XPATH_NODESET)
+ {
+ xmlNodeSetPtr pXmlNodes = pXmlXpathObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("xpath should match exactly 1 node", 1,
+ xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlNodePtr pXmlNode = pXmlNodes->nodeTab[0];
+ if (aAttribute.getLength())
+ pXpathStrResult = xmlGetProp(pXmlNode, BAD_CAST(aAttribute.getStr()));
+ else
+ pXpathStrResult = xmlNodeGetContent(pXmlNode);
+ }
+ else
+ {
+ // the xpath expression evaluated to a value, not a node
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("attr name should not be supplied when xpath evals to a value",
+ sal_Int32(0), aAttribute.getLength());
+ pXpathStrResult = xmlXPathCastToString(pXmlXpathObj);
+ CPPUNIT_ASSERT_MESSAGE("xpath result cannot be cast to string", pXpathStrResult);
+ }
+
+ OUString aRet(reinterpret_cast<char*>(pXpathStrResult), xmlStrlen(pXpathStrResult),
+ RTL_TEXTENCODING_UTF8);
+ xmlFree(pXpathStrResult);
+ xmlFree(pXmlXpathObj);
+ xmlFree(pXmlXpathCtx);
+
+ return aRet;
+}
+
+bool SwModelTestBase::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);
+}
+
+xml::AttributeData SwModelTestBase::getUserDefineAttribute(const uno::Any& obj,
+ const OUString& name,
+ const OUString& rValue) const
+{
+ uno::Reference<container::XNameContainer> attrsCnt(
+ getProperty<uno::Any>(obj, "UserDefinedAttributes"), uno::UNO_QUERY_THROW);
+
+ xml::AttributeData aValue;
+ attrsCnt->getByName(name) >>= aValue;
+ if (!rValue.isEmpty())
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("attribute of cell does not contain expected value", rValue,
+ aValue.Value);
+
+ return aValue;
+}
+
+int SwModelTestBase::getParagraphs(uno::Reference<text::XText> const& xText)
+{
+ int nRet = 0;
+ if (!xText.is())
+ return nRet;
+
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xText->getText(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ while (xParaEnum->hasMoreElements())
+ {
+ xParaEnum->nextElement();
+ nRet++;
+ }
+ return nRet;
+}
+
+int SwModelTestBase::getParagraphs()
+{
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ return getParagraphs(xTextDocument->getText());
+}
+
+uno::Reference<text::XTextContent>
+SwModelTestBase::getParagraphOrTable(int number, uno::Reference<text::XText> const& xText) const
+{
+ assert(number != 0); // this thing is 1-based
+ 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;
+}
+
+uno::Reference<text::XTextRange> SwModelTestBase::getParagraph(int number,
+ const OUString& content) 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;
+}
+
+sal_Int16 SwModelTestBase::getNumberingTypeOfParagraph(int nPara)
+{
+ sal_Int16 nNumberingType = -1;
+ uno::Reference<text::XTextRange> xPara(getParagraph(nPara));
+ uno::Reference<beans::XPropertySet> properties(xPara, uno::UNO_QUERY);
+ bool isNumber = false;
+ properties->getPropertyValue("NumberingIsNumber") >>= isNumber;
+ if (isNumber)
+ {
+ uno::Reference<container::XIndexAccess> xLevels(
+ properties->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
+ sal_Int16 nNumberingLevel = -1;
+ properties->getPropertyValue("NumberingLevel") >>= nNumberingLevel;
+ if (nNumberingLevel >= 0 && nNumberingLevel < xLevels->getCount())
+ {
+ uno::Sequence<beans::PropertyValue> aPropertyValue;
+ xLevels->getByIndex(nNumberingLevel) >>= aPropertyValue;
+ auto pProp = std::find_if(
+ std::cbegin(aPropertyValue), std::cend(aPropertyValue),
+ [](const beans::PropertyValue& rProp) { return rProp.Name == "NumberingType"; });
+ if (pProp != std::cend(aPropertyValue))
+ nNumberingType = pProp->Value.get<sal_Int16>();
+ }
+ }
+ return nNumberingType;
+}
+
+uno::Reference<text::XTextRange>
+SwModelTestBase::getParagraphOfText(int number, uno::Reference<text::XText> const& xText,
+ const OUString& content) 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;
+}
+
+uno::Reference<beans::XPropertySet>
+SwModelTestBase::getParagraphAnchoredObject(int const index,
+ uno::Reference<text::XTextRange> const& xPara) const
+{
+ uno::Reference<container::XContentEnumerationAccess> xContentEnumAccess(xPara, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xContentEnum
+ = xContentEnumAccess->createContentEnumeration("com.sun.star.text.TextContent");
+ for (int i = 1; i < index; ++i)
+ {
+ xContentEnum->nextElement();
+ }
+ return uno::Reference<beans::XPropertySet>(xContentEnum->nextElement(), uno::UNO_QUERY);
+}
+
+uno::Reference<text::XTextRange>
+SwModelTestBase::getRun(uno::Reference<text::XTextRange> const& xParagraph, int number,
+ const OUString& content) 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;
+}
+
+OUString SwModelTestBase::getFormula(uno::Reference<text::XTextRange> const& xRun) const
+{
+ uno::Reference<container::XContentEnumerationAccess> xContentEnumAccess(xRun, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xContentEnum
+ = xContentEnumAccess->createContentEnumeration("");
+ uno::Reference<beans::XPropertySet> xFormula(xContentEnum->nextElement(), uno::UNO_QUERY);
+ return getProperty<OUString>(
+ getProperty<uno::Reference<beans::XPropertySet>>(xFormula, "Model"), "Formula");
+}
+
+uno::Reference<table::XCell>
+SwModelTestBase::getCell(uno::Reference<uno::XInterface> const& xTableIfc, OUString const& rCell,
+ OUString const& rContent)
+{
+ 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;
+}
+
+uno::Reference<drawing::XShape> SwModelTestBase::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;
+}
+
+uno::Reference<drawing::XShape> SwModelTestBase::getShapeByName(std::u16string_view aName)
+{
+ uno::Reference<drawing::XShape> xRet;
+
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ for (sal_Int32 i = 0; i < xDrawPage->getCount(); ++i)
+ {
+ uno::Reference<container::XNamed> xShape(xDrawPage->getByIndex(i), uno::UNO_QUERY);
+ if (xShape->getName() == aName)
+ {
+ xRet.set(xShape, uno::UNO_QUERY);
+ break;
+ }
+ }
+
+ return xRet;
+}
+
+uno::Reference<drawing::XShape> SwModelTestBase::getTextFrameByName(const OUString& aName)
+{
+ uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xNameAccess = xTextFramesSupplier->getTextFrames();
+ uno::Reference<drawing::XShape> xShape(xNameAccess->getByName(aName), uno::UNO_QUERY);
+ return xShape;
+}
+
+void SwModelTestBase::setTestInteractionHandler(const char* pPassword,
+ std::vector<beans::PropertyValue>& rFilterOptions)
+{
+ OUString sPassword = OUString::createFromAscii(pPassword);
+ rFilterOptions.emplace_back();
+ xInteractionHandler
+ = rtl::Reference<TestInteractionHandler>(new TestInteractionHandler(sPassword));
+ uno::Reference<task::XInteractionHandler2> const xInteraction(xInteractionHandler);
+ rFilterOptions[0].Name = "InteractionHandler";
+ rFilterOptions[0].Value <<= xInteraction;
+}
+
+void SwModelTestBase::header() {}
+
+void SwModelTestBase::loadURLWithComponent(OUString const& rURL, OUString const& rComponent,
+ const char* pName, const char* pPassword)
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ std::vector<beans::PropertyValue> aFilterOptions;
+
+ if (pPassword)
+ {
+ setTestInteractionHandler(pPassword, aFilterOptions);
+ }
+
+ if (!maImportFilterOptions.isEmpty())
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "FilterOptions";
+ aValue.Value <<= maImportFilterOptions;
+ aFilterOptions.push_back(aValue);
+ }
+
+ if (!maImportFilterName.isEmpty())
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "FilterName";
+ aValue.Value <<= maImportFilterName;
+ aFilterOptions.push_back(aValue);
+ }
+
+ // Output name early, so in the case of a hang, the name of the hanging input file is visible.
+ if (pName)
+ std::cout << pName << ":\n";
+ mnStartTime = osl_getGlobalTimer();
+ mxComponent
+ = loadFromDesktop(rURL, rComponent, comphelper::containerToSequence(aFilterOptions));
+
+ if (pPassword)
+ {
+ CPPUNIT_ASSERT_MESSAGE("Password set but not requested",
+ xInteractionHandler->wasPasswordRequested());
+ }
+
+ discardDumpedLayout();
+ if (pName && mustCalcLayoutOf(pName))
+ calcLayout();
+}
+
+void SwModelTestBase::loadURL(OUString const& rURL, const char* pName, const char* pPassword)
+{
+ loadURLWithComponent(rURL, "com.sun.star.text.TextDocument", pName, pPassword);
+}
+
+void SwModelTestBase::reload(const char* pFilter, const char* filename, const char* pPassword)
+{
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ OUString aFilterName = OUString::createFromAscii(pFilter);
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["FilterName"] <<= aFilterName;
+ if (!maFilterOptions.isEmpty())
+ aMediaDescriptor["FilterOptions"] <<= maFilterOptions;
+ if (pPassword)
+ {
+ if (strcmp(pFilter, "Office Open XML Text"))
+ {
+ aMediaDescriptor["Password"] <<= OUString::createFromAscii(pPassword);
+ }
+ else
+ {
+ OUString sPassword = OUString::createFromAscii(pPassword);
+ css::uno::Sequence<css::beans::NamedValue> aEncryptionData{
+ { "CryptoType", css::uno::Any(OUString("Standard")) },
+ { "OOXPassword", css::uno::Any(sPassword) }
+ };
+ aMediaDescriptor[utl::MediaDescriptor::PROP_ENCRYPTIONDATA] <<= aEncryptionData;
+ }
+ }
+ xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+ uno::Reference<lang::XComponent> xComponent(xStorable, uno::UNO_QUERY);
+ xComponent->dispose();
+ mbExported = true;
+
+ std::vector<beans::PropertyValue> aFilterOptions;
+ if (pPassword)
+ {
+ setTestInteractionHandler(pPassword, aFilterOptions);
+ }
+
+ if (!maImportFilterOptions.isEmpty())
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "FilterOptions";
+ aValue.Value <<= maImportFilterOptions;
+ aFilterOptions.push_back(aValue);
+ }
+
+ if (!maImportFilterName.isEmpty())
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "FilterName";
+ aValue.Value <<= maImportFilterName;
+ aFilterOptions.push_back(aValue);
+ }
+
+ mxComponent = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument",
+ comphelper::containerToSequence(aFilterOptions));
+ if (pPassword)
+ {
+ CPPUNIT_ASSERT_MESSAGE("Password set but not requested",
+ xInteractionHandler->wasPasswordRequested());
+ }
+ if (mustValidate(filename) || aFilterName == "writer8"
+ || aFilterName == "OpenDocument Text Flat XML")
+ {
+ if (aFilterName == "Office Open XML Text")
+ {
+ // too many validation errors right now
+ validate(maTempFile.GetFileName(), test::OOXML);
+ }
+ else if (aFilterName == "writer8" || aFilterName == "OpenDocument Text Flat XML")
+ {
+ validate(maTempFile.GetFileName(), test::ODF);
+ }
+ else if (aFilterName == "MS Word 97")
+ {
+ validate(maTempFile.GetFileName(), test::MSBINARY);
+ }
+ else
+ {
+ OString aMessage
+ = OString::Concat("validation requested, but don't know how to validate ")
+ + filename + " (" + OUStringToOString(aFilterName, RTL_TEXTENCODING_UTF8) + ")";
+ CPPUNIT_FAIL(aMessage.getStr());
+ }
+ }
+ discardDumpedLayout();
+ if (mustCalcLayoutOf(filename))
+ calcLayout();
+}
+
+void SwModelTestBase::save(const OUString& aFilterName, utl::TempFile& rTempFile)
+{
+ rTempFile.EnableKillingFile();
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["FilterName"] <<= aFilterName;
+ if (!maFilterOptions.isEmpty())
+ aMediaDescriptor["FilterOptions"] <<= maFilterOptions;
+ xStorable->storeToURL(rTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+ // TODO: for now, validate only ODF here
+ if (aFilterName == "writer8" || aFilterName == "OpenDocument Text Flat XML")
+ {
+ validate(rTempFile.GetFileName(), test::ODF);
+ }
+}
+
+void SwModelTestBase::loadAndSave(const char* pName)
+{
+ load(mpTestDocumentPath, pName);
+ save(OUString::createFromAscii(mpFilter), maTempFile);
+ mbExported = true;
+}
+
+void SwModelTestBase::loadAndReload(const char* pName)
+{
+ load(mpTestDocumentPath, pName);
+ reload(mpFilter, pName);
+}
+
+void SwModelTestBase::finish()
+{
+ sal_uInt32 nEndTime = osl_getGlobalTimer();
+ std::cout << (nEndTime - mnStartTime) << std::endl;
+ discardDumpedLayout();
+}
+
+int SwModelTestBase::getPages() const
+{
+ 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();
+}
+
+int SwModelTestBase::getShapes() const
+{
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xDraws = xDrawPageSupplier->getDrawPage();
+ return xDraws->getCount();
+}
+
+xmlDocUniquePtr SwModelTestBase::parseExport(const OUString& rStreamName)
+{
+ if (!mbExported)
+ return nullptr;
+
+ return parseExportInternal(maTempFile.GetURL(), rStreamName);
+}
+
+xmlDocUniquePtr SwModelTestBase::parseExportedFile()
+{
+ auto stream(SvFileStream(maTempFile.GetURL(), StreamMode::READ | StreamMode::TEMPORARY));
+ return parseXmlStream(&stream);
+}
+
+std::unique_ptr<SvStream> SwModelTestBase::parseExportStream(const OUString& url,
+ const OUString& rStreamName)
+{
+ // Read the stream we're interested in.
+ uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
+ = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
+ url);
+ uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName(rStreamName),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xInputStream.is());
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+ return pStream;
+}
+
+xmlDocUniquePtr SwModelTestBase::parseExportInternal(const OUString& url,
+ const OUString& rStreamName)
+{
+ std::unique_ptr<SvStream> pStream(parseExportStream(url, rStreamName));
+
+ xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+ pXmlDoc->name = reinterpret_cast<char*>(xmlStrdup(
+ reinterpret_cast<xmlChar const*>(OUStringToOString(url, RTL_TEXTENCODING_UTF8).getStr())));
+ return pXmlDoc;
+}
+
+void SwModelTestBase::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
+{
+ // docx
+ XmlTestTools::registerOOXMLNamespaces(pXmlXpathCtx);
+ // odt
+ XmlTestTools::registerODFNamespaces(pXmlXpathCtx);
+ // reqif-xhtml
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("reqif-xhtml"),
+ BAD_CAST("http://www.w3.org/1999/xhtml"));
+}
+
+SwDoc* SwModelTestBase::createSwDoc(std::u16string_view rDataDirectory, const char* pName)
+{
+ if (rDataDirectory.empty() || !pName)
+ loadURL("private:factory/swriter", nullptr);
+ else
+ load(rDataDirectory, pName);
+
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ return pTextDoc->GetDocShell()->GetDoc();
+}
+
+SwDoc* SwModelTestBase::createSwWebDoc(std::u16string_view rDataDirectory, const char* pName)
+{
+ if (rDataDirectory.empty() || !pName)
+ loadURL("private:factory/swriter/web", nullptr);
+ else
+ load_web(rDataDirectory, pName);
+
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ return pTextDoc->GetDocShell()->GetDoc();
+}
+
+void SwModelTestBase::WrapReqifFromTempFile(SvMemoryStream& rStream)
+{
+ rStream.WriteCharPtr("<reqif-xhtml:html xmlns:reqif-xhtml=\"http://www.w3.org/1999/xhtml\">\n");
+ SvFileStream aFileStream(maTempFile.GetURL(), StreamMode::READ);
+ rStream.WriteStream(aFileStream);
+ rStream.WriteCharPtr("</reqif-xhtml:html>\n");
+ rStream.Seek(0);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/unit/uibase.cxx b/sw/qa/unit/uibase.cxx
new file mode 100644
index 000000000..519510977
--- /dev/null
+++ b/sw/qa/unit/uibase.cxx
@@ -0,0 +1,44 @@
+/* -*- 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 <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <tools/urlobj.hxx>
+
+#include <dbmgr.hxx>
+
+namespace
+{
+/// Test suite for unit tests covering uibase code.
+class Test : public CppUnit::TestFixture
+{
+public:
+ void testTdf98168();
+
+ CPPUNIT_TEST_SUITE(Test);
+ CPPUNIT_TEST(testTdf98168);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void Test::testTdf98168()
+{
+ INetURLObject aURL(u"file:///tmp/test.xlsx");
+ // This was sw::DBConnURIType::UNKNOWN, xlsx was not recognized.
+ CPPUNIT_ASSERT_EQUAL(sw::DBConnURIType::CALC, sw::GetDBunoType(aURL));
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(Test);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */