1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "mailmergetestbase.cxx"
14 class MMTest
: public MailMergeTestBase
18 DECLARE_SHELL_MAILMERGE_TEST(testMultiPageAnchoredDraws
, "multiple-page-anchored-draws.odt", "4_v01.ods", "Tabelle1")
22 CPPUNIT_ASSERT(mxSwTextDocument
);
23 sal_uInt16 nPhysPages
= mxSwTextDocument
->GetDocShell()->GetWrtShell()->GetPhyPageNum();
24 CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), nPhysPages
);
26 uno::Reference
<container::XIndexAccess
> xDraws
= mxSwTextDocument
->getDrawPage();
27 CPPUNIT_ASSERT_EQUAL(sal_Int32(8), xDraws
->getCount());
29 std::set
<sal_uInt16
> pages
;
30 uno::Reference
<beans::XPropertySet
> xPropertySet
;
32 for (sal_Int32 i
= 0; i
< xDraws
->getCount(); i
++)
34 xPropertySet
.set(xDraws
->getByIndex(i
), uno::UNO_QUERY
);
36 text::TextContentAnchorType nAnchorType
;
37 CPPUNIT_ASSERT(xPropertySet
->getPropertyValue( UNO_NAME_ANCHOR_TYPE
) >>= nAnchorType
);
38 CPPUNIT_ASSERT_EQUAL( text::TextContentAnchorType_AT_PAGE
, nAnchorType
);
40 sal_uInt16 nAnchorPageNo
= {};
41 CPPUNIT_ASSERT(xPropertySet
->getPropertyValue( UNO_NAME_ANCHOR_PAGE_NO
) >>= nAnchorPageNo
);
42 // are all shapes are on different page numbers?
43 CPPUNIT_ASSERT(pages
.insert(nAnchorPageNo
).second
);
47 DECLARE_FILE_MAILMERGE_TEST(testMissingDefaultLineColor
, "missing-default-line-color.ott", "one-empty-address.ods", "one-empty-address")
50 // The document was created by LO version which didn't write out the default value for line color
51 // (see XMLGraphicsDefaultStyle::SetDefaults()).
52 uno::Reference
<beans::XPropertySet
> xPropertySet(getShape(5), uno::UNO_QUERY
);
53 // Lines do not have a line color.
54 CPPUNIT_ASSERT( !xPropertySet
->getPropertySetInfo()->hasPropertyByName( u
"LineColor"_ustr
));
55 uno::Reference
< lang::XMultiServiceFactory
> xFact( mxComponent
, uno::UNO_QUERY
);
56 uno::Reference
< beans::XPropertySet
> xDefaults( xFact
->createInstance( u
"com.sun.star.drawing.Defaults"_ustr
), uno::UNO_QUERY
);
57 CPPUNIT_ASSERT( xDefaults
.is());
58 uno::Reference
< beans::XPropertySetInfo
> xInfo( xDefaults
->getPropertySetInfo());
59 CPPUNIT_ASSERT( xInfo
->hasPropertyByName( u
"LineColor"_ustr
));
61 xDefaults
->getPropertyValue( u
"LineColor"_ustr
) >>= lineColor
;
62 // And the default value is black (wasn't copied properly by mailmerge).
63 CPPUNIT_ASSERT_EQUAL( COL_BLACK
, lineColor
);
64 // And check that the resulting file has the proper default.
65 xmlDocUniquePtr pXmlDoc
= parseMailMergeExport( u
"styles.xml"_ustr
);
66 assertXPath(pXmlDoc
, "/office:document-styles/office:styles/style:default-style[1]", "family", u
"graphic");
67 assertXPath(pXmlDoc
, "/office:document-styles/office:styles/style:default-style[1]/style:graphic-properties", "stroke-color", u
"#000000");
70 DECLARE_FILE_MAILMERGE_TEST(testSimpleMailMerge
, "simple-mail-merge.odt", "10-testing-addresses.ods", "testing-addresses")
77 loadMailMergeDocument( doc
);
78 CPPUNIT_ASSERT_EQUAL( 1, getPages());
79 CPPUNIT_ASSERT_EQUAL( u
"Fixed text."_ustr
, getRun( getParagraph( 1 ), 1 )->getString());
80 CPPUNIT_ASSERT_EQUAL( OUString( "lastname" + OUString::number( doc
+ 1 )), getRun( getParagraph( 2 ), 1 )->getString());
81 CPPUNIT_ASSERT_EQUAL( u
"Another fixed text."_ustr
, getRun( getParagraph( 3 ), 1 )->getString());
85 DECLARE_FILE_MAILMERGE_TEST(testWriterDataSource
, "writer-mail-merge.odt", "10-testing-addresses-writer.odt", "testing-addresses-writer")
87 // This failed as the .odt data source was mapped to the jdbc: protocol.
89 for (int doc
= 0; doc
< 10; ++doc
)
91 loadMailMergeDocument(doc
);
92 CPPUNIT_ASSERT_EQUAL(1, getPages());
93 CPPUNIT_ASSERT_EQUAL(u
"Fixed text."_ustr
, getRun(getParagraph(1), 1)->getString());
94 CPPUNIT_ASSERT_EQUAL(OUString("lastname" + OUString::number(doc
+ 1)), getRun(getParagraph(2), 1)->getString());
95 CPPUNIT_ASSERT_EQUAL(u
"Another fixed text."_ustr
, getRun(getParagraph(3), 1)->getString());
99 DECLARE_FILE_MAILMERGE_TEST(testWriterMergedDataSource
, "writer-merged-mail-merge.odt", "10-testing-addresses-writer-merged.odt", "testing-addresses-writer-merged")
101 // This failed with com.sun.star.lang.IndexOutOfBoundsException, leading to
102 // a crash, as the last row had merged cells in
103 // 10-testing-addresses-writer-merged.odt.
105 for (int doc
= 0; doc
< 10; ++doc
)
107 loadMailMergeDocument(doc
);
108 CPPUNIT_ASSERT_EQUAL(1, getPages());
109 CPPUNIT_ASSERT_EQUAL(u
"Fixed text."_ustr
, getRun(getParagraph(1), 1)->getString());
110 CPPUNIT_ASSERT_EQUAL(OUString("lastname" + OUString::number(doc
+ 1)), getRun(getParagraph(2), 1)->getString());
111 CPPUNIT_ASSERT_EQUAL(u
"Another fixed text."_ustr
, getRun(getParagraph(3), 1)->getString());
115 DECLARE_FILE_MAILMERGE_TEST(test2Pages
, "simple-mail-merge-2pages.odt", "10-testing-addresses.ods", "testing-addresses")
122 loadMailMergeDocument( doc
);
123 OUString lastname
= "lastname" + OUString::number( doc
+ 1 );
124 OUString firstname
= "firstname" + OUString::number( doc
+ 1 );
125 CPPUNIT_ASSERT_EQUAL( 2, getPages());
126 CPPUNIT_ASSERT_EQUAL( u
"Fixed text."_ustr
, getRun( getParagraph( 1 ), 1 )->getString());
127 CPPUNIT_ASSERT_EQUAL( lastname
, getRun( getParagraph( 2 ), 1 )->getString());
128 CPPUNIT_ASSERT_EQUAL( u
"Another fixed text."_ustr
, getRun( getParagraph( 3 ), 1 )->getString());
129 CPPUNIT_ASSERT_EQUAL( OUString(), getRun( getParagraph( 4 ), 1 )->getString()); // empty para at the end of page 1
130 CPPUNIT_ASSERT_EQUAL( u
"Second page."_ustr
, getRun( getParagraph( 5 ), 1 )->getString());
131 CPPUNIT_ASSERT_EQUAL( firstname
, getRun( getParagraph( 6 ), 1 )->getString());
132 // Also verify the layout.
134 xmlDocUniquePtr pXmlDoc
= parseLayoutDump(static_cast<SfxBaseModel
*>(mxSwTextDocument
.get()));
135 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/SwParaPortion/SwLineLayout/SwFieldPortion", "expand", lastname
);
136 assertXPathContent(pXmlDoc
, "/root/page[1]/body/txt[1]", u
"Fixed text.");
137 assertXPathContent(pXmlDoc
, "/root/page[1]/body/txt[4]", u
"");
138 assertXPathContent(pXmlDoc
, "/root/page[2]/body/txt[1]", u
"Second page.");
139 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[2]/SwParaPortion/SwLineLayout/SwFieldPortion", "expand", firstname
);
143 DECLARE_SHELL_MAILMERGE_TEST(testPageBoundariesSimpleMailMerge
, "simple-mail-merge.odt", "10-testing-addresses.ods", "testing-addresses")
145 // This is like the test above, but this one uses the create-single-document-containing-everything-generated approach,
146 // and verifies that boundaries of the generated sub-documents are correct inside that document.
147 // These boundaries are done using "documentStartPageNumber<number>" UNO bookmarks (see also
148 // documentStartPageNumber() ).
150 // Here getPages() works on the source document, so get pages of the resulting one.
151 CPPUNIT_ASSERT(mxSwTextDocument
);
152 CPPUNIT_ASSERT_EQUAL( sal_uInt16( 19 ), mxSwTextDocument
->GetDocShell()->GetWrtShell()->GetPhyPageNum()); // 10 pages, but each sub-document starts on odd page number
157 CPPUNIT_ASSERT_EQUAL( doc
* 2 + 1, documentStartPageNumber( doc
));
161 DECLARE_SHELL_MAILMERGE_TEST(testPageBoundaries2Pages
, "simple-mail-merge-2pages.odt", "10-testing-addresses.ods", "testing-addresses")
164 CPPUNIT_ASSERT(mxSwTextDocument
);
165 CPPUNIT_ASSERT_EQUAL( sal_uInt16( 20 ), mxSwTextDocument
->GetDocShell()->GetWrtShell()->GetPhyPageNum()); // 20 pages, each sub-document starts on odd page number
170 CPPUNIT_ASSERT_EQUAL( doc
* 2 + 1, documentStartPageNumber( doc
));
174 DECLARE_SHELL_MAILMERGE_TEST(testTdf89214
, "tdf89214.odt", "10-testing-addresses.ods", "testing-addresses")
178 uno::Reference
<text::XTextRange
> xParagraph(getParagraphOrTable(3, mxSwTextDocument
->getText()), uno::UNO_QUERY
);
179 // Make sure that we assert the right paragraph.
180 CPPUNIT_ASSERT_EQUAL(u
"a"_ustr
, xParagraph
->getString());
181 // This paragraph had a bullet numbering, make sure that the list id is not empty.
182 CPPUNIT_ASSERT(!getProperty
<OUString
>(xParagraph
, u
"ListId"_ustr
).isEmpty());
185 DECLARE_SHELL_MAILMERGE_TEST(testTdf90230
, "empty.odt", "10-testing-addresses.ods", "testing-addresses")
187 // MM of an empty document caused an assertion in the SwContentIndexReg dtor.
191 DECLARE_SHELL_MAILMERGE_TEST(testTdf92623
, "tdf92623.odt", "10-testing-addresses.ods", "testing-addresses")
193 // Copying bookmarks for MM was broken because of the StartOfContent node copy
194 // copied marks were off by one
197 IDocumentMarkAccess
const *pIDMA
= getSwDoc()->getIDocumentMarkAccess();
198 // There is just one mark...
199 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pIDMA
->getAllMarksCount());
200 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pIDMA
->getBookmarksCount());
201 auto mark
= pIDMA
->getAllMarksBegin();
202 // and it's a TEXT_FIELDMARK
203 CPPUNIT_ASSERT_EQUAL( sal_Int32(IDocumentMarkAccess::MarkType::TEXT_FIELDMARK
),
204 sal_Int32(IDocumentMarkAccess::GetType( **mark
)) );
205 SwNodeOffset src_pos
= (*mark
)->GetMarkPos().GetNodeIndex();
207 // Get the size of the document in nodes
208 SwDoc
*doc
= getSwDoc();
209 SwNodeOffset size
= doc
->GetNodes().GetEndOfContent().GetIndex() - doc
->GetNodes().GetEndOfExtras().GetIndex();
210 CPPUNIT_ASSERT_EQUAL( SwNodeOffset(13), size
);
211 size
-= SwNodeOffset(2); // For common start and end nodes
213 // Iterate over all field marks in the target document and check that they
214 // are positioned at a multitude of the document size
215 CPPUNIT_ASSERT(mxSwTextDocument
);
216 pIDMA
= mxSwTextDocument
->GetDocShell()->GetDoc()->getIDocumentMarkAccess();
217 // The target document has the duplicated amount of bookmarks
218 // as the helping uno bookmark from the mail merge is left in the doc
219 // TODO should be fixed!
220 CPPUNIT_ASSERT_EQUAL(sal_Int32(20), pIDMA
->getAllMarksCount());
221 std::set
<SwNodeOffset
> pages
;
222 sal_Int32 countFieldMarks
= 0;
223 for( mark
= pIDMA
->getAllMarksBegin(); mark
!= pIDMA
->getAllMarksEnd(); ++mark
)
225 IDocumentMarkAccess::MarkType markType
= IDocumentMarkAccess::GetType( **mark
);
226 if( markType
== IDocumentMarkAccess::MarkType::TEXT_FIELDMARK
)
228 SwNodeOffset pos
= (*mark
)->GetMarkPos().GetNodeIndex() - src_pos
;
229 CPPUNIT_ASSERT_EQUAL(SwNodeOffset(0), pos
% size
);
230 CPPUNIT_ASSERT(pages
.insert(pos
).second
);
233 else // see previous TODO
234 CPPUNIT_ASSERT_EQUAL( sal_Int32(IDocumentMarkAccess::MarkType::UNO_BOOKMARK
), sal_Int32(markType
) );
236 CPPUNIT_ASSERT_EQUAL(sal_Int32(10), countFieldMarks
);
239 DECLARE_SHELL_MAILMERGE_TEST(testBookmarkCondition
, "bookmarkcondition.fodt", "bookmarkcondition.ods", "data")
243 xmlDocUniquePtr pXmlDoc
= parseLayoutDump(static_cast<SfxBaseModel
*>(mxSwTextDocument
.get()));
244 // check that conditions on sections and bookmarks are evaluated the same
245 assertXPath(pXmlDoc
, "/root/page", 7);
246 assertXPath(pXmlDoc
, "/root/page[1]/body/section", 1);
247 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[1]/SwParaPortion/SwLineLayout", "portion", u
"In den Bergen war es anstrengend.");
248 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[5]/SwParaPortion/SwLineLayout", "portion", u
"Mein Urlaub war anstrengend . ");
249 assertXPath(pXmlDoc
, "/root/page[3]/body/section", 1);
250 assertXPath(pXmlDoc
, "/root/page[3]/body/section[1]/txt[1]/SwParaPortion/SwLineLayout", "portion", u
"In Barcelona war es schön.");
251 assertXPath(pXmlDoc
, "/root/page[3]/body/txt[5]/SwParaPortion/SwLineLayout", "portion", u
"Mein Urlaub war schön . ");
252 assertXPath(pXmlDoc
, "/root/page[5]/body/section", 1);
253 assertXPath(pXmlDoc
, "/root/page[5]/body/section[1]/txt[1]/SwParaPortion/SwLineLayout", "portion", u
"In Paris war es erlebnisreich.");
254 assertXPath(pXmlDoc
, "/root/page[5]/body/txt[5]/SwParaPortion/SwLineLayout", "portion", u
"Mein Urlaub war erlebnisreich . ");
255 assertXPath(pXmlDoc
, "/root/page[7]/body/section", 3);
256 assertXPath(pXmlDoc
, "/root/page[7]/body/section[1]/txt[1]/SwParaPortion/SwLineLayout", "portion", u
"In den Bergen war es anstrengend.");
257 assertXPath(pXmlDoc
, "/root/page[7]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout", "portion", u
"In Barcelona war es schön.");
258 assertXPath(pXmlDoc
, "/root/page[7]/body/section[3]/txt[1]/SwParaPortion/SwLineLayout", "portion", u
"In Paris war es erlebnisreich.");
259 assertXPath(pXmlDoc
, "/root/page[7]/body/txt[5]/SwParaPortion/SwLineLayout", "portion", u
"Mein Urlaub war anstrengend schön erlebnisreich . ");
262 DECLARE_SHELL_MAILMERGE_TEST_SELECTION(testTdf95292
, "linked-labels.odt", "10-testing-addresses.ods", "testing-addresses", 5)
264 // A document with two labels merged with 5 datasets should result in three pages
267 SwWrtShell
*pWrtShell
= getSwDocShell()->GetWrtShell();
268 CPPUNIT_ASSERT( pWrtShell
->IsLabelDoc() );
270 CPPUNIT_ASSERT( mxSwTextDocument
);
271 pWrtShell
= mxSwTextDocument
->GetDocShell()->GetWrtShell();
272 CPPUNIT_ASSERT( !pWrtShell
->IsLabelDoc() );
273 CPPUNIT_ASSERT_EQUAL( sal_uInt16( 5 ), pWrtShell
->GetPhyPageNum() );
276 DECLARE_SHELL_MAILMERGE_TEST(test_sections_first_last
, "sections_first_last.odt", "10-testing-addresses.ods", "testing-addresses")
278 // A document with a leading, middle and trailing section
279 // Originally we were losing the trailing section during merge
282 // Get the size of the document in nodes
283 SwDoc
*pDoc
= getSwDoc();
284 SwNodeOffset nSize
= pDoc
->GetNodes().GetEndOfContent().GetIndex() - pDoc
->GetNodes().GetEndOfExtras().GetIndex();
285 nSize
-= SwNodeOffset(2); // The common start and end node
286 CPPUNIT_ASSERT_EQUAL( SwNodeOffset(13), nSize
);
288 CPPUNIT_ASSERT(mxSwTextDocument
);
290 SwDoc
*pDocMM
= mxSwTextDocument
->GetDocShell()->GetDoc();
291 SwNodeOffset nSizeMM
= pDocMM
->GetNodes().GetEndOfContent().GetIndex() - pDocMM
->GetNodes().GetEndOfExtras().GetIndex();
292 nSizeMM
-= SwNodeOffset(2);
293 CPPUNIT_ASSERT_EQUAL( SwNodeOffset(10) * nSize
, nSizeMM
);
295 CPPUNIT_ASSERT_EQUAL( sal_uInt16(19), pDocMM
->GetDocShell()->GetWrtShell()->GetPhyPageNum() );
297 // All even pages should be empty, all sub-documents have two pages
298 const SwRootFrame
* pLayout
= pDocMM
->getIDocumentLayoutAccess().GetCurrentLayout();
299 const SwPageFrame
* pPageFrm
= static_cast<const SwPageFrame
*>( pLayout
->Lower() );
302 bool bOdd
= (1 == (pPageFrm
->GetPhyPageNum() % 2));
303 CPPUNIT_ASSERT_EQUAL( !bOdd
, pPageFrm
->IsEmptyPage() );
304 CPPUNIT_ASSERT_EQUAL( sal_uInt16( bOdd
? 1 : 2 ), pPageFrm
->GetVirtPageNum() );
305 pPageFrm
= static_cast<const SwPageFrame
*>( pPageFrm
->GetNext() );
309 DECLARE_FILE_MAILMERGE_TEST_COLUMN(testDirMailMerge
, "simple-mail-merge.odt", "10-testing-addresses.ods", "testing-addresses", "Filename")
316 OUString filename
= "sub/lastname" + OUString::number( doc
)
317 + " firstname" + OUString::number( doc
) + ".odt";
318 loadMailMergeDocument( filename
);
319 CPPUNIT_ASSERT_EQUAL( 1, getPages());
320 CPPUNIT_ASSERT_EQUAL( u
"Fixed text."_ustr
, getRun( getParagraph( 1 ), 1 )->getString());
321 CPPUNIT_ASSERT_EQUAL( OUString( "lastname" + OUString::number( doc
)), getRun( getParagraph( 2 ), 1 )->getString());
322 CPPUNIT_ASSERT_EQUAL( u
"Another fixed text."_ustr
, getRun( getParagraph( 3 ), 1 )->getString());
326 DECLARE_FILE_MAILMERGE_TEST(testTdf102010
, "empty.odt", "10-testing-addresses.ods", "testing-addresses")
328 // Create "correct" automatic filename for non-user-supplied-prefix
329 for (auto aNamedValueIter
= mMMargs
.begin(); aNamedValueIter
!= mMMargs
.end();)
331 if ( aNamedValueIter
->Name
== UNO_NAME_FILE_NAME_PREFIX
)
332 aNamedValueIter
= mMMargs
.erase( aNamedValueIter
);
335 std::cout
<< aNamedValueIter
->Name
<< ": " << aNamedValueIter
->Value
<< std::endl
;
339 mMMargs
.emplace_back( UNO_NAME_SAVE_AS_SINGLE_FILE
, uno::Any( true ) );
341 // Generate correct mail merge result filename
343 // Don't overwrite previous result
344 executeMailMerge( true );
345 loadMailMergeDocument( 1 );
348 DECLARE_SHELL_MAILMERGE_TEST(testTdf118113
, "tdf118113.odt", "tdf118113.ods", "testing-addresses")
352 // The document contains a text box anchored to the page and a conditionally hidden
353 // section that is only shown for one of the 4 recipients, namely the 3rd record.
354 // In case the hidden section is shown, the page count is 3 for a single data entry, otherwise 1.
355 // Previously, the page number was calculated incorrectly which led to the
356 // text box being anchored to the wrong page.
358 CPPUNIT_ASSERT(mxSwTextDocument
);
359 // 3 documents with 1 page size each + 1 document with 3 pages
360 // + an additional page after each of the first 3 documents to make
361 // sure that each document starts on an odd page number
362 sal_uInt16 nPhysPages
= mxSwTextDocument
->GetDocShell()->GetWrtShell()->GetPhyPageNum();
363 CPPUNIT_ASSERT_EQUAL(sal_uInt16(9), nPhysPages
);
365 // verify that there is a text box for each data record
366 uno::Reference
<container::XIndexAccess
> xDraws
= mxSwTextDocument
->getDrawPage();
367 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xDraws
->getCount());
369 // verify the text box for each data record is anchored to the first page of the given data record's pages
370 std::vector
<sal_uInt16
> expectedPageNumbers
{1, 3, 5, 9};
371 uno::Reference
<beans::XPropertySet
> xPropertySet
;
372 for (sal_Int32 i
= 0; i
< xDraws
->getCount(); i
++)
374 xPropertySet
.set(xDraws
->getByIndex(i
), uno::UNO_QUERY
);
376 text::TextContentAnchorType nAnchorType
;
377 CPPUNIT_ASSERT(xPropertySet
->getPropertyValue( UNO_NAME_ANCHOR_TYPE
) >>= nAnchorType
);
378 CPPUNIT_ASSERT_EQUAL( text::TextContentAnchorType_AT_PAGE
, nAnchorType
);
380 sal_uInt16 nAnchorPageNo
= {};
381 CPPUNIT_ASSERT(xPropertySet
->getPropertyValue( UNO_NAME_ANCHOR_PAGE_NO
) >>= nAnchorPageNo
);
383 CPPUNIT_ASSERT_EQUAL(expectedPageNumbers
.at(i
), nAnchorPageNo
);
388 constexpr char const* const EmptyValuesLegacyData
[][8]
389 = { { "Heading", "Title: ", "First Name: firstname1", "Last Name: lastname1",
390 "Title: First Name: firstname1", "First Name: firstname1 Last Name: lastname1",
391 "Title: First Name: firstname1 Last Name: lastname1", "Trailing text" },
392 { "Heading", "Title: title2", "First Name: ", "Last Name: lastname2",
393 "Title: title2 First Name: ", "First Name: Last Name: lastname2",
394 "Title: title2 First Name: Last Name: lastname2", "Trailing text" },
395 { "Heading", "Title: title3", "First Name: firstname3", "Last Name: ",
396 "Title: title3 First Name: firstname3", "First Name: firstname3 Last Name: ",
397 "Title: title3 First Name: firstname3 Last Name: ", "Trailing text" },
398 { "Heading", "Title: ", "First Name: ", "Last Name: lastname4",
399 "Title: First Name: ", "First Name: Last Name: lastname4",
400 "Title: First Name: Last Name: lastname4", "Trailing text" },
401 { "Heading", "Title: title5", "First Name: ", "Last Name: ", "Title: title5 First Name: ",
402 "First Name: Last Name: ", "Title: title5 First Name: Last Name: ", "Trailing text" } };
403 constexpr char const* const EmptyValuesNewData
[][8]
404 = { { "Heading", "First Name: firstname1", "Last Name: lastname1",
405 "Title: First Name: firstname1", "First Name: firstname1 Last Name: lastname1",
406 "Title: First Name: firstname1 Last Name: lastname1", "Trailing text" },
407 { "Heading", "Title: title2", "Last Name: lastname2",
408 "Title: title2 First Name: ", "First Name: Last Name: lastname2",
409 "Title: title2 First Name: Last Name: lastname2", "Trailing text" },
410 { "Heading", "Title: title3", "First Name: firstname3",
411 "Title: title3 First Name: firstname3", "First Name: firstname3 Last Name: ",
412 "Title: title3 First Name: firstname3 Last Name: ", "Trailing text" },
413 { "Heading", "Last Name: lastname4", "First Name: Last Name: lastname4",
414 "Title: First Name: Last Name: lastname4", "Trailing text" },
415 { "Heading", "Title: title5", "Title: title5 First Name: ",
416 "Title: title5 First Name: Last Name: ", "Trailing text" } };
419 // The following four tests (testEmptyValuesLegacyODT, testEmptyValuesNewODT, (testEmptyValuesLegacyFODT, testEmptyValuesNewFODT)
420 // check that for native documents without "EmptyDbFieldHidesPara" compatibility option, all paragraphs are exported visible,
421 // while for documents with the option enabled, the paragraphs with all Database fields having empty values are hidden.
423 DECLARE_FILE_MAILMERGE_TEST(testEmptyValuesLegacyODT
, "tdf35798-legacy.odt", "5-with-blanks.ods",
427 for (int doc
= 0; doc
< 5; ++doc
)
429 loadMailMergeDocument(doc
);
430 SwDoc
* pDoc
= getSwDoc();
431 pDoc
->RemoveInvisibleContent();
432 CPPUNIT_ASSERT_EQUAL(1, getPages());
433 for (int i
= 0; i
< 8; ++i
)
435 auto xPara
= getParagraph(i
+1);
436 CPPUNIT_ASSERT_EQUAL_MESSAGE(
437 OString("in doc " + OString::number(doc
) + " paragraph " + OString::number(i
+ 1))
439 OUString::createFromAscii(EmptyValuesLegacyData
[doc
][i
]), xPara
->getString());
441 CPPUNIT_ASSERT_EQUAL(8, getParagraphs());
445 DECLARE_FILE_MAILMERGE_TEST(testEmptyValuesNewODT
, "tdf35798-new.odt", "5-with-blanks.ods",
449 for (int doc
= 0; doc
< 5; ++doc
)
451 loadMailMergeDocument(doc
);
452 SwDoc
* pDoc
= getSwDoc();
453 pDoc
->RemoveInvisibleContent();
454 CPPUNIT_ASSERT_EQUAL(1, getPages());
456 for (i
= 0; i
< 8; ++i
)
458 const char* pExpected
= EmptyValuesNewData
[doc
][i
];
461 auto xPara
= getParagraph(i
+ 1);
462 CPPUNIT_ASSERT_EQUAL_MESSAGE(
463 OString("in doc " + OString::number(doc
) + " paragraph " + OString::number(i
+ 1))
465 OUString::createFromAscii(pExpected
), xPara
->getString());
467 CPPUNIT_ASSERT_EQUAL(i
, getParagraphs());
471 DECLARE_FILE_MAILMERGE_TEST(testEmptyValuesLegacyFODT
, "tdf35798-legacy.fodt", "5-with-blanks.ods",
475 for (int doc
= 0; doc
< 5; ++doc
)
477 loadMailMergeDocument(doc
);
478 SwDoc
* pDoc
= getSwDoc();
479 pDoc
->RemoveInvisibleContent();
480 CPPUNIT_ASSERT_EQUAL(1, getPages());
481 for (int i
= 0; i
< 8; ++i
)
483 auto xPara
= getParagraph(i
+ 1);
484 CPPUNIT_ASSERT_EQUAL_MESSAGE(
485 OString("in doc " + OString::number(doc
) + " paragraph " + OString::number(i
+ 1))
487 OUString::createFromAscii(EmptyValuesLegacyData
[doc
][i
]), xPara
->getString());
489 CPPUNIT_ASSERT_EQUAL(8, getParagraphs());
493 DECLARE_FILE_MAILMERGE_TEST(testEmptyValuesNewFODT
, "tdf35798-new.fodt", "5-with-blanks.ods",
497 for (int doc
= 0; doc
< 5; ++doc
)
499 loadMailMergeDocument(doc
);
500 SwDoc
* pDoc
= getSwDoc();
501 pDoc
->RemoveInvisibleContent();
502 CPPUNIT_ASSERT_EQUAL(1, getPages());
504 for (i
= 0; i
< 8; ++i
)
506 const char* pExpected
= EmptyValuesNewData
[doc
][i
];
509 auto xPara
= getParagraph(i
+ 1);
510 CPPUNIT_ASSERT_EQUAL_MESSAGE(
511 OString("in doc " + OString::number(doc
) + " paragraph " + OString::number(i
+ 1))
513 OUString::createFromAscii(pExpected
), xPara
->getString());
515 CPPUNIT_ASSERT_EQUAL(i
, getParagraphs());
519 DECLARE_SHELL_MAILMERGE_TEST(testTdf118845
, "tdf118845.fodt", "4_v01.ods", "Tabelle1")
523 // Both male and female greetings were shown, thus each page had 3 paragraphs
525 CPPUNIT_ASSERT(mxSwTextDocument
);
526 sal_uInt16 nPhysPages
= mxSwTextDocument
->GetDocShell()->GetWrtShell()->GetPhyPageNum();
527 CPPUNIT_ASSERT_EQUAL(sal_uInt16(7), nPhysPages
); // 4 pages, each odd, and 3 blanks
529 CPPUNIT_ASSERT_EQUAL(8, getParagraphs(mxSwTextDocument
->getText()));
531 uno::Reference
<text::XTextRange
> xParagraph(getParagraphOrTable(1, mxSwTextDocument
->getText()),
533 CPPUNIT_ASSERT_EQUAL(u
"Dear Mrs. Mustermann1,"_ustr
, xParagraph
->getString());
535 xParagraph
.set(getParagraphOrTable(2, mxSwTextDocument
->getText()), uno::UNO_QUERY
);
536 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, xParagraph
->getString());
538 xParagraph
.set(getParagraphOrTable(3, mxSwTextDocument
->getText()), uno::UNO_QUERY
);
539 CPPUNIT_ASSERT_EQUAL(u
"Dear Mr. Mustermann2,"_ustr
, xParagraph
->getString());
541 xParagraph
.set(getParagraphOrTable(4, mxSwTextDocument
->getText()), uno::UNO_QUERY
);
542 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, xParagraph
->getString());
544 xParagraph
.set(getParagraphOrTable(5, mxSwTextDocument
->getText()), uno::UNO_QUERY
);
545 CPPUNIT_ASSERT_EQUAL(u
"Dear Mrs. Mustermann3,"_ustr
, xParagraph
->getString());
547 xParagraph
.set(getParagraphOrTable(6, mxSwTextDocument
->getText()), uno::UNO_QUERY
);
548 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, xParagraph
->getString());
550 xParagraph
.set(getParagraphOrTable(7, mxSwTextDocument
->getText()), uno::UNO_QUERY
);
551 CPPUNIT_ASSERT_EQUAL(u
"Dear Mr. Mustermann4,"_ustr
, xParagraph
->getString());
553 xParagraph
.set(getParagraphOrTable(8, mxSwTextDocument
->getText()), uno::UNO_QUERY
);
554 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, xParagraph
->getString());
557 DECLARE_SHELL_MAILMERGE_TEST(testTdf62364
, "tdf62364.odt", "10-testing-addresses.ods", "testing-addresses")
559 // prepare unit test and run
561 CPPUNIT_ASSERT(mxSwTextDocument
);
562 CPPUNIT_ASSERT_EQUAL( sal_uInt16( 19 ), mxSwTextDocument
->GetDocShell()->GetWrtShell()->GetPhyPageNum()); // 10 pages, but each sub-document starts on odd page number
564 // check: each page (one page is one sub doc) has 4 paragraphs:
565 // - 1st and 2nd are regular paragraphs
566 // - 3rd and 4th are inside list
567 const bool nodeInList
[4] = { false, false, true, true };
569 const auto & rNodes
= mxSwTextDocument
->GetDocShell()->GetDoc()->GetNodes();
570 for (int pageIndex
=0; pageIndex
<10; pageIndex
++)
572 for (int nodeIndex
= 0; nodeIndex
<4; nodeIndex
++)
574 SwNode
* aNode
= rNodes
[SwNodeOffset(9 + pageIndex
* 4 + nodeIndex
)];
575 CPPUNIT_ASSERT_EQUAL(true, aNode
->IsTextNode());
577 const SwTextNode
* pTextNode
= aNode
->GetTextNode();
578 CPPUNIT_ASSERT(pTextNode
);
579 CPPUNIT_ASSERT_EQUAL(nodeInList
[nodeIndex
], pTextNode
->GetSwAttrSet().HasItem(RES_PARATR_LIST_ID
));
584 } // end of anonymous namespace
585 CPPUNIT_PLUGIN_IMPLEMENT();
586 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */