remove assert looking for new compatibilityMode DOCX
[LibreOffice.git] / sw / qa / extras / mailmerge / mailmergetestbase.cxx
blob72e3ddfdb58894ba3719dc6bf3cacf9bd0921c08
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <sal/config.h>
12 #include <set>
13 #include <vector>
15 #include <swmodeltestbase.hxx>
17 #include <com/sun/star/text/MailMergeType.hpp>
18 #include <com/sun/star/sdb/CommandType.hpp>
19 #include <com/sun/star/table/TableBorder.hpp>
20 #include <com/sun/star/text/TextContentAnchorType.hpp>
21 #include <com/sun/star/text/XTextTable.hpp>
22 #include <com/sun/star/sdbc/XRowSet.hpp>
23 #include <com/sun/star/sdbcx/XRowLocate.hpp>
24 #include <com/sun/star/task/XJob.hpp>
26 #include <tools/urlobj.hxx>
27 #include <comphelper/sequence.hxx>
29 #include <wrtsh.hxx>
30 #include <ndtxt.hxx>
31 #include <pagefrm.hxx>
32 #include <unoprnms.hxx>
33 #include <dbmgr.hxx>
34 #include <unotxdoc.hxx>
35 #include <docsh.hxx>
36 #include <IDocumentLayoutAccess.hxx>
37 #include <rootfrm.hxx>
39 /**
40 * Maps database URIs to the registered database names for quick lookups
42 typedef std::map<OUString, OUString> DBuriMap;
43 DBuriMap aDBuriMap;
45 class MailMergeTestBase : public SwModelTestBase
47 public:
48 MailMergeTestBase()
49 : SwModelTestBase(u"/sw/qa/extras/mailmerge/data/"_ustr, u"writer8"_ustr)
50 , mnCurOutputType(0)
51 , maMMtestFilename(nullptr)
55 virtual void tearDown() override
57 if (mxSwTextDocument.is())
59 if (mnCurOutputType == text::MailMergeType::SHELL)
60 mxSwTextDocument->GetDocShell()->DoClose();
61 else
62 mxSwTextDocument->dispose();
64 if (mxCurResultSet.is())
66 css::uno::Reference<css::lang::XComponent>(mxCurResultSet, css::uno::UNO_QUERY_THROW)
67 ->dispose();
69 SwModelTestBase::tearDown();
72 /**
73 * Helper func used by each unit test to test the 'mail merge' code.
75 * Registers the data source, loads the original file as reference,
76 * initializes the mail merge job and its default argument sequence.
78 * The 'verify' method actually has to execute the mail merge by
79 * calling executeMailMerge() after modifying the job arguments.
81 void executeMailMergeTest(const char* filename, const char* datasource, const char* tablename,
82 char const* const filter, int selection, const char* column)
84 maMMtestFilename = filename;
85 header();
87 utl::TempFileNamed aTempDir(nullptr, true);
88 aTempDir.EnableKillingFile();
89 const OUString aWorkDir = aTempDir.GetURL();
90 const OUString aURI(createFileURL(OUString::createFromAscii(datasource)));
91 const OUString aPrefix = column ? OUString::createFromAscii(column) : u"LOMM_"_ustr;
92 const OUString aDBName = registerDBsource(aURI, aWorkDir);
93 initMailMergeJobAndArgs(filename, tablename, aDBName, aPrefix, aWorkDir, filter, selection,
94 column != nullptr);
96 verify();
98 mnCurOutputType = 0;
101 OUString registerDBsource(const OUString& aURI, const OUString& aWorkDir)
103 OUString aDBName;
104 DBuriMap::const_iterator pos = aDBuriMap.find(aURI);
105 if (pos == aDBuriMap.end())
107 aDBName = SwDBManager::LoadAndRegisterDataSource(aURI, &aWorkDir);
108 aDBuriMap.insert(std::pair<OUString, OUString>(aURI, aDBName));
109 std::cout << "New datasource name: '" << aDBName << "'" << std::endl;
111 else
113 aDBName = pos->second;
114 std::cout << "Old datasource name: '" << aDBName << "'" << std::endl;
116 CPPUNIT_ASSERT(!aDBName.isEmpty());
117 return aDBName;
120 uno::Reference<sdbc::XRowSet> getXResultFromDataset(const char* tablename,
121 const OUString& aDBName)
123 uno::Reference<sdbc::XRowSet> xCurResultSet;
124 uno::Reference<uno::XInterface> xInstance
125 = getMultiServiceFactory()->createInstance(u"com.sun.star.sdb.RowSet"_ustr);
126 uno::Reference<beans::XPropertySet> xRowSetPropSet(xInstance, uno::UNO_QUERY);
127 assert(xRowSetPropSet.is() && "failed to get XPropertySet interface from RowSet");
128 if (xRowSetPropSet.is())
130 xRowSetPropSet->setPropertyValue(u"DataSourceName"_ustr, uno::Any(aDBName));
131 xRowSetPropSet->setPropertyValue(u"Command"_ustr,
132 uno::Any(OUString::createFromAscii(tablename)));
133 xRowSetPropSet->setPropertyValue(u"CommandType"_ustr,
134 uno::Any(sdb::CommandType::TABLE));
136 uno::Reference<sdbc::XRowSet> xRowSet(xInstance, uno::UNO_QUERY);
137 if (xRowSet.is())
138 xRowSet->execute(); // build ResultSet from properties
139 xCurResultSet = xRowSet;
140 assert(xCurResultSet.is() && "failed to build ResultSet");
142 return xCurResultSet;
145 void initMailMergeJobAndArgs(const char* filename, const char* tablename,
146 const OUString& aDBName, const OUString& aPrefix,
147 const OUString& aWorkDir, char const* const filter, int nDataSets,
148 const bool bPrefixIsColumn)
150 uno::Reference<task::XJob> xJob(
151 getMultiServiceFactory()->createInstance(u"com.sun.star.text.MailMerge"_ustr),
152 uno::UNO_QUERY_THROW);
153 mxJob.set(xJob);
155 mMMargs.reserve(15);
157 mMMargs.emplace_back(UNO_NAME_OUTPUT_TYPE, uno::Any(filter ? text::MailMergeType::FILE
158 : text::MailMergeType::SHELL));
159 mMMargs.emplace_back(UNO_NAME_DOCUMENT_URL,
160 uno::Any((createFileURL(OUString::createFromAscii(filename)))));
161 mMMargs.emplace_back(UNO_NAME_DATA_SOURCE_NAME, uno::Any(aDBName));
162 mMMargs.emplace_back(UNO_NAME_OUTPUT_URL, uno::Any(aWorkDir));
163 if (filter)
165 mMMargs.emplace_back(UNO_NAME_FILE_NAME_PREFIX, uno::Any(aPrefix));
166 mMMargs.emplace_back(UNO_NAME_SAVE_FILTER, uno::Any(OUString::createFromAscii(filter)));
169 if (bPrefixIsColumn)
170 mMMargs.emplace_back(UNO_NAME_FILE_NAME_FROM_COLUMN, uno::Any(true));
172 if (tablename)
174 mMMargs.emplace_back(UNO_NAME_DAD_COMMAND_TYPE, uno::Any(sdb::CommandType::TABLE));
175 mMMargs.emplace_back(UNO_NAME_DAD_COMMAND,
176 uno::Any(OUString::createFromAscii(tablename)));
179 if (nDataSets > 0)
181 mxCurResultSet = getXResultFromDataset(tablename, aDBName);
182 uno::Reference<sdbcx::XRowLocate> xCurRowLocate(mxCurResultSet, uno::UNO_QUERY);
183 mMMargs.emplace_back(UNO_NAME_RESULT_SET, uno::Any(mxCurResultSet));
184 std::vector<uno::Any> vResult;
185 vResult.reserve(nDataSets);
186 sal_Int32 i;
187 for (i = 0, mxCurResultSet->first(); i < nDataSets; i++, mxCurResultSet->next())
189 vResult.emplace_back(xCurRowLocate->getBookmark());
191 mMMargs.emplace_back(UNO_NAME_SELECTION,
192 uno::Any(comphelper::containerToSequence(vResult)));
196 void executeMailMerge(bool bDontLoadResult = false)
198 const uno::Sequence<beans::NamedValue> aSeqMailMergeArgs
199 = comphelper::containerToSequence(mMMargs);
200 uno::Any res = mxJob->execute(aSeqMailMergeArgs);
202 bool bOk = true;
203 bool bMMFilenameFromColumn = false;
205 for (const beans::NamedValue& rArgument : aSeqMailMergeArgs)
207 const OUString& rName = rArgument.Name;
208 const uno::Any& rValue = rArgument.Value;
210 // all error checking was already done by the MM job execution
211 if (rName == UNO_NAME_OUTPUT_URL)
212 bOk &= rValue >>= msMailMergeOutputURL;
213 else if (rName == UNO_NAME_FILE_NAME_PREFIX)
214 bOk &= rValue >>= msMailMergeOutputPrefix;
215 else if (rName == UNO_NAME_OUTPUT_TYPE)
216 bOk &= rValue >>= mnCurOutputType;
217 else if (rName == UNO_NAME_FILE_NAME_FROM_COLUMN)
218 bOk &= rValue >>= bMMFilenameFromColumn;
219 else if (rName == UNO_NAME_DOCUMENT_URL)
220 bOk &= rValue >>= msMailMergeDocumentURL;
223 CPPUNIT_ASSERT(bOk);
225 // MM via UNO just works with file names. If we load the file on
226 // Windows before MM uses it, MM won't work, as it's already open.
227 // Don't move the load before the mail merge execution!
228 // (see gb_CppunitTest_use_instdir_configuration)
229 createSwDoc(maMMtestFilename);
231 if (mnCurOutputType == text::MailMergeType::SHELL)
233 uno::Reference<lang::XComponent> xTmp;
234 CPPUNIT_ASSERT(res >>= xTmp);
235 mxSwTextDocument = dynamic_cast<SwXTextDocument*>(xTmp.get());
236 CPPUNIT_ASSERT(mxSwTextDocument.is());
238 else
240 CPPUNIT_ASSERT_EQUAL(uno::Any(true), res);
241 if (!bMMFilenameFromColumn && !bDontLoadResult)
242 loadMailMergeDocument(0);
247 * Like parseExport(), but for given mail merge document.
249 xmlDocUniquePtr parseMailMergeExport(const OUString& rStreamName)
251 if (mnCurOutputType != text::MailMergeType::FILE)
252 return nullptr;
254 OUString name = msMailMergeOutputPrefix + OUString::number(0) + ".odt";
255 std::unique_ptr<SvStream> pStream(
256 parseExportStream(msMailMergeOutputURL + "/" + name, rStreamName));
258 return parseXmlStream(pStream.get());
261 void loadMailMergeDocument(const OUString& filename)
263 assert(mnCurOutputType == text::MailMergeType::FILE);
264 // Output name early, so in the case of a hang, the name of the hanging input file is visible.
265 std::cout << filename << ",";
266 loadFromURL(msMailMergeOutputURL + "/" + filename);
267 calcLayout();
271 Loads number-th document from mail merge. Requires file output from mail merge.
273 void loadMailMergeDocument(int number, char const* const ext = ".odt")
275 OUString name;
276 if (!msMailMergeOutputPrefix.isEmpty())
277 name = msMailMergeOutputPrefix;
278 else
280 INetURLObject aURLObj;
281 aURLObj.SetSmartProtocol(INetProtocol::File);
282 aURLObj.SetSmartURL(msMailMergeDocumentURL);
283 name = aURLObj.GetBase();
285 name += OUString::number(number)
286 + OStringToOUString(std::string_view(ext, strlen(ext)), RTL_TEXTENCODING_ASCII_US);
287 loadMailMergeDocument(name);
290 // Returns page number of the first page of a MM document inside the large MM document (used in the SHELL case).
291 int documentStartPageNumber(int document) const
292 { // See documentStartPageNumber() .
293 CPPUNIT_ASSERT(mxSwTextDocument);
294 SwWrtShell* shell = mxSwTextDocument->GetDocShell()->GetWrtShell();
295 IDocumentMarkAccess* marks = shell->GetDoc()->getIDocumentMarkAccess();
296 // Unfortunately, the pages are marked using UNO bookmarks, which have internals names, so they cannot be referred to by their names.
297 // Assume that there are no other UNO bookmarks than the ones used by mail merge, and that they are in the sorted order.
298 IDocumentMarkAccess::const_iterator mark;
299 int pos = 0;
300 for (mark = marks->getAllMarksBegin(); mark != marks->getAllMarksEnd() && pos < document;
301 ++mark)
303 if (IDocumentMarkAccess::GetType(**mark) == IDocumentMarkAccess::MarkType::UNO_BOOKMARK)
304 ++pos;
306 CPPUNIT_ASSERT_EQUAL(document, pos);
307 sal_uInt16 page, dummy;
308 shell->Push();
309 shell->GotoMark(*mark);
310 shell->GetPageNum(page, dummy);
311 shell->Pop(SwCursorShell::PopMode::DeleteCurrent);
312 return page;
315 protected:
316 uno::Reference<css::task::XJob> mxJob;
317 std::vector<beans::NamedValue> mMMargs;
318 OUString msMailMergeDocumentURL;
319 OUString msMailMergeOutputURL;
320 OUString msMailMergeOutputPrefix;
321 sal_Int16 mnCurOutputType;
322 rtl::Reference<SwXTextDocument> mxSwTextDocument;
323 uno::Reference<sdbc::XRowSet> mxCurResultSet;
324 const char* maMMtestFilename;
327 #define DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, filter, BaseClass, \
328 selection, column) \
329 class TestName : public BaseClass \
331 public: \
332 CPPUNIT_TEST_SUITE(TestName); \
333 CPPUNIT_TEST(MailMerge); \
334 CPPUNIT_TEST_SUITE_END(); \
336 void MailMerge() \
338 executeMailMergeTest(filename, datasource, tablename, filter, selection, column); \
340 void verify() override; \
341 }; \
342 CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
343 void TestName::verify()
345 // Will generate the resulting document in mxMMDocument.
346 #define DECLARE_SHELL_MAILMERGE_TEST(TestName, filename, datasource, tablename) \
347 DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, nullptr, MailMergeTestBase, \
348 0, nullptr)
350 // Will generate documents as files, use loadMailMergeDocument().
351 #define DECLARE_FILE_MAILMERGE_TEST(TestName, filename, datasource, tablename) \
352 DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, "writer8", \
353 MailMergeTestBase, 0, nullptr)
355 #define DECLARE_SHELL_MAILMERGE_TEST_SELECTION(TestName, filename, datasource, tablename, \
356 selection) \
357 DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, nullptr, MailMergeTestBase, \
358 selection, nullptr)
360 #define DECLARE_FILE_MAILMERGE_TEST_COLUMN(TestName, filename, datasource, tablename, column) \
361 DECLARE_MAILMERGE_TEST(TestName, filename, datasource, tablename, "writer8", \
362 MailMergeTestBase, 0, column)
364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */