summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2022-09-20 13:59:15 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2022-09-20 15:49:13 +0200
commite4fe4a2918fbca0dc38441261a0f890720538639 (patch)
treeaeb9688ffa1633a421bdf31f371826f0a7fcefd9 /sw
parent06c9e1d27093ca7bbe38a1eb93fbb85b80f75f75 (diff)
split the mailmerge unit test
since it is substantially longer running than the next longest test Change-Id: Iec8f1e2f3d98a1c290c1a66620443c79dda9c237 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140239 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'sw')
-rw-r--r--sw/CppunitTest_sw_mailmerge2.mk62
-rw-r--r--sw/Module_sw.mk1
-rw-r--r--sw/qa/extras/mailmerge/mailmerge.cxx391
-rw-r--r--sw/qa/extras/mailmerge/mailmerge2.cxx718
4 files changed, 781 insertions, 391 deletions
diff --git a/sw/CppunitTest_sw_mailmerge2.mk b/sw/CppunitTest_sw_mailmerge2.mk
new file mode 100644
index 000000000000..2fd6e107258a
--- /dev/null
+++ b/sw/CppunitTest_sw_mailmerge2.mk
@@ -0,0 +1,62 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,sw_mailmerge2))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_mailmerge2))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sw_mailmerge2, \
+ sw/qa/extras/mailmerge/mailmerge2 \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sw_mailmerge2, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ sfx \
+ svl \
+ sw \
+ swqahelper \
+ test \
+ tl \
+ unotest \
+ utl \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sw_mailmerge2, \
+ boost_headers \
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sw_mailmerge2,\
+ udkapi \
+ offapi \
+ oovbaapi \
+))
+
+$(eval $(call gb_CppunitTest_use_rdb,sw_mailmerge2,services))
+
+$(eval $(call gb_CppunitTest_use_configuration,sw_mailmerge2))
+$(eval $(call gb_CppunitTest_use_ure,sw_mailmerge2))
+$(eval $(call gb_CppunitTest_use_vcl,sw_mailmerge2))
+
+$(eval $(call gb_CppunitTest_set_include,sw_mailmerge2,\
+ -I$(SRCDIR)/sw/inc \
+ -I$(SRCDIR)/sw/source/core/inc \
+ -I$(SRCDIR)/sw/qa/inc \
+ -I$(SRCDIR)/sw/source/uibase/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_uiconfigs,sw_mailmerge2,\
+ modules/swriter \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk
index 8b5a42e0ff14..754411a7dc42 100644
--- a/sw/Module_sw.mk
+++ b/sw/Module_sw.mk
@@ -120,6 +120,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
CppunitTest_sw_layoutwriter \
CppunitTest_sw_layoutwriter2 \
CppunitTest_sw_mailmerge \
+ CppunitTest_sw_mailmerge2 \
CppunitTest_sw_globalfilter \
CppunitTest_sw_accessible_relation_set \
CppunitTest_sw_apiterminate \
diff --git a/sw/qa/extras/mailmerge/mailmerge.cxx b/sw/qa/extras/mailmerge/mailmerge.cxx
index fbeded40b94b..8d024194c985 100644
--- a/sw/qa/extras/mailmerge/mailmerge.cxx
+++ b/sw/qa/extras/mailmerge/mailmerge.cxx
@@ -974,397 +974,6 @@ DECLARE_SHELL_MAILMERGE_TEST(testTdf62364, "tdf62364.odt", "10-testing-addresses
}
}
-DECLARE_SHELL_MAILMERGE_TEST(tdf125522_shell, "tdf125522.odt", "10-testing-addresses.ods", "testing-addresses")
-{
- // prepare unit test and run
- executeMailMerge();
-
- // reset currently opened layout of the original template,
- // and create the layout of the document with 10 mails inside
- dumpMMLayout();
-
- // there should be no any text frame in output
- SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxMMComponent.get());
- CPPUNIT_ASSERT(pTextDoc);
-
- const auto & rNodes = pTextDoc->GetDocShell()->GetDoc()->GetNodes();
- for (SwNodeOffset nodeIndex(0); nodeIndex<rNodes.Count(); nodeIndex++)
- {
- SwNode* aNode = rNodes[nodeIndex];
- if (aNode->StartOfSectionNode())
- {
- CPPUNIT_ASSERT(!aNode->StartOfSectionNode()->GetFlyFormat());
- }
- }
-}
-
-DECLARE_SHELL_MAILMERGE_TEST(testTd78611_shell, "tdf78611.odt", "10-testing-addresses.ods", "testing-addresses")
-{
- // prepare unit test and run
- executeMailMerge();
-
- // reset currently opened layout of the original template,
- // and create the layout of the document with 10 mails inside
- dumpMMLayout();
-
- // check: each page (one page is one sub doc) has different paragraphs and header paragraphs.
- // All header paragraphs should have numbering.
-
- // check first page
- CPPUNIT_ASSERT_EQUAL( OUString("1"), parseDump("/root/page[1]/body/txt[6]/Special", "rText"));
- CPPUNIT_ASSERT_EQUAL( OUString("1.1"), parseDump("/root/page[1]/body/txt[8]/Special", "rText"));
- CPPUNIT_ASSERT_EQUAL( OUString("1.2"), parseDump("/root/page[1]/body/txt[10]/Special", "rText"));
-
- // check some other pages
- CPPUNIT_ASSERT_EQUAL( OUString("1"), parseDump("/root/page[3]/body/txt[6]/Special", "rText"));
- CPPUNIT_ASSERT_EQUAL( OUString("1.1"), parseDump("/root/page[5]/body/txt[8]/Special", "rText"));
- CPPUNIT_ASSERT_EQUAL( OUString("1.2"), parseDump("/root/page[7]/body/txt[10]/Special", "rText"));
-}
-
-DECLARE_FILE_MAILMERGE_TEST(testTd78611_file, "tdf78611.odt", "10-testing-addresses.ods", "testing-addresses")
-{
- executeMailMerge(true);
- for (int doc = 0; doc < 10; ++doc)
- {
- loadMailMergeDocument( doc );
- CPPUNIT_ASSERT_EQUAL( OUString("1"), parseDump("/root/page[1]/body/txt[6]/Special", "rText"));
- CPPUNIT_ASSERT_EQUAL( OUString("1.1"), parseDump("/root/page[1]/body/txt[8]/Special", "rText"));
- CPPUNIT_ASSERT_EQUAL( OUString("1.2"), parseDump("/root/page[1]/body/txt[10]/Special", "rText"));
- }
-}
-
-DECLARE_SHELL_MAILMERGE_TEST(testTdf122156_shell, "linked-with-condition.odt", "5-with-blanks.ods",
- "names")
-{
- // A document with a linked section hidden on an "empty field" condition
- // For combined documents, hidden sections are removed completely
- executeMailMerge();
- SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxMMComponent.get());
- CPPUNIT_ASSERT(pTextDoc);
- // 5 documents 1 page each, starting at odd page numbers => 9
- CPPUNIT_ASSERT_EQUAL(sal_uInt16(9), pTextDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum());
- uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxMMComponent,
- uno::UNO_QUERY_THROW);
- uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
- uno::UNO_QUERY_THROW);
- // 2 out of 5 dataset records have empty "Title" field => no sections in respective documents
- CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xSections->getCount());
-}
-
-DECLARE_FILE_MAILMERGE_TEST(testTdf122156_file, "linked-with-condition.odt", "5-with-blanks.ods",
- "names")
-{
- // A document with a linked section hidden on an "empty field" condition
- // For separate documents, the sections are hidden, but not removed
- executeMailMerge();
- {
- loadMailMergeDocument(0);
- uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
- uno::UNO_QUERY_THROW);
- uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
- uno::UNO_QUERY_THROW);
- CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
- uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
- // Record 1 has empty "Title" field => section is not shown
- CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect, "IsCurrentlyVisible"));
- }
- {
- loadMailMergeDocument(1);
- uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
- uno::UNO_QUERY_THROW);
- uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
- uno::UNO_QUERY_THROW);
- CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
- uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
- // Record 2 has non-empty "Title" field => section is shown
- CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect, "IsCurrentlyVisible"));
- }
- {
- loadMailMergeDocument(2);
- uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
- uno::UNO_QUERY_THROW);
- uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
- uno::UNO_QUERY_THROW);
- CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
- uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
- // Record 3 has non-empty "Title" field => section is shown
- CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect, "IsCurrentlyVisible"));
- }
- {
- loadMailMergeDocument(3);
- uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
- uno::UNO_QUERY_THROW);
- uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
- uno::UNO_QUERY_THROW);
- CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
- uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
- // Record 4 has empty "Title" field => section is not shown
- CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect, "IsCurrentlyVisible"));
- }
- {
- loadMailMergeDocument(4);
- uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
- uno::UNO_QUERY_THROW);
- uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
- uno::UNO_QUERY_THROW);
- CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
- uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
- // Record 5 has non-empty "Title" field => section is shown
- CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect, "IsCurrentlyVisible"));
- }
-}
-
-DECLARE_SHELL_MAILMERGE_TEST(testTdf121168, "section_ps.odt", "4_v01.ods", "Tabelle1")
-{
- // A document starting with a section on a page with non-default page style with header
- executeMailMerge();
- SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxMMComponent.get());
- CPPUNIT_ASSERT(pTextDoc);
- // 4 documents 1 page each, starting at odd page numbers => 7
- CPPUNIT_ASSERT_EQUAL(sal_uInt16(7), pTextDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum());
-
- SwDoc* pDocMM = pTextDoc->GetDocShell()->GetDoc();
- SwNodeOffset nSizeMM = pDocMM->GetNodes().GetEndOfContent().GetIndex()
- - pDocMM->GetNodes().GetEndOfExtras().GetIndex() - 2;
- CPPUNIT_ASSERT_EQUAL(SwNodeOffset(16), nSizeMM);
-
- // All even pages should be empty, all sub-documents have one page
- const SwRootFrame* pLayout = pDocMM->getIDocumentLayoutAccess().GetCurrentLayout();
- const SwPageFrame* pPageFrm = static_cast<const SwPageFrame*>(pLayout->Lower());
- while (pPageFrm)
- {
- sal_uInt16 nPageNum = pPageFrm->GetPhyPageNum();
- bool bOdd = (1 == (nPageNum % 2));
- CPPUNIT_ASSERT_EQUAL(!bOdd, pPageFrm->IsEmptyPage());
- CPPUNIT_ASSERT_EQUAL(sal_uInt16(bOdd ? 1 : 2), pPageFrm->GetVirtPageNum());
- if (bOdd)
- {
- const SwPageDesc* pDesc = pPageFrm->GetPageDesc();
- CPPUNIT_ASSERT_EQUAL(OUString("Teststyle" + OUString::number(nPageNum / 2 + 1)),
- pDesc->GetName());
- }
- pPageFrm = static_cast<const SwPageFrame*>(pPageFrm->GetNext());
- }
-}
-
-DECLARE_FILE_MAILMERGE_TEST(testTdf81782_file, "tdf78611.odt", "10-testing-addresses.ods", "testing-addresses")
-{
- executeMailMerge(true);
- for (int doc = 0; doc < 10; ++doc)
- {
- loadMailMergeDocument( doc );
-
- // get document properties
- uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(mxComponent, uno::UNO_QUERY);
- uno::Reference<document::XDocumentProperties> xDocumentProperties(xDocumentPropertiesSupplier->getDocumentProperties());
-
- // check if properties were set
- uno::Sequence<OUString> aKeywords(xDocumentProperties->getKeywords());
- CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aKeywords.getLength());
- CPPUNIT_ASSERT_EQUAL(OUString("one two"), aKeywords[0]);
-
- // check title and subject
- CPPUNIT_ASSERT_EQUAL(OUString("my title"), xDocumentProperties->getTitle());
- CPPUNIT_ASSERT_EQUAL(OUString("my subject"), xDocumentProperties->getSubject());
- }
-}
-
-// problem was: field content was duplicated & truncated
-DECLARE_SHELL_MAILMERGE_TEST(testTdf81750_shell, "tdf81750.odt", "10-testing-addresses.ods", "testing-addresses")
-{
- // prepare unit test and run
- executeMailMerge();
-
- // reset currently opened layout of the original template,
- // and create the layout of the document with 10 mails inside
- dumpMMLayout();
-
- // check several pages page
- OUString aExpected("Text: Foo ");
- CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[1]/body/txt[2]", ""));
- CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[3]/body/txt[2]", ""));
- CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[5]/body/txt[2]", ""));
- CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[7]/body/txt[2]", ""));
- CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[9]/body/txt[2]", ""));
-}
-
-
-DECLARE_FILE_MAILMERGE_TEST(testTdf123057_file, "pagecounttest.ott", "db_pagecounttest.ods", "Sheet1")
-{
- executeMailMerge(true);
-
- for (int doc = 0; doc < 4; ++doc)
- {
- loadMailMergeDocument(doc);
-
- // get document properties
- uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent, uno::UNO_QUERY_THROW);
- uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(), uno::UNO_QUERY_THROW);
-
- CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections->getCount());
- uno::Reference<beans::XPropertySet> xSect0(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
- uno::Reference<beans::XPropertySet> xSect1(xSections->getByIndex(1), uno::UNO_QUERY_THROW);
-
- OUString sFieldPageCount;
- uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
- uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
- uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
-
- if (xFields.is())
- {
- while (xFields->hasMoreElements())
- {
- uno::Any aField = xFields->nextElement();
- uno::Reference<lang::XServiceInfo> xServiceInfo(aField, uno::UNO_QUERY);
- if (xServiceInfo->supportsService("com.sun.star.text.textfield.PageCount"))
- {
- uno::Reference<text::XTextContent> xField(aField, uno::UNO_QUERY);
- sFieldPageCount = xField->getAnchor()->getString();
- }
- }
- }
-
- switch (doc)
- {
- case 0:
- // both sections visible, page num is 2
- CPPUNIT_ASSERT_EQUAL(2, getPages());
- CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect0, "IsCurrentlyVisible"));
- CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect1, "IsCurrentlyVisible"));
- CPPUNIT_ASSERT_EQUAL(OUString("2"), sFieldPageCount);
- break;
- case 1:
- // second section hidden, page num is 1
- CPPUNIT_ASSERT_EQUAL(1, getPages());
- CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect0, "IsCurrentlyVisible"));
- CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect1, "IsCurrentlyVisible"));
- CPPUNIT_ASSERT_EQUAL(OUString("1"), sFieldPageCount);
- break;
- case 2:
- // first section hidden, page num is 1
- CPPUNIT_ASSERT_EQUAL(1, getPages());
- CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect0, "IsCurrentlyVisible"));
- CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect1, "IsCurrentlyVisible"));
- CPPUNIT_ASSERT_EQUAL(OUString("1"), sFieldPageCount);
- break;
- case 3:
- // both sections hidden, page num is 1
- CPPUNIT_ASSERT_EQUAL(1, getPages());
- CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect0, "IsCurrentlyVisible"));
- CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect1, "IsCurrentlyVisible"));
- CPPUNIT_ASSERT_EQUAL(OUString("1"), sFieldPageCount);
- break;
- }
- }
-}
-
-// The document has a header with page number and total page count on page 2
-// (which uses page style "Default Style") but doesn't have a header set
-// for the first page (which uses page style "First Page").
-// Fields in the header hadn't been replaced properly.
-DECLARE_SHELL_MAILMERGE_TEST(testTdf128148, "tdf128148.odt", "4_v01.ods", "Tabelle1")
-{
- executeMailMerge();
- SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxMMComponent.get());
- CPPUNIT_ASSERT(pTextDoc);
-
- // 4 documents with 2 pages each => 8 pages in total
- CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), pTextDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum());
-
- SwDoc* pDocMM = pTextDoc->GetDocShell()->GetDoc();
- uno::Reference<frame::XModel> xModel = pTextDoc->GetDocShell()->GetBaseModel();
- uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xModel, uno::UNO_QUERY);
- uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
- uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY);
-
- // All odd pages have no header, all even pages should have header with text "Page 2 of 2"
- const SwRootFrame* pLayout = pDocMM->getIDocumentLayoutAccess().GetCurrentLayout();
- const SwPageFrame* pPageFrm = static_cast<const SwPageFrame*>(pLayout->Lower());
- while (pPageFrm)
- {
- const sal_uInt16 nPageNum = pPageFrm->GetPhyPageNum();
- const bool bIsEvenPage = ((nPageNum % 2) == 0);
-
- const OUString& sPageStyle = pPageFrm->GetPageDesc()->GetName();
- uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(sPageStyle), uno::UNO_QUERY);
-
- bool bHeaderIsOn = false;
- xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_ON) >>= bHeaderIsOn;
-
- // first page for every data record shouldn't have header, second should
- CPPUNIT_ASSERT_EQUAL(bIsEvenPage, bHeaderIsOn);
- if (bIsEvenPage)
- {
- // text in header on even pages with correctly replaced fields is "Page 2 of 2"
- uno::Reference<text::XText> xHeaderText;
- xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT) >>= xHeaderText;
- const OUString sHeaderText = xHeaderText->getString();
- CPPUNIT_ASSERT_EQUAL(OUString("Page 2 of 2"), sHeaderText);
- }
-
- pPageFrm = static_cast<const SwPageFrame*>(pPageFrm->GetNext());
- }
-}
-
-namespace com::sun::star::table {
-
-static std::ostream& operator<<(std::ostream& rStream, table::BorderLine const& rLine)
-{
- rStream << "BorderLine(" << rLine.Color << "," << rLine.InnerLineWidth << "," << rLine.OuterLineWidth << "," << rLine.LineDistance << ")";
- return rStream;
-}
-
-static std::ostream& operator<<(std::ostream& rStream, table::TableBorder const& rBorder)
-{
- rStream << "TableBorder(\n "
- << rBorder.TopLine << "," << static_cast<bool>(rBorder.IsTopLineValid) << ",\n "
- << rBorder.BottomLine << "," << static_cast<bool>(rBorder.IsBottomLineValid) << ",\n "
- << rBorder.LeftLine << "," << static_cast<bool>(rBorder.IsLeftLineValid) << ",\n "
- << rBorder.RightLine << "," << static_cast<bool>(rBorder.IsRightLineValid) << ",\n "
- << rBorder.HorizontalLine << "," << static_cast<bool>(rBorder.IsHorizontalLineValid) << ",\n "
- << rBorder.VerticalLine << "," << static_cast<bool>(rBorder.IsVerticalLineValid) << ",\n "
- << rBorder.Distance << "," << static_cast<bool>(rBorder.IsDistanceValid) << ")";
- return rStream;
-}
-
-}
-
-DECLARE_MAILMERGE_TEST(testGrabBag, "grabbagtest.docx", "onecell.xlsx", "Sheet1", "MS Word 2007 XML", MMTest, 0, nullptr)
-{
- executeMailMerge(true);
-
- loadMailMergeDocument(0, ".docx");
-
- SwXTextDocument *const pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
- CPPUNIT_ASSERT(pTextDoc);
-
- CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pTextDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum());
-
- // check grabbag
- uno::Reference<beans::XPropertySet> const xModel(
- mxComponent, uno::UNO_QUERY_THROW);
- uno::Sequence<beans::PropertyValue> aInteropGrabBag;
- pTextDoc->getPropertyValue("InteropGrabBag") >>= aInteropGrabBag;
- CPPUNIT_ASSERT_EQUAL(sal_Int32(12), aInteropGrabBag.getLength());
-
- // check table border - comes from table style "Tabellenraster"
- uno::Reference<text::XTextTable> const xTable(getParagraphOrTable(1, pTextDoc->getText()), uno::UNO_QUERY_THROW);
- uno::Reference<beans::XPropertySet> const xTableProps(xTable, uno::UNO_QUERY_THROW);
- CPPUNIT_ASSERT_EQUAL(table::TableBorder(
- table::BorderLine(util::Color(0), 0, 18, 0), true,
- table::BorderLine(util::Color(0), 0, 18, 0), true,
- table::BorderLine(util::Color(0), 0, 18, 0), true,
- table::BorderLine(util::Color(0), 0, 18, 0), true,
- table::BorderLine(util::Color(0), 0, 18, 0), true,
- table::BorderLine(util::Color(0), 0, 0, 0), true,
- sal_Int16(191), true),
- getProperty<table::TableBorder>(xTableProps, "TableBorder"));
-
- // check font is Arial - comes from theme (wrong result was "" - nothing)
- uno::Reference<text::XText> const xCell(xTable->getCellByName("A1"), uno::UNO_QUERY_THROW);
- uno::Reference<beans::XPropertySet> const xParaA1(getParagraphOrTable(1, xCell->getText()), uno::UNO_QUERY_THROW);
- CPPUNIT_ASSERT_EQUAL(OUString("Arial"), getProperty<OUString>(xParaA1, "CharFontName"));
-}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/mailmerge/mailmerge2.cxx b/sw/qa/extras/mailmerge/mailmerge2.cxx
new file mode 100644
index 000000000000..af49344e52b9
--- /dev/null
+++ b/sw/qa/extras/mailmerge/mailmerge2.cxx
@@ -0,0 +1,718 @@
+/* -*- 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 <set>
+#include <vector>
+
+#include <swmodeltestbase.hxx>
+
+#include <com/sun/star/text/MailMergeType.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/task/XJob.hpp>
+
+#include <tools/urlobj.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <wrtsh.hxx>
+#include <ndtxt.hxx>
+#include <pagefrm.hxx>
+#include <unoprnms.hxx>
+#include <dbmgr.hxx>
+#include <unotxdoc.hxx>
+#include <docsh.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <rootfrm.hxx>
+
+/**
+ * Maps database URIs to the registered database names for quick lookups
+ */
+typedef std::map<OUString, OUString> DBuriMap;
+static DBuriMap aDBuriMap;
+
+class MMTest2 : public SwModelTestBase
+{
+public:
+ MMTest2();
+
+ virtual void tearDown() override
+ {
+ if (mxMMComponent.is())
+ {
+ if (mnCurOutputType == text::MailMergeType::SHELL)
+ {
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxMMComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ pTextDoc->GetDocShell()->DoClose();
+ }
+ else
+ mxMMComponent->dispose();
+ }
+ if (mxCurResultSet.is())
+ {
+ css::uno::Reference<css::lang::XComponent>(
+ mxCurResultSet, css::uno::UNO_QUERY_THROW)->dispose();
+ }
+ SwModelTestBase::tearDown();
+ }
+
+ /**
+ * Helper func used by each unit test to test the 'mail merge' code.
+ *
+ * Registers the data source, loads the original file as reference,
+ * initializes the mail merge job and its default argument sequence.
+ *
+ * The 'verify' method actually has to execute the mail merge by
+ * calling executeMailMerge() after modifying the job arguments.
+ */
+ void executeMailMergeTest( const char* filename, const char* datasource, const char* tablename,
+ char const*const filter, int selection, const char* column )
+ {
+ maMMTest2Filename = filename;
+ header();
+ preTest(filename);
+
+ utl::TempFile aTempDir(nullptr, true);
+ aTempDir.EnableKillingFile();
+ const OUString aWorkDir = aTempDir.GetURL();
+ const OUString aURI( m_directories.getURLFromSrc(mpTestDocumentPath) + OUString::createFromAscii(datasource) );
+ const OUString aPrefix = column ? OUString::createFromAscii( column ) : "LOMM_";
+ const OUString aDBName = registerDBsource( aURI, aWorkDir );
+ initMailMergeJobAndArgs( filename, tablename, aDBName, aPrefix, aWorkDir, filter, selection, column != nullptr );
+
+ verify();
+ finish();
+
+ mnCurOutputType = 0;
+ }
+
+ OUString registerDBsource( const OUString &aURI, const OUString &aWorkDir )
+ {
+ OUString aDBName;
+ DBuriMap::const_iterator pos = aDBuriMap.find( aURI );
+ if (pos == aDBuriMap.end())
+ {
+ aDBName = SwDBManager::LoadAndRegisterDataSource( aURI, &aWorkDir );
+ aDBuriMap.insert( std::pair< OUString, OUString >( aURI, aDBName ) );
+ std::cout << "New datasource name: '" << aDBName << "'" << std::endl;
+ }
+ else
+ {
+ aDBName = pos->second;
+ std::cout << "Old datasource name: '" << aDBName << "'" << std::endl;
+ }
+ CPPUNIT_ASSERT(!aDBName.isEmpty());
+ return aDBName;
+ }
+
+ uno::Reference< sdbc::XRowSet > getXResultFromDataset( const char* tablename, const OUString &aDBName )
+ {
+ uno::Reference< sdbc::XRowSet > xCurResultSet;
+ uno::Reference< uno::XInterface > xInstance = getMultiServiceFactory()->createInstance( "com.sun.star.sdb.RowSet" );
+ uno::Reference< beans::XPropertySet > xRowSetPropSet( xInstance, uno::UNO_QUERY );
+ assert( xRowSetPropSet.is() && "failed to get XPropertySet interface from RowSet" );
+ if (xRowSetPropSet.is())
+ {
+ xRowSetPropSet->setPropertyValue( "DataSourceName", uno::Any( aDBName ) );
+ xRowSetPropSet->setPropertyValue( "Command", uno::Any( OUString::createFromAscii(tablename) ) );
+ xRowSetPropSet->setPropertyValue( "CommandType", uno::Any( sdb::CommandType::TABLE ) );
+
+ uno::Reference< sdbc::XRowSet > xRowSet( xInstance, uno::UNO_QUERY );
+ if (xRowSet.is())
+ xRowSet->execute(); // build ResultSet from properties
+ xCurResultSet = xRowSet;
+ assert( xCurResultSet.is() && "failed to build ResultSet" );
+ }
+ return xCurResultSet;
+ }
+
+ void initMailMergeJobAndArgs( const char* filename, const char* tablename, const OUString &aDBName,
+ const OUString &aPrefix, const OUString &aWorkDir,
+ char const*const filter, int nDataSets,
+ const bool bPrefixIsColumn )
+ {
+ uno::Reference< task::XJob > xJob( getMultiServiceFactory()->createInstance( "com.sun.star.text.MailMerge" ), uno::UNO_QUERY_THROW );
+ mxJob.set( xJob );
+
+ mMMargs.reserve( 15 );
+
+ mMMargs.emplace_back( UNO_NAME_OUTPUT_TYPE, uno::Any( filter ? text::MailMergeType::FILE : text::MailMergeType::SHELL ) );
+ mMMargs.emplace_back( UNO_NAME_DOCUMENT_URL, uno::Any(
+ ( OUString( m_directories.getURLFromSrc(mpTestDocumentPath) + OUString::createFromAscii(filename)) ) ) );
+ mMMargs.emplace_back( UNO_NAME_DATA_SOURCE_NAME, uno::Any( aDBName ) );
+ mMMargs.emplace_back( UNO_NAME_OUTPUT_URL, uno::Any( aWorkDir ) );
+ if (filter)
+ {
+ mMMargs.emplace_back( UNO_NAME_FILE_NAME_PREFIX, uno::Any( aPrefix ) );
+ mMMargs.emplace_back(UNO_NAME_SAVE_FILTER, uno::Any(OUString::createFromAscii(filter)));
+ }
+
+ if (bPrefixIsColumn)
+ mMMargs.emplace_back( UNO_NAME_FILE_NAME_FROM_COLUMN, uno::Any( true ) );
+
+ if (tablename)
+ {
+ mMMargs.emplace_back( UNO_NAME_DAD_COMMAND_TYPE, uno::Any( sdb::CommandType::TABLE ) );
+ mMMargs.emplace_back( UNO_NAME_DAD_COMMAND, uno::Any( OUString::createFromAscii(tablename) ) );
+ }
+
+ if (nDataSets > 0)
+ {
+ mxCurResultSet = getXResultFromDataset( tablename, aDBName );
+ uno::Reference< sdbcx::XRowLocate > xCurRowLocate( mxCurResultSet, uno::UNO_QUERY );
+ mMMargs.emplace_back( UNO_NAME_RESULT_SET, uno::Any( mxCurResultSet ) );
+ std::vector< uno::Any > vResult;
+ vResult.reserve( nDataSets );
+ sal_Int32 i;
+ for (i = 0, mxCurResultSet->first(); i < nDataSets; i++, mxCurResultSet->next())
+ {
+ vResult.emplace_back( xCurRowLocate->getBookmark() );
+ }
+ mMMargs.emplace_back( UNO_NAME_SELECTION, uno::Any( comphelper::containerToSequence(vResult) ) );
+ }
+
+ }
+
+ void executeMailMerge( bool bDontLoadResult = false )
+ {
+ const uno::Sequence< beans::NamedValue > aSeqMailMergeArgs = comphelper::containerToSequence( mMMargs );
+ uno::Any res = mxJob->execute( aSeqMailMergeArgs );
+
+ bool bOk = true;
+ bool bMMFilenameFromColumn = false;
+
+ for (const beans::NamedValue& rArgument : aSeqMailMergeArgs) {
+ const OUString &rName = rArgument.Name;
+ const uno::Any &rValue = rArgument.Value;
+
+ // all error checking was already done by the MM job execution
+ if (rName == UNO_NAME_OUTPUT_URL)
+ bOk &= rValue >>= msMailMergeOutputURL;
+ else if (rName == UNO_NAME_FILE_NAME_PREFIX)
+ bOk &= rValue >>= msMailMergeOutputPrefix;
+ else if (rName == UNO_NAME_OUTPUT_TYPE)
+ bOk &= rValue >>= mnCurOutputType;
+ else if (rName == UNO_NAME_FILE_NAME_FROM_COLUMN)
+ bOk &= rValue >>= bMMFilenameFromColumn;
+ else if (rName == UNO_NAME_DOCUMENT_URL)
+ bOk &= rValue >>= msMailMergeDocumentURL;
+ }
+
+ CPPUNIT_ASSERT(bOk);
+
+ // MM via UNO just works with file names. If we load the file on
+ // Windows before MM uses it, MM won't work, as it's already open.
+ // Don't move the load before the mail merge execution!
+ // (see gb_CppunitTest_use_instdir_configuration)
+ load(mpTestDocumentPath, maMMTest2Filename);
+
+ if (mnCurOutputType == text::MailMergeType::SHELL)
+ {
+ CPPUNIT_ASSERT(res >>= mxMMComponent);
+ CPPUNIT_ASSERT(mxMMComponent.is());
+ }
+ else
+ {
+ CPPUNIT_ASSERT_EQUAL(uno::Any(true), res);
+ if( !bMMFilenameFromColumn && !bDontLoadResult )
+ loadMailMergeDocument( 0 );
+ }
+ }
+
+ void loadMailMergeDocument( const OUString &filename )
+ {
+ assert( mnCurOutputType == text::MailMergeType::FILE );
+ 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 << filename << ",";
+ mnStartTime = osl_getGlobalTimer();
+ mxComponent = loadFromDesktop(msMailMergeOutputURL + "/" + filename, "com.sun.star.text.TextDocument");
+ OString name2 = OUStringToOString( filename, RTL_TEXTENCODING_UTF8 );
+ discardDumpedLayout();
+ if (mustCalcLayoutOf(name2.getStr()))
+ calcLayout();
+ }
+
+ /**
+ Loads number-th document from mail merge. Requires file output from mail merge.
+ */
+ void loadMailMergeDocument(int number, char const*const ext = ".odt")
+ {
+ OUString name;
+ if (!msMailMergeOutputPrefix.isEmpty())
+ name = msMailMergeOutputPrefix;
+ else
+ {
+ INetURLObject aURLObj;
+ aURLObj.SetSmartProtocol( INetProtocol::File );
+ aURLObj.SetSmartURL( msMailMergeDocumentURL );
+ name = aURLObj.GetBase();
+ }
+ name += OUString::number(number) + OStringToOUString(std::string_view(ext, strlen(ext)), RTL_TEXTENCODING_ASCII_US);
+ loadMailMergeDocument( name );
+ }
+
+ /**
+ Resets currently opened layout of the original template,
+ and creates the layout of the document with N mails inside
+ (result run with text::MailMergeType::SHELL)
+ */
+ void dumpMMLayout()
+ {
+ mpXmlBuffer = xmlBufferPtr();
+ dumpLayout(mxMMComponent);
+ }
+
+protected:
+ uno::Reference< css::task::XJob > mxJob;
+ std::vector< beans::NamedValue > mMMargs;
+ OUString msMailMergeDocumentURL;
+ OUString msMailMergeOutputURL;
+ OUString msMailMergeOutputPrefix;
+ sal_Int16 mnCurOutputType;
+ uno::Reference< lang::XComponent > mxMMComponent;
+ uno::Reference< sdbc::XRowSet > mxCurResultSet;
+ const char* maMMTest2Filename;
+};
+
+#define DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, filter, BaseClass, selection, column) \
+ class TestName : public BaseClass { \
+ protected: \
+ virtual OUString getTestName() override { return #TestName; } \
+ public: \
+ CPPUNIT_TEST_SUITE(TestName); \
+ CPPUNIT_TEST(MailMerge); \
+ CPPUNIT_TEST_SUITE_END(); \
+ \
+ void MailMerge() { \
+ executeMailMergeTest(filename, datasource, tablename, filter, selection, column); \
+ } \
+ void verify() override; \
+ }; \
+ CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
+ void TestName::verify()
+
+// Will generate the resulting document in mxMMDocument.
+#define DECLARE_SHELL_MAILMERGE_TEST(TestName, filename, datasource, tablename) \
+ DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, nullptr, MMTest2, 0, nullptr)
+
+// Will generate documents as files, use loadMailMergeDocument().
+#define DECLARE_FILE_MAILMERGE_TEST(TestName, filename, datasource, tablename) \
+ DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, "writer8", MMTest2, 0, nullptr)
+
+MMTest2::MMTest2()
+ : SwModelTestBase("/sw/qa/extras/mailmerge/data/", "writer8")
+ , mnCurOutputType(0)
+ , maMMTest2Filename(nullptr)
+{
+}
+
+DECLARE_SHELL_MAILMERGE_TEST(tdf125522_shell, "tdf125522.odt", "10-testing-addresses.ods", "testing-addresses")
+{
+ // prepare unit test and run
+ executeMailMerge();
+
+ // reset currently opened layout of the original template,
+ // and create the layout of the document with 10 mails inside
+ dumpMMLayout();
+
+ // there should be no any text frame in output
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxMMComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+
+ const auto & rNodes = pTextDoc->GetDocShell()->GetDoc()->GetNodes();
+ for (SwNodeOffset nodeIndex(0); nodeIndex<rNodes.Count(); nodeIndex++)
+ {
+ SwNode* aNode = rNodes[nodeIndex];
+ if (aNode->StartOfSectionNode())
+ {
+ CPPUNIT_ASSERT(!aNode->StartOfSectionNode()->GetFlyFormat());
+ }
+ }
+}
+
+DECLARE_SHELL_MAILMERGE_TEST(testTd78611_shell, "tdf78611.odt", "10-testing-addresses.ods", "testing-addresses")
+{
+ // prepare unit test and run
+ executeMailMerge();
+
+ // reset currently opened layout of the original template,
+ // and create the layout of the document with 10 mails inside
+ dumpMMLayout();
+
+ // check: each page (one page is one sub doc) has different paragraphs and header paragraphs.
+ // All header paragraphs should have numbering.
+
+ // check first page
+ CPPUNIT_ASSERT_EQUAL( OUString("1"), parseDump("/root/page[1]/body/txt[6]/Special", "rText"));
+ CPPUNIT_ASSERT_EQUAL( OUString("1.1"), parseDump("/root/page[1]/body/txt[8]/Special", "rText"));
+ CPPUNIT_ASSERT_EQUAL( OUString("1.2"), parseDump("/root/page[1]/body/txt[10]/Special", "rText"));
+
+ // check some other pages
+ CPPUNIT_ASSERT_EQUAL( OUString("1"), parseDump("/root/page[3]/body/txt[6]/Special", "rText"));
+ CPPUNIT_ASSERT_EQUAL( OUString("1.1"), parseDump("/root/page[5]/body/txt[8]/Special", "rText"));
+ CPPUNIT_ASSERT_EQUAL( OUString("1.2"), parseDump("/root/page[7]/body/txt[10]/Special", "rText"));
+}
+
+
+DECLARE_FILE_MAILMERGE_TEST(testTd78611_file, "tdf78611.odt", "10-testing-addresses.ods", "testing-addresses")
+{
+ executeMailMerge(true);
+ for (int doc = 0; doc < 10; ++doc)
+ {
+ loadMailMergeDocument( doc );
+ CPPUNIT_ASSERT_EQUAL( OUString("1"), parseDump("/root/page[1]/body/txt[6]/Special", "rText"));
+ CPPUNIT_ASSERT_EQUAL( OUString("1.1"), parseDump("/root/page[1]/body/txt[8]/Special", "rText"));
+ CPPUNIT_ASSERT_EQUAL( OUString("1.2"), parseDump("/root/page[1]/body/txt[10]/Special", "rText"));
+ }
+}
+
+DECLARE_SHELL_MAILMERGE_TEST(testTdf122156_shell, "linked-with-condition.odt", "5-with-blanks.ods",
+ "names")
+{
+ // A document with a linked section hidden on an "empty field" condition
+ // For combined documents, hidden sections are removed completely
+ executeMailMerge();
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxMMComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ // 5 documents 1 page each, starting at odd page numbers => 9
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(9), pTextDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum());
+ uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxMMComponent,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
+ uno::UNO_QUERY_THROW);
+ // 2 out of 5 dataset records have empty "Title" field => no sections in respective documents
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xSections->getCount());
+}
+
+DECLARE_FILE_MAILMERGE_TEST(testTdf122156_file, "linked-with-condition.odt", "5-with-blanks.ods",
+ "names")
+{
+ // A document with a linked section hidden on an "empty field" condition
+ // For separate documents, the sections are hidden, but not removed
+ executeMailMerge();
+ {
+ loadMailMergeDocument(0);
+ uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
+ uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
+ // Record 1 has empty "Title" field => section is not shown
+ CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect, "IsCurrentlyVisible"));
+ }
+ {
+ loadMailMergeDocument(1);
+ uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
+ uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
+ // Record 2 has non-empty "Title" field => section is shown
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect, "IsCurrentlyVisible"));
+ }
+ {
+ loadMailMergeDocument(2);
+ uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
+ uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
+ // Record 3 has non-empty "Title" field => section is shown
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect, "IsCurrentlyVisible"));
+ }
+ {
+ loadMailMergeDocument(3);
+ uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
+ uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
+ // Record 4 has empty "Title" field => section is not shown
+ CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect, "IsCurrentlyVisible"));
+ }
+ {
+ loadMailMergeDocument(4);
+ uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(),
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
+ uno::Reference<beans::XPropertySet> xSect(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
+ // Record 5 has non-empty "Title" field => section is shown
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect, "IsCurrentlyVisible"));
+ }
+}
+
+DECLARE_SHELL_MAILMERGE_TEST(testTdf121168, "section_ps.odt", "4_v01.ods", "Tabelle1")
+{
+ // A document starting with a section on a page with non-default page style with header
+ executeMailMerge();
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxMMComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ // 4 documents 1 page each, starting at odd page numbers => 7
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(7), pTextDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum());
+
+ SwDoc* pDocMM = pTextDoc->GetDocShell()->GetDoc();
+ SwNodeOffset nSizeMM = pDocMM->GetNodes().GetEndOfContent().GetIndex()
+ - pDocMM->GetNodes().GetEndOfExtras().GetIndex() - 2;
+ CPPUNIT_ASSERT_EQUAL(SwNodeOffset(16), nSizeMM);
+
+ // All even pages should be empty, all sub-documents have one page
+ const SwRootFrame* pLayout = pDocMM->getIDocumentLayoutAccess().GetCurrentLayout();
+ const SwPageFrame* pPageFrm = static_cast<const SwPageFrame*>(pLayout->Lower());
+ while (pPageFrm)
+ {
+ sal_uInt16 nPageNum = pPageFrm->GetPhyPageNum();
+ bool bOdd = (1 == (nPageNum % 2));
+ CPPUNIT_ASSERT_EQUAL(!bOdd, pPageFrm->IsEmptyPage());
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(bOdd ? 1 : 2), pPageFrm->GetVirtPageNum());
+ if (bOdd)
+ {
+ const SwPageDesc* pDesc = pPageFrm->GetPageDesc();
+ CPPUNIT_ASSERT_EQUAL(OUString("Teststyle" + OUString::number(nPageNum / 2 + 1)),
+ pDesc->GetName());
+ }
+ pPageFrm = static_cast<const SwPageFrame*>(pPageFrm->GetNext());
+ }
+}
+
+
+DECLARE_FILE_MAILMERGE_TEST(testTdf81782_file, "tdf78611.odt", "10-testing-addresses.ods", "testing-addresses")
+{
+ executeMailMerge(true);
+ for (int doc = 0; doc < 10; ++doc)
+ {
+ loadMailMergeDocument( doc );
+
+ // get document properties
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDocumentProperties(xDocumentPropertiesSupplier->getDocumentProperties());
+
+ // check if properties were set
+ uno::Sequence<OUString> aKeywords(xDocumentProperties->getKeywords());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aKeywords.getLength());
+ CPPUNIT_ASSERT_EQUAL(OUString("one two"), aKeywords[0]);
+
+ // check title and subject
+ CPPUNIT_ASSERT_EQUAL(OUString("my title"), xDocumentProperties->getTitle());
+ CPPUNIT_ASSERT_EQUAL(OUString("my subject"), xDocumentProperties->getSubject());
+ }
+}
+
+// problem was: field content was duplicated & truncated
+DECLARE_SHELL_MAILMERGE_TEST(testTdf81750_shell, "tdf81750.odt", "10-testing-addresses.ods", "testing-addresses")
+{
+ // prepare unit test and run
+ executeMailMerge();
+
+ // reset currently opened layout of the original template,
+ // and create the layout of the document with 10 mails inside
+ dumpMMLayout();
+
+ // check several pages page
+ OUString aExpected("Text: Foo ");
+ CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[1]/body/txt[2]", ""));
+ CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[3]/body/txt[2]", ""));
+ CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[5]/body/txt[2]", ""));
+ CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[7]/body/txt[2]", ""));
+ CPPUNIT_ASSERT_EQUAL( aExpected, parseDump("/root/page[9]/body/txt[2]", ""));
+}
+
+
+DECLARE_FILE_MAILMERGE_TEST(testTdf123057_file, "pagecounttest.ott", "db_pagecounttest.ods", "Sheet1")
+{
+ executeMailMerge(true);
+
+ for (int doc = 0; doc < 4; ++doc)
+ {
+ loadMailMergeDocument(doc);
+
+ // get document properties
+ uno::Reference<text::XTextSectionsSupplier> xSectionsSupplier(mxComponent, uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xSections(xSectionsSupplier->getTextSections(), uno::UNO_QUERY_THROW);
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xSections->getCount());
+ uno::Reference<beans::XPropertySet> xSect0(xSections->getByIndex(0), uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xSect1(xSections->getByIndex(1), uno::UNO_QUERY_THROW);
+
+ OUString sFieldPageCount;
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
+ uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
+
+ if (xFields.is())
+ {
+ while (xFields->hasMoreElements())
+ {
+ uno::Any aField = xFields->nextElement();
+ uno::Reference<lang::XServiceInfo> xServiceInfo(aField, uno::UNO_QUERY);
+ if (xServiceInfo->supportsService("com.sun.star.text.textfield.PageCount"))
+ {
+ uno::Reference<text::XTextContent> xField(aField, uno::UNO_QUERY);
+ sFieldPageCount = xField->getAnchor()->getString();
+ }
+ }
+ }
+
+ switch (doc)
+ {
+ case 0:
+ // both sections visible, page num is 2
+ CPPUNIT_ASSERT_EQUAL(2, getPages());
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect0, "IsCurrentlyVisible"));
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect1, "IsCurrentlyVisible"));
+ CPPUNIT_ASSERT_EQUAL(OUString("2"), sFieldPageCount);
+ break;
+ case 1:
+ // second section hidden, page num is 1
+ CPPUNIT_ASSERT_EQUAL(1, getPages());
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect0, "IsCurrentlyVisible"));
+ CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect1, "IsCurrentlyVisible"));
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), sFieldPageCount);
+ break;
+ case 2:
+ // first section hidden, page num is 1
+ CPPUNIT_ASSERT_EQUAL(1, getPages());
+ CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect0, "IsCurrentlyVisible"));
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xSect1, "IsCurrentlyVisible"));
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), sFieldPageCount);
+ break;
+ case 3:
+ // both sections hidden, page num is 1
+ CPPUNIT_ASSERT_EQUAL(1, getPages());
+ CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect0, "IsCurrentlyVisible"));
+ CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xSect1, "IsCurrentlyVisible"));
+ CPPUNIT_ASSERT_EQUAL(OUString("1"), sFieldPageCount);
+ break;
+ }
+ }
+}
+
+// The document has a header with page number and total page count on page 2
+// (which uses page style "Default Style") but doesn't have a header set
+// for the first page (which uses page style "First Page").
+// Fields in the header hadn't been replaced properly.
+DECLARE_SHELL_MAILMERGE_TEST(testTdf128148, "tdf128148.odt", "4_v01.ods", "Tabelle1")
+{
+ executeMailMerge();
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxMMComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+
+ // 4 documents with 2 pages each => 8 pages in total
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), pTextDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum());
+
+ SwDoc* pDocMM = pTextDoc->GetDocShell()->GetDoc();
+ uno::Reference<frame::XModel> xModel = pTextDoc->GetDocShell()->GetBaseModel();
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xModel, uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY);
+
+ // All odd pages have no header, all even pages should have header with text "Page 2 of 2"
+ const SwRootFrame* pLayout = pDocMM->getIDocumentLayoutAccess().GetCurrentLayout();
+ const SwPageFrame* pPageFrm = static_cast<const SwPageFrame*>(pLayout->Lower());
+ while (pPageFrm)
+ {
+ const sal_uInt16 nPageNum = pPageFrm->GetPhyPageNum();
+ const bool bIsEvenPage = ((nPageNum % 2) == 0);
+
+ const OUString& sPageStyle = pPageFrm->GetPageDesc()->GetName();
+ uno::Reference<beans::XPropertySet> xPageStyle(xStyleFamily->getByName(sPageStyle), uno::UNO_QUERY);
+
+ bool bHeaderIsOn = false;
+ xPageStyle->getPropertyValue(UNO_NAME_HEADER_IS_ON) >>= bHeaderIsOn;
+
+ // first page for every data record shouldn't have header, second should
+ CPPUNIT_ASSERT_EQUAL(bIsEvenPage, bHeaderIsOn);
+ if (bIsEvenPage)
+ {
+ // text in header on even pages with correctly replaced fields is "Page 2 of 2"
+ uno::Reference<text::XText> xHeaderText;
+ xPageStyle->getPropertyValue(UNO_NAME_HEADER_TEXT) >>= xHeaderText;
+ const OUString sHeaderText = xHeaderText->getString();
+ CPPUNIT_ASSERT_EQUAL(OUString("Page 2 of 2"), sHeaderText);
+ }
+
+ pPageFrm = static_cast<const SwPageFrame*>(pPageFrm->GetNext());
+ }
+}
+
+DECLARE_MAILMERGE_TEST(testGrabBag, "grabbagtest.docx", "onecell.xlsx", "Sheet1", "MS Word 2007 XML", MMTest2, 0, nullptr)
+{
+ executeMailMerge(true);
+
+ loadMailMergeDocument(0, ".docx");
+
+ SwXTextDocument *const pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pTextDoc->GetDocShell()->GetWrtShell()->GetPhyPageNum());
+
+ // check grabbag
+ uno::Reference<beans::XPropertySet> const xModel(
+ mxComponent, uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aInteropGrabBag;
+ pTextDoc->getPropertyValue("InteropGrabBag") >>= aInteropGrabBag;
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(12), aInteropGrabBag.getLength());
+
+ // check table border - comes from table style "Tabellenraster"
+ uno::Reference<text::XTextTable> const xTable(getParagraphOrTable(1, pTextDoc->getText()), uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> const xTableProps(xTable, uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(table::TableBorder(
+ table::BorderLine(util::Color(0), 0, 18, 0), true,
+ table::BorderLine(util::Color(0), 0, 18, 0), true,
+ table::BorderLine(util::Color(0), 0, 18, 0), true,
+ table::BorderLine(util::Color(0), 0, 18, 0), true,
+ table::BorderLine(util::Color(0), 0, 18, 0), true,
+ table::BorderLine(util::Color(0), 0, 0, 0), true,
+ sal_Int16(191), true),
+ getProperty<table::TableBorder>(xTableProps, "TableBorder"));
+
+ // check font is Arial - comes from theme (wrong result was "" - nothing)
+ uno::Reference<text::XText> const xCell(xTable->getCellByName("A1"), uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> const xParaA1(getParagraphOrTable(1, xCell->getText()), uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(OUString("Arial"), getProperty<OUString>(xParaA1, "CharFontName"));
+}
+
+namespace com::sun::star::table {
+
+static std::ostream& operator<<(std::ostream& rStream, table::BorderLine const& rLine)
+{
+ rStream << "BorderLine(" << rLine.Color << "," << rLine.InnerLineWidth << "," << rLine.OuterLineWidth << "," << rLine.LineDistance << ")";
+ return rStream;
+}
+
+static std::ostream& operator<<(std::ostream& rStream, table::TableBorder const& rBorder)
+{
+ rStream << "TableBorder(\n "
+ << rBorder.TopLine << "," << static_cast<bool>(rBorder.IsTopLineValid) << ",\n "
+ << rBorder.BottomLine << "," << static_cast<bool>(rBorder.IsBottomLineValid) << ",\n "
+ << rBorder.LeftLine << "," << static_cast<bool>(rBorder.IsLeftLineValid) << ",\n "
+ << rBorder.RightLine << "," << static_cast<bool>(rBorder.IsRightLineValid) << ",\n "
+ << rBorder.HorizontalLine << "," << static_cast<bool>(rBorder.IsHorizontalLineValid) << ",\n "
+ << rBorder.VerticalLine << "," << static_cast<bool>(rBorder.IsVerticalLineValid) << ",\n "
+ << rBorder.Distance << "," << static_cast<bool>(rBorder.IsDistanceValid) << ")";
+ return rStream;
+}
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */