Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / sw / qa / core / uwriter.cxx
blobd573c84ffd45b730e74be24226c140cc6242dc12
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>
11 #include <test/bootstrapfixture.hxx>
13 #include <com/sun/star/i18n/WordType.hpp>
15 #include <rtl/strbuf.hxx>
16 #include <osl/file.hxx>
18 #include <comphelper/processfactory.hxx>
19 #include <comphelper/random.hxx>
20 #include <i18nutil/transliteration.hxx>
21 #include <tools/urlobj.hxx>
22 #include <unotools/tempfile.hxx>
23 #include <unotools/transliterationwrapper.hxx>
25 #include <editeng/langitem.hxx>
26 #include <editeng/charhiddenitem.hxx>
28 #include <sfx2/app.hxx>
29 #include <sfx2/docfilt.hxx>
30 #include <sfx2/docfile.hxx>
31 #include <sfx2/sfxmodelfactory.hxx>
33 #include <xmloff/odffields.hxx>
35 #include <breakit.hxx>
36 #include <doc.hxx>
37 #include <IDocumentRedlineAccess.hxx>
38 #include <IDocumentFieldsAccess.hxx>
39 #include <IDocumentStatistics.hxx>
40 #include <cellfml.hxx>
41 #include <docsh.hxx>
42 #include <docstat.hxx>
43 #include <docufld.hxx>
44 #include <fmtanchr.hxx>
45 #include <init.hxx>
46 #include <ndtxt.hxx>
47 #include <shellio.hxx>
48 #include <shellres.hxx>
49 #include <swcrsr.hxx>
50 #include <swscanner.hxx>
51 #include <swmodule.hxx>
52 #include <swdll.hxx>
53 #include <swtypes.hxx>
54 #include <fmtftn.hxx>
55 #include <fmtrfmrk.hxx>
56 #include <fmtinfmt.hxx>
57 #include <fchrfmt.hxx>
58 #include <fmtfld.hxx>
59 #include <redline.hxx>
60 #include <docary.hxx>
61 #include <modeltoviewhelper.hxx>
62 #include <scriptinfo.hxx>
63 #include <IMark.hxx>
64 #include <ring.hxx>
65 #include <calbck.hxx>
66 #include <pagedesc.hxx>
67 #include <calc.hxx>
69 #include <tblafmt.hxx>
70 #include <unotbl.hxx>
71 #include <IDocumentMarkAccess.hxx>
72 #include <itabenum.hxx>
74 typedef tools::SvRef<SwDocShell> SwDocShellRef;
76 using namespace ::com::sun::star;
78 /* Implementation of Swdoc-Test class */
80 class SwDocTest : public test::BootstrapFixture
82 public:
83 SwDocTest()
84 : m_pDoc(nullptr)
88 virtual void setUp() override;
89 virtual void tearDown() override;
91 void randomTest();
92 void testTableAutoFormats();
93 void testPageDescName();
94 void testFileNameFields();
95 void testDocStat();
96 void testModelToViewHelperPassthrough();
97 void testModelToViewHelperExpandFieldsExpandFootnote();
98 void testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode();
99 void testModelToViewHelperExpandFields();
100 void testModelToViewHelperExpandFieldsReplaceMode();
101 void testModelToViewHelperExpandFieldsHideInvisible();
102 void testModelToViewHelperExpandFieldsHideRedlined();
103 void testModelToViewHelperExpandFieldsHideInvisibleExpandFootnote();
104 void testModelToViewHelperExpandFieldsHideInvisibleExpandFootnoteReplaceMode();
105 void testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnote();
106 void testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnoteReplaceMode();
107 void testModelToViewHelperHideInvisibleHideRedlined();
108 void testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnote();
109 void testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnoteReplaceMode();
110 void testModelToViewHelperExpandFieldsExpandFootnote2();
111 void testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode2();
112 void testSwScanner();
113 void testUserPerceivedCharCount();
114 void testMergePortionsDeleteNotSorted();
115 void testGraphicAnchorDeletion();
116 void testTransliterate();
117 void testMarkMove();
118 void testFormulas();
119 void testIntrusiveRing();
120 void testClientModify();
121 void testWriterMultiListener();
122 void test64kPageDescs();
123 void testTdf92308();
124 void testTableCellComparison();
126 CPPUNIT_TEST_SUITE(SwDocTest);
128 CPPUNIT_TEST(testTransliterate);
129 CPPUNIT_TEST(randomTest);
130 CPPUNIT_TEST(testTableAutoFormats);
131 CPPUNIT_TEST(testPageDescName);
132 CPPUNIT_TEST(testFileNameFields);
133 CPPUNIT_TEST(testDocStat);
134 CPPUNIT_TEST(testModelToViewHelperPassthrough);
135 CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnote);
136 CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode);
137 CPPUNIT_TEST(testModelToViewHelperExpandFields);
138 CPPUNIT_TEST(testModelToViewHelperExpandFieldsReplaceMode);
139 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisible);
140 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideRedlined);
141 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleExpandFootnote);
142 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleExpandFootnoteReplaceMode);
143 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnote);
144 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnoteReplaceMode);
145 CPPUNIT_TEST(testModelToViewHelperHideInvisibleHideRedlined);
146 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnote);
147 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnoteReplaceMode);
148 CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnote2);
149 CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode2);
150 CPPUNIT_TEST(testSwScanner);
151 CPPUNIT_TEST(testUserPerceivedCharCount);
152 CPPUNIT_TEST(testMergePortionsDeleteNotSorted);
153 CPPUNIT_TEST(testGraphicAnchorDeletion);
154 CPPUNIT_TEST(testMarkMove);
155 CPPUNIT_TEST(testFormulas);
156 CPPUNIT_TEST(testIntrusiveRing);
157 CPPUNIT_TEST(testClientModify);
158 CPPUNIT_TEST(testWriterMultiListener);
159 CPPUNIT_TEST(test64kPageDescs);
160 CPPUNIT_TEST(testTdf92308);
161 CPPUNIT_TEST(testTableCellComparison);
162 CPPUNIT_TEST_SUITE_END();
164 private:
165 SwDoc *m_pDoc;
166 SwDocShellRef m_xDocShRef;
169 void SwDocTest::testPageDescName()
171 ShellResource aShellResources;
173 std::vector<OUString> aResults;
175 //These names must be unique for each different combination, otherwise
176 //duplicate page description names may exist, which will causes lookup
177 //by name to be incorrect, and so the corresponding export to .odt
178 aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::NORMAL_PAGE));
179 aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::FIRST_PAGE));
180 aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::FOLLOW_PAGE));
182 std::sort(aResults.begin(), aResults.end());
183 aResults.erase(std::unique(aResults.begin(), aResults.end()), aResults.end());
185 CPPUNIT_ASSERT_EQUAL_MESSAGE("GetPageDescName results must be unique", static_cast<size_t>(3), aResults.size());
188 //See https://bugs.libreoffice.org/show_bug.cgi?id=32463
189 void SwDocTest::testFileNameFields()
191 //Here's a file name with some chars in it that will be %% encoded, when expanding
192 //SwFileNameFields we want to restore the original readable filename
193 utl::TempFile aTempFile("demo [name]");
194 aTempFile.EnableKillingFile();
196 INetURLObject aTempFileURL(aTempFile.GetURL());
197 OUString sFileURL = aTempFileURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
198 SfxMedium aDstMed(sFileURL, StreamMode::STD_READWRITE);
200 std::shared_ptr<SfxFilter> pFilter(new SfxFilter(
201 "Text",
202 OUString(), SfxFilterFlags::NONE, SotClipboardFormatId::NONE, OUString(), OUString(),
203 "TEXT", OUString() ));
204 aDstMed.SetFilter(pFilter);
206 m_xDocShRef->DoSaveAs(aDstMed);
207 m_xDocShRef->DoSaveCompleted(&aDstMed);
209 const INetURLObject &rUrlObj = m_xDocShRef->GetMedium()->GetURLObject();
211 SwFileNameFieldType aNameField(m_pDoc);
214 OUString sResult(aNameField.Expand(FF_NAME));
215 OUString sExpected(rUrlObj.getName(INetURLObject::LAST_SEGMENT,
216 true,INetURLObject::DecodeMechanism::WithCharset));
217 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected Readable FileName", sExpected, sResult);
221 OUString sResult(aNameField.Expand(FF_PATHNAME));
222 OUString sExpected(rUrlObj.GetFull());
223 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected Readable FileName", sExpected, sResult);
227 OUString sResult(aNameField.Expand(FF_PATH));
228 INetURLObject aTemp(rUrlObj);
229 aTemp.removeSegment();
230 OUString sExpected(aTemp.PathToFileName());
231 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected Readable FileName", sExpected, sResult);
235 OUString sResult(aNameField.Expand(FF_NAME_NOEXT));
236 OUString sExpected(rUrlObj.getName(INetURLObject::LAST_SEGMENT,
237 true,INetURLObject::DecodeMechanism::WithCharset));
238 //Chop off .tmp
239 sExpected = sExpected.copy(0, sExpected.getLength() - 4);
240 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected Readable FileName", sExpected, sResult);
243 m_xDocShRef->DoInitNew();
246 //See http://lists.freedesktop.org/archives/libreoffice/2011-August/016666.html
247 //Remove unnecessary parameter to IDocumentStatistics::UpdateDocStat for
248 //motivation
249 void SwDocTest::testDocStat()
251 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected initial 0 count", static_cast<sal_uLong>(0), m_pDoc->getIDocumentStatistics().GetDocStat().nChar);
253 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
254 SwPaM aPaM(aIdx);
256 OUString sText("Hello World");
257 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sText);
259 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should still be non-updated 0 count", static_cast<sal_uLong>(0), m_pDoc->getIDocumentStatistics().GetDocStat().nChar);
261 SwDocStat aDocStat = m_pDoc->getIDocumentStatistics().GetUpdatedDocStat( false, true );
262 sal_uLong nLen = static_cast<sal_uLong>(sText.getLength());
264 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should now have updated count", nLen, aDocStat.nChar);
266 CPPUNIT_ASSERT_EQUAL_MESSAGE("And cache is updated too", nLen, m_pDoc->getIDocumentStatistics().GetDocStat().nChar);
269 //For UI character counts we should follow UAX#29 and display the user
270 //perceived characters, not the number of codepoints, nor the number of code
271 //units http://unicode.org/reports/tr29/
272 void SwDocTest::testUserPerceivedCharCount()
274 SwBreakIt *pBreakIter = SwBreakIt::Get();
276 //Grapheme example, two different unicode code-points perceived by the user as a single
277 //glyph
278 const sal_Unicode ALEF_QAMATS [] = { 0x05D0, 0x05B8 };
279 OUString sALEF_QAMATS(ALEF_QAMATS, SAL_N_ELEMENTS(ALEF_QAMATS));
280 sal_Int32 nGraphemeCount = pBreakIter->getGraphemeCount(sALEF_QAMATS);
281 CPPUNIT_ASSERT_EQUAL_MESSAGE("Grapheme Count should be 1", static_cast<sal_Int32>(1), nGraphemeCount);
283 //Surrogate pair example, one single unicode code-point (U+1D11E)
284 //represented as two code units in UTF-16
285 const sal_Unicode GCLEF[] = { 0xD834, 0xDD1E };
286 OUString sGCLEF(GCLEF, SAL_N_ELEMENTS(GCLEF));
287 sal_Int32 nCount = pBreakIter->getGraphemeCount(sGCLEF);
288 CPPUNIT_ASSERT_EQUAL_MESSAGE("Surrogate Pair should be counted as single character", static_cast<sal_Int32>(1), nCount);
291 SwTextNode* getModelToViewTestDocument(SwDoc *pDoc)
293 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
294 SwPaM aPaM(aIdx);
296 SwFormatFootnote aFootnote;
297 aFootnote.SetNumStr("foo");
299 pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
300 pDoc->getIDocumentContentOperations().InsertString(aPaM, "AAAAA BBBBB ");
301 SwTextNode* pTextNode = aPaM.GetNode().GetTextNode();
302 sal_Int32 nPos = aPaM.GetPoint()->nContent.GetIndex();
303 pTextNode->InsertItem(aFootnote, nPos, nPos);
304 pDoc->getIDocumentContentOperations().InsertString(aPaM, " CCCCC ");
305 nPos = aPaM.GetPoint()->nContent.GetIndex();
306 pTextNode->InsertItem(aFootnote, nPos, nPos);
307 pDoc->getIDocumentContentOperations().InsertString(aPaM, " DDDDD");
308 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>((4*5) + 5 + 2), pTextNode->GetText().getLength());
310 //set start of selection to first B
311 aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 6);
312 aPaM.SetMark();
313 //set end of selection to last C
314 aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 14);
315 //set character attribute hidden on range
316 SvxCharHiddenItem aHidden(true, RES_CHRATR_HIDDEN);
317 pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aHidden );
318 aPaM.DeleteMark();
320 //turn on red-lining and show changes
321 pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete|RedlineFlags::ShowInsert);
322 CPPUNIT_ASSERT_MESSAGE("redlining should be on", pDoc->getIDocumentRedlineAccess().IsRedlineOn());
323 CPPUNIT_ASSERT_MESSAGE("redlines should be visible", IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
325 //set start of selection to last A
326 aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 4);
327 aPaM.SetMark();
328 //set end of selection to second last B
329 aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 9);
330 pDoc->getIDocumentContentOperations().DeleteAndJoin(aPaM); //redline-aware deletion api
331 aPaM.DeleteMark();
333 return pTextNode;
336 SwTextNode* getModelToViewTestDocument2(SwDoc *pDoc)
338 getModelToViewTestDocument(pDoc);
340 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
341 SwPaM aPaM(aIdx);
343 pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
344 pDoc->getIDocumentContentOperations().InsertString(aPaM, "AAAAA");
345 IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess();
346 sw::mark::IFieldmark *pFieldmark =
347 pMarksAccess->makeNoTextFieldBookmark(aPaM, "test", ODF_FORMDROPDOWN);
348 CPPUNIT_ASSERT(pFieldmark);
349 uno::Sequence< OUString > vListEntries { "BBBBB" };
350 (*pFieldmark->GetParameters())[ODF_FORMDROPDOWN_LISTENTRY] <<= vListEntries;
351 (*pFieldmark->GetParameters())[ODF_FORMDROPDOWN_RESULT] <<= sal_Int32(0);
352 pDoc->getIDocumentContentOperations().InsertString(aPaM, "CCCCC");
353 SwTextNode* pTextNode = aPaM.GetNode().GetTextNode();
354 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11),
355 pTextNode->GetText().getLength());
357 return pTextNode;
360 void SwDocTest::testModelToViewHelperPassthrough()
362 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
364 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::PassThrough);
365 OUString sViewText = aModelToViewHelper.getViewText();
366 OUString sModelText = pTextNode->GetText();
367 CPPUNIT_ASSERT_EQUAL(sModelText, sViewText);
370 void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnote()
372 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
374 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::ExpandFootnote);
375 OUString sViewText = aModelToViewHelper.getViewText();
376 CPPUNIT_ASSERT_EQUAL(
377 OUString("AAAAA BBBBB foo CCCCC foo DDDDD"), sViewText);
380 void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode()
382 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
384 ModelToViewHelper aModelToViewHelper(*pTextNode,
385 ExpandMode::ExpandFields | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
386 OUString sViewText = aModelToViewHelper.getViewText();
387 CPPUNIT_ASSERT_EQUAL(
388 OUString("AAAAA BBBBB " + OUStringLiteral1(CHAR_ZWSP) + " CCCCC " + OUStringLiteral1(CHAR_ZWSP) + " DDDDD"),
389 sViewText);
390 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2),
391 aModelToViewHelper.getFootnotePositions().size());
392 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12),
393 aModelToViewHelper.getFootnotePositions()[0]);
394 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(20),
395 aModelToViewHelper.getFootnotePositions()[1]);
396 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
397 aModelToViewHelper.getFieldPositions().size());
400 void SwDocTest::testModelToViewHelperExpandFields()
402 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
404 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields);
405 OUString sViewText = aModelToViewHelper.getViewText();
406 CPPUNIT_ASSERT_EQUAL(
407 OUString("AAAAA BBBBB CCCCC DDDDD"), sViewText);
410 void SwDocTest::testModelToViewHelperExpandFieldsReplaceMode()
412 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
414 ModelToViewHelper aModelToViewHelper(*pTextNode,
415 ExpandMode::ExpandFields | ExpandMode::ReplaceMode);
416 OUString sViewText = aModelToViewHelper.getViewText();
417 CPPUNIT_ASSERT_EQUAL(OUString("AAAAA BBBBB CCCCC DDDDD"),
418 sViewText);
419 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
420 aModelToViewHelper.getFootnotePositions().size());
421 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
422 aModelToViewHelper.getFieldPositions().size());
425 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisible()
427 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
429 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::HideInvisible);
430 OUString sViewText = aModelToViewHelper.getViewText();
431 CPPUNIT_ASSERT_EQUAL(
432 OUString("AAAAA CCCCC " + OUStringLiteral1(CH_TXTATR_BREAKWORD) + " DDDDD"),
433 sViewText);
436 void SwDocTest::testModelToViewHelperExpandFieldsHideRedlined()
438 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
440 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::HideDeletions);
441 OUString sViewText = aModelToViewHelper.getViewText();
442 CPPUNIT_ASSERT_EQUAL(
443 OUString("AAAABB " + OUStringLiteral1(CH_TXTATR_BREAKWORD) + " CCCCC " + OUStringLiteral1(CH_TXTATR_BREAKWORD) + " DDDDD"),
444 sViewText);
447 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleExpandFootnote()
449 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
451 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::ExpandFootnote);
452 OUString sViewText = aModelToViewHelper.getViewText();
453 CPPUNIT_ASSERT_EQUAL(OUString("AAAAA CCCCC foo DDDDD"), sViewText);
456 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleExpandFootnoteReplaceMode()
458 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
460 ModelToViewHelper aModelToViewHelper(*pTextNode,
461 ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
462 OUString sViewText = aModelToViewHelper.getViewText();
463 CPPUNIT_ASSERT_EQUAL(
464 OUString("AAAAA CCCCC " + OUStringLiteral1(CHAR_ZWSP) + " DDDDD"),
465 sViewText);
466 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
467 aModelToViewHelper.getFootnotePositions().size());
468 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12),
469 aModelToViewHelper.getFootnotePositions()[0]);
470 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
471 aModelToViewHelper.getFieldPositions().size());
474 void SwDocTest::testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnote()
476 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
478 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote);
479 OUString sViewText = aModelToViewHelper.getViewText();
480 CPPUNIT_ASSERT_EQUAL(
481 OUString("AAAABB foo CCCCC foo DDDDD"), sViewText);
484 void SwDocTest::testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnoteReplaceMode()
486 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
488 ModelToViewHelper aModelToViewHelper(*pTextNode,
489 ExpandMode::ExpandFields | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
490 OUString sViewText = aModelToViewHelper.getViewText();
491 CPPUNIT_ASSERT_EQUAL(
492 OUString("AAAABB " + OUStringLiteral1(CHAR_ZWSP) + " CCCCC " + OUStringLiteral1(CHAR_ZWSP) + " DDDDD"),
493 sViewText);
494 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2),
495 aModelToViewHelper.getFootnotePositions().size());
496 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(7),
497 aModelToViewHelper.getFootnotePositions()[0]);
498 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(15),
499 aModelToViewHelper.getFootnotePositions()[1]);
500 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
501 aModelToViewHelper.getFieldPositions().size());
504 void SwDocTest::testModelToViewHelperHideInvisibleHideRedlined()
506 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
508 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::HideInvisible | ExpandMode::HideDeletions);
509 OUString sViewText = aModelToViewHelper.getViewText();
510 OUStringBuffer aBuffer;
511 aBuffer.append("AAAACCCCC ");
512 aBuffer.append(CH_TXTATR_BREAKWORD);
513 aBuffer.append(" DDDDD");
514 CPPUNIT_ASSERT_EQUAL(aBuffer.makeStringAndClear(), sViewText);
517 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnote()
519 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
521 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote);
522 OUString sViewText = aModelToViewHelper.getViewText();
523 CPPUNIT_ASSERT_EQUAL(OUString("AAAACCCCC foo DDDDD"), sViewText);
526 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnoteReplaceMode()
528 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
530 ModelToViewHelper aModelToViewHelper(*pTextNode,
531 ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
532 OUString sViewText = aModelToViewHelper.getViewText();
533 CPPUNIT_ASSERT_EQUAL(sViewText,
534 OUString("AAAACCCCC " + OUStringLiteral1(CHAR_ZWSP) + " DDDDD"));
535 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
536 aModelToViewHelper.getFootnotePositions().size());
537 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(10),
538 aModelToViewHelper.getFootnotePositions()[0]);
539 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
540 aModelToViewHelper.getFieldPositions().size());
543 void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnote2()
545 SwTextNode* pTextNode = getModelToViewTestDocument2(m_pDoc);
547 ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::ExpandFootnote);
548 OUString sViewText = aModelToViewHelper.getViewText();
549 CPPUNIT_ASSERT_EQUAL(OUString("AAAAABBBBBCCCCC"), sViewText);
552 void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode2()
554 SwTextNode* pTextNode = getModelToViewTestDocument2(m_pDoc);
556 ModelToViewHelper aModelToViewHelper(*pTextNode,
557 ExpandMode::ExpandFields | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
558 OUString sViewText = aModelToViewHelper.getViewText();
559 CPPUNIT_ASSERT_EQUAL(
560 OUString("AAAAA" + OUStringLiteral1(CHAR_ZWSP) + "CCCCC"),
561 sViewText);
562 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
563 aModelToViewHelper.getFootnotePositions().size());
564 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
565 aModelToViewHelper.getFieldPositions().size());
566 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5),
567 aModelToViewHelper.getFieldPositions()[0]);
570 void SwDocTest::testSwScanner()
572 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
573 SwPaM aPaM(aIdx);
575 SwTextNode* pTextNode = aPaM.GetNode().GetTextNode();
577 CPPUNIT_ASSERT_MESSAGE("Has Text Node", pTextNode);
579 //See https://bugs.libreoffice.org/show_bug.cgi?id=40449
580 //See https://bugs.libreoffice.org/show_bug.cgi?id=39365
581 //Use a temporary OUString as the arg, as that's the trouble behind
582 //fdo#40449 and fdo#39365
584 SwScanner aScanner(*pTextNode,
585 "Hello World",
586 nullptr, ModelToViewHelper(), i18n::WordType::DICTIONARY_WORD, 0,
587 RTL_CONSTASCII_LENGTH("Hello World"));
589 bool bFirstOk = aScanner.NextWord();
590 CPPUNIT_ASSERT_MESSAGE("First Token", bFirstOk);
591 const OUString &rHello = aScanner.GetWord();
592 CPPUNIT_ASSERT_EQUAL(OUString("Hello"), rHello);
594 bool bSecondOk = aScanner.NextWord();
595 CPPUNIT_ASSERT_MESSAGE("Second Token", bSecondOk);
596 const OUString &rWorld = aScanner.GetWord();
597 CPPUNIT_ASSERT_EQUAL(OUString("World"), rWorld);
600 //See https://www.libreoffice.org/bugzilla/show_bug.cgi?id=45271
602 const sal_Unicode IDEOGRAPHICFULLSTOP_D[] = { 0x3002, 'D' };
604 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(IDEOGRAPHICFULLSTOP_D,
605 SAL_N_ELEMENTS(IDEOGRAPHICFULLSTOP_D)));
607 SvxLanguageItem aCJKLangItem( LANGUAGE_CHINESE_SIMPLIFIED, RES_CHRATR_CJK_LANGUAGE );
608 SvxLanguageItem aWestLangItem( LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE );
609 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aCJKLangItem );
610 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aWestLangItem );
612 SwDocStat aDocStat;
613 pTextNode = aPaM.GetNode().GetTextNode();
614 pTextNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(IDEOGRAPHICFULLSTOP_D));
616 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), aDocStat.nChar);
617 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), aDocStat.nCharExcludingSpaces);
620 const sal_Unicode test[] =
622 0x3053, 0x306E, 0x65E5, 0x672C, 0x8A9E, 0x306F, 0x6B63, 0x3057,
623 0x304F, 0x6570, 0x3048, 0x3089, 0x308C, 0x308B, 0x3067, 0x3057,
624 0x3087, 0x3046, 0x304B, 0x3002, 0x0041, 0x006E, 0x0064, 0x0020,
625 0x006C, 0x0065, 0x0074, 0x0027, 0x0073, 0x0020, 0x0074, 0x0068,
626 0x0072, 0x006F, 0x0077, 0x0020, 0x0073, 0x006F, 0x006D, 0x0065,
627 0x0020, 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068,
628 0x0020, 0x0069, 0x006E, 0x0020, 0x0074, 0x006F, 0x0020, 0x006D,
629 0x0061, 0x006B, 0x0065, 0x0020, 0x0069, 0x0074, 0x0020, 0x0069,
630 0x006E, 0x0074, 0x0065, 0x0072, 0x0065, 0x0073, 0x0074, 0x0069,
631 0x006E, 0x0067, 0x002E, 0x0020, 0x0020, 0x305D, 0x3057, 0x3066,
632 0x3001, 0x307E, 0x305F, 0x65E5, 0x672C, 0x8A9E, 0x3000, 0x3000,
633 0x3067, 0x3082, 0x4ECA, 0x56DE, 0x306F, 0x7A7A, 0x767D, 0x3092,
634 0x3000, 0x3000, 0x5165, 0x308C, 0x307E, 0x3057, 0x305F, 0x3002,
635 0x0020, 0x0020, 0x0053, 0x006F, 0x0020, 0x0068, 0x006F, 0x0077,
636 0x0020, 0x0064, 0x006F, 0x0065, 0x0073, 0x0020, 0x0074, 0x0068,
637 0x0069, 0x0073, 0x0020, 0x0064, 0x006F, 0x003F, 0x0020, 0x0020
639 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
640 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(test,
641 SAL_N_ELEMENTS(test)));
643 SvxLanguageItem aCJKLangItem( LANGUAGE_JAPANESE, RES_CHRATR_CJK_LANGUAGE );
644 SvxLanguageItem aWestLangItem( LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE );
645 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aCJKLangItem );
646 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aWestLangItem );
648 SwDocStat aDocStat;
649 pTextNode = aPaM.GetNode().GetTextNode();
650 pTextNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(test));
651 CPPUNIT_ASSERT_EQUAL_MESSAGE("words", static_cast<sal_uLong>(58), aDocStat.nWord);
652 CPPUNIT_ASSERT_EQUAL_MESSAGE("Asian characters and Korean syllables", static_cast<sal_uLong>(43), aDocStat.nAsianWord);
653 CPPUNIT_ASSERT_EQUAL_MESSAGE("non-whitespace chars", static_cast<sal_uLong>(105), aDocStat.nCharExcludingSpaces);
654 CPPUNIT_ASSERT_EQUAL_MESSAGE("characters", static_cast<sal_uLong>(128), aDocStat.nChar);
657 //See https://bz.apache.org/ooo/show_bug.cgi?id=89042
658 //See https://bugs.libreoffice.org/show_bug.cgi?id=53399
660 SwDocStat aDocStat;
662 const sal_Unicode aShouldBeThree[] = {
663 0x0053, 0x0068, 0x006F, 0x0075, 0x006C, 0x0064, 0x0020,
664 0x2018, 0x0062, 0x0065, 0x0020, 0x0074, 0x0068, 0x0072,
665 0x0065, 0x0065, 0x2019
668 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
669 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(aShouldBeThree, SAL_N_ELEMENTS(aShouldBeThree)));
670 pTextNode = aPaM.GetNode().GetTextNode();
671 pTextNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(aShouldBeThree));
672 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(3), aDocStat.nWord);
674 const sal_Unicode aShouldBeFive[] = {
675 // f r e n c h space
676 0x0046, 0x0072, 0x0065, 0x006E, 0x0063, 0x0068, 0x0020,
677 // << nbsp s a v o i
678 0x00AB, 0x00A0, 0x0073, 0x0061, 0x0076, 0x006F, 0x0069,
679 // r nnbsp c a l c u
680 0x0072, 0x202f, 0x0063, 0x0061, 0x006C, 0x0063, 0x0075,
681 // l e r idspace >>
682 0x006C, 0x0065, 0x0072, 0x3000, 0x00BB
685 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
686 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(aShouldBeFive, SAL_N_ELEMENTS(aShouldBeFive)));
687 pTextNode = aPaM.GetNode().GetTextNode();
688 aDocStat.Reset();
689 pTextNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(aShouldBeFive));
690 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(5), aDocStat.nWord);
693 //See https://bugs.libreoffice.org/show_bug.cgi?id=49629
695 SwDocStat aDocStat;
697 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
698 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "Apple");
699 pTextNode = aPaM.GetNode().GetTextNode();
700 sal_Int32 nPos = aPaM.GetPoint()->nContent.GetIndex();
701 SwFormatFootnote aFootnote;
702 aFootnote.SetNumStr("banana");
703 SwTextAttr* pTA = pTextNode->InsertItem(aFootnote, nPos, nPos);
704 CPPUNIT_ASSERT(pTA);
705 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6), pTextNode->Len()); //Apple + 0x02
706 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
707 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), aDocStat.nWord);
708 CPPUNIT_ASSERT_EQUAL_MESSAGE("footnote should be expanded", static_cast<sal_uLong>(11), aDocStat.nChar);
710 const sal_Int32 nNextPos = aPaM.GetPoint()->nContent.GetIndex();
711 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(nPos+1), nNextPos);
712 SwFormatRefMark aRef("refmark");
713 pTA = pTextNode->InsertItem(aRef, nNextPos, nNextPos);
714 CPPUNIT_ASSERT(pTA);
716 aDocStat.Reset();
717 pTextNode->SetWordCountDirty(true);
718 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
719 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), aDocStat.nWord);
720 CPPUNIT_ASSERT_EQUAL_MESSAGE("refmark anchor should not be counted", static_cast<sal_uLong>(11), aDocStat.nChar);
722 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
723 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "Apple");
725 DateTime aDate(DateTime::SYSTEM);
726 SwPostItField aPostIt(
727 static_cast<SwPostItFieldType*>(m_pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit)), "An Author",
728 "Some Text", "Initials", "Name", aDate );
729 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, SwFormatField(aPostIt));
731 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "Apple");
732 pTextNode = aPaM.GetNode().GetTextNode();
733 aDocStat.Reset();
734 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
735 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), aDocStat.nWord);
736 CPPUNIT_ASSERT_EQUAL_MESSAGE("postit anchor should effectively not exist", static_cast<sal_uLong>(10), aDocStat.nChar);
737 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11), pTextNode->Len());
739 aDocStat.Reset();
742 //See https://bugs.libreoffice.org/show_bug.cgi?id=46757
744 SwDocStat aDocStat;
746 const char aString[] = "Lorem ipsum";
747 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
748 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, aString);
749 pTextNode = aPaM.GetNode().GetTextNode();
750 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
751 CPPUNIT_ASSERT_EQUAL(aDocStat.nWord, static_cast<sal_uLong>(2));
753 //turn on red-lining and show changes
754 m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete|RedlineFlags::ShowInsert);
755 CPPUNIT_ASSERT_MESSAGE("redlining should be on", m_pDoc->getIDocumentRedlineAccess().IsRedlineOn());
756 CPPUNIT_ASSERT_MESSAGE("redlines should be visible", IDocumentRedlineAccess::IsShowChanges(m_pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
758 //delete everything except the first word
759 aPaM.SetMark(); //set start of selection to current pos
760 aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 5); //set end of selection to fifth char of current node
761 m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aPaM); //redline-aware deletion api
762 //"real underlying text should be the same"
763 CPPUNIT_ASSERT_EQUAL(pTextNode->GetText(), OUString(aString));
765 aDocStat.Reset();
766 pTextNode->SetWordCountDirty(true);
767 pTextNode->CountWords(aDocStat, 0, pTextNode->Len()); //but word-counting the text should only count the non-deleted text
768 CPPUNIT_ASSERT_EQUAL(aDocStat.nWord, static_cast<sal_uLong>(1));
770 pTextNode->SetWordCountDirty(true);
772 //keep red-lining on but hide changes
773 m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On);
774 CPPUNIT_ASSERT_MESSAGE("redlining should be still on", m_pDoc->getIDocumentRedlineAccess().IsRedlineOn());
775 CPPUNIT_ASSERT_MESSAGE("redlines should be invisible", !IDocumentRedlineAccess::IsShowChanges(m_pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
777 aDocStat.Reset();
778 pTextNode->CountWords(aDocStat, 0, pTextNode->Len()); //but word-counting the text should only count the non-deleted text
779 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), aDocStat.nWord);
781 OUString sLorem = pTextNode->GetText();
782 CPPUNIT_ASSERT_EQUAL(OUString("Lorem"), sLorem);
784 const SwRedlineTable& rTable = m_pDoc->getIDocumentRedlineAccess().GetRedlineTable();
786 SwNodes& rNds = m_pDoc->GetNodes();
787 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), rTable.size());
789 SwNodeIndex* pNodeIdx = rTable[0]->GetContentIdx();
790 CPPUNIT_ASSERT(pNodeIdx);
792 pTextNode = rNds[ pNodeIdx->GetIndex() + 1 ]->GetTextNode(); //first deleted txtnode
793 CPPUNIT_ASSERT(pTextNode);
795 OUString sIpsum = pTextNode->GetText();
796 CPPUNIT_ASSERT_EQUAL(OUString(" ipsum"), sIpsum);
798 aDocStat.Reset();
799 pTextNode->CountWords(aDocStat, 0, pTextNode->Len()); //word-counting the text should only count the non-deleted text, and this whole chunk should be ignored
800 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), aDocStat.nWord);
801 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), aDocStat.nChar);
803 // https://bugs.libreoffice.org/show_bug.cgi?id=68347 we do want to count
804 // redline *added* text though
805 m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete|RedlineFlags::ShowInsert);
806 aPaM.DeleteMark();
807 aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 0);
808 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "redline-new-text ");
809 aDocStat.Reset();
810 pTextNode = aPaM.GetNode().GetTextNode();
811 pTextNode->SetWordCountDirty(true);
812 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
813 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), aDocStat.nWord);
814 //redline-new-text Lorem ipsum
815 //+++++++++++++++++ ------
816 //select start of original text and part of deleted text
817 aDocStat.Reset();
818 pTextNode->CountWords(aDocStat, 17, 25);
819 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(5), aDocStat.nChar);
822 //See https://bugs.libreoffice.org/show_bug.cgi?id=38983
824 SwDocStat aDocStat;
826 OUString sTemplate("ThisXis a test.");
828 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
829 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', ' '));
830 pTextNode = aPaM.GetNode().GetTextNode();
831 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
832 CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
833 aDocStat.nCharExcludingSpaces == 12 &&
834 aDocStat.nChar == 15);
835 aDocStat.Reset();
837 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
838 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll("X", " = "));
839 pTextNode = aPaM.GetNode().GetTextNode();
840 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
841 CPPUNIT_ASSERT(aDocStat.nWord == 5 &&
842 aDocStat.nCharExcludingSpaces == 13 &&
843 aDocStat.nChar == 17);
844 aDocStat.Reset();
846 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
847 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll("X", " _ "));
848 pTextNode = aPaM.GetNode().GetTextNode();
849 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
850 CPPUNIT_ASSERT(aDocStat.nWord == 5 &&
851 aDocStat.nCharExcludingSpaces == 13 &&
852 aDocStat.nChar == 17);
853 aDocStat.Reset();
855 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
856 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll("X", " -- "));
857 pTextNode = aPaM.GetNode().GetTextNode();
858 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
859 CPPUNIT_ASSERT(aDocStat.nWord == 5 &&
860 aDocStat.nCharExcludingSpaces == 14 &&
861 aDocStat.nChar == 18);
862 aDocStat.Reset();
864 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
865 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', '_'));
866 pTextNode = aPaM.GetNode().GetTextNode();
867 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
868 CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
869 aDocStat.nCharExcludingSpaces == 13 &&
870 aDocStat.nChar == 15);
871 aDocStat.Reset();
873 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
874 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', '-'));
875 pTextNode = aPaM.GetNode().GetTextNode();
876 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
877 CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
878 aDocStat.nCharExcludingSpaces == 13 &&
879 aDocStat.nChar == 15);
880 aDocStat.Reset();
882 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
883 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2012));
884 pTextNode = aPaM.GetNode().GetTextNode();
885 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
886 CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
887 aDocStat.nCharExcludingSpaces == 13 &&
888 aDocStat.nChar == 15);
889 aDocStat.Reset();
891 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
892 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2015));
893 pTextNode = aPaM.GetNode().GetTextNode();
894 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
895 CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
896 aDocStat.nCharExcludingSpaces == 13 &&
897 aDocStat.nChar == 15);
898 aDocStat.Reset();
900 //But default configuration should, msword-alike treat emdash
901 //and endash as word separators for word-counting
902 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
903 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2013));
904 pTextNode = aPaM.GetNode().GetTextNode();
905 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
906 CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
907 aDocStat.nCharExcludingSpaces == 13 &&
908 aDocStat.nChar == 15);
909 aDocStat.Reset();
911 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
912 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2014));
913 pTextNode = aPaM.GetNode().GetTextNode();
914 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
915 CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
916 aDocStat.nCharExcludingSpaces == 13 &&
917 aDocStat.nChar == 15);
918 aDocStat.Reset();
920 const sal_Unicode aChunk[] = {' ', 0x2013, ' '};
921 OUString sChunk(aChunk, SAL_N_ELEMENTS(aChunk));
922 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
923 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll("X", sChunk));
924 pTextNode = aPaM.GetNode().GetTextNode();
925 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
926 CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
927 aDocStat.nCharExcludingSpaces == 13 &&
928 aDocStat.nChar == 17);
929 aDocStat.Reset();
933 void SwDocTest::testMergePortionsDeleteNotSorted()
935 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
936 SwPaM aPaM(aIdx);
937 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, " AABBCC");
939 SwCharFormat *const pCharFormat(m_pDoc->MakeCharFormat("foo", nullptr));
940 SwFormatCharFormat const charFormat(pCharFormat);
942 SwFormatINetFormat const inetFormat("http://example.com", "");
944 IDocumentContentOperations & rIDCO(m_pDoc->getIDocumentContentOperations());
945 aPaM.SetMark();
946 aPaM.GetPoint()->nContent = 2;
947 aPaM.GetMark()->nContent = 4;
948 rIDCO.InsertPoolItem(aPaM, charFormat);
949 aPaM.GetPoint()->nContent = 2;
950 aPaM.GetMark()->nContent = 5;
951 rIDCO.InsertPoolItem(aPaM, inetFormat);
952 aPaM.GetPoint()->nContent = 6;
953 aPaM.GetMark()->nContent = 8;
954 rIDCO.InsertPoolItem(aPaM, charFormat);
955 aPaM.GetPoint()->nContent = 4;
956 aPaM.GetMark()->nContent = 6;
957 // this triggered an STL assert in SwpHints::MergePortions()
958 rIDCO.InsertPoolItem(aPaM, charFormat);
961 //See https://bugs.libreoffice.org/show_bug.cgi?id=40599
962 void SwDocTest::testGraphicAnchorDeletion()
964 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected initial 0 count", static_cast<sal_uLong>(0), m_pDoc->getIDocumentStatistics().GetDocStat().nChar);
966 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
967 SwPaM aPaM(aIdx);
969 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "Paragraph 1");
970 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
972 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "graphic anchor>><<graphic anchor");
973 SwNodeIndex nPara2 = aPaM.GetPoint()->nNode;
974 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
976 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "Paragraph 3");
978 aPaM.GetPoint()->nNode = nPara2;
979 aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), RTL_CONSTASCII_LENGTH("graphic anchor>>"));
981 //Insert a graphic at X of >>X<< in paragraph 2
982 SfxItemSet aFlySet(m_pDoc->GetAttrPool(), svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END-1>{});
983 SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
984 aAnchor.SetAnchor(aPaM.GetPoint());
985 aFlySet.Put(aAnchor);
986 SwFlyFrameFormat *pFrame = m_pDoc->getIDocumentContentOperations().InsertGraphic(aPaM, OUString(), OUString(), nullptr, &aFlySet, nullptr, nullptr);
987 CPPUNIT_ASSERT_MESSAGE("Expected frame", pFrame != nullptr);
989 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be 1 graphic", static_cast<size_t>(1), m_pDoc->GetFlyCount(FLYCNTTYPE_GRF));
991 //Delete >X<
992 aPaM.GetPoint()->nNode = nPara2;
993 aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(),
994 RTL_CONSTASCII_LENGTH("graphic anchor>><")+1);
995 aPaM.SetMark();
996 aPaM.GetPoint()->nNode = nPara2;
997 aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), RTL_CONSTASCII_LENGTH("graphic anchor>"));
998 m_pDoc->getIDocumentContentOperations().DeleteRange(aPaM);
1000 #ifdef DEBUG_AS_HTML
1002 SvFileStream aPasteDebug(OUString("cppunitDEBUG.html"), StreamMode::WRITE|StreamMode::TRUNC);
1003 WriterRef xWrt;
1004 GetHTMLWriter( String(), String(), xWrt );
1005 SwWriter aDbgWrt( aPasteDebug, *m_pDoc );
1006 aDbgWrt.Write( xWrt );
1008 #endif
1010 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be 0 graphics", static_cast<size_t>(0), m_pDoc->GetFlyCount(FLYCNTTYPE_GRF));
1012 //Now, if instead we swap RndStdIds::FLY_AS_CHAR (inline graphic) to RndStdIds::FLY_AT_CHAR (anchored to character)
1013 //and repeat the above, graphic is *not* deleted, i.e. it belongs to the paragraph, not the
1014 //range to which its anchored, which is annoying.
1017 static int
1018 getRand(int modulus)
1020 if (modulus <= 0)
1021 return 0;
1022 return comphelper::rng::uniform_int_distribution(0, modulus-1);
1025 static OUString
1026 getRandString()
1028 OUString aText("AAAAA BBBB CCC DD E \n");
1029 int s = getRand(aText.getLength());
1030 int j = getRand(aText.getLength() - s);
1031 OUString aRet(aText.copy(s, j));
1032 if (!getRand(5))
1033 aRet += "\n";
1034 // fprintf (stderr, "rand string '%s'\n", OUStringToOString(aRet, RTL_TEXTENCODING_UTF8).getStr());
1035 return aRet;
1038 static SwPosition
1039 getRandomPosition(SwDoc *pDoc, int /* nOffset */)
1041 const SwPosition aPos(pDoc->GetNodes().GetEndOfContent());
1042 size_t nNodes = aPos.nNode.GetNode().GetIndex() - aPos.nNode.GetNode().StartOfSectionIndex();
1043 size_t n = comphelper::rng::uniform_size_distribution(0, nNodes);
1044 SwPaM pam(aPos);
1045 for (sal_uLong i = 0; i < n; ++i)
1047 pam.Move(fnMoveBackward, GoInNode);
1049 return *pam.GetPoint();
1052 void SwDocTest::randomTest()
1054 CPPUNIT_ASSERT_MESSAGE("SwDoc::IsRedlineOn()", !m_pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1055 RedlineFlags modes[] = {
1056 RedlineFlags::On,
1057 RedlineFlags::ShowMask,
1058 RedlineFlags::NONE,
1059 RedlineFlags::On | RedlineFlags::ShowMask,
1060 RedlineFlags::On | RedlineFlags::Ignore,
1061 RedlineFlags::On | RedlineFlags::Ignore | RedlineFlags::ShowMask,
1062 RedlineFlags::On | RedlineFlags::ShowInsert,
1063 RedlineFlags::On | RedlineFlags::ShowDelete
1065 static const char *authors[] = {
1066 "Jim", "Bob", "JimBobina", "Helga", "Gertrude", "Spagna", "Hurtleweed"
1069 for( size_t rlm = 0; rlm < SAL_N_ELEMENTS(modes); rlm++ )
1071 m_pDoc->ClearDoc();
1073 // setup redlining
1074 m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags(modes[rlm]);
1075 SW_MOD()->SetRedlineAuthor(OUString::createFromAscii(authors[0]));
1077 for( int i = 0; i < 2000; i++ )
1079 SwCursor aCrs(getRandomPosition(m_pDoc, i/20), nullptr);
1080 aCrs.SetMark();
1082 switch (getRand (i < 50 ? 3 : 6)) {
1083 // insert ops first
1084 case 0: {
1085 if (!m_pDoc->getIDocumentContentOperations().InsertString(aCrs, getRandString())) {
1086 // fprintf (stderr, "failed to insert string !\n");
1088 break;
1090 case 1:
1091 break;
1092 case 2: { // switch author
1093 int a = getRand(SAL_N_ELEMENTS(authors));
1094 SW_MOD()->SetRedlineAuthor(OUString::createFromAscii(authors[a]));
1095 break;
1098 // movement / deletion ops later
1099 case 3: // deletion
1100 switch (getRand(6)) {
1101 case 0:
1102 m_pDoc->getIDocumentContentOperations().DelFullPara(aCrs);
1103 break;
1104 case 1:
1105 m_pDoc->getIDocumentContentOperations().DeleteRange(aCrs);
1106 break;
1107 case 2:
1108 m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aCrs, !!getRand(1));
1109 break;
1110 case 3:
1111 default:
1112 m_pDoc->getIDocumentContentOperations().Overwrite(aCrs, getRandString());
1113 break;
1115 break;
1116 case 4: { // movement
1117 SwMoveFlags nFlags =
1118 getRand(1) // FIXME: puterb this more ?
1119 ? SwMoveFlags::DEFAULT
1120 : SwMoveFlags::ALLFLYS |
1121 SwMoveFlags::CREATEUNDOOBJ |
1122 SwMoveFlags::REDLINES |
1123 SwMoveFlags::NO_DELFRMS;
1124 SwPosition aTo(getRandomPosition(m_pDoc, i/10));
1125 m_pDoc->getIDocumentContentOperations().MoveRange(aCrs, aTo, nFlags);
1126 break;
1129 case 5:
1130 break;
1132 // undo / redo ?
1133 default:
1134 break;
1138 // Debug / verify the produced document has real content
1139 #if 0
1140 OStringBuffer aBuffer("nodes-");
1141 aBuffer.append(sal_Int32(rlm));
1142 aBuffer.append(".xml");
1144 xmlTextWriterPtr writer;
1145 writer = xmlNewTextWriterFilename( aBuffer.makeStringAndClear().getStr(), 0 );
1146 xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
1147 m_pDoc->dumpAsXml(writer);
1148 xmlTextWriterEndDocument( writer );
1149 xmlFreeTextWriter( writer );
1150 #endif
1154 void SwDocTest::testTableAutoFormats()
1156 SwGlobals::ensure();
1158 //create new AutoFormatTable
1159 SwTableAutoFormatTable aTableAFT;
1161 //check the style size - default is expected
1162 CPPUNIT_ASSERT_EQUAL( size_t(1), aTableAFT.size() );
1164 //create new style
1165 SwTableAutoFormat aTableAF( "TestItemStyle" );
1167 //create new AutoFormat
1168 SwBoxAutoFormat aBoxAF;
1170 //SetFont
1171 SvxFontItem aFont( RES_CHRATR_FONT );
1172 aFont.SetFamily( FontFamily::FAMILY_DECORATIVE );
1173 aFont.SetPitch( FontPitch::PITCH_VARIABLE );
1174 aFont.SetCharSet( RTL_TEXTENCODING_MS_1251 );
1175 aBoxAF.SetFont( aFont );
1176 //SetHeight
1177 SvxFontHeightItem aHeight( 280, 120, RES_CHRATR_FONTSIZE );
1178 aBoxAF.SetHeight( aHeight );
1179 //SetWeight
1180 SvxWeightItem aWeight( FontWeight::WEIGHT_BOLD, RES_CHRATR_WEIGHT );
1181 aBoxAF.SetWeight( aWeight );
1182 //SetPosture
1183 SvxPostureItem aPosture( FontItalic::ITALIC_NORMAL, RES_CHRATR_POSTURE );
1184 aBoxAF.SetPosture( aPosture );
1185 //SetCJKFont
1186 SvxFontItem aCJKFont( RES_CHRATR_FONT );
1187 aCJKFont.SetFamily( FontFamily::FAMILY_MODERN );
1188 aCJKFont.SetPitch( FontPitch::PITCH_FIXED );
1189 aCJKFont.SetCharSet( RTL_TEXTENCODING_MS_1251 );
1190 aBoxAF.SetCJKFont( aCJKFont );
1191 //SetCJKHeight
1192 SvxFontHeightItem aCJKHeight( 230, 110, RES_CHRATR_FONTSIZE );
1193 aBoxAF.SetCJKHeight( aCJKHeight );
1194 //SetCJKWeight
1195 SvxWeightItem aCJKWeight( FontWeight::WEIGHT_SEMIBOLD, RES_CHRATR_WEIGHT );
1196 aBoxAF.SetCJKWeight( aCJKWeight );
1197 //SetCJKPosture
1198 SvxPostureItem aCJKPosture( FontItalic::ITALIC_OBLIQUE, RES_CHRATR_POSTURE );
1199 aBoxAF.SetCJKPosture( aCJKPosture );
1200 //SetCTLFont
1201 SvxFontItem aCTLFont( RES_CHRATR_FONT );
1202 aCTLFont.SetFamily( FontFamily::FAMILY_ROMAN );
1203 aCTLFont.SetPitch( FontPitch::PITCH_FIXED );
1204 aCTLFont.SetCharSet( RTL_TEXTENCODING_MS_1251 );
1205 aBoxAF.SetCTLFont( aCTLFont );
1206 //SetCTLHeight
1207 SvxFontHeightItem aCTLHeight( 215, 105, RES_CHRATR_FONTSIZE );
1208 aBoxAF.SetCTLHeight( aCTLHeight );
1209 //SetCTLWeight
1210 SvxWeightItem aCTLWeight( FontWeight::WEIGHT_ULTRABOLD, RES_CHRATR_WEIGHT );
1211 aBoxAF.SetCTLWeight( aCTLWeight );
1212 //SetCTLPosture
1213 SvxPostureItem aCTLPosture( FontItalic::ITALIC_OBLIQUE, RES_CHRATR_POSTURE );
1214 aBoxAF.SetCTLPosture( aCTLPosture );
1215 //SetUnderline
1216 SvxUnderlineItem aUnderline( FontLineStyle::LINESTYLE_DOTTED, RES_CHRATR_UNDERLINE );
1217 aBoxAF.SetUnderline( aUnderline );
1218 //SetOverline
1219 SvxOverlineItem aOverline( FontLineStyle::LINESTYLE_DASH, RES_CHRATR_OVERLINE );
1220 aBoxAF.SetOverline( aOverline );
1221 //SetCrossedOut
1222 SvxCrossedOutItem aCrossedOut( FontStrikeout::STRIKEOUT_BOLD, RES_CHRATR_CROSSEDOUT );
1223 aBoxAF.SetCrossedOut( aCrossedOut );
1224 //SetContour
1225 SvxContourItem aContour( true, RES_CHRATR_CONTOUR );
1226 aBoxAF.SetContour( aContour );
1227 //SetShadowed
1228 SvxShadowedItem aShadowed( false, RES_CHRATR_SHADOWED );
1229 aBoxAF.SetShadowed( aShadowed );
1230 //SetColor
1231 SvxColorItem aColor( Color(0xFF23FF), RES_CHRATR_COLOR );
1232 aBoxAF.SetColor( aColor );
1233 //SetAdjust
1234 SvxAdjustItem aAdjust( SvxAdjust::Center, RES_PARATR_ADJUST );
1235 aBoxAF.SetAdjust( aAdjust );
1236 //SetTextOrientation
1237 SvxFrameDirectionItem aTOrientation( SvxFrameDirection::Vertical_RL_TB, RES_FRAMEDIR );
1238 aBoxAF.SetTextOrientation( aTOrientation );
1239 //SetVerticalAlignment
1240 SwFormatVertOrient aVAlignment( 3, css::text::VertOrientation::CENTER, css::text::RelOrientation::PAGE_LEFT );
1241 aBoxAF.SetVerticalAlignment( aVAlignment );
1242 //SetBox
1243 SvxBoxItem aBox( RES_BOX );
1244 aBox.SetAllDistances( 5 );
1245 aBoxAF.SetBox( aBox );
1246 //SetBackground
1247 SvxBrushItem aBackground( Color(0xFF11FF), RES_BACKGROUND );
1248 aBoxAF.SetBackground( aBackground );
1249 //Set m_aTLBR
1250 aBoxAF.m_aTLBR.ScaleMetrics( 11,12 );
1251 SvxLineItem aTLBRLine = aBoxAF.m_aTLBR;
1252 //Set m_aBLTR
1253 aBoxAF.m_aBLTR.ScaleMetrics( 13,14 );
1254 SvxLineItem aBLTRLine = aBoxAF.m_aBLTR;
1255 //Set m_aHorJustify
1256 SvxHorJustifyItem aHJustify( SvxCellHorJustify::Center, 0 );
1257 aBoxAF.m_aHorJustify = aHJustify;
1258 //Set m_aVerJustify
1259 SvxVerJustifyItem aVJustify( SvxCellVerJustify::Center , 0 );
1260 aBoxAF.m_aVerJustify = aVJustify;
1261 //Set m_aStacked
1262 aBoxAF.m_aStacked.SetValue( true );
1263 SfxBoolItem aStacked = aBoxAF.m_aStacked;
1264 //Set m_aMargin
1265 aBoxAF.m_aMargin.SetLeftMargin( sal_Int16(4) );
1266 aBoxAF.m_aMargin.SetRightMargin( sal_Int16(3) );
1267 aBoxAF.m_aMargin.SetTopMargin( sal_Int16(2) );
1268 aBoxAF.m_aMargin.SetBottomMargin( sal_Int16(3) );
1269 SvxMarginItem aMargin = aBoxAF.m_aMargin;
1270 //Set m_aLinebreak
1271 aBoxAF.m_aLinebreak.SetValue( true );
1272 SfxBoolItem aLBreak = aBoxAF.m_aLinebreak;
1273 //Set m_aRotateAngle
1274 aBoxAF.m_aRotateAngle.SetValue( sal_Int32(5) );
1275 SfxInt32Item aRAngle = aBoxAF.m_aRotateAngle;
1276 //Set m_aRotateMode
1277 aBoxAF.m_aRotateMode.SetValue( SVX_ROTATE_MODE_CENTER );
1278 //Set m_sNumFormatString
1279 OUString aNFString = "UnitTestFormat";
1280 aBoxAF.m_sNumFormatString = aNFString;
1281 //Set m_eSysLanguage
1282 LanguageType aSLang( LANGUAGE_ENGLISH_INDIA );
1283 aBoxAF.m_eSysLanguage = aSLang;
1284 //Set m_eNumFormatLanguage
1285 LanguageType aNFLang( LANGUAGE_GERMAN );
1286 aBoxAF.m_eNumFormatLanguage = aNFLang;
1287 //Set m_aBreak
1288 SvxFormatBreakItem aBreak( SvxBreak::PageBefore, 0 );
1289 aTableAF.m_aBreak = aBreak;
1290 //Set m_aKeepWithNextPara
1291 SvxFormatKeepItem aKWNPara( true, 0 );
1292 aTableAF.m_aKeepWithNextPara = aKWNPara;
1293 //Set m_aPageDesc
1294 SwFormatPageDesc aPDesc;
1295 uno::Any aPDAny( sal_uInt16(3) );
1296 aPDesc.PutValue( aPDAny, 0 );
1297 aTableAF.m_aPageDesc = aPDesc;
1298 //Set m_aRepeatHeading
1299 sal_uInt16 aRHeading = 3;
1300 aTableAF.m_aRepeatHeading = aRHeading;
1301 //Set m_bLayoutSplit
1302 bool aLSplit = false;
1303 aTableAF.m_bLayoutSplit = aLSplit;
1304 //Set m_bRowSplit
1305 bool aRSplit = false;
1306 aTableAF.m_bRowSplit = aRSplit;
1307 //Set m_bCollapsingBorders
1308 bool aCBorders = false;
1309 aTableAF.m_bCollapsingBorders = aCBorders;
1310 //Set m_aShadow
1311 SvxShadowItem aShadow( 0, nullptr, 103, SvxShadowLocation::BottomLeft );
1312 aTableAF.m_aShadow = aShadow;
1313 //Set bInclFont
1314 bool aIFont = false;
1315 aTableAF.bInclFont = aIFont;
1316 //Set bInclJustify
1317 bool aIJustify = false;
1318 aTableAF.bInclJustify = aIJustify;
1319 //Set bInclFrame
1320 bool aIFrame = false;
1321 aTableAF.bInclFrame = aIFrame;
1322 //Set bInclBackground
1323 bool aIBackground = false;
1324 aTableAF.bInclBackground = aIBackground;
1325 //Set bInclValueFormat
1326 bool aIVFormat = false;
1327 aTableAF.bInclValueFormat = aIVFormat;
1329 //set the box format to AutoFormat
1330 aTableAF.SetBoxFormat( aBoxAF, sal_uInt8(0) );
1331 //add AutoFormat to AutoFormatTable
1332 aTableAFT.AddAutoFormat( aTableAF );
1334 //check the style size
1335 CPPUNIT_ASSERT_EQUAL( size_t(2), aTableAFT.size() );
1337 //save the bInclFontstyles
1338 aTableAFT.Save();
1340 //check the style size after save
1341 CPPUNIT_ASSERT_EQUAL( size_t(2), aTableAFT.size() );
1343 //create new AutoFormatTable
1344 SwTableAutoFormatTable aLoadTAFT;
1346 //check the style size
1347 CPPUNIT_ASSERT_EQUAL( size_t(1), aLoadTAFT.size() );
1349 //load the saved styles
1350 aLoadTAFT.Load();
1352 //check the style size after load
1353 CPPUNIT_ASSERT_EQUAL( size_t(2), aLoadTAFT.size() );
1355 //assert the values
1356 SwTableAutoFormat* pLoadAF = aLoadTAFT.FindAutoFormat( "TestItemStyle" );
1357 CPPUNIT_ASSERT( pLoadAF );
1358 //GetFont
1359 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetFont() == aFont ) );
1360 //GetHeight
1361 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetHeight() == aHeight ) );
1362 //GetWeight
1363 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetWeight() == aWeight ) );
1364 //GetPosture
1365 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetPosture() == aPosture ) );
1366 //GetCJKFont
1367 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCJKFont() == aCJKFont ) );
1368 //GetCJKHeight
1369 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCJKHeight() == aCJKHeight ) );
1370 //GetCJKWeight
1371 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCJKWeight() == aCJKWeight ) );
1372 //GetCJKPosture
1373 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCJKPosture() == aCJKPosture ) );
1374 //GetCTLFont
1375 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCTLFont() == aCTLFont ) );
1376 //GetCTLHeight
1377 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCTLHeight() == aCTLHeight ) );
1378 //GetCTLWeight
1379 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCTLWeight() == aCTLWeight ) );
1380 //GetCTLPosture
1381 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCTLPosture() == aCTLPosture ) );
1382 //GetUnderline
1383 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetUnderline() == aUnderline ) );
1384 //GetOverline
1385 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetOverline() == aOverline ) );
1386 //GetCrossedOut
1387 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCrossedOut() == aCrossedOut ) );
1388 //GetContour
1389 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetContour() == aContour ) );
1390 //GetShadowed
1391 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetShadowed() == aShadowed ) );
1392 //GetColor
1393 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetColor() == aColor) );
1394 //GetAdjust
1395 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetAdjust() == aAdjust ) );
1396 //GetTextOrientation
1397 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetTextOrientation() == aTOrientation ) );
1398 //GetVerticalAlignment
1399 CPPUNIT_ASSERT (bool( pLoadAF->GetBoxFormat(0).GetVerticalAlignment() == aVAlignment ) );
1400 //GetBox
1401 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetBox() == aBox ) );
1402 //GetBackground
1403 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetBackground() == aBackground ) );
1404 //Get m_aTLBR
1405 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_aTLBR == aTLBRLine ) );
1406 //Get m_aBLTR
1407 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_aBLTR == aBLTRLine ) );
1408 //Get m_aHorJustify
1409 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_aHorJustify == aHJustify ) );
1410 //Get m_aVerJustify
1411 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_aVerJustify == aVJustify ) );
1412 //Get m_aStacked
1413 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_aStacked == aStacked ) );
1414 //Get m_aMargin
1415 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_aMargin == aMargin ) );
1416 //Get m_aLinebreak
1417 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_aLinebreak == aLBreak ) );
1418 //Get m_aRotateAngle
1419 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_aRotateAngle == aRAngle ) );
1420 #if !((defined(__clang__) && __clang_major__ == 4 && __clang_minor__ == 0) \
1421 || (defined __APPLE__ && defined __clang__ \
1422 && defined __apple_build_version__ \
1423 && __apple_build_version__ >= 9000000 \
1424 && __apple_build_version__ <= 9000099))
1425 // Temporary fix for mysterious problem with Clang in F26 and Xcode 9
1426 //Get m_aRotateMode
1427 SvxRotateModeItem aRMode = aBoxAF.m_aRotateMode;
1428 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_aRotateMode == aRMode ) );
1429 #endif
1430 //Get m_sNumFormatString
1431 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_sNumFormatString == aNFString ) );
1432 //Get m_eSysLanguage
1433 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_eSysLanguage == aSLang ) );
1434 //Get m_eNumFormatLanguage
1435 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).m_eNumFormatLanguage == aNFLang ) );
1436 //Get m_aBreak
1437 CPPUNIT_ASSERT( bool( pLoadAF->m_aBreak == aBreak ) );
1438 //Get m_aKeepWithNextPara
1439 CPPUNIT_ASSERT( bool( pLoadAF->m_aKeepWithNextPara == aKWNPara ) );
1440 //Get m_aPageDesc
1441 CPPUNIT_ASSERT( bool( pLoadAF->m_aPageDesc == aPDesc ) );
1442 //Get m_aRepeatHeading
1443 CPPUNIT_ASSERT( bool( pLoadAF->m_aRepeatHeading == aRHeading ) );
1444 //Get m_bLayoutSplit
1445 CPPUNIT_ASSERT( bool( pLoadAF->m_bLayoutSplit == aLSplit ) );
1446 //Get m_bRowSplit
1447 CPPUNIT_ASSERT( bool( pLoadAF->m_bRowSplit == aRSplit ) );
1448 //Get m_bCollapsingBorders
1449 CPPUNIT_ASSERT( bool( pLoadAF->m_bCollapsingBorders == aCBorders ) );
1450 //Get m_aShadow
1451 CPPUNIT_ASSERT( bool( pLoadAF->m_aShadow == aShadow ) );
1452 //Get bInclFont
1453 CPPUNIT_ASSERT( bool( pLoadAF->bInclFont == aIFont ) );
1454 //Get bInclJustify
1455 CPPUNIT_ASSERT( bool( pLoadAF->bInclJustify == aIJustify ) );
1456 //Get bInclFrame
1457 CPPUNIT_ASSERT( bool( pLoadAF->bInclFrame == aIFrame ) );
1458 //Get bInclBackground
1459 CPPUNIT_ASSERT( bool( pLoadAF->bInclBackground == aIBackground ) );
1460 //Get bInclValueFormat
1461 CPPUNIT_ASSERT( bool( pLoadAF->bInclValueFormat == aIVFormat ) );
1464 static OUString
1465 translitTest(SwDoc & rDoc, const SwPaM & rPaM, TransliterationFlags const nType)
1467 utl::TransliterationWrapper aTrans(
1468 ::comphelper::getProcessComponentContext(), nType);
1469 rDoc.getIDocumentContentOperations().TransliterateText(rPaM, aTrans);
1470 return rPaM.GetText();
1473 void SwDocTest::testTransliterate()
1475 // just some simple test to see if it's totally broken
1476 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1477 SwPaM aPaM(aIdx);
1478 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "foobar");
1479 aPaM.SetMark();
1480 aPaM.GetPoint()->nContent = 0;
1481 CPPUNIT_ASSERT_EQUAL(OUString("foobar"), aPaM.GetText());
1483 CPPUNIT_ASSERT_EQUAL(OUString("FOOBAR"),
1484 translitTest(*m_pDoc, aPaM,
1485 TransliterationFlags::LOWERCASE_UPPERCASE));
1486 CPPUNIT_ASSERT_EQUAL(OUString("Foobar"),
1487 translitTest(*m_pDoc, aPaM,
1488 TransliterationFlags::TITLE_CASE));
1489 CPPUNIT_ASSERT_EQUAL(OUString("fOOBAR"),
1490 translitTest(*m_pDoc, aPaM,
1491 TransliterationFlags::TOGGLE_CASE));
1492 CPPUNIT_ASSERT_EQUAL(OUString("foobar"),
1493 translitTest(*m_pDoc, aPaM,
1494 TransliterationFlags::UPPERCASE_LOWERCASE));
1495 CPPUNIT_ASSERT_EQUAL(OUString("Foobar"),
1496 translitTest(*m_pDoc, aPaM,
1497 TransliterationFlags::SENTENCE_CASE));
1498 CPPUNIT_ASSERT_EQUAL(OUString("Foobar"),
1499 translitTest(*m_pDoc, aPaM,
1500 TransliterationFlags::HIRAGANA_KATAKANA));
1502 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
1503 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "one (two) three");
1504 CPPUNIT_ASSERT_EQUAL(OUString("One (Two) Three"),
1505 translitTest(*m_pDoc, aPaM,
1506 TransliterationFlags::TITLE_CASE));
1509 namespace
1511 class SwTableFormulaTest : public SwTableFormula
1513 SwTableNode *m_pNode;
1514 public:
1515 SwTableFormulaTest(const OUString &rStr, SwTableNode *pNode)
1516 : SwTableFormula(rStr)
1517 , m_pNode(pNode)
1519 m_eNmType = INTRNL_NAME;
1521 virtual const SwNode* GetNodeOfFormula() const override
1523 return m_pNode;
1528 //tdf#66353 Expression is faulty
1529 void SwDocTest::testFormulas()
1531 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1532 SwPosition aPos(aIdx);
1534 const SwTable *pTable = m_pDoc->InsertTable(
1535 SwInsertTableOptions(SwInsertTableFlags::HeadlineNoBorder, 0), aPos, 1, 3, 0);
1536 SwTableNode* pTableNode = pTable->GetTableNode();
1537 SwTableFormulaTest aFormula("<\x12-1,0>+<Table1.A1>", pTableNode);
1539 aFormula.PtrToBoxNm(pTable);
1541 CPPUNIT_ASSERT_EQUAL(OUString("<?>+<Table1.?>"), aFormula.GetFormula());
1543 // tdf#61228: Evaluating non-defined function should return an error
1544 SwCalc aCalc(*m_pDoc);
1545 SwSbxValue val = aCalc.Calculate("foobar()");
1546 CPPUNIT_ASSERT(aCalc.IsCalcError() && val.IsVoidValue() && val.IsDouble());
1547 CPPUNIT_ASSERT_EQUAL(DBL_MAX, val.GetDouble());
1548 // Evaluating non-defined variable should return 0 without an error
1549 val = aCalc.Calculate("foobar");
1550 CPPUNIT_ASSERT(!aCalc.IsCalcError() && val.IsVoidValue() && val.IsLong());
1551 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), val.GetLong());
1554 void SwDocTest::testMarkMove()
1556 IDocumentMarkAccess* pMarksAccess = m_pDoc->getIDocumentMarkAccess();
1559 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1560 SwPaM aPaM(aIdx);
1561 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "Paragraph 1");
1562 aPaM.SetMark();
1563 aPaM.GetMark()->nContent -= aPaM.GetMark()->nContent.GetIndex();
1564 pMarksAccess->makeMark(aPaM, "Para1",
1565 IDocumentMarkAccess::MarkType::BOOKMARK, sw::mark::InsertMode::New);
1567 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
1568 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "Paragraph 2");
1569 aPaM.SetMark();
1570 aPaM.GetMark()->nContent -= aPaM.GetMark()->nContent.GetIndex();
1571 pMarksAccess->makeMark(aPaM, "Para2",
1572 IDocumentMarkAccess::MarkType::BOOKMARK, sw::mark::InsertMode::New);
1574 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
1575 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "Paragraph 3");
1576 aPaM.SetMark();
1577 aPaM.GetMark()->nContent -= aPaM.GetMark()->nContent.GetIndex();
1578 pMarksAccess->makeMark(aPaM, "Para3",
1579 IDocumentMarkAccess::MarkType::BOOKMARK, sw::mark::InsertMode::New);
1582 // join paragraph 2 and 3 and check
1584 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -2);
1585 SwTextNode& rParaNode2 = dynamic_cast<SwTextNode&>(aIdx.GetNode());
1586 rParaNode2.JoinNext();
1588 ::sw::mark::IMark* pBM1 = pMarksAccess->findMark("Para1")->get();
1589 ::sw::mark::IMark* pBM2 = pMarksAccess->findMark("Para2")->get();
1590 ::sw::mark::IMark* pBM3 = pMarksAccess->findMark("Para3")->get();
1592 CPPUNIT_ASSERT_EQUAL(sal_Int32(0) , pBM1->GetMarkStart().nContent.GetIndex());
1593 CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pBM1->GetMarkEnd().nContent.GetIndex());
1594 CPPUNIT_ASSERT_EQUAL(
1595 pBM1->GetMarkStart().nNode.GetIndex(),
1596 pBM1->GetMarkEnd().nNode.GetIndex());
1598 CPPUNIT_ASSERT_EQUAL(sal_Int32(0) , pBM2->GetMarkStart().nContent.GetIndex());
1599 CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pBM2->GetMarkEnd().nContent.GetIndex());
1600 CPPUNIT_ASSERT_EQUAL(
1601 pBM2->GetMarkStart().nNode.GetIndex(),
1602 pBM2->GetMarkEnd().nNode.GetIndex());
1604 CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pBM3->GetMarkStart().nContent.GetIndex());
1605 CPPUNIT_ASSERT_EQUAL(sal_Int32(22), pBM3->GetMarkEnd().nContent.GetIndex());
1606 CPPUNIT_ASSERT_EQUAL(
1607 pBM3->GetMarkStart().nNode.GetIndex(),
1608 pBM3->GetMarkEnd().nNode.GetIndex());
1610 CPPUNIT_ASSERT_EQUAL(
1611 pBM1->GetMarkStart().nNode.GetIndex()+1,
1612 pBM2->GetMarkStart().nNode.GetIndex());
1613 CPPUNIT_ASSERT_EQUAL(
1614 pBM2->GetMarkStart().nNode.GetIndex(),
1615 pBM3->GetMarkStart().nNode.GetIndex());
1617 // cut some text
1619 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1620 SwPaM aPaM(aIdx, aIdx, -1);
1621 aPaM.GetPoint()->nContent += 5;
1622 aPaM.GetMark()->nContent += 6;
1623 m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aPaM);
1625 pBM1 = pMarksAccess->findMark("Para1")->get();
1626 pBM2 = pMarksAccess->findMark("Para2")->get();
1627 pBM3 = pMarksAccess->findMark("Para3")->get();
1629 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pBM1->GetMarkStart().nContent.GetIndex());
1630 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pBM1->GetMarkEnd().nContent.GetIndex());
1631 CPPUNIT_ASSERT_EQUAL(
1632 pBM1->GetMarkStart().nNode.GetIndex(),
1633 pBM1->GetMarkEnd().nNode.GetIndex());
1635 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pBM2->GetMarkStart().nContent.GetIndex());
1636 CPPUNIT_ASSERT_EQUAL(sal_Int32(12), pBM2->GetMarkEnd().nContent.GetIndex());
1637 CPPUNIT_ASSERT_EQUAL(
1638 pBM2->GetMarkStart().nNode.GetIndex(),
1639 pBM2->GetMarkEnd().nNode.GetIndex());
1641 CPPUNIT_ASSERT_EQUAL(sal_Int32(12), pBM3->GetMarkStart().nContent.GetIndex());
1642 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), pBM3->GetMarkEnd().nContent.GetIndex());
1643 CPPUNIT_ASSERT_EQUAL(
1644 pBM3->GetMarkStart().nNode.GetIndex(),
1645 pBM3->GetMarkEnd().nNode.GetIndex());
1647 CPPUNIT_ASSERT_EQUAL(
1648 pBM1->GetMarkStart().nNode.GetIndex(),
1649 pBM2->GetMarkStart().nNode.GetIndex());
1650 CPPUNIT_ASSERT_EQUAL(
1651 pBM2->GetMarkStart().nNode.GetIndex(),
1652 pBM3->GetMarkStart().nNode.GetIndex());
1654 // split the paragraph
1656 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1657 SwPosition aPos(aIdx);
1658 aPos.nContent += 8;
1659 m_pDoc->getIDocumentContentOperations().SplitNode(aPos, false);
1661 pBM1 = pMarksAccess->findMark("Para1")->get();
1662 pBM2 = pMarksAccess->findMark("Para2")->get();
1663 pBM3 = pMarksAccess->findMark("Para3")->get();
1665 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pBM1->GetMarkStart().nContent.GetIndex());
1666 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pBM1->GetMarkEnd().nContent.GetIndex());
1667 CPPUNIT_ASSERT_EQUAL(
1668 pBM1->GetMarkStart().nNode.GetIndex(),
1669 pBM1->GetMarkEnd().nNode.GetIndex());
1671 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pBM2->GetMarkStart().nContent.GetIndex());
1672 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pBM2->GetMarkEnd().nContent.GetIndex());
1673 CPPUNIT_ASSERT_EQUAL(
1674 pBM2->GetMarkStart().nNode.GetIndex()+1,
1675 pBM2->GetMarkEnd().nNode.GetIndex());
1677 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pBM3->GetMarkStart().nContent.GetIndex());
1678 CPPUNIT_ASSERT_EQUAL(sal_Int32(15), pBM3->GetMarkEnd().nContent.GetIndex());
1679 CPPUNIT_ASSERT_EQUAL(
1680 pBM3->GetMarkStart().nNode.GetIndex(),
1681 pBM3->GetMarkEnd().nNode.GetIndex());
1683 CPPUNIT_ASSERT_EQUAL(
1684 pBM1->GetMarkStart().nNode.GetIndex(),
1685 pBM2->GetMarkStart().nNode.GetIndex());
1686 CPPUNIT_ASSERT_EQUAL(
1687 pBM2->GetMarkEnd().nNode.GetIndex(),
1688 pBM3->GetMarkEnd().nNode.GetIndex());
1691 namespace
1693 struct TestRing : public sw::Ring<TestRing>
1695 TestRing() : sw::Ring<TestRing>() {};
1696 TestRing* GetNext()
1697 { return GetNextInRing(); }
1698 TestRing* GetPrev()
1699 { return GetPrevInRing(); }
1700 bool lonely() const
1701 { return unique(); }
1702 #if 0
1703 void debug()
1705 SAL_DEBUG("TestRing at: " << this << " prev: " << GetPrev() << " next: " << GetNext());
1707 #endif
1711 void SwDocTest::testIntrusiveRing()
1713 TestRing aRing1, aRing2, aRing3, aRing4, aRing5;
1714 std::vector<TestRing*> vRings;
1715 vRings.push_back(&aRing1);
1716 vRings.push_back(&aRing2);
1717 vRings.push_back(&aRing3);
1718 vRings.push_back(&aRing4);
1719 vRings.push_back(&aRing5);
1720 CPPUNIT_ASSERT_EQUAL(aRing1.GetRingContainer().size(), static_cast<size_t>(1));
1721 CPPUNIT_ASSERT(aRing1.lonely());
1722 CPPUNIT_ASSERT(aRing2.lonely());
1723 CPPUNIT_ASSERT(aRing3.lonely());
1724 aRing2.MoveTo(&aRing1);
1725 aRing3.MoveTo(&aRing1);
1726 CPPUNIT_ASSERT_EQUAL(aRing1.GetRingContainer().size(), static_cast<size_t>(3));
1727 CPPUNIT_ASSERT_EQUAL(aRing2.GetRingContainer().size(), static_cast<size_t>(3));
1728 CPPUNIT_ASSERT_EQUAL(aRing3.GetRingContainer().size(), static_cast<size_t>(3));
1729 CPPUNIT_ASSERT(!aRing1.lonely());
1730 CPPUNIT_ASSERT(!aRing2.lonely());
1731 CPPUNIT_ASSERT(!aRing3.lonely());
1732 aRing5.MoveTo(&aRing4);
1733 CPPUNIT_ASSERT_EQUAL(aRing4.GetRingContainer().size(), static_cast<size_t>(2));
1734 aRing4.GetRingContainer().merge(aRing1.GetRingContainer());
1735 for(TestRing* pRing : vRings)
1737 CPPUNIT_ASSERT_EQUAL(pRing->GetRingContainer().size(), static_cast<size_t>(5));
1739 for(std::vector<TestRing*>::iterator ppRing = vRings.begin(); ppRing != vRings.end(); ++ppRing)
1741 std::vector<TestRing*>::iterator ppNext = ppRing+1;
1742 if(ppNext==vRings.end())
1743 ppNext = vRings.begin();
1744 CPPUNIT_ASSERT_EQUAL((*ppRing)->GetNext(), *ppNext);
1745 CPPUNIT_ASSERT_EQUAL((*ppNext)->GetPrev(), *ppRing);
1747 for(TestRing& r: aRing1.GetRingContainer())
1749 TestRing* pRing = &r;
1750 CPPUNIT_ASSERT(pRing);
1751 //pRing->debug();
1753 const TestRing* pConstRing = &aRing1;
1754 for(const TestRing& r: pConstRing->GetRingContainer()) // this should fail without r being const
1756 const TestRing* pRing = &r;
1757 CPPUNIT_ASSERT(pRing);
1759 TestRing foo, bar;
1760 foo.MoveTo(&bar);
1761 CPPUNIT_ASSERT_EQUAL(&foo, bar.GetNext());
1762 CPPUNIT_ASSERT_EQUAL(&foo, bar.GetPrev());
1763 CPPUNIT_ASSERT_EQUAL(&bar, foo.GetNext());
1764 CPPUNIT_ASSERT_EQUAL(&bar, foo.GetPrev());
1765 foo.MoveTo(&foo);
1766 CPPUNIT_ASSERT_EQUAL(&bar, bar.GetNext());
1767 CPPUNIT_ASSERT_EQUAL(&bar, bar.GetPrev());
1768 CPPUNIT_ASSERT_EQUAL(&foo, foo.GetNext());
1769 CPPUNIT_ASSERT_EQUAL(&foo, foo.GetPrev());
1772 namespace
1774 struct TestHint final : SfxHint {};
1775 struct TestModify : SwModify
1778 struct TestClient : SwClient
1780 int m_nModifyCount;
1781 int m_nNotifyCount;
1782 int m_nModifyChangedCount;
1783 const SwModify* m_pLastChangedModify;
1784 TestClient() : m_nModifyCount(0), m_nNotifyCount(0), m_nModifyChangedCount(0), m_pLastChangedModify(nullptr) {};
1785 virtual void Modify( const SfxPoolItem*, const SfxPoolItem*) override
1786 { assert(false); }
1787 virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) override
1789 if(typeid(TestHint) == typeid(rHint))
1790 ++m_nNotifyCount;
1791 else if(dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
1792 ++m_nModifyCount;
1793 else if(auto pModifyChangedHint = dynamic_cast<const sw::ModifyChangedHint*>(&rHint))
1795 ++m_nModifyChangedCount;
1796 m_pLastChangedModify = pModifyChangedHint->m_pNew;
1800 struct OtherTestClient : SwClient
1802 int m_nModifyCount;
1803 OtherTestClient() : m_nModifyCount(0) {};
1804 virtual void Modify( const SfxPoolItem*, const SfxPoolItem*) override
1805 { ++m_nModifyCount; }
1808 void SwDocTest::testClientModify()
1810 (void) OtherTestClient(); // avoid loplugin:unreffun
1811 TestModify aMod;
1812 TestClient aClient1, aClient2;
1813 OtherTestClient aOtherClient1;
1814 // test client registration
1815 CPPUNIT_ASSERT(!aMod.HasWriterListeners());
1816 CPPUNIT_ASSERT(!aMod.HasOnlyOneListener());
1817 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient1.GetRegisteredIn());
1818 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient2.GetRegisteredIn());
1819 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient2.GetRegisteredIn());
1820 aMod.Add(&aClient1);
1821 CPPUNIT_ASSERT(aMod.HasWriterListeners());
1822 CPPUNIT_ASSERT(aMod.HasOnlyOneListener());
1823 aMod.Add(&aClient2);
1824 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod),aClient1.GetRegisteredIn());
1825 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod), aClient2.GetRegisteredIn());
1826 CPPUNIT_ASSERT(aMod.HasWriterListeners());
1827 CPPUNIT_ASSERT(!aMod.HasOnlyOneListener());
1828 // test broadcast
1829 aMod.ModifyBroadcast(nullptr, nullptr);
1830 CPPUNIT_ASSERT_EQUAL(1,aClient1.m_nModifyCount);
1831 CPPUNIT_ASSERT_EQUAL(1,aClient2.m_nModifyCount);
1832 CPPUNIT_ASSERT_EQUAL(0,aClient1.m_nNotifyCount);
1833 CPPUNIT_ASSERT_EQUAL(0,aClient2.m_nNotifyCount);
1834 aMod.ModifyBroadcast(nullptr, nullptr);
1835 CPPUNIT_ASSERT_EQUAL(2,aClient1.m_nModifyCount);
1836 CPPUNIT_ASSERT_EQUAL(2,aClient2.m_nModifyCount);
1837 CPPUNIT_ASSERT_EQUAL(0,aClient1.m_nNotifyCount);
1838 CPPUNIT_ASSERT_EQUAL(0,aClient2.m_nNotifyCount);
1839 // test notify
1841 TestHint aHint;
1842 aMod.CallSwClientNotify(aHint);
1843 CPPUNIT_ASSERT_EQUAL(2,aClient1.m_nModifyCount);
1844 CPPUNIT_ASSERT_EQUAL(2,aClient2.m_nModifyCount);
1845 CPPUNIT_ASSERT_EQUAL(1,aClient1.m_nNotifyCount);
1846 CPPUNIT_ASSERT_EQUAL(1,aClient2.m_nNotifyCount);
1848 // test typed iteration
1849 CPPUNIT_ASSERT(typeid(aClient1) != typeid(OtherTestClient));
1851 SwIterator<OtherTestClient,SwModify> aIter(aMod);
1852 for(OtherTestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1853 CPPUNIT_ASSERT(false);
1856 int nCount = 0;
1857 SwIterator<TestClient,SwModify> aIter(aMod);
1858 for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1860 CPPUNIT_ASSERT_EQUAL(2,pClient->m_nModifyCount);
1861 ++nCount;
1863 CPPUNIT_ASSERT_EQUAL(2,nCount);
1865 aMod.Add(&aOtherClient1);
1866 CPPUNIT_ASSERT_EQUAL(0,aOtherClient1.m_nModifyCount);
1868 int nCount = 0;
1869 SwIterator<TestClient,SwModify> aIter(aMod);
1870 for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1872 CPPUNIT_ASSERT_EQUAL(2,pClient->m_nModifyCount);
1873 ++nCount;
1875 CPPUNIT_ASSERT_EQUAL(2,nCount);
1877 CPPUNIT_ASSERT_EQUAL(0,aOtherClient1.m_nModifyCount);
1878 aMod.Remove(&aOtherClient1);
1879 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod),aClient1.GetRegisteredIn());
1880 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod),aClient2.GetRegisteredIn());
1881 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aOtherClient1.GetRegisteredIn());
1882 // test client self-deregistration during iteration
1884 int nCount = 0;
1885 SwIterator<TestClient,SwModify> aIter(aMod);
1886 for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1888 aMod.Remove(pClient);
1889 ++nCount;
1891 CPPUNIT_ASSERT_EQUAL(2,nCount);
1893 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient1.GetRegisteredIn());
1894 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient2.GetRegisteredIn());
1896 SwIterator<TestClient,SwModify> aIter(aMod);
1897 for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1899 CPPUNIT_ASSERT(false);
1902 aMod.ModifyBroadcast(nullptr, nullptr);
1903 CPPUNIT_ASSERT_EQUAL(2,aClient1.m_nModifyCount);
1904 CPPUNIT_ASSERT_EQUAL(2,aClient2.m_nModifyCount);
1905 CPPUNIT_ASSERT_EQUAL(1,aClient1.m_nNotifyCount);
1906 CPPUNIT_ASSERT_EQUAL(1,aClient2.m_nNotifyCount);
1908 void SwDocTest::testWriterMultiListener()
1910 TestModify aMod;
1911 TestClient aClient;
1912 sw::WriterMultiListener aMulti(aClient);
1913 CPPUNIT_ASSERT(!aMulti.IsListeningTo(&aMod));
1914 aMulti.StartListening(&aMod);
1915 CPPUNIT_ASSERT(aMulti.IsListeningTo(&aMod));
1916 aMulti.EndListeningAll();
1917 CPPUNIT_ASSERT(!aMulti.IsListeningTo(&aMod));
1918 aMulti.StartListening(&aMod);
1919 aMulti.EndListening(&aMod);
1920 CPPUNIT_ASSERT(!aMulti.IsListeningTo(&aMod));
1921 int nPreDeathChangedCount;
1923 TestModify aTempMod;
1924 aMod.Add(&aTempMod);
1925 aMulti.StartListening(&aTempMod);
1926 nPreDeathChangedCount = aClient.m_nModifyChangedCount;
1928 CPPUNIT_ASSERT(aMulti.IsListeningTo(&aMod));
1929 CPPUNIT_ASSERT_EQUAL(nPreDeathChangedCount+1, aClient.m_nModifyChangedCount);
1930 CPPUNIT_ASSERT_EQUAL(static_cast<const SwModify*>(&aMod),aClient.m_pLastChangedModify);
1933 void SwDocTest::test64kPageDescs()
1935 size_t nPageDescCount = 65536; // USHRT_MAX + 1
1937 for (size_t i = 0; i < nPageDescCount; ++i)
1939 OUString aName = "Page" + OUString::number(i);
1940 m_pDoc->MakePageDesc( aName );
1943 size_t nCount = m_pDoc->GetPageDescCnt();
1944 // +1 because Writer always creates a dummy page desc
1945 // in a new SwDoc
1946 CPPUNIT_ASSERT_EQUAL( nPageDescCount + 1, nCount );
1948 const SwPageDesc &rDesc = m_pDoc->GetPageDesc( nPageDescCount );
1949 SwPageDesc &rZeroDesc = m_pDoc->GetPageDesc( 0 );
1950 CPPUNIT_ASSERT_EQUAL( OUString("Page65535"), rDesc.GetName() );
1952 SwPageDesc aDesc( rDesc );
1953 const OUString aChanged("Changed01");
1954 aDesc.SetName( aChanged );
1955 m_pDoc->ChgPageDesc( nPageDescCount, aDesc );
1957 size_t nPos;
1958 SwPageDesc *pDesc = m_pDoc->FindPageDesc( aChanged, &nPos );
1959 CPPUNIT_ASSERT( pDesc != nullptr );
1960 CPPUNIT_ASSERT_EQUAL( nPageDescCount, nPos );
1962 // check if we didn't mess up PageDesc at pos 0
1963 // (happens with 16bit int overflow)
1964 OUString aZeroName = rZeroDesc.GetName();
1965 rZeroDesc = m_pDoc->GetPageDesc( 0 );
1966 CPPUNIT_ASSERT_EQUAL( aZeroName, rZeroDesc.GetName() );
1968 m_pDoc->DelPageDesc( aChanged, /*bBroadcast*/true );
1969 pDesc = m_pDoc->FindPageDesc( aChanged, &nPos );
1970 // not there anymore
1971 CPPUNIT_ASSERT( !pDesc );
1972 CPPUNIT_ASSERT_EQUAL( std::numeric_limits<size_t>::max(), nPos);
1974 // check if PageDesc at pos 0 is still there
1975 pDesc = m_pDoc->FindPageDesc( aZeroName, &nPos );
1976 CPPUNIT_ASSERT( pDesc != nullptr );
1977 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), nPos );
1980 void SwDocTest::testTdf92308()
1982 CPPUNIT_ASSERT_EQUAL(m_pDoc->HasInvisibleContent(), false);
1985 void SwDocTest::testTableCellComparison()
1987 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellsByColFirst("A1", "Z1") );
1988 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByColFirst("Z1", "A1") );
1989 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellsByColFirst("A1", "A1") );
1991 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByColFirst("A2", "A1") );
1992 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByColFirst("Z3", "A2") );
1993 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellsByColFirst("A3", "Z1") );
1995 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellsByRowFirst("A1", "Z1") );
1996 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByRowFirst("Z1", "A1") );
1997 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellsByRowFirst("A1", "A1") );
1999 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByRowFirst("A2", "A1") );
2000 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByRowFirst("Z3", "A2") );
2001 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByRowFirst("A3", "Z1") );
2003 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellRanges("A1", "A1", "A1", "A1", true) );
2004 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellRanges("A1", "Z1", "A1", "Z1", true) );
2005 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellRanges("A1", "Z1", "A1", "Z1", false) );
2007 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellRanges("A1", "Z1", "B1", "Z1", true) );
2008 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellRanges("A1", "Z1", "A2", "Z2", false) );
2009 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellRanges("A1", "Z1", "A2", "Z2", true) );
2010 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellRanges("A1", "Z1", "A6", "Z2", true) );
2012 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellRanges("B1", "Z1", "A1", "Z1", true) );
2013 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellRanges("A2", "Z2", "A1", "Z1", false) );
2014 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellRanges("A2", "Z2", "A1", "Z1", true) );
2015 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellRanges("A6", "Z2", "A1", "Z1", true) );
2017 OUString rCell1 = OUString("A1");
2018 OUString rCell2 = OUString("C5");
2020 sw_NormalizeRange(rCell1, rCell2);
2021 CPPUNIT_ASSERT_EQUAL( OUString("A1"), rCell1 );
2022 CPPUNIT_ASSERT_EQUAL( OUString("C5"), rCell2 );
2024 sw_NormalizeRange(rCell2, rCell1);
2025 CPPUNIT_ASSERT_EQUAL( OUString("C5"), rCell1 );
2026 CPPUNIT_ASSERT_EQUAL( OUString("A1"), rCell2 );
2028 rCell1 = OUString("A5");
2029 rCell2 = OUString("C1");
2031 sw_NormalizeRange(rCell1, rCell2);
2032 CPPUNIT_ASSERT_EQUAL( OUString("A1"), rCell1 );
2033 CPPUNIT_ASSERT_EQUAL( OUString("C5"), rCell2 );
2035 sw_NormalizeRange(rCell2, rCell1);
2036 CPPUNIT_ASSERT_EQUAL( OUString("C5"), rCell1 );
2037 CPPUNIT_ASSERT_EQUAL( OUString("A1"), rCell2 );
2039 CPPUNIT_ASSERT_EQUAL( OUString(), sw_GetCellName(-1, -1) );
2042 void SwDocTest::setUp()
2044 BootstrapFixture::setUp();
2046 SwGlobals::ensure();
2047 m_pDoc = new SwDoc;
2048 m_xDocShRef = new SwDocShell(m_pDoc, SfxObjectCreateMode::EMBEDDED);
2049 m_xDocShRef->DoInitNew();
2052 void SwDocTest::tearDown()
2054 m_pDoc = nullptr; // deleted by DoClose()
2055 m_xDocShRef->DoClose();
2056 m_xDocShRef.clear();
2058 BootstrapFixture::tearDown();
2061 CPPUNIT_TEST_SUITE_REGISTRATION(SwDocTest);
2063 CPPUNIT_PLUGIN_IMPLEMENT();
2065 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */