remove assert looking for new compatibilityMode DOCX
[LibreOffice.git] / sw / qa / core / uwriter.cxx
blob8a03254e7c5d24cff42c53958ec9035411efe235
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 <comphelper/processfactory.hxx>
16 #include <i18nutil/transliteration.hxx>
17 #include <editeng/adjustitem.hxx>
18 #include <editeng/boxitem.hxx>
19 #include <editeng/brushitem.hxx>
20 #include <editeng/colritem.hxx>
21 #include <editeng/contouritem.hxx>
22 #include <editeng/crossedoutitem.hxx>
23 #include <editeng/fhgtitem.hxx>
24 #include <editeng/fontitem.hxx>
25 #include <editeng/justifyitem.hxx>
26 #include <editeng/lineitem.hxx>
27 #include <editeng/postitem.hxx>
28 #include <editeng/shdditem.hxx>
29 #include <editeng/udlnitem.hxx>
30 #include <editeng/wghtitem.hxx>
31 #include <svl/intitem.hxx>
32 #include <svx/algitem.hxx>
33 #include <svx/rotmodit.hxx>
34 #include <tools/urlobj.hxx>
35 #include <unotools/tempfile.hxx>
36 #include <unotools/transliterationwrapper.hxx>
38 #include <editeng/langitem.hxx>
39 #include <editeng/charhiddenitem.hxx>
41 #include <sfx2/docfilt.hxx>
42 #include <sfx2/docfile.hxx>
44 #include <xmloff/odffields.hxx>
46 #include <breakit.hxx>
47 #include <doc.hxx>
48 #include <IDocumentRedlineAccess.hxx>
49 #include <IDocumentFieldsAccess.hxx>
50 #include <IDocumentStatistics.hxx>
51 #include <cellfml.hxx>
52 #include <docsh.hxx>
53 #include <docstat.hxx>
54 #include <docufld.hxx>
55 #include <fmtanchr.hxx>
56 #include <ndtxt.hxx>
57 #include <shellres.hxx>
58 #include <swscanner.hxx>
59 #include <swdll.hxx>
60 #include <swtypes.hxx>
61 #include <fmtftn.hxx>
62 #include <fmtrfmrk.hxx>
63 #include <fmtinfmt.hxx>
64 #include <fchrfmt.hxx>
65 #include <fmtfld.hxx>
66 #include <redline.hxx>
67 #include <docary.hxx>
68 #include <modeltoviewhelper.hxx>
69 #include <IMark.hxx>
70 #include <ring.hxx>
71 #include <calbck.hxx>
72 #include <pagedesc.hxx>
73 #include <calc.hxx>
74 #include <scriptinfo.hxx>
75 #include <rubylist.hxx>
76 #include <txatbase.hxx>
78 #include <tblafmt.hxx>
79 #include <unotbl.hxx>
80 #include <IDocumentMarkAccess.hxx>
81 #include <itabenum.hxx>
83 typedef rtl::Reference<SwDocShell> SwDocShellRef;
85 using namespace ::com::sun::star;
87 /* Implementation of Swdoc-Test class */
89 class SwDocTest : public test::BootstrapFixture
91 public:
92 SwDocTest()
93 : m_pDoc(nullptr)
97 virtual void setUp() override;
98 virtual void tearDown() override;
100 void testTableAutoFormats();
101 void testPageDescName();
102 void testFileNameFields();
103 void testDocStat();
104 void testModelToViewHelperPassthrough();
105 void testModelToViewHelperExpandFieldsExpandFootnote();
106 void testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode();
107 void testModelToViewHelperExpandFields();
108 void testModelToViewHelperExpandFieldsReplaceMode();
109 void testModelToViewHelperExpandFieldsHideInvisible();
110 void testModelToViewHelperExpandFieldsHideRedlined();
111 void testModelToViewHelperExpandFieldsHideInvisibleExpandFootnote();
112 void testModelToViewHelperExpandFieldsHideInvisibleExpandFootnoteReplaceMode();
113 void testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnote();
114 void testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnoteReplaceMode();
115 void testModelToViewHelperHideInvisibleHideRedlined();
116 void testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnote();
117 void testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnoteReplaceMode();
118 void testModelToViewHelperExpandFieldsExpandFootnote2();
119 void testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode2();
120 void testSwScanner();
121 void testUserPerceivedCharCount();
122 void testMergePortionsDeleteNotSorted();
123 void testGraphicAnchorDeletion();
124 void testTransliterate();
125 void testMarkMove();
126 void testFormulas();
127 void testIntrusiveRing();
128 void testClientModify();
129 void testBroadcastingModify();
130 void testWriterMultiListener();
131 void test64kPageDescs();
132 void testTdf92308();
133 void testTableCellComparison();
134 void testTdf156211();
135 void testFillRubyList();
136 void testSetRubyList();
138 CPPUNIT_TEST_SUITE(SwDocTest);
140 CPPUNIT_TEST(testTransliterate);
141 CPPUNIT_TEST(testTableAutoFormats);
142 CPPUNIT_TEST(testPageDescName);
143 CPPUNIT_TEST(testFileNameFields);
144 CPPUNIT_TEST(testDocStat);
145 CPPUNIT_TEST(testModelToViewHelperPassthrough);
146 CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnote);
147 CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode);
148 CPPUNIT_TEST(testModelToViewHelperExpandFields);
149 CPPUNIT_TEST(testModelToViewHelperExpandFieldsReplaceMode);
150 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisible);
151 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideRedlined);
152 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleExpandFootnote);
153 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleExpandFootnoteReplaceMode);
154 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnote);
155 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnoteReplaceMode);
156 CPPUNIT_TEST(testModelToViewHelperHideInvisibleHideRedlined);
157 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnote);
158 CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnoteReplaceMode);
159 CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnote2);
160 CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode2);
161 CPPUNIT_TEST(testSwScanner);
162 CPPUNIT_TEST(testUserPerceivedCharCount);
163 CPPUNIT_TEST(testMergePortionsDeleteNotSorted);
164 CPPUNIT_TEST(testGraphicAnchorDeletion);
165 CPPUNIT_TEST(testMarkMove);
166 CPPUNIT_TEST(testFormulas);
167 CPPUNIT_TEST(testIntrusiveRing);
168 CPPUNIT_TEST(testClientModify);
169 CPPUNIT_TEST(testBroadcastingModify);
170 CPPUNIT_TEST(testWriterMultiListener);
171 CPPUNIT_TEST(test64kPageDescs);
172 CPPUNIT_TEST(testTdf92308);
173 CPPUNIT_TEST(testTableCellComparison);
174 CPPUNIT_TEST(testTdf156211);
175 CPPUNIT_TEST(testFillRubyList);
176 CPPUNIT_TEST(testSetRubyList);
177 CPPUNIT_TEST_SUITE_END();
179 private:
180 SwDoc *m_pDoc;
181 SwDocShellRef m_xDocShRef;
184 void SwDocTest::testPageDescName()
186 ShellResource aShellResources;
188 std::vector<OUString> aResults;
190 //These names must be unique for each different combination, otherwise
191 //duplicate page description names may exist, which will causes lookup
192 //by name to be incorrect, and so the corresponding export to .odt
193 aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::NORMAL_PAGE));
194 aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::FIRST_PAGE));
195 aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::FOLLOW_PAGE));
197 std::sort(aResults.begin(), aResults.end());
198 aResults.erase(std::unique(aResults.begin(), aResults.end()), aResults.end());
200 CPPUNIT_ASSERT_EQUAL_MESSAGE("GetPageDescName results must be unique", static_cast<size_t>(3), aResults.size());
203 //See https://bugs.libreoffice.org/show_bug.cgi?id=32463
204 void SwDocTest::testFileNameFields()
206 //Here's a file name with some chars in it that will be %% encoded, when expanding
207 //SwFileNameFields we want to restore the original readable filename
208 utl::TempFileNamed aTempFile(u"demo [name]");
209 aTempFile.EnableKillingFile();
211 INetURLObject aTempFileURL(aTempFile.GetURL());
212 OUString sFileURL = aTempFileURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
213 SfxMedium aDstMed(sFileURL, StreamMode::STD_READWRITE);
215 auto pFilter = std::make_shared<SfxFilter>(
216 "Text",
217 OUString(), SfxFilterFlags::NONE, SotClipboardFormatId::NONE, OUString(), OUString(),
218 "TEXT", OUString() );
219 aDstMed.SetFilter(pFilter);
221 m_xDocShRef->DoSaveAs(aDstMed);
222 m_xDocShRef->DoSaveCompleted(&aDstMed);
224 const INetURLObject &rUrlObj = m_xDocShRef->GetMedium()->GetURLObject();
226 SwFileNameFieldType aNameField(*m_pDoc);
229 OUString sResult(aNameField.Expand(FF_NAME));
230 OUString sExpected(rUrlObj.getName(INetURLObject::LAST_SEGMENT,
231 true,INetURLObject::DecodeMechanism::WithCharset));
232 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected Readable FileName", sExpected, sResult);
236 OUString sResult(aNameField.Expand(FF_PATHNAME));
237 OUString sExpected(rUrlObj.GetFull());
238 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected Readable FileName", sExpected, sResult);
242 OUString sResult(aNameField.Expand(FF_PATH));
243 INetURLObject aTemp(rUrlObj);
244 aTemp.removeSegment();
245 OUString sExpected(aTemp.PathToFileName());
246 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected Readable FileName", sExpected, sResult);
250 OUString sResult(aNameField.Expand(FF_NAME_NOEXT));
251 OUString sExpected(rUrlObj.getName(INetURLObject::LAST_SEGMENT,
252 true,INetURLObject::DecodeMechanism::WithCharset));
253 //Chop off .tmp
254 sExpected = sExpected.copy(0, sExpected.getLength() - 4);
255 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected Readable FileName", sExpected, sResult);
258 m_xDocShRef->DoInitNew();
261 //See http://lists.freedesktop.org/archives/libreoffice/2011-August/016666.html
262 //Remove unnecessary parameter to IDocumentStatistics::UpdateDocStat for
263 //motivation
264 void SwDocTest::testDocStat()
266 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected initial 0 count", static_cast<sal_uLong>(0), m_pDoc->getIDocumentStatistics().GetDocStat().nChar);
268 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
269 SwPaM aPaM(aIdx);
271 OUString sText(u"Hello World"_ustr);
272 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sText);
274 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should still be non-updated 0 count", static_cast<sal_uLong>(0), m_pDoc->getIDocumentStatistics().GetDocStat().nChar);
276 SwDocStat aDocStat = m_pDoc->getIDocumentStatistics().GetUpdatedDocStat( false, true );
277 sal_uLong nLen = static_cast<sal_uLong>(sText.getLength());
279 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should now have updated count", nLen, aDocStat.nChar);
281 CPPUNIT_ASSERT_EQUAL_MESSAGE("And cache is updated too", nLen, m_pDoc->getIDocumentStatistics().GetDocStat().nChar);
284 //For UI character counts we should follow UAX#29 and display the user
285 //perceived characters, not the number of codepoints, nor the number of code
286 //units http://unicode.org/reports/tr29/
287 void SwDocTest::testUserPerceivedCharCount()
289 SwBreakIt *pBreakIter = SwBreakIt::Get();
291 //Grapheme example, two different unicode code-points perceived by the user as a single
292 //glyph
293 static constexpr OUStringLiteral sALEF_QAMATS = u"\u05D0\u05B8";
294 sal_Int32 nGraphemeCount = pBreakIter->getGraphemeCount(sALEF_QAMATS);
295 CPPUNIT_ASSERT_EQUAL_MESSAGE("Grapheme Count should be 1", static_cast<sal_Int32>(1), nGraphemeCount);
297 //Surrogate pair example, one single unicode code-point (U+1D11E)
298 //represented as two code units in UTF-16
299 static constexpr OUStringLiteral sGCLEF = u"\U0001D11E";
300 sal_Int32 nCount = pBreakIter->getGraphemeCount(sGCLEF);
301 CPPUNIT_ASSERT_EQUAL_MESSAGE("Surrogate Pair should be counted as single character", static_cast<sal_Int32>(1), nCount);
304 static SwTextNode* getModelToViewTestDocument(SwDoc *pDoc)
306 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
307 SwPaM aPaM(aIdx);
309 SwFormatFootnote aFootnote;
310 aFootnote.SetNumStr(u"foo"_ustr);
312 pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
313 pDoc->getIDocumentContentOperations().InsertString(aPaM, u"AAAAA BBBBB "_ustr);
314 SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
315 sal_Int32 nPos = aPaM.GetPoint()->GetContentIndex();
316 pTextNode->InsertItem(aFootnote, nPos, nPos);
317 pDoc->getIDocumentContentOperations().InsertString(aPaM, u" CCCCC "_ustr);
318 nPos = aPaM.GetPoint()->GetContentIndex();
319 pTextNode->InsertItem(aFootnote, nPos, nPos);
320 pDoc->getIDocumentContentOperations().InsertString(aPaM, u" DDDDD"_ustr);
321 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>((4*5) + 5 + 2), pTextNode->GetText().getLength());
323 //set start of selection to first B
324 aPaM.GetPoint()->nContent.Assign(aPaM.GetPointContentNode(), 6);
325 aPaM.SetMark();
326 //set end of selection to last C
327 aPaM.GetPoint()->nContent.Assign(aPaM.GetPointContentNode(), 14);
328 //set character attribute hidden on range
329 SvxCharHiddenItem aHidden(true, RES_CHRATR_HIDDEN);
330 pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aHidden );
331 aPaM.DeleteMark();
333 //turn on red-lining and show changes
334 pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete|RedlineFlags::ShowInsert);
335 CPPUNIT_ASSERT_MESSAGE("redlining should be on", pDoc->getIDocumentRedlineAccess().IsRedlineOn());
336 CPPUNIT_ASSERT_MESSAGE("redlines should be visible", IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
338 //set start of selection to last A
339 aPaM.GetPoint()->nContent.Assign(aPaM.GetPointContentNode(), 4);
340 aPaM.SetMark();
341 //set end of selection to second last B
342 aPaM.GetPoint()->nContent.Assign(aPaM.GetPointContentNode(), 9);
343 pDoc->getIDocumentContentOperations().DeleteAndJoin(aPaM); //redline-aware deletion api
344 aPaM.DeleteMark();
346 return pTextNode;
349 static SwTextNode* getModelToViewTestDocument2(SwDoc *pDoc)
351 getModelToViewTestDocument(pDoc);
353 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
354 SwPaM aPaM(aIdx);
356 pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
357 pDoc->getIDocumentContentOperations().InsertString(aPaM, u"AAAAA"_ustr);
358 IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess();
359 sw::mark::Fieldmark *pFieldmark =
360 pMarksAccess->makeNoTextFieldBookmark(aPaM, u"test"_ustr, ODF_FORMDROPDOWN);
361 CPPUNIT_ASSERT(pFieldmark);
362 uno::Sequence< OUString > vListEntries { u"BBBBB"_ustr };
363 (*pFieldmark->GetParameters())[ODF_FORMDROPDOWN_LISTENTRY] <<= vListEntries;
364 (*pFieldmark->GetParameters())[ODF_FORMDROPDOWN_RESULT] <<= sal_Int32(0);
365 pDoc->getIDocumentContentOperations().InsertString(aPaM, u"CCCCC"_ustr);
366 SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
367 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11),
368 pTextNode->GetText().getLength());
370 return pTextNode;
373 void SwDocTest::testModelToViewHelperPassthrough()
375 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
377 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr, ExpandMode::PassThrough);
378 OUString sViewText = aModelToViewHelper.getViewText();
379 OUString sModelText = pTextNode->GetText();
380 CPPUNIT_ASSERT_EQUAL(sModelText, sViewText);
383 void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnote()
385 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
387 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
388 ExpandMode::ExpandFields | ExpandMode::ExpandFootnote);
389 OUString sViewText = aModelToViewHelper.getViewText();
390 CPPUNIT_ASSERT_EQUAL(
391 u"AAAAA BBBBB foo CCCCC foo DDDDD"_ustr, sViewText);
394 void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode()
396 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
398 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
399 ExpandMode::ExpandFields | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
400 OUString sViewText = aModelToViewHelper.getViewText();
401 CPPUNIT_ASSERT_EQUAL(
402 OUString("AAAAA BBBBB " + OUStringChar(CHAR_ZWSP) + " CCCCC " + OUStringChar(CHAR_ZWSP) + " DDDDD"),
403 sViewText);
404 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2),
405 aModelToViewHelper.getFootnotePositions().size());
406 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12),
407 aModelToViewHelper.getFootnotePositions()[0]);
408 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(20),
409 aModelToViewHelper.getFootnotePositions()[1]);
410 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
411 aModelToViewHelper.getFieldPositions().size());
414 void SwDocTest::testModelToViewHelperExpandFields()
416 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
418 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr, ExpandMode::ExpandFields);
419 OUString sViewText = aModelToViewHelper.getViewText();
420 CPPUNIT_ASSERT_EQUAL(
421 u"AAAAA BBBBB CCCCC DDDDD"_ustr, sViewText);
424 void SwDocTest::testModelToViewHelperExpandFieldsReplaceMode()
426 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
428 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
429 ExpandMode::ExpandFields | ExpandMode::ReplaceMode);
430 OUString sViewText = aModelToViewHelper.getViewText();
431 CPPUNIT_ASSERT_EQUAL(u"AAAAA BBBBB CCCCC DDDDD"_ustr,
432 sViewText);
433 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
434 aModelToViewHelper.getFootnotePositions().size());
435 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
436 aModelToViewHelper.getFieldPositions().size());
439 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisible()
441 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
443 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr, ExpandMode::HideInvisible);
444 OUString sViewText = aModelToViewHelper.getViewText();
445 CPPUNIT_ASSERT_EQUAL(
446 OUString("AAAAA CCCCC " + OUStringChar(CH_TXTATR_BREAKWORD) + " DDDDD"),
447 sViewText);
450 void SwDocTest::testModelToViewHelperExpandFieldsHideRedlined()
452 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
454 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr, ExpandMode::HideDeletions);
455 OUString sViewText = aModelToViewHelper.getViewText();
456 CPPUNIT_ASSERT_EQUAL(
457 OUString("AAAABB " + OUStringChar(CH_TXTATR_BREAKWORD) + " CCCCC " + OUStringChar(CH_TXTATR_BREAKWORD) + " DDDDD"),
458 sViewText);
461 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleExpandFootnote()
463 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
465 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
466 ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::ExpandFootnote);
467 OUString sViewText = aModelToViewHelper.getViewText();
468 CPPUNIT_ASSERT_EQUAL(u"AAAAA CCCCC foo DDDDD"_ustr, sViewText);
471 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleExpandFootnoteReplaceMode()
473 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
475 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
476 ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
477 OUString sViewText = aModelToViewHelper.getViewText();
478 CPPUNIT_ASSERT_EQUAL(
479 OUString("AAAAA CCCCC " + OUStringChar(CHAR_ZWSP) + " DDDDD"),
480 sViewText);
481 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
482 aModelToViewHelper.getFootnotePositions().size());
483 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12),
484 aModelToViewHelper.getFootnotePositions()[0]);
485 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
486 aModelToViewHelper.getFieldPositions().size());
489 void SwDocTest::testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnote()
491 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
493 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
494 ExpandMode::ExpandFields | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote);
495 OUString sViewText = aModelToViewHelper.getViewText();
496 CPPUNIT_ASSERT_EQUAL(
497 u"AAAABB foo CCCCC foo DDDDD"_ustr, sViewText);
500 void SwDocTest::testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnoteReplaceMode()
502 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
504 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
505 ExpandMode::ExpandFields | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
506 OUString sViewText = aModelToViewHelper.getViewText();
507 CPPUNIT_ASSERT_EQUAL(
508 OUString("AAAABB " + OUStringChar(CHAR_ZWSP) + " CCCCC " + OUStringChar(CHAR_ZWSP) + " DDDDD"),
509 sViewText);
510 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2),
511 aModelToViewHelper.getFootnotePositions().size());
512 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(7),
513 aModelToViewHelper.getFootnotePositions()[0]);
514 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(15),
515 aModelToViewHelper.getFootnotePositions()[1]);
516 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
517 aModelToViewHelper.getFieldPositions().size());
520 void SwDocTest::testModelToViewHelperHideInvisibleHideRedlined()
522 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
524 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
525 ExpandMode::HideInvisible | ExpandMode::HideDeletions);
526 OUString sViewText = aModelToViewHelper.getViewText();
527 OUString aBuffer = "AAAACCCCC " +
528 OUStringChar(CH_TXTATR_BREAKWORD) +
529 " DDDDD";
530 CPPUNIT_ASSERT_EQUAL(aBuffer, sViewText);
533 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnote()
535 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
537 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
538 ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote);
539 OUString sViewText = aModelToViewHelper.getViewText();
540 CPPUNIT_ASSERT_EQUAL(u"AAAACCCCC foo DDDDD"_ustr, sViewText);
543 void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnoteReplaceMode()
545 SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
547 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
548 ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
549 OUString sViewText = aModelToViewHelper.getViewText();
550 CPPUNIT_ASSERT_EQUAL(sViewText,
551 OUString("AAAACCCCC " + OUStringChar(CHAR_ZWSP) + " DDDDD"));
552 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
553 aModelToViewHelper.getFootnotePositions().size());
554 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(10),
555 aModelToViewHelper.getFootnotePositions()[0]);
556 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
557 aModelToViewHelper.getFieldPositions().size());
560 void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnote2()
562 SwTextNode* pTextNode = getModelToViewTestDocument2(m_pDoc);
564 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
565 ExpandMode::ExpandFields | ExpandMode::ExpandFootnote);
566 OUString sViewText = aModelToViewHelper.getViewText();
567 CPPUNIT_ASSERT_EQUAL(u"AAAAABBBBBCCCCC"_ustr, sViewText);
570 void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode2()
572 SwTextNode* pTextNode = getModelToViewTestDocument2(m_pDoc);
574 ModelToViewHelper aModelToViewHelper(*pTextNode, nullptr,
575 ExpandMode::ExpandFields | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
576 OUString sViewText = aModelToViewHelper.getViewText();
577 CPPUNIT_ASSERT_EQUAL(
578 OUString("AAAAA" + OUStringChar(CHAR_ZWSP) + "CCCCC"),
579 sViewText);
580 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
581 aModelToViewHelper.getFootnotePositions().size());
582 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
583 aModelToViewHelper.getFieldPositions().size());
584 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5),
585 aModelToViewHelper.getFieldPositions()[0]);
588 void SwDocTest::testSwScanner()
590 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
591 SwPaM aPaM(aIdx);
593 SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
595 CPPUNIT_ASSERT_MESSAGE("Has Text Node", pTextNode);
597 //See https://bugs.libreoffice.org/show_bug.cgi?id=40449
598 //See https://bugs.libreoffice.org/show_bug.cgi?id=39365
599 //Use a temporary OUString as the arg, as that's the trouble behind
600 //fdo#40449 and fdo#39365
602 SwScanner aScanner(*pTextNode,
603 u"Hello World"_ustr,
604 nullptr, ModelToViewHelper(), i18n::WordType::DICTIONARY_WORD, 0,
605 RTL_CONSTASCII_LENGTH("Hello World"));
607 bool bFirstOk = aScanner.NextWord();
608 CPPUNIT_ASSERT_MESSAGE("First Token", bFirstOk);
609 const OUString &rHello = aScanner.GetWord();
610 CPPUNIT_ASSERT_EQUAL(u"Hello"_ustr, rHello);
612 bool bSecondOk = aScanner.NextWord();
613 CPPUNIT_ASSERT_MESSAGE("Second Token", bSecondOk);
614 const OUString &rWorld = aScanner.GetWord();
615 CPPUNIT_ASSERT_EQUAL(u"World"_ustr, rWorld);
618 //See https://www.libreoffice.org/bugzilla/show_bug.cgi?id=45271
620 static constexpr OUString IDEOGRAPHICFULLSTOP_D = u"\u3002D"_ustr;
622 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, IDEOGRAPHICFULLSTOP_D);
624 SvxLanguageItem aCJKLangItem( LANGUAGE_CHINESE_SIMPLIFIED, RES_CHRATR_CJK_LANGUAGE );
625 SvxLanguageItem aWestLangItem( LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE );
626 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aCJKLangItem );
627 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aWestLangItem );
629 SwDocStat aDocStat;
630 pTextNode = aPaM.GetPointNode().GetTextNode();
631 pTextNode->CountWords(aDocStat, 0, IDEOGRAPHICFULLSTOP_D.getLength());
633 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), aDocStat.nChar);
634 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), aDocStat.nCharExcludingSpaces);
637 static constexpr OUString test =
638 u"\u3053\u306E\u65E5\u672C\u8A9E\u306F\u6B63\u3057"
639 "\u304F\u6570\u3048\u3089\u308C\u308B\u3067\u3057"
640 "\u3087\u3046\u304B\u3002And "
641 "let's th"
642 "row some"
643 " English"
644 " in to m"
645 "ake it i"
646 "nteresti"
647 "ng. \u305D\u3057\u3066"
648 "\u3001\u307E\u305F\u65E5\u672C\u8A9E\u3000\u3000"
649 "\u3067\u3082\u4ECA\u56DE\u306F\u7A7A\u767D\u3092"
650 "\u3000\u3000\u5165\u308C\u307E\u3057\u305F\u3002"
651 " So how"
652 " does th"
653 "is do? "_ustr;
654 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
655 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, test);
657 SvxLanguageItem aCJKLangItem( LANGUAGE_JAPANESE, RES_CHRATR_CJK_LANGUAGE );
658 SvxLanguageItem aWestLangItem( LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE );
659 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aCJKLangItem );
660 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aWestLangItem );
662 SwDocStat aDocStat;
663 pTextNode = aPaM.GetPointNode().GetTextNode();
664 pTextNode->CountWords(aDocStat, 0, test.getLength());
665 CPPUNIT_ASSERT_EQUAL_MESSAGE("words", static_cast<sal_uLong>(58), aDocStat.nWord);
666 CPPUNIT_ASSERT_EQUAL_MESSAGE("Asian characters and Korean words", static_cast<sal_uLong>(43), aDocStat.nAsianWord);
667 CPPUNIT_ASSERT_EQUAL_MESSAGE("non-whitespace chars", static_cast<sal_uLong>(105), aDocStat.nCharExcludingSpaces);
668 CPPUNIT_ASSERT_EQUAL_MESSAGE("characters", static_cast<sal_uLong>(128), aDocStat.nChar);
671 //See https://bz.apache.org/ooo/show_bug.cgi?id=89042
672 //See https://bugs.libreoffice.org/show_bug.cgi?id=53399
674 SwDocStat aDocStat;
676 static constexpr OUString aShouldBeThree =
677 u"Should "
678 "\u2018be thr"
679 "ee\u2019"_ustr;
681 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
682 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, aShouldBeThree);
683 pTextNode = aPaM.GetPointNode().GetTextNode();
684 pTextNode->CountWords(aDocStat, 0, aShouldBeThree.getLength());
685 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(3), aDocStat.nWord);
687 static constexpr OUString aShouldBeFive =
688 u"french "
689 // << nbsp
690 "\u00AB\u00A0savoi"
691 // nnbsp
692 "r\u202fcalcu"
693 // idspace >>
694 "ler\u3000\u00BB"_ustr;
696 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
697 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, aShouldBeFive);
698 pTextNode = aPaM.GetPointNode().GetTextNode();
699 aDocStat.Reset();
700 pTextNode->CountWords(aDocStat, 0, aShouldBeFive.getLength());
701 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(5), aDocStat.nWord);
704 //See https://bugs.libreoffice.org/show_bug.cgi?id=49629
706 SwDocStat aDocStat;
708 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
709 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"Apple"_ustr);
710 pTextNode = aPaM.GetPointNode().GetTextNode();
711 sal_Int32 nPos = aPaM.GetPoint()->GetContentIndex();
712 SwFormatFootnote aFootnote;
713 aFootnote.SetNumStr(u"banana"_ustr);
714 SwTextAttr* pTA = pTextNode->InsertItem(aFootnote, nPos, nPos);
715 CPPUNIT_ASSERT(pTA);
716 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6), pTextNode->Len()); //Apple + 0x02
717 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
718 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), aDocStat.nWord);
719 CPPUNIT_ASSERT_EQUAL_MESSAGE("footnote should be expanded", static_cast<sal_uLong>(11), aDocStat.nChar);
721 const sal_Int32 nNextPos = aPaM.GetPoint()->GetContentIndex();
722 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(nPos+1), nNextPos);
723 SwFormatRefMark aRef(u"refmark"_ustr);
724 pTA = pTextNode->InsertItem(aRef, nNextPos, nNextPos);
725 CPPUNIT_ASSERT(pTA);
727 aDocStat.Reset();
728 pTextNode->SetWordCountDirty(true);
729 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
730 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), aDocStat.nWord);
731 CPPUNIT_ASSERT_EQUAL_MESSAGE("refmark anchor should not be counted", static_cast<sal_uLong>(11), aDocStat.nChar);
733 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
734 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"Apple"_ustr);
736 DateTime aDate(DateTime::SYSTEM);
737 SwPostItField aPostIt(
738 static_cast<SwPostItFieldType*>(m_pDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit)), u"An Author"_ustr,
739 u"Some Text"_ustr, u"Initials"_ustr, u"Name"_ustr, aDate );
740 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, SwFormatField(aPostIt));
742 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"Apple"_ustr);
743 pTextNode = aPaM.GetPointNode().GetTextNode();
744 aDocStat.Reset();
745 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
746 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), aDocStat.nWord);
747 CPPUNIT_ASSERT_EQUAL_MESSAGE("postit anchor should effectively not exist", static_cast<sal_uLong>(10), aDocStat.nChar);
748 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11), pTextNode->Len());
750 aDocStat.Reset();
753 //See https://bugs.libreoffice.org/show_bug.cgi?id=46757
755 SwDocStat aDocStat;
757 static constexpr OUString aString = u"Lorem ipsum"_ustr;
758 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
759 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, aString);
760 pTextNode = aPaM.GetPointNode().GetTextNode();
761 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
762 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), aDocStat.nWord);
764 //turn on red-lining and show changes
765 m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete|RedlineFlags::ShowInsert);
766 CPPUNIT_ASSERT_MESSAGE("redlining should be on", m_pDoc->getIDocumentRedlineAccess().IsRedlineOn());
767 CPPUNIT_ASSERT_MESSAGE("redlines should be visible", IDocumentRedlineAccess::IsShowChanges(m_pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
769 //delete everything except the first word
770 aPaM.SetMark(); //set start of selection to current pos
771 aPaM.GetPoint()->nContent.Assign(aPaM.GetPointContentNode(), 5); //set end of selection to fifth char of current node
772 m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aPaM); //redline-aware deletion api
773 //"real underlying text should be the same"
774 CPPUNIT_ASSERT_EQUAL(aString, pTextNode->GetText());
776 aDocStat.Reset();
777 pTextNode->SetWordCountDirty(true);
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 pTextNode->SetWordCountDirty(true);
783 //keep red-lining on but hide changes
784 m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On);
785 CPPUNIT_ASSERT_MESSAGE("redlining should be still on", m_pDoc->getIDocumentRedlineAccess().IsRedlineOn());
786 CPPUNIT_ASSERT_MESSAGE("redlines should be invisible", !IDocumentRedlineAccess::IsShowChanges(m_pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
788 aDocStat.Reset();
789 pTextNode->CountWords(aDocStat, 0, pTextNode->Len()); //but word-counting the text should only count the non-deleted text
790 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), aDocStat.nWord);
792 OUString sLorem = pTextNode->GetText();
793 CPPUNIT_ASSERT_EQUAL(u"Lorem"_ustr, sLorem);
795 const SwRedlineTable& rTable = m_pDoc->getIDocumentRedlineAccess().GetRedlineTable();
797 SwNodes& rNds = m_pDoc->GetNodes();
798 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), rTable.size());
800 const SwNodeIndex* pNodeIdx = rTable[0]->GetContentIdx();
801 CPPUNIT_ASSERT(pNodeIdx);
803 pTextNode = rNds[ pNodeIdx->GetIndex() + 1 ]->GetTextNode(); //first deleted txtnode
804 CPPUNIT_ASSERT(pTextNode);
806 OUString sIpsum = pTextNode->GetText();
807 CPPUNIT_ASSERT_EQUAL(u" ipsum"_ustr, sIpsum);
809 aDocStat.Reset();
810 pTextNode->CountWords(aDocStat, 0, pTextNode->Len()); //word-counting the text should only count the non-deleted text, and this whole chunk should be ignored
811 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), aDocStat.nWord);
812 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), aDocStat.nChar);
814 // https://bugs.libreoffice.org/show_bug.cgi?id=68347 we do want to count
815 // redline *added* text though
816 m_pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete|RedlineFlags::ShowInsert);
817 aPaM.DeleteMark();
818 aPaM.GetPoint()->nContent.Assign(aPaM.GetPointContentNode(), 0);
819 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"redline-new-text "_ustr);
820 aDocStat.Reset();
821 pTextNode = aPaM.GetPointNode().GetTextNode();
822 pTextNode->SetWordCountDirty(true);
823 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
824 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), aDocStat.nWord);
825 //redline-new-text Lorem ipsum
826 //+++++++++++++++++ ------
827 //select start of original text and part of deleted text
828 aDocStat.Reset();
829 pTextNode->CountWords(aDocStat, 17, 25);
830 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(5), aDocStat.nChar);
833 //See https://bugs.libreoffice.org/show_bug.cgi?id=38983
835 SwDocStat aDocStat;
837 OUString sTemplate(u"ThisXis a test."_ustr);
839 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
840 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', ' '));
841 pTextNode = aPaM.GetPointNode().GetTextNode();
842 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
843 CPPUNIT_ASSERT_EQUAL(sal_uLong(4), aDocStat.nWord);
844 CPPUNIT_ASSERT_EQUAL(sal_uLong(12), aDocStat.nCharExcludingSpaces);
845 CPPUNIT_ASSERT_EQUAL(sal_uLong(15), aDocStat.nChar);
846 aDocStat.Reset();
848 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
849 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll("X", " = "));
850 pTextNode = aPaM.GetPointNode().GetTextNode();
851 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
852 CPPUNIT_ASSERT_EQUAL(sal_uLong(5), aDocStat.nWord);
853 CPPUNIT_ASSERT_EQUAL(sal_uLong(13), aDocStat.nCharExcludingSpaces);
854 CPPUNIT_ASSERT_EQUAL(sal_uLong(17), aDocStat.nChar);
855 aDocStat.Reset();
857 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
858 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll("X", " _ "));
859 pTextNode = aPaM.GetPointNode().GetTextNode();
860 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
861 CPPUNIT_ASSERT_EQUAL(sal_uLong(5), aDocStat.nWord);
862 CPPUNIT_ASSERT_EQUAL(sal_uLong(13), aDocStat.nCharExcludingSpaces);
863 CPPUNIT_ASSERT_EQUAL(sal_uLong(17), aDocStat.nChar);
864 aDocStat.Reset();
866 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
867 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll("X", " -- "));
868 pTextNode = aPaM.GetPointNode().GetTextNode();
869 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
870 CPPUNIT_ASSERT_EQUAL(sal_uLong(5), aDocStat.nWord);
871 CPPUNIT_ASSERT_EQUAL(sal_uLong(14), aDocStat.nCharExcludingSpaces);
872 CPPUNIT_ASSERT_EQUAL(sal_uLong(18), aDocStat.nChar);
873 aDocStat.Reset();
875 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
876 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', '_'));
877 pTextNode = aPaM.GetPointNode().GetTextNode();
878 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
879 CPPUNIT_ASSERT_EQUAL(sal_uLong(3), aDocStat.nWord);
880 CPPUNIT_ASSERT_EQUAL(sal_uLong(13), aDocStat.nCharExcludingSpaces);
881 CPPUNIT_ASSERT_EQUAL(sal_uLong(15), aDocStat.nChar);
882 aDocStat.Reset();
884 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
885 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', '-'));
886 pTextNode = aPaM.GetPointNode().GetTextNode();
887 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
888 CPPUNIT_ASSERT_EQUAL(sal_uLong(3), aDocStat.nWord);
889 CPPUNIT_ASSERT_EQUAL(sal_uLong(13), aDocStat.nCharExcludingSpaces);
890 CPPUNIT_ASSERT_EQUAL(sal_uLong(15), aDocStat.nChar);
891 aDocStat.Reset();
893 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
894 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2012));
895 pTextNode = aPaM.GetPointNode().GetTextNode();
896 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
897 CPPUNIT_ASSERT_EQUAL(sal_uLong(3), aDocStat.nWord);
898 CPPUNIT_ASSERT_EQUAL(sal_uLong(13), aDocStat.nCharExcludingSpaces);
899 CPPUNIT_ASSERT_EQUAL(sal_uLong(15), aDocStat.nChar);
900 aDocStat.Reset();
902 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
903 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2015));
904 pTextNode = aPaM.GetPointNode().GetTextNode();
905 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
906 CPPUNIT_ASSERT_EQUAL(sal_uLong(3), aDocStat.nWord);
907 CPPUNIT_ASSERT_EQUAL(sal_uLong(13), aDocStat.nCharExcludingSpaces);
908 CPPUNIT_ASSERT_EQUAL(sal_uLong(15), aDocStat.nChar);
909 aDocStat.Reset();
911 //But default configuration should, msword-alike treat emdash
912 //and endash as word separators for word-counting
913 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
914 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2013));
915 pTextNode = aPaM.GetPointNode().GetTextNode();
916 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
917 CPPUNIT_ASSERT_EQUAL(sal_uLong(4), aDocStat.nWord);
918 CPPUNIT_ASSERT_EQUAL(sal_uLong(13), aDocStat.nCharExcludingSpaces);
919 CPPUNIT_ASSERT_EQUAL(sal_uLong(15), aDocStat.nChar);
920 aDocStat.Reset();
922 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
923 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2014));
924 pTextNode = aPaM.GetPointNode().GetTextNode();
925 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
926 CPPUNIT_ASSERT_EQUAL(sal_uLong(4), aDocStat.nWord);
927 CPPUNIT_ASSERT_EQUAL(sal_uLong(13), aDocStat.nCharExcludingSpaces);
928 CPPUNIT_ASSERT_EQUAL(sal_uLong(15), aDocStat.nChar);
929 aDocStat.Reset();
931 static constexpr OUStringLiteral sChunk = u" \u2013 ";
932 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
933 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll("X", sChunk));
934 pTextNode = aPaM.GetPointNode().GetTextNode();
935 pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
936 CPPUNIT_ASSERT_EQUAL(sal_uLong(4), aDocStat.nWord);
937 CPPUNIT_ASSERT_EQUAL(sal_uLong(13), aDocStat.nCharExcludingSpaces);
938 CPPUNIT_ASSERT_EQUAL(sal_uLong(17), aDocStat.nChar);
939 aDocStat.Reset();
942 // tdf#150621 Korean words should be counted individually, rather than by syllable.
944 // Per i#80815, the intention for the word count feature is to emulate the behavior of MS Word.
946 auto fnAssertWords = [&](const OUString& aStr, sal_uLong nWords, sal_uLong nAsianWords)
948 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
950 SvxLanguageItem aCJKLangItem(LANGUAGE_KOREAN, RES_CHRATR_CJK_LANGUAGE);
951 SvxLanguageItem aWestLangItem(LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE);
952 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aCJKLangItem);
953 m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aWestLangItem);
955 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, aStr);
957 SwDocStat aDocStat;
958 pTextNode = aPaM.GetPointNode().GetTextNode();
959 pTextNode->CountWords(aDocStat, 0, aStr.getLength());
960 CPPUNIT_ASSERT_EQUAL_MESSAGE("words", nWords, aDocStat.nWord);
961 CPPUNIT_ASSERT_EQUAL_MESSAGE("Asian characters and Korean words", nAsianWords,
962 aDocStat.nAsianWord);
965 // Basic case: Korean words are counted as space-delimited. In particular, grammatical
966 // particles are treated as part of the previous word.
967 fnAssertWords(u"저는 영화를 봤어요"_ustr, 3, 3);
969 // Mixed script: Korean is mostly written in hangul, but hanja are still used in certain
970 // situations (e.g. abbreviations in newspaper articles). For Chinese and Japanese, such
971 // ideographs would be counted individually as words. In Korean, however, they are treated
972 // no differently than hangul characters.
973 fnAssertWords(u"尹탄핵"_ustr, 1, 1);
974 fnAssertWords(u"尹 탄핵"_ustr, 2, 2);
976 // These mixed-script results are anomalous, but reflect the behavior of MSW.
977 fnAssertWords(u"불렀다...與"_ustr, 1, 1);
978 fnAssertWords(u"불렀다 ...與"_ustr, 2, 1);
979 fnAssertWords(u"불렀다 ... 與"_ustr, 3, 2);
983 void SwDocTest::testMergePortionsDeleteNotSorted()
985 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
986 SwPaM aPaM(aIdx);
987 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u" AABBCC"_ustr);
989 SwCharFormat *const pCharFormat(m_pDoc->MakeCharFormat(u"foo"_ustr, nullptr));
990 SwFormatCharFormat const charFormat(pCharFormat);
992 SwFormatINetFormat const inetFormat(u"http://example.com"_ustr, u""_ustr);
994 IDocumentContentOperations & rIDCO(m_pDoc->getIDocumentContentOperations());
995 aPaM.SetMark();
996 aPaM.GetPoint()->nContent = 2;
997 aPaM.GetMark()->nContent = 4;
998 rIDCO.InsertPoolItem(aPaM, charFormat);
999 aPaM.GetPoint()->nContent = 2;
1000 aPaM.GetMark()->nContent = 5;
1001 rIDCO.InsertPoolItem(aPaM, inetFormat);
1002 aPaM.GetPoint()->nContent = 6;
1003 aPaM.GetMark()->nContent = 8;
1004 rIDCO.InsertPoolItem(aPaM, charFormat);
1005 aPaM.GetPoint()->nContent = 4;
1006 aPaM.GetMark()->nContent = 6;
1007 // this triggered an STL assert in SwpHints::MergePortions()
1008 rIDCO.InsertPoolItem(aPaM, charFormat);
1011 //See https://bugs.libreoffice.org/show_bug.cgi?id=40599
1012 void SwDocTest::testGraphicAnchorDeletion()
1014 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected initial 0 count", static_cast<sal_uLong>(0), m_pDoc->getIDocumentStatistics().GetDocStat().nChar);
1016 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1017 SwPaM aPaM(aIdx);
1019 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"Paragraph 1"_ustr);
1020 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
1022 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"graphic anchor>><<graphic anchor"_ustr);
1023 SwNodeIndex nPara2(aPaM.GetPoint()->GetNode());
1024 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
1026 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"Paragraph 3"_ustr);
1028 aPaM.GetPoint()->Assign(nPara2);
1029 aPaM.GetPoint()->SetContent(RTL_CONSTASCII_LENGTH("graphic anchor>>"));
1031 //Insert a graphic at X of >>X<< in paragraph 2
1032 SfxItemSet aFlySet(m_pDoc->GetAttrPool(), svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END-1>);
1033 SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
1034 aAnchor.SetAnchor(aPaM.GetPoint());
1035 aFlySet.Put(aAnchor);
1036 SwFlyFrameFormat *pFrame = m_pDoc->getIDocumentContentOperations().InsertGraphic(aPaM, OUString(), OUString(), nullptr, &aFlySet, nullptr, nullptr);
1037 CPPUNIT_ASSERT_MESSAGE("Expected frame", pFrame != nullptr);
1039 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be 1 graphic", static_cast<size_t>(1), m_pDoc->GetFlyCount(FLYCNTTYPE_GRF));
1041 //Delete >X<
1042 aPaM.GetPoint()->Assign(nPara2);
1043 aPaM.GetPoint()->SetContent(
1044 RTL_CONSTASCII_LENGTH("graphic anchor>><")+1);
1045 aPaM.SetMark();
1046 aPaM.GetPoint()->Assign(nPara2);
1047 aPaM.GetPoint()->SetContent(RTL_CONSTASCII_LENGTH("graphic anchor>"));
1048 m_pDoc->getIDocumentContentOperations().DeleteRange(aPaM);
1050 #ifdef DEBUG_AS_HTML
1052 SvFileStream aPasteDebug(OUString("cppunitDEBUG.html"), StreamMode::WRITE|StreamMode::TRUNC);
1053 WriterRef xWrt;
1054 GetHTMLWriter( String(), String(), xWrt );
1055 SwWriter aDbgWrt( aPasteDebug, *m_pDoc );
1056 aDbgWrt.Write( xWrt );
1058 #endif
1060 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be 0 graphics", static_cast<size_t>(0), m_pDoc->GetFlyCount(FLYCNTTYPE_GRF));
1062 //Now, if instead we swap RndStdIds::FLY_AS_CHAR (inline graphic) to RndStdIds::FLY_AT_CHAR (anchored to character)
1063 //and repeat the above, graphic is *not* deleted, i.e. it belongs to the paragraph, not the
1064 //range to which its anchored, which is annoying.
1067 void SwDocTest::testTableAutoFormats()
1069 SwGlobals::ensure();
1071 //create new AutoFormatTable
1072 SwTableAutoFormatTable aTableAFT;
1074 //check the style size - default is expected
1075 CPPUNIT_ASSERT_EQUAL( size_t(1), aTableAFT.size() );
1077 //create new style
1078 SwTableAutoFormat aTableAF( u"TestItemStyle"_ustr );
1080 //create new AutoFormat
1081 SwBoxAutoFormat aBoxAF;
1083 //SetFont
1084 SvxFontItem aFont( RES_CHRATR_FONT );
1085 aFont.SetFamily( FontFamily::FAMILY_DECORATIVE );
1086 aFont.SetPitch( FontPitch::PITCH_VARIABLE );
1087 aFont.SetCharSet( RTL_TEXTENCODING_MS_1251 );
1088 aBoxAF.SetFont( aFont );
1089 //SetHeight
1090 SvxFontHeightItem aHeight( 280, 120, RES_CHRATR_FONTSIZE );
1091 aBoxAF.SetHeight( aHeight );
1092 //SetWeight
1093 SvxWeightItem aWeight( FontWeight::WEIGHT_BOLD, RES_CHRATR_WEIGHT );
1094 aBoxAF.SetWeight( aWeight );
1095 //SetPosture
1096 SvxPostureItem aPosture( FontItalic::ITALIC_NORMAL, RES_CHRATR_POSTURE );
1097 aBoxAF.SetPosture( aPosture );
1098 //SetCJKFont
1099 SvxFontItem aCJKFont( RES_CHRATR_FONT );
1100 aCJKFont.SetFamily( FontFamily::FAMILY_MODERN );
1101 aCJKFont.SetPitch( FontPitch::PITCH_FIXED );
1102 aCJKFont.SetCharSet( RTL_TEXTENCODING_MS_1251 );
1103 aBoxAF.SetCJKFont( aCJKFont );
1104 //SetCJKHeight
1105 SvxFontHeightItem aCJKHeight( 230, 110, RES_CHRATR_FONTSIZE );
1106 aBoxAF.SetCJKHeight( aCJKHeight );
1107 //SetCJKWeight
1108 SvxWeightItem aCJKWeight( FontWeight::WEIGHT_SEMIBOLD, RES_CHRATR_WEIGHT );
1109 aBoxAF.SetCJKWeight( aCJKWeight );
1110 //SetCJKPosture
1111 SvxPostureItem aCJKPosture( FontItalic::ITALIC_OBLIQUE, RES_CHRATR_POSTURE );
1112 aBoxAF.SetCJKPosture( aCJKPosture );
1113 //SetCTLFont
1114 SvxFontItem aCTLFont( RES_CHRATR_FONT );
1115 aCTLFont.SetFamily( FontFamily::FAMILY_ROMAN );
1116 aCTLFont.SetPitch( FontPitch::PITCH_FIXED );
1117 aCTLFont.SetCharSet( RTL_TEXTENCODING_MS_1251 );
1118 aBoxAF.SetCTLFont( aCTLFont );
1119 //SetCTLHeight
1120 SvxFontHeightItem aCTLHeight( 215, 105, RES_CHRATR_FONTSIZE );
1121 aBoxAF.SetCTLHeight( aCTLHeight );
1122 //SetCTLWeight
1123 SvxWeightItem aCTLWeight( FontWeight::WEIGHT_ULTRABOLD, RES_CHRATR_WEIGHT );
1124 aBoxAF.SetCTLWeight( aCTLWeight );
1125 //SetCTLPosture
1126 SvxPostureItem aCTLPosture( FontItalic::ITALIC_OBLIQUE, RES_CHRATR_POSTURE );
1127 aBoxAF.SetCTLPosture( aCTLPosture );
1128 //SetUnderline
1129 SvxUnderlineItem aUnderline( FontLineStyle::LINESTYLE_DOTTED, RES_CHRATR_UNDERLINE );
1130 aBoxAF.SetUnderline( aUnderline );
1131 //SetOverline
1132 SvxOverlineItem aOverline( FontLineStyle::LINESTYLE_DASH, RES_CHRATR_OVERLINE );
1133 aBoxAF.SetOverline( aOverline );
1134 //SetCrossedOut
1135 SvxCrossedOutItem aCrossedOut( FontStrikeout::STRIKEOUT_BOLD, RES_CHRATR_CROSSEDOUT );
1136 aBoxAF.SetCrossedOut( aCrossedOut );
1137 //SetContour
1138 SvxContourItem aContour( true, RES_CHRATR_CONTOUR );
1139 aBoxAF.SetContour( aContour );
1140 //SetShadowed
1141 SvxShadowedItem aShadowed( false, RES_CHRATR_SHADOWED );
1142 aBoxAF.SetShadowed( aShadowed );
1143 //SetColor
1144 SvxColorItem aColor( Color(0xFF23FF), RES_CHRATR_COLOR );
1145 aBoxAF.SetColor( aColor );
1146 //SetAdjust
1147 SvxAdjustItem aAdjust( SvxAdjust::Center, RES_PARATR_ADJUST );
1148 aBoxAF.SetAdjust( aAdjust );
1149 //SetTextOrientation
1150 SvxFrameDirectionItem aTOrientation( SvxFrameDirection::Vertical_RL_TB, RES_FRAMEDIR );
1151 aBoxAF.SetTextOrientation( aTOrientation );
1152 //SetVerticalAlignment
1153 SwFormatVertOrient aVAlignment( 3, css::text::VertOrientation::CENTER, css::text::RelOrientation::PAGE_LEFT );
1154 aBoxAF.SetVerticalAlignment( aVAlignment );
1155 //SetBox
1156 SvxBoxItem aBox( RES_BOX );
1157 aBox.SetAllDistances( 5 );
1158 aBoxAF.SetBox( aBox );
1159 //SetBackground
1160 SvxBrushItem aBackground( Color(0xFF11FF), RES_BACKGROUND );
1161 aBoxAF.SetBackground( aBackground );
1162 //Set m_aTLBR
1163 SvxLineItem aTLBRLine(0); aTLBRLine.ScaleMetrics( 11,12 );
1164 aBoxAF.SetTLBR(aTLBRLine);
1165 //Set m_aBLTR
1166 SvxLineItem aBLTRLine(0); aBLTRLine.ScaleMetrics( 13,14 );
1167 aBoxAF.SetBLTR(aBLTRLine);
1168 //Set m_aHorJustify
1169 SvxHorJustifyItem aHJustify( SvxCellHorJustify::Center, 0 );
1170 aBoxAF.SetHorJustify(aHJustify);
1171 //Set m_aVerJustify
1172 SvxVerJustifyItem aVJustify( SvxCellVerJustify::Center , 0 );
1173 aBoxAF.SetVerJustify(aVJustify);
1174 //Set m_aStacked
1175 SfxBoolItem aStacked(0, true);
1176 aBoxAF.SetStacked(aStacked);
1177 //Set m_aMargin
1178 SvxMarginItem aSvxMarginItem(sal_Int16(4), sal_Int16(2), sal_Int16(3), sal_Int16(3), TypedWhichId<SvxMarginItem>(0));
1179 aBoxAF.SetMargin(aSvxMarginItem);
1180 //Set m_aLinebreak
1181 SfxBoolItem aLBreak(0, true);
1182 aBoxAF.SetLinebreak(aLBreak);
1183 //Set m_aRotateAngle
1184 SfxInt32Item aRAngle(sal_Int32(5));
1185 aBoxAF.SetRotateAngle(aRAngle);
1186 //Set m_aRotateMode
1187 SvxRotateModeItem aSvxRotateModeItem(SVX_ROTATE_MODE_CENTER, TypedWhichId<SvxRotateModeItem>(0));
1188 aBoxAF.SetRotateMode(aSvxRotateModeItem);
1189 //Set m_sNumFormatString
1190 OUString aNFString = u"UnitTestFormat"_ustr;
1191 aBoxAF.SetNumFormatString(aNFString);
1192 //Set m_eSysLanguage
1193 LanguageType aSLang( LANGUAGE_ENGLISH_INDIA );
1194 aBoxAF.SetSysLanguage(aSLang);
1195 //Set m_eNumFormatLanguage
1196 LanguageType aNFLang( LANGUAGE_GERMAN );
1197 aBoxAF.SetNumFormatLanguage(aNFLang);
1198 //Set m_aKeepWithNextPara
1199 SvxFormatKeepItem aKWNPara( true, 0 );
1200 aTableAF.SetKeepWithNextPara(aKWNPara);
1201 //Set m_aRepeatHeading
1202 sal_uInt16 aRHeading = 3;
1203 aTableAF.m_aRepeatHeading = aRHeading;
1204 //Set m_bLayoutSplit
1205 bool aLSplit = false;
1206 aTableAF.m_bLayoutSplit = aLSplit;
1207 //Set m_bRowSplit
1208 bool aRSplit = false;
1209 aTableAF.m_bRowSplit = aRSplit;
1210 //Set m_bCollapsingBorders
1211 bool aCBorders = false;
1212 aTableAF.m_bCollapsingBorders = aCBorders;
1213 //Set m_aShadow
1214 SvxShadowItem aShadow( 0, nullptr, 103, SvxShadowLocation::BottomLeft );
1215 aTableAF.SetShadow(aShadow);
1216 //Set bInclFont
1217 bool aIFont = false;
1218 aTableAF.m_bInclFont = aIFont;
1219 //Set bInclJustify
1220 bool aIJustify = false;
1221 aTableAF.m_bInclJustify = aIJustify;
1222 //Set bInclFrame
1223 bool aIFrame = false;
1224 aTableAF.m_bInclFrame = aIFrame;
1225 //Set bInclBackground
1226 bool aIBackground = false;
1227 aTableAF.m_bInclBackground = aIBackground;
1228 //Set bInclValueFormat
1229 bool aIVFormat = false;
1230 aTableAF.m_bInclValueFormat = aIVFormat;
1232 //set the box format to AutoFormat
1233 aTableAF.SetBoxFormat( aBoxAF, sal_uInt8(0) );
1234 //add AutoFormat to AutoFormatTable
1235 aTableAFT.AddAutoFormat( aTableAF );
1237 //check the style size
1238 CPPUNIT_ASSERT_EQUAL( size_t(2), aTableAFT.size() );
1240 //save the bInclFontstyles
1241 aTableAFT.Save();
1243 //check the style size after save
1244 CPPUNIT_ASSERT_EQUAL( size_t(2), aTableAFT.size() );
1246 //create new AutoFormatTable
1247 SwTableAutoFormatTable aLoadTAFT;
1249 //check the style size
1250 CPPUNIT_ASSERT_EQUAL( size_t(1), aLoadTAFT.size() );
1252 //load the saved styles
1253 aLoadTAFT.Load();
1255 //check the style size after load
1256 CPPUNIT_ASSERT_EQUAL( size_t(2), aLoadTAFT.size() );
1258 //assert the values
1259 SwTableAutoFormat* pLoadAF = aLoadTAFT.FindAutoFormat( u"TestItemStyle" );
1260 CPPUNIT_ASSERT( pLoadAF );
1261 //GetFont
1262 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetFont() == aFont ) );
1263 //GetHeight
1264 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetHeight() == aHeight ) );
1265 //GetWeight
1266 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetWeight() == aWeight ) );
1267 //GetPosture
1268 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetPosture() == aPosture ) );
1269 //GetCJKFont
1270 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCJKFont() == aCJKFont ) );
1271 //GetCJKHeight
1272 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCJKHeight() == aCJKHeight ) );
1273 //GetCJKWeight
1274 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCJKWeight() == aCJKWeight ) );
1275 //GetCJKPosture
1276 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCJKPosture() == aCJKPosture ) );
1277 //GetCTLFont
1278 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCTLFont() == aCTLFont ) );
1279 //GetCTLHeight
1280 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCTLHeight() == aCTLHeight ) );
1281 //GetCTLWeight
1282 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCTLWeight() == aCTLWeight ) );
1283 //GetCTLPosture
1284 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCTLPosture() == aCTLPosture ) );
1285 //GetUnderline
1286 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetUnderline() == aUnderline ) );
1287 //GetOverline
1288 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetOverline() == aOverline ) );
1289 //GetCrossedOut
1290 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetCrossedOut() == aCrossedOut ) );
1291 //GetContour
1292 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetContour() == aContour ) );
1293 //GetShadowed
1294 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetShadowed() == aShadowed ) );
1295 //GetColor
1296 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetColor() == aColor) );
1297 //GetAdjust
1298 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetAdjust() == aAdjust ) );
1299 //GetTextOrientation
1300 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetTextOrientation() == aTOrientation ) );
1301 //GetVerticalAlignment
1302 CPPUNIT_ASSERT (bool( pLoadAF->GetBoxFormat(0).GetVerticalAlignment() == aVAlignment ) );
1303 //GetBox
1304 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetBox() == aBox ) );
1305 //GetBackground
1306 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetBackground() == aBackground ) );
1307 //Get m_aTLBR
1308 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetTLBR() == aTLBRLine ) );
1309 //Get m_aBLTR
1310 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetBLTR() == aBLTRLine ) );
1311 //Get m_aHorJustify
1312 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetHorJustify() == aHJustify ) );
1313 //Get m_aVerJustify
1314 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetVerJustify() == aVJustify ) );
1315 //Get m_aStacked
1316 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetStacked() == aStacked ) );
1317 //Get m_aMargin
1318 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetMargin() == aSvxMarginItem ) );
1319 //Get m_aLinebreak
1320 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetLinebreak() == aLBreak ) );
1321 //Get m_aRotateAngle
1322 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetRotateAngle() == aRAngle ) );
1323 //Get m_aRotateMode
1324 //SvxRotateModeItem aRMode = aBoxAF.m_aRotateMode;GetRotateMode
1325 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetRotateMode() == aSvxRotateModeItem ) );
1326 //Get m_sNumFormatString
1327 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetNumFormatString() == aNFString ) );
1328 //Get m_eSysLanguage
1329 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetSysLanguage() == aSLang ) );
1330 //Get m_eNumFormatLanguage
1331 CPPUNIT_ASSERT( bool( pLoadAF->GetBoxFormat(0).GetNumFormatLanguage() == aNFLang ) );
1332 //Get m_aKeepWithNextPara
1333 CPPUNIT_ASSERT( bool( pLoadAF->GetKeepWithNextPara() == aKWNPara ) );
1334 //Get m_aRepeatHeading
1335 CPPUNIT_ASSERT( bool( pLoadAF->m_aRepeatHeading == aRHeading ) );
1336 //Get m_bLayoutSplit
1337 CPPUNIT_ASSERT( bool( pLoadAF->m_bLayoutSplit == aLSplit ) );
1338 //Get m_bRowSplit
1339 CPPUNIT_ASSERT( bool( pLoadAF->m_bRowSplit == aRSplit ) );
1340 //Get m_bCollapsingBorders
1341 CPPUNIT_ASSERT( bool( pLoadAF->m_bCollapsingBorders == aCBorders ) );
1342 //Get m_aShadow
1343 CPPUNIT_ASSERT( bool( pLoadAF->GetShadow() == aShadow ) );
1344 //Get bInclFont
1345 CPPUNIT_ASSERT( bool( pLoadAF->m_bInclFont == aIFont ) );
1346 //Get bInclJustify
1347 CPPUNIT_ASSERT( bool( pLoadAF->m_bInclJustify == aIJustify ) );
1348 //Get bInclFrame
1349 CPPUNIT_ASSERT( bool( pLoadAF->m_bInclFrame == aIFrame ) );
1350 //Get bInclBackground
1351 CPPUNIT_ASSERT( bool( pLoadAF->m_bInclBackground == aIBackground ) );
1352 //Get bInclValueFormat
1353 CPPUNIT_ASSERT( bool( pLoadAF->m_bInclValueFormat == aIVFormat ) );
1356 static OUString
1357 translitTest(SwDoc & rDoc, const SwPaM & rPaM, TransliterationFlags const nType)
1359 utl::TransliterationWrapper aTrans(
1360 ::comphelper::getProcessComponentContext(), nType);
1361 rDoc.getIDocumentContentOperations().TransliterateText(rPaM, aTrans);
1362 return rPaM.GetText();
1365 void SwDocTest::testTransliterate()
1367 // just some simple test to see if it's totally broken
1368 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1369 SwPaM aPaM(aIdx);
1370 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"foobar"_ustr);
1371 aPaM.SetMark();
1372 aPaM.GetPoint()->nContent = 0;
1373 CPPUNIT_ASSERT_EQUAL(u"foobar"_ustr, aPaM.GetText());
1375 CPPUNIT_ASSERT_EQUAL(u"FOOBAR"_ustr,
1376 translitTest(*m_pDoc, aPaM,
1377 TransliterationFlags::LOWERCASE_UPPERCASE));
1378 CPPUNIT_ASSERT_EQUAL(u"Foobar"_ustr,
1379 translitTest(*m_pDoc, aPaM,
1380 TransliterationFlags::TITLE_CASE));
1381 CPPUNIT_ASSERT_EQUAL(u"fOOBAR"_ustr,
1382 translitTest(*m_pDoc, aPaM,
1383 TransliterationFlags::TOGGLE_CASE));
1384 CPPUNIT_ASSERT_EQUAL(u"foobar"_ustr,
1385 translitTest(*m_pDoc, aPaM,
1386 TransliterationFlags::UPPERCASE_LOWERCASE));
1387 CPPUNIT_ASSERT_EQUAL(u"Foobar"_ustr,
1388 translitTest(*m_pDoc, aPaM,
1389 TransliterationFlags::SENTENCE_CASE));
1390 CPPUNIT_ASSERT_EQUAL(u"Foobar"_ustr,
1391 translitTest(*m_pDoc, aPaM,
1392 TransliterationFlags::HIRAGANA_KATAKANA));
1394 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
1395 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"one (two) three"_ustr);
1396 aPaM.SetMark();
1397 aPaM.GetMark()->nContent = 0;
1398 CPPUNIT_ASSERT_EQUAL(u"One (Two) Three"_ustr,
1399 translitTest(*m_pDoc, aPaM,
1400 TransliterationFlags::TITLE_CASE));
1403 namespace
1405 class SwTableFormulaTest : public SwTableFormula
1407 SwTableNode *m_pNode;
1408 public:
1409 SwTableFormulaTest(const OUString &rStr, SwTableNode *pNode)
1410 : SwTableFormula(rStr)
1411 , m_pNode(pNode)
1413 m_eNmType = INTRNL_NAME;
1415 virtual const SwNode* GetNodeOfFormula() const override
1417 return m_pNode;
1422 //tdf#66353 Expression is faulty
1423 void SwDocTest::testFormulas()
1425 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1426 SwPosition aPos(aIdx);
1428 const SwTable *pTable = m_pDoc->InsertTable(
1429 SwInsertTableOptions(SwInsertTableFlags::HeadlineNoBorder, 0), aPos, 1, 3, 0);
1430 SwTableNode* pTableNode = pTable->GetTableNode();
1431 SwTableFormulaTest aFormula(u"<\x12-1,0>+<Table1.A1>"_ustr, pTableNode);
1433 aFormula.PtrToBoxNm(pTable);
1435 CPPUNIT_ASSERT_EQUAL(u"<?>+<Table1.?>"_ustr, aFormula.GetFormula());
1437 // tdf#61228: Evaluating non-defined function should return an error
1438 SwCalc aCalc(*m_pDoc);
1439 SwSbxValue val = aCalc.Calculate(u"foobar()"_ustr);
1440 CPPUNIT_ASSERT(aCalc.IsCalcError());
1441 CPPUNIT_ASSERT(val.IsVoidValue());
1442 CPPUNIT_ASSERT(val.IsDouble());
1443 CPPUNIT_ASSERT_EQUAL(DBL_MAX, val.GetDouble());
1444 // Evaluating non-defined variable should return 0 without an error
1445 val = aCalc.Calculate(u"foobar"_ustr);
1446 CPPUNIT_ASSERT(!aCalc.IsCalcError());
1447 CPPUNIT_ASSERT(val.IsVoidValue());
1448 CPPUNIT_ASSERT(val.IsLong());
1449 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), val.GetLong());
1452 void SwDocTest::testMarkMove()
1454 IDocumentMarkAccess* pMarksAccess = m_pDoc->getIDocumentMarkAccess();
1457 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1458 SwPaM aPaM(aIdx);
1459 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"Paragraph 1"_ustr);
1460 aPaM.SetMark();
1461 aPaM.GetMark()->nContent -= aPaM.GetMark()->GetContentIndex();
1462 pMarksAccess->makeMark(aPaM, u"Para1"_ustr,
1463 IDocumentMarkAccess::MarkType::BOOKMARK, sw::mark::InsertMode::New);
1465 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
1466 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"Paragraph 2"_ustr);
1467 aPaM.SetMark();
1468 aPaM.GetMark()->nContent -= aPaM.GetMark()->GetContentIndex();
1469 pMarksAccess->makeMark(aPaM, u"Para2"_ustr,
1470 IDocumentMarkAccess::MarkType::BOOKMARK, sw::mark::InsertMode::New);
1472 m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
1473 m_pDoc->getIDocumentContentOperations().InsertString(aPaM, u"Paragraph 3"_ustr);
1474 aPaM.SetMark();
1475 aPaM.GetMark()->nContent -= aPaM.GetMark()->GetContentIndex();
1476 pMarksAccess->makeMark(aPaM, u"Para3"_ustr,
1477 IDocumentMarkAccess::MarkType::BOOKMARK, sw::mark::InsertMode::New);
1480 // join paragraph 2 and 3 and check
1482 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -2);
1483 SwTextNode& rParaNode2 = dynamic_cast<SwTextNode&>(aIdx.GetNode());
1484 rParaNode2.JoinNext();
1486 ::sw::mark::MarkBase* pBM1 = *pMarksAccess->findMark(u"Para1"_ustr);
1487 ::sw::mark::MarkBase* pBM2 = *pMarksAccess->findMark(u"Para2"_ustr);
1488 ::sw::mark::MarkBase* pBM3 = *pMarksAccess->findMark(u"Para3"_ustr);
1490 CPPUNIT_ASSERT_EQUAL(sal_Int32(0) , pBM1->GetMarkStart().GetContentIndex());
1491 CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pBM1->GetMarkEnd().GetContentIndex());
1492 CPPUNIT_ASSERT_EQUAL(
1493 pBM1->GetMarkStart().GetNodeIndex(),
1494 pBM1->GetMarkEnd().GetNodeIndex());
1496 CPPUNIT_ASSERT_EQUAL(sal_Int32(0) , pBM2->GetMarkStart().GetContentIndex());
1497 CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pBM2->GetMarkEnd().GetContentIndex());
1498 CPPUNIT_ASSERT_EQUAL(
1499 pBM2->GetMarkStart().GetNodeIndex(),
1500 pBM2->GetMarkEnd().GetNodeIndex());
1502 CPPUNIT_ASSERT_EQUAL(sal_Int32(11), pBM3->GetMarkStart().GetContentIndex());
1503 CPPUNIT_ASSERT_EQUAL(sal_Int32(22), pBM3->GetMarkEnd().GetContentIndex());
1504 CPPUNIT_ASSERT_EQUAL(
1505 pBM3->GetMarkStart().GetNodeIndex(),
1506 pBM3->GetMarkEnd().GetNodeIndex());
1508 CPPUNIT_ASSERT_EQUAL(
1509 pBM1->GetMarkStart().GetNodeIndex()+1,
1510 pBM2->GetMarkStart().GetNodeIndex());
1511 CPPUNIT_ASSERT_EQUAL(
1512 pBM2->GetMarkStart().GetNodeIndex(),
1513 pBM3->GetMarkStart().GetNodeIndex());
1515 // cut some text
1517 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1518 SwPaM aPaM(aIdx, aIdx, SwNodeOffset(-1));
1519 aPaM.GetPoint()->nContent += 5;
1520 aPaM.GetMark()->nContent += 6;
1521 m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aPaM);
1523 pBM1 = *pMarksAccess->findMark(u"Para1"_ustr);
1524 pBM2 = *pMarksAccess->findMark(u"Para2"_ustr);
1525 pBM3 = *pMarksAccess->findMark(u"Para3"_ustr);
1527 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pBM1->GetMarkStart().GetContentIndex());
1528 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pBM1->GetMarkEnd().GetContentIndex());
1529 CPPUNIT_ASSERT_EQUAL(
1530 pBM1->GetMarkStart().GetNodeIndex(),
1531 pBM1->GetMarkEnd().GetNodeIndex());
1533 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pBM2->GetMarkStart().GetContentIndex());
1534 CPPUNIT_ASSERT_EQUAL(sal_Int32(12), pBM2->GetMarkEnd().GetContentIndex());
1535 CPPUNIT_ASSERT_EQUAL(
1536 pBM2->GetMarkStart().GetNodeIndex(),
1537 pBM2->GetMarkEnd().GetNodeIndex());
1539 CPPUNIT_ASSERT_EQUAL(sal_Int32(12), pBM3->GetMarkStart().GetContentIndex());
1540 CPPUNIT_ASSERT_EQUAL(sal_Int32(23), pBM3->GetMarkEnd().GetContentIndex());
1541 CPPUNIT_ASSERT_EQUAL(
1542 pBM3->GetMarkStart().GetNodeIndex(),
1543 pBM3->GetMarkEnd().GetNodeIndex());
1545 CPPUNIT_ASSERT_EQUAL(
1546 pBM1->GetMarkStart().GetNodeIndex(),
1547 pBM2->GetMarkStart().GetNodeIndex());
1548 CPPUNIT_ASSERT_EQUAL(
1549 pBM2->GetMarkStart().GetNodeIndex(),
1550 pBM3->GetMarkStart().GetNodeIndex());
1552 // split the paragraph
1554 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1555 SwPosition aPos(aIdx);
1556 aPos.nContent += 8;
1557 m_pDoc->getIDocumentContentOperations().SplitNode(aPos, false);
1559 pBM1 = *pMarksAccess->findMark(u"Para1"_ustr);
1560 pBM2 = *pMarksAccess->findMark(u"Para2"_ustr);
1561 pBM3 = *pMarksAccess->findMark(u"Para3"_ustr);
1563 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pBM1->GetMarkStart().GetContentIndex());
1564 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pBM1->GetMarkEnd().GetContentIndex());
1565 CPPUNIT_ASSERT_EQUAL(
1566 pBM1->GetMarkStart().GetNodeIndex(),
1567 pBM1->GetMarkEnd().GetNodeIndex());
1569 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), pBM2->GetMarkStart().GetContentIndex());
1570 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pBM2->GetMarkEnd().GetContentIndex());
1571 CPPUNIT_ASSERT_EQUAL(
1572 pBM2->GetMarkStart().GetNodeIndex()+1,
1573 pBM2->GetMarkEnd().GetNodeIndex());
1575 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pBM3->GetMarkStart().GetContentIndex());
1576 CPPUNIT_ASSERT_EQUAL(sal_Int32(15), pBM3->GetMarkEnd().GetContentIndex());
1577 CPPUNIT_ASSERT_EQUAL(
1578 pBM3->GetMarkStart().GetNodeIndex(),
1579 pBM3->GetMarkEnd().GetNodeIndex());
1581 CPPUNIT_ASSERT_EQUAL(
1582 pBM1->GetMarkStart().GetNodeIndex(),
1583 pBM2->GetMarkStart().GetNodeIndex());
1584 CPPUNIT_ASSERT_EQUAL(
1585 pBM2->GetMarkEnd().GetNodeIndex(),
1586 pBM3->GetMarkEnd().GetNodeIndex());
1589 namespace
1591 struct TestRing : public sw::Ring<TestRing>
1593 TestRing() : sw::Ring<TestRing>() {};
1594 TestRing* GetNext()
1595 { return GetNextInRing(); }
1596 TestRing* GetPrev()
1597 { return GetPrevInRing(); }
1598 bool lonely() const
1599 { return unique(); }
1603 void SwDocTest::testIntrusiveRing()
1605 TestRing aRing1, aRing2, aRing3, aRing4, aRing5;
1606 std::vector<TestRing*> vRings
1608 &aRing1,
1609 &aRing2,
1610 &aRing3,
1611 &aRing4,
1612 &aRing5
1614 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aRing1.GetRingContainer().size());
1615 CPPUNIT_ASSERT(aRing1.lonely());
1616 CPPUNIT_ASSERT(aRing2.lonely());
1617 CPPUNIT_ASSERT(aRing3.lonely());
1618 aRing2.MoveTo(&aRing1);
1619 aRing3.MoveTo(&aRing1);
1620 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aRing1.GetRingContainer().size());
1621 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aRing2.GetRingContainer().size());
1622 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aRing3.GetRingContainer().size());
1623 CPPUNIT_ASSERT(!aRing1.lonely());
1624 CPPUNIT_ASSERT(!aRing2.lonely());
1625 CPPUNIT_ASSERT(!aRing3.lonely());
1626 aRing5.MoveTo(&aRing4);
1627 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aRing4.GetRingContainer().size());
1628 aRing4.GetRingContainer().merge(aRing1.GetRingContainer());
1629 for(TestRing* pRing : vRings)
1631 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(5), pRing->GetRingContainer().size());
1633 for(std::vector<TestRing*>::iterator ppRing = vRings.begin(); ppRing != vRings.end(); ++ppRing)
1635 std::vector<TestRing*>::iterator ppNext = ppRing+1;
1636 if(ppNext==vRings.end())
1637 ppNext = vRings.begin();
1638 CPPUNIT_ASSERT_EQUAL((*ppRing)->GetNext(), *ppNext);
1639 CPPUNIT_ASSERT_EQUAL((*ppNext)->GetPrev(), *ppRing);
1641 for(TestRing& r: aRing1.GetRingContainer())
1643 TestRing* pRing = &r;
1644 CPPUNIT_ASSERT(pRing);
1646 const TestRing* pConstRing = &aRing1;
1647 for(const TestRing& r: pConstRing->GetRingContainer()) // this should fail without r being const
1649 const TestRing* pRing = &r;
1650 CPPUNIT_ASSERT(pRing);
1652 TestRing foo, bar;
1653 foo.MoveTo(&bar);
1654 CPPUNIT_ASSERT_EQUAL(&foo, bar.GetNext());
1655 CPPUNIT_ASSERT_EQUAL(&foo, bar.GetPrev());
1656 CPPUNIT_ASSERT_EQUAL(&bar, foo.GetNext());
1657 CPPUNIT_ASSERT_EQUAL(&bar, foo.GetPrev());
1658 foo.MoveTo(&foo);
1659 CPPUNIT_ASSERT_EQUAL(&bar, bar.GetNext());
1660 CPPUNIT_ASSERT_EQUAL(&bar, bar.GetPrev());
1661 CPPUNIT_ASSERT_EQUAL(&foo, foo.GetNext());
1662 CPPUNIT_ASSERT_EQUAL(&foo, foo.GetPrev());
1665 namespace
1667 struct TestHint final : SfxHint {};
1668 struct TestModify : sw::BroadcastingModify
1671 struct TestClient : SwClient
1673 int m_nModifyCount;
1674 int m_nNotifyCount;
1675 int m_nModifyChangedCount;
1676 const SwModify* m_pLastChangedModify;
1677 TestClient() : m_nModifyCount(0), m_nNotifyCount(0), m_nModifyChangedCount(0), m_pLastChangedModify(nullptr) {};
1678 virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) override
1680 if(typeid(TestHint) == typeid(rHint))
1681 ++m_nNotifyCount;
1682 else if(dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
1683 ++m_nModifyCount;
1684 else if(dynamic_cast<const sw::AttrSetChangeHint*>(&rHint))
1685 ++m_nModifyCount;
1686 else if(auto pModifyChangedHint = dynamic_cast<const sw::ModifyChangedHint*>(&rHint))
1688 ++m_nModifyChangedCount;
1689 m_pLastChangedModify = pModifyChangedHint->m_pNew;
1693 struct OtherTestClient : SwClient
1695 int m_nModifyCount;
1696 OtherTestClient() : m_nModifyCount(0) {};
1697 virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) override
1699 if(dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
1700 ++m_nModifyCount;
1701 else if(dynamic_cast<const sw::AttrSetChangeHint*>(&rHint))
1702 ++m_nModifyCount;
1705 struct TestListener : SvtListener
1707 int m_nNotifyCount;
1708 TestListener() : m_nNotifyCount(0) {};
1709 virtual void Notify( const SfxHint& ) override
1711 ++m_nNotifyCount;
1715 void SwDocTest::testClientModify()
1717 (void) OtherTestClient(); // avoid loplugin:unreffun
1718 TestModify aMod;
1719 TestClient aClient1, aClient2;
1720 OtherTestClient aOtherClient1;
1721 // test client registration
1722 CPPUNIT_ASSERT(!aMod.HasWriterListeners());
1723 CPPUNIT_ASSERT(!aMod.HasOnlyOneListener());
1724 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient1.GetRegisteredIn());
1725 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient2.GetRegisteredIn());
1726 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient2.GetRegisteredIn());
1727 aMod.Add(aClient1);
1728 CPPUNIT_ASSERT(aMod.HasWriterListeners());
1729 CPPUNIT_ASSERT(aMod.HasOnlyOneListener());
1730 aMod.Add(aClient2);
1731 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod),aClient1.GetRegisteredIn());
1732 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod), aClient2.GetRegisteredIn());
1733 CPPUNIT_ASSERT(aMod.HasWriterListeners());
1734 CPPUNIT_ASSERT(!aMod.HasOnlyOneListener());
1735 // test broadcast
1736 aMod.CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1737 CPPUNIT_ASSERT_EQUAL(1,aClient1.m_nModifyCount);
1738 CPPUNIT_ASSERT_EQUAL(1,aClient2.m_nModifyCount);
1739 CPPUNIT_ASSERT_EQUAL(0,aClient1.m_nNotifyCount);
1740 CPPUNIT_ASSERT_EQUAL(0,aClient2.m_nNotifyCount);
1741 aMod.CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1742 CPPUNIT_ASSERT_EQUAL(2,aClient1.m_nModifyCount);
1743 CPPUNIT_ASSERT_EQUAL(2,aClient2.m_nModifyCount);
1744 CPPUNIT_ASSERT_EQUAL(0,aClient1.m_nNotifyCount);
1745 CPPUNIT_ASSERT_EQUAL(0,aClient2.m_nNotifyCount);
1746 // test notify
1748 TestHint aHint;
1749 aMod.CallSwClientNotify(aHint);
1750 CPPUNIT_ASSERT_EQUAL(2,aClient1.m_nModifyCount);
1751 CPPUNIT_ASSERT_EQUAL(2,aClient2.m_nModifyCount);
1752 CPPUNIT_ASSERT_EQUAL(1,aClient1.m_nNotifyCount);
1753 CPPUNIT_ASSERT_EQUAL(1,aClient2.m_nNotifyCount);
1755 // test typed iteration
1756 CPPUNIT_ASSERT(typeid(aClient1) != typeid(OtherTestClient));
1758 SwIterator<OtherTestClient,SwModify> aIter(aMod);
1759 for(OtherTestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1760 CPPUNIT_ASSERT(false);
1763 int nCount = 0;
1764 SwIterator<TestClient,SwModify> aIter(aMod);
1765 for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1767 CPPUNIT_ASSERT_EQUAL(2,pClient->m_nModifyCount);
1768 ++nCount;
1770 CPPUNIT_ASSERT_EQUAL(2,nCount);
1772 aMod.Add(aOtherClient1);
1773 CPPUNIT_ASSERT_EQUAL(0,aOtherClient1.m_nModifyCount);
1775 int nCount = 0;
1776 SwIterator<TestClient,SwModify> aIter(aMod);
1777 for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1779 CPPUNIT_ASSERT_EQUAL(2,pClient->m_nModifyCount);
1780 ++nCount;
1782 CPPUNIT_ASSERT_EQUAL(2,nCount);
1784 CPPUNIT_ASSERT_EQUAL(0,aOtherClient1.m_nModifyCount);
1785 aMod.Remove(aOtherClient1);
1786 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod),aClient1.GetRegisteredIn());
1787 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(&aMod),aClient2.GetRegisteredIn());
1788 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aOtherClient1.GetRegisteredIn());
1789 // test client self-deregistration during iteration
1791 int nCount = 0;
1792 SwIterator<TestClient,SwModify> aIter(aMod);
1793 for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1795 aMod.Remove(*pClient);
1796 ++nCount;
1798 CPPUNIT_ASSERT_EQUAL(2,nCount);
1800 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient1.GetRegisteredIn());
1801 CPPUNIT_ASSERT_EQUAL(static_cast<SwModify*>(nullptr),aClient2.GetRegisteredIn());
1803 SwIterator<TestClient,SwModify> aIter(aMod);
1804 for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
1806 CPPUNIT_ASSERT(false);
1809 aMod.CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1810 CPPUNIT_ASSERT_EQUAL(2,aClient1.m_nModifyCount);
1811 CPPUNIT_ASSERT_EQUAL(2,aClient2.m_nModifyCount);
1812 CPPUNIT_ASSERT_EQUAL(1,aClient1.m_nNotifyCount);
1813 CPPUNIT_ASSERT_EQUAL(1,aClient2.m_nNotifyCount);
1815 void SwDocTest::testBroadcastingModify()
1817 sw::BroadcastingModify aMod;
1818 TestClient aClient;
1819 TestListener aListener;
1821 aMod.Add(aClient);
1822 aListener.StartListening(aMod.GetNotifier());
1824 aMod.CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1825 CPPUNIT_ASSERT_EQUAL(1,aClient.m_nModifyCount);
1826 CPPUNIT_ASSERT_EQUAL(1,aClient.m_nModifyCount);
1827 CPPUNIT_ASSERT_EQUAL(1,aListener.m_nNotifyCount);
1829 void SwDocTest::testWriterMultiListener()
1831 TestModify aMod;
1832 TestClient aClient;
1833 sw::WriterMultiListener aMulti(aClient);
1834 CPPUNIT_ASSERT(!aMulti.IsListeningTo(&aMod));
1835 aMulti.StartListening(&aMod);
1836 CPPUNIT_ASSERT(aMulti.IsListeningTo(&aMod));
1837 aMulti.EndListeningAll();
1838 CPPUNIT_ASSERT(!aMulti.IsListeningTo(&aMod));
1839 aMulti.StartListening(&aMod);
1840 aMulti.EndListening(&aMod);
1841 CPPUNIT_ASSERT(!aMulti.IsListeningTo(&aMod));
1842 int nPreDeathChangedCount;
1844 TestModify aTempMod;
1845 aMod.Add(aTempMod);
1846 aMulti.StartListening(&aTempMod);
1847 nPreDeathChangedCount = aClient.m_nModifyChangedCount;
1849 CPPUNIT_ASSERT(aMulti.IsListeningTo(&aMod));
1850 CPPUNIT_ASSERT_EQUAL(nPreDeathChangedCount+1, aClient.m_nModifyChangedCount);
1851 CPPUNIT_ASSERT_EQUAL(static_cast<const SwModify*>(&aMod),aClient.m_pLastChangedModify);
1854 void SwDocTest::test64kPageDescs()
1856 size_t nPageDescCount = 65536; // USHRT_MAX + 1
1858 for (size_t i = 0; i < nPageDescCount; ++i)
1860 OUString aName = "Page" + OUString::number(i);
1861 m_pDoc->MakePageDesc( aName );
1864 size_t nCount = m_pDoc->GetPageDescCnt();
1865 // +1 because Writer always creates a dummy page desc
1866 // in a new SwDoc
1867 CPPUNIT_ASSERT_EQUAL( nPageDescCount + 1, nCount );
1869 const SwPageDesc &rDesc = m_pDoc->GetPageDesc( nPageDescCount );
1870 SwPageDesc &rZeroDesc = m_pDoc->GetPageDesc( 0 );
1871 CPPUNIT_ASSERT_EQUAL( u"Page65535"_ustr, rDesc.GetName() );
1873 SwPageDesc aDesc( rDesc );
1874 static constexpr OUString aChanged(u"Changed01"_ustr);
1875 aDesc.SetName( aChanged );
1876 m_pDoc->ChgPageDesc( nPageDescCount, aDesc );
1878 size_t nPos;
1879 SwPageDesc *pDesc = m_pDoc->FindPageDesc( aChanged, &nPos );
1880 CPPUNIT_ASSERT( pDesc != nullptr );
1881 CPPUNIT_ASSERT_EQUAL( nPageDescCount, nPos );
1883 // check if we didn't mess up PageDesc at pos 0
1884 // (happens with 16bit int overflow)
1885 OUString aZeroName = rZeroDesc.GetName();
1886 rZeroDesc = m_pDoc->GetPageDesc( 0 );
1887 CPPUNIT_ASSERT_EQUAL( aZeroName, rZeroDesc.GetName() );
1889 m_pDoc->DelPageDesc( aChanged, /*bBroadcast*/true );
1890 pDesc = m_pDoc->FindPageDesc( aChanged, &nPos );
1891 // not there anymore
1892 CPPUNIT_ASSERT( !pDesc );
1893 CPPUNIT_ASSERT_EQUAL( std::numeric_limits<size_t>::max(), nPos);
1895 // check if PageDesc at pos 0 is still there
1896 pDesc = m_pDoc->FindPageDesc( aZeroName, &nPos );
1897 CPPUNIT_ASSERT( pDesc != nullptr );
1898 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(0), nPos );
1901 void SwDocTest::testTdf92308()
1903 CPPUNIT_ASSERT_EQUAL(false, m_pDoc->HasInvisibleContent());
1906 void SwDocTest::testTableCellComparison()
1908 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellsByColFirst(u"A1", u"Z1") );
1909 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByColFirst(u"Z1", u"A1") );
1910 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellsByColFirst(u"A1", u"A1") );
1912 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByColFirst(u"A2", u"A1") );
1913 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByColFirst(u"Z3", u"A2") );
1914 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellsByColFirst(u"A3", u"Z1") );
1916 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellsByRowFirst(u"A1", u"Z1") );
1917 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByRowFirst(u"Z1", u"A1") );
1918 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellsByRowFirst(u"A1", u"A1") );
1920 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByRowFirst(u"A2", u"A1") );
1921 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByRowFirst(u"Z3", u"A2") );
1922 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellsByRowFirst(u"A3", u"Z1") );
1924 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellRanges(u"A1", u"A1", u"A1", u"A1", true) );
1925 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellRanges(u"A1", u"Z1", u"A1", u"Z1", true) );
1926 CPPUNIT_ASSERT_EQUAL( 0, sw_CompareCellRanges(u"A1", u"Z1", u"A1", u"Z1", false) );
1928 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellRanges(u"A1", u"Z1", u"B1", u"Z1", true) );
1929 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellRanges(u"A1", u"Z1", u"A2", u"Z2", false) );
1930 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellRanges(u"A1", u"Z1", u"A2", u"Z2", true) );
1931 CPPUNIT_ASSERT_EQUAL( -1, sw_CompareCellRanges(u"A1", u"Z1", u"A6", u"Z2", true) );
1933 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellRanges(u"B1", u"Z1", u"A1", u"Z1", true) );
1934 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellRanges(u"A2", u"Z2", u"A1", u"Z1", false) );
1935 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellRanges(u"A2", u"Z2", u"A1", u"Z1", true) );
1936 CPPUNIT_ASSERT_EQUAL( +1, sw_CompareCellRanges(u"A6", u"Z2", u"A1", u"Z1", true) );
1938 OUString rCell1(u"A1"_ustr);
1939 OUString rCell2(u"C5"_ustr);
1941 sw_NormalizeRange(rCell1, rCell2);
1942 CPPUNIT_ASSERT_EQUAL( u"A1"_ustr, rCell1 );
1943 CPPUNIT_ASSERT_EQUAL( u"C5"_ustr, rCell2 );
1945 sw_NormalizeRange(rCell2, rCell1);
1946 CPPUNIT_ASSERT_EQUAL( u"C5"_ustr, rCell1 );
1947 CPPUNIT_ASSERT_EQUAL( u"A1"_ustr, rCell2 );
1949 rCell1 = u"A5"_ustr;
1950 rCell2 = u"C1"_ustr;
1952 sw_NormalizeRange(rCell1, rCell2);
1953 CPPUNIT_ASSERT_EQUAL( u"A1"_ustr, rCell1 );
1954 CPPUNIT_ASSERT_EQUAL( u"C5"_ustr, rCell2 );
1956 sw_NormalizeRange(rCell2, rCell1);
1957 CPPUNIT_ASSERT_EQUAL( u"C5"_ustr, rCell1 );
1958 CPPUNIT_ASSERT_EQUAL( u"A1"_ustr, rCell2 );
1960 CPPUNIT_ASSERT_EQUAL( OUString(), sw_GetCellName(-1, -1) );
1963 void SwDocTest::setUp()
1965 BootstrapFixture::setUp();
1967 SwGlobals::ensure();
1968 m_pDoc = new SwDoc;
1969 m_xDocShRef = new SwDocShell(*m_pDoc, SfxObjectCreateMode::EMBEDDED);
1970 m_xDocShRef->DoInitNew();
1973 void SwDocTest::tearDown()
1975 m_pDoc = nullptr; // deleted by DoClose()
1976 m_xDocShRef->DoClose();
1977 m_xDocShRef.clear();
1979 BootstrapFixture::tearDown();
1982 void SwDocTest::testTdf156211()
1984 SwScriptInfo oSI;
1985 oSI.SetNoKashidaLine(TextFrameIndex{ 89 }, TextFrameIndex{ 95 });
1987 CPPUNIT_ASSERT(!oSI.IsKashidaLine(TextFrameIndex{ 95 }));
1989 oSI.ClearNoKashidaLine(TextFrameIndex{ 0 }, TextFrameIndex{ 89 });
1991 CPPUNIT_ASSERT(!oSI.IsKashidaLine(TextFrameIndex{ 95 }));
1994 void SwDocTest::testFillRubyList()
1996 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
1997 SwPaM aPaM(aIdx);
1999 SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
2000 CPPUNIT_ASSERT(pTextNode);
2002 auto& rOps = m_pDoc->getIDocumentContentOperations();
2004 auto fnAppendJapanese = [&](const OUString& rText)
2006 rOps.AppendTextNode(*aPaM.GetPoint());
2008 SvxLanguageItem aCJKLangItem(LANGUAGE_JAPANESE, RES_CHRATR_CJK_LANGUAGE);
2009 SvxLanguageItem aWestLangItem(LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE);
2010 rOps.InsertPoolItem(aPaM, aCJKLangItem);
2011 rOps.InsertPoolItem(aPaM, aWestLangItem);
2013 rOps.InsertString(aPaM, rText);
2015 aPaM.SetMark();
2016 aPaM.GetPoint()->nContent = 0;
2018 CPPUNIT_ASSERT_EQUAL(rText, aPaM.GetText());
2021 auto fnAppendRuby = [](SwRubyList* rList, OUString aBase, OUString aRuby)
2023 auto pEnt = std::make_unique<SwRubyListEntry>();
2024 pEnt->SetText(std::move(aBase));
2025 pEnt->SetRubyAttr(SwFormatRuby{ std::move(aRuby) });
2027 rList->push_back(std::move(pEnt));
2030 auto fnGetCombinedString = [](SwPaM& rPaM)
2032 SwRubyList aRubies;
2033 SwDoc::FillRubyList(rPaM, aRubies);
2035 OUStringBuffer aTemp;
2037 for (auto const& rRuby : aRubies)
2039 aTemp.append(rRuby->GetText() + u"["_ustr + rRuby->GetRubyAttr().GetText() + u"]"_ustr);
2042 return aTemp.toString();
2045 // Single word without existing rubies
2047 fnAppendJapanese(u"学校"_ustr);
2048 CPPUNIT_ASSERT_EQUAL(u"学校[]"_ustr, fnGetCombinedString(aPaM));
2051 // Compound word without existing rubies
2053 fnAppendJapanese(u"自動販売機"_ustr);
2054 CPPUNIT_ASSERT_EQUAL(u"自動[]販売[]機[]"_ustr, fnGetCombinedString(aPaM));
2057 // Single word with existing rubies
2059 fnAppendJapanese(u"学校"_ustr);
2061 SwRubyList rList;
2062 fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr);
2064 m_pDoc->SetRubyList(aPaM, rList);
2066 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]"_ustr, fnGetCombinedString(aPaM));
2069 // Compound word with existing rubies
2071 fnAppendJapanese(u"自動販売機"_ustr);
2073 SwRubyList rList;
2074 fnAppendRuby(&rList, u"自動"_ustr, u"じどう"_ustr);
2075 fnAppendRuby(&rList, u"販売"_ustr, u"はんばい"_ustr);
2076 fnAppendRuby(&rList, u"機"_ustr, u"き"_ustr);
2078 m_pDoc->SetRubyList(aPaM, rList);
2080 CPPUNIT_ASSERT_EQUAL(u"自動[じどう]販売[はんばい]機[き]"_ustr, fnGetCombinedString(aPaM));
2083 // Compound word with existing rubies treated as a single word
2085 fnAppendJapanese(u"自動販売機"_ustr);
2087 SwRubyList rList;
2088 fnAppendRuby(&rList, u"自動販売機"_ustr, u"じどうはんばいき"_ustr);
2089 fnAppendRuby(&rList, u""_ustr, u""_ustr);
2090 fnAppendRuby(&rList, u""_ustr, u""_ustr);
2092 m_pDoc->SetRubyList(aPaM, rList);
2094 CPPUNIT_ASSERT_EQUAL(u"自動販売機[じどうはんばいき]"_ustr, fnGetCombinedString(aPaM));
2097 // tdf#141466: Characteristic test from bug
2099 fnAppendJapanese(u"学校に行きます。"_ustr);
2101 SwRubyList rList;
2102 fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr);
2103 fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
2104 fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
2105 fnAppendRuby(&rList, u"きます"_ustr, u""_ustr);
2106 fnAppendRuby(&rList, u"。"_ustr, u""_ustr);
2108 m_pDoc->SetRubyList(aPaM, rList);
2110 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に[]行[い]き[]ます[]。[]"_ustr,
2111 fnGetCombinedString(aPaM));
2114 // tdf#107184: Characteristic test for ruby group mode editing
2116 fnAppendJapanese(u"学校に行きます"_ustr);
2118 SwRubyList rList;
2119 fnAppendRuby(&rList, u"学校に行きます"_ustr, u"がっこうにいきます"_ustr);
2121 m_pDoc->SetRubyList(aPaM, rList);
2123 CPPUNIT_ASSERT_EQUAL(u"学校に行きます[がっこうにいきます]"_ustr, fnGetCombinedString(aPaM));
2126 // tdf#156543: Characteristic test for ruby mono mode editing
2128 fnAppendJapanese(u"学校に行きます"_ustr);
2130 SwRubyList rList;
2131 fnAppendRuby(&rList, u"学"_ustr, u"がっ"_ustr);
2132 fnAppendRuby(&rList, u"校"_ustr, u"こう"_ustr);
2133 fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
2134 fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
2135 fnAppendRuby(&rList, u"き"_ustr, u""_ustr);
2136 fnAppendRuby(&rList, u"ま"_ustr, u""_ustr);
2137 fnAppendRuby(&rList, u"す"_ustr, u""_ustr);
2139 m_pDoc->SetRubyList(aPaM, rList);
2141 CPPUNIT_ASSERT_EQUAL(u"学[がっ]校[こう]に[]行[い]き[]ます[]"_ustr,
2142 fnGetCombinedString(aPaM));
2145 // tdf#156543: Characteristic test for ruby mono mode editing
2147 fnAppendJapanese(u"学校に行きます"_ustr);
2149 SwRubyList rList;
2150 fnAppendRuby(&rList, u"学"_ustr, u"がっ"_ustr);
2151 fnAppendRuby(&rList, u"校"_ustr, u"こう"_ustr);
2152 fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
2153 fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
2154 fnAppendRuby(&rList, u"き"_ustr, u""_ustr);
2155 fnAppendRuby(&rList, u"ま"_ustr, u""_ustr);
2156 fnAppendRuby(&rList, u"す"_ustr, u""_ustr);
2158 m_pDoc->SetRubyList(aPaM, rList);
2160 CPPUNIT_ASSERT_EQUAL(u"学[がっ]校[こう]に[]行[い]き[]ます[]"_ustr,
2161 fnGetCombinedString(aPaM));
2164 // Partial PaM
2166 fnAppendJapanese(u"学校に行こう。"_ustr);
2168 SwPaM aAdjPaM{ *aPaM.GetPoint(), *aPaM.GetMark() };
2169 aAdjPaM.Normalize();
2170 aAdjPaM.GetMark()->AdjustContent(-1);
2172 CPPUNIT_ASSERT_EQUAL(u"学校[]に[]行[]こう[]"_ustr, fnGetCombinedString(aAdjPaM));
2175 // Empty PaM
2177 fnAppendJapanese(u"学校"_ustr);
2179 aPaM.DeleteMark();
2181 CPPUNIT_ASSERT_EQUAL(u"学校[]"_ustr, fnGetCombinedString(aPaM));
2185 void SwDocTest::testSetRubyList()
2187 SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
2188 SwPaM aPaM(aIdx);
2190 SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
2191 CPPUNIT_ASSERT(pTextNode);
2193 auto& rOps = m_pDoc->getIDocumentContentOperations();
2195 auto fnAppendJapanese = [&](const OUString& rText)
2197 rOps.AppendTextNode(*aPaM.GetPoint());
2199 SvxLanguageItem aCJKLangItem(LANGUAGE_JAPANESE, RES_CHRATR_CJK_LANGUAGE);
2200 SvxLanguageItem aWestLangItem(LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE);
2201 rOps.InsertPoolItem(aPaM, aCJKLangItem);
2202 rOps.InsertPoolItem(aPaM, aWestLangItem);
2204 rOps.InsertString(aPaM, rText);
2206 aPaM.SetMark();
2207 aPaM.GetPoint()->nContent = 0;
2209 CPPUNIT_ASSERT_EQUAL(rText, aPaM.GetText());
2212 auto fnAppendRuby = [](SwRubyList* rList, OUString aBase, OUString aRuby)
2214 auto pEnt = std::make_unique<SwRubyListEntry>();
2215 pEnt->SetText(std::move(aBase));
2216 pEnt->SetRubyAttr(SwFormatRuby{ std::move(aRuby) });
2218 rList->push_back(std::move(pEnt));
2221 auto fnGetCombinedString = [&]
2223 OUStringBuffer aTemp;
2225 auto* pPos = aPaM.GetPoint();
2226 const auto* pTNd = pPos->GetNode().GetTextNode();
2227 const auto& rText = pTNd->GetText();
2228 const auto* pHts = pTNd->GetpSwpHints();
2230 for (sal_Int32 i = 0; i < rText.getLength(); ++i)
2232 aTemp.append(rText[i]);
2234 if (pHts)
2236 for (size_t j = 0; j < pHts->Count(); ++j)
2238 const auto* pHt = pHts->Get(j);
2239 if (pHt->Which() == RES_TXTATR_CJK_RUBY && pHt->GetAnyEnd() == (i + 1))
2241 aTemp.append(u"["_ustr + pHt->GetRuby().GetText() + u"]"_ustr);
2247 return aTemp.toString();
2250 // Trivial characteristic test
2252 fnAppendJapanese(u"学校"_ustr);
2254 SwRubyList rList;
2255 fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr);
2257 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2258 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPaM.GetMark()->GetContentIndex());
2259 m_pDoc->SetRubyList(aPaM, rList);
2260 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2261 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPaM.GetMark()->GetContentIndex());
2263 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]"_ustr, fnGetCombinedString());
2265 // Operation should be idempotent
2266 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2267 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPaM.GetMark()->GetContentIndex());
2268 m_pDoc->SetRubyList(aPaM, rList);
2269 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2270 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPaM.GetMark()->GetContentIndex());
2272 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]"_ustr, fnGetCombinedString());
2275 // tdf#141466: Characteristic test from bug
2277 fnAppendJapanese(u"学校に行きます。"_ustr);
2279 SwRubyList rList;
2280 fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr);
2281 fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
2282 fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
2283 fnAppendRuby(&rList, u"きます"_ustr, u""_ustr);
2284 fnAppendRuby(&rList, u"。"_ustr, u""_ustr);
2286 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2287 CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
2288 m_pDoc->SetRubyList(aPaM, rList);
2289 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2290 CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
2292 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に行[い]きます。"_ustr, fnGetCombinedString());
2294 // Operation should be idempotent
2295 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2296 CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
2297 m_pDoc->SetRubyList(aPaM, rList);
2298 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2299 CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
2301 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に行[い]きます。"_ustr, fnGetCombinedString());
2304 // Base text merging/deletion at end of selection
2306 fnAppendJapanese(u"学校に行こう。"_ustr);
2308 SwPaM aAdjPaM{ *aPaM.GetPoint(), *aPaM.GetMark() };
2309 aAdjPaM.GetPoint()->AdjustContent(-1);
2311 SwRubyList rList;
2312 fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr);
2313 fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
2314 fnAppendRuby(&rList, u"行こう"_ustr, u"いこう"_ustr);
2315 fnAppendRuby(&rList, u""_ustr, u""_ustr);
2316 fnAppendRuby(&rList, u""_ustr, u"this ruby should not appear"_ustr);
2317 fnAppendRuby(&rList, u""_ustr, u""_ustr);
2319 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aAdjPaM.GetPoint()->GetContentIndex());
2320 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aAdjPaM.GetMark()->GetContentIndex());
2321 m_pDoc->SetRubyList(aAdjPaM, rList);
2322 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aAdjPaM.GetPoint()->GetContentIndex());
2323 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aAdjPaM.GetMark()->GetContentIndex());
2325 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に行こう[いこう]。"_ustr, fnGetCombinedString());
2327 // Operation should be idempotent
2328 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aAdjPaM.GetPoint()->GetContentIndex());
2329 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aAdjPaM.GetMark()->GetContentIndex());
2330 m_pDoc->SetRubyList(aAdjPaM, rList);
2331 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aAdjPaM.GetPoint()->GetContentIndex());
2332 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aAdjPaM.GetMark()->GetContentIndex());
2334 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に行こう[いこう]。"_ustr, fnGetCombinedString());
2337 // Base text deletion
2339 fnAppendJapanese(u"学校に行きます。"_ustr);
2341 SwRubyList rList;
2342 fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr);
2343 fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
2344 fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
2345 fnAppendRuby(&rList, u"きます"_ustr, u""_ustr);
2346 fnAppendRuby(&rList, u"。"_ustr, u""_ustr);
2348 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2349 CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
2350 m_pDoc->SetRubyList(aPaM, rList);
2351 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2352 CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
2354 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に行[い]きます。"_ustr, fnGetCombinedString());
2356 SwRubyList rList2;
2357 fnAppendRuby(&rList2, u"学校"_ustr, u"がっこう"_ustr);
2358 fnAppendRuby(&rList2, u"に"_ustr, u""_ustr);
2359 fnAppendRuby(&rList2, u""_ustr, u"い"_ustr);
2360 fnAppendRuby(&rList2, u"来"_ustr, u"き"_ustr);
2361 fnAppendRuby(&rList2, u"ます"_ustr, u""_ustr);
2362 fnAppendRuby(&rList2, u"。"_ustr, u""_ustr);
2364 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2365 CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
2366 m_pDoc->SetRubyList(aPaM, rList2);
2367 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2368 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2370 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に来[き]ます。"_ustr, fnGetCombinedString());
2372 // Operation should be idempotent
2373 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2374 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2375 m_pDoc->SetRubyList(aPaM, rList2);
2376 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2377 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2379 CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に来[き]ます。"_ustr, fnGetCombinedString());
2382 // tdf#107184: Characteristic test for ruby group mode editing
2384 fnAppendJapanese(u"学校に行きます"_ustr);
2386 SwRubyList rList;
2387 fnAppendRuby(&rList, u"学校に行きます"_ustr, u"がっこうにいきます"_ustr);
2389 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2390 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2391 m_pDoc->SetRubyList(aPaM, rList);
2392 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2393 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2395 CPPUNIT_ASSERT_EQUAL(u"学校に行きます[がっこうにいきます]"_ustr, fnGetCombinedString());
2397 // Operation should be idempotent
2398 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2399 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2400 m_pDoc->SetRubyList(aPaM, rList);
2401 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2402 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2404 CPPUNIT_ASSERT_EQUAL(u"学校に行きます[がっこうにいきます]"_ustr, fnGetCombinedString());
2407 // tdf#107184: Delete ruby in group mode after populating
2409 fnAppendJapanese(u"学校に行きます"_ustr);
2411 SwRubyList rList;
2412 fnAppendRuby(&rList, u"学校に行きます"_ustr, u"がっこうにいきます"_ustr);
2414 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2415 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2416 m_pDoc->SetRubyList(aPaM, rList);
2417 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2418 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2420 CPPUNIT_ASSERT_EQUAL(u"学校に行きます[がっこうにいきます]"_ustr, fnGetCombinedString());
2422 SwRubyList rList2;
2423 fnAppendRuby(&rList2, u"学校に行きます"_ustr, u""_ustr);
2425 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2426 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2427 m_pDoc->SetRubyList(aPaM, rList2);
2428 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2429 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2431 CPPUNIT_ASSERT_EQUAL(u"学校に行きます"_ustr, fnGetCombinedString());
2433 // Operation should be idempotent
2434 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2435 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2436 m_pDoc->SetRubyList(aPaM, rList2);
2437 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2438 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2440 CPPUNIT_ASSERT_EQUAL(u"学校に行きます"_ustr, fnGetCombinedString());
2443 // tdf#156543: Characteristic test for ruby mono mode editing
2445 fnAppendJapanese(u"学校に行きます"_ustr);
2447 SwRubyList rList;
2448 fnAppendRuby(&rList, u"学"_ustr, u"がっ"_ustr);
2449 fnAppendRuby(&rList, u"校"_ustr, u"こう"_ustr);
2450 fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
2451 fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
2452 fnAppendRuby(&rList, u"き"_ustr, u""_ustr);
2453 fnAppendRuby(&rList, u"ま"_ustr, u""_ustr);
2454 fnAppendRuby(&rList, u"す"_ustr, u"す"_ustr);
2456 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2457 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2458 m_pDoc->SetRubyList(aPaM, rList);
2459 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2460 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2462 CPPUNIT_ASSERT_EQUAL(u"学[がっ]校[こう]に行[い]きます[す]"_ustr, fnGetCombinedString());
2464 // Operation should be idempotent
2465 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2466 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2467 m_pDoc->SetRubyList(aPaM, rList);
2468 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
2469 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
2471 CPPUNIT_ASSERT_EQUAL(u"学[がっ]校[こう]に行[い]きます[す]"_ustr, fnGetCombinedString());
2474 // Offset PaM - Combination of insert and replace
2476 fnAppendJapanese(u"学校員"_ustr);
2478 SwPosition aNewPos{ aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent };
2479 const SwTextNode* pTNd = aNewPos.GetNode().GetTextNode();
2480 pTNd->GoNext(aNewPos, SwCursorSkipMode::Chars);
2482 SwPaM aEmptyPaM{ aNewPos };
2483 aEmptyPaM.SetMark();
2484 aEmptyPaM.GetMark()->AdjustContent(1);
2486 SwRubyList rList;
2487 fnAppendRuby(&rList, u"森林"_ustr, u"しんりん"_ustr);
2488 fnAppendRuby(&rList, u"海上"_ustr, u"かいじょう"_ustr);
2489 fnAppendRuby(&rList, u"地面"_ustr, u"じめん"_ustr);
2491 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
2492 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aEmptyPaM.GetMark()->GetContentIndex());
2493 m_pDoc->SetRubyList(aEmptyPaM, rList);
2494 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
2495 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aEmptyPaM.GetMark()->GetContentIndex());
2497 CPPUNIT_ASSERT_EQUAL(u"学森林[しんりん]海上[かいじょう]地面[じめん]員"_ustr,
2498 fnGetCombinedString());
2500 // Operation should be idempotent
2501 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
2502 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aEmptyPaM.GetMark()->GetContentIndex());
2503 m_pDoc->SetRubyList(aEmptyPaM, rList);
2504 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
2505 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aEmptyPaM.GetMark()->GetContentIndex());
2507 CPPUNIT_ASSERT_EQUAL(u"学森林[しんりん]海上[かいじょう]地面[じめん]員"_ustr,
2508 fnGetCombinedString());
2511 // Partial PaM with mono replacement
2513 fnAppendJapanese(u"学校に行こう。"_ustr);
2515 SwPaM aAdjPaM{ *aPaM.GetPoint(), *aPaM.GetMark() };
2516 aAdjPaM.Normalize();
2517 aAdjPaM.GetMark()->AdjustContent(-1);
2519 SwRubyList rList;
2520 fnAppendRuby(&rList, u"学"_ustr, u"がっ"_ustr);
2521 fnAppendRuby(&rList, u"校"_ustr, u"こう"_ustr);
2522 fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
2523 fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
2524 fnAppendRuby(&rList, u"こ"_ustr, u""_ustr);
2525 fnAppendRuby(&rList, u"う"_ustr, u""_ustr);
2527 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aAdjPaM.GetPoint()->GetContentIndex());
2528 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aAdjPaM.GetMark()->GetContentIndex());
2529 m_pDoc->SetRubyList(aAdjPaM, rList);
2530 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aAdjPaM.GetPoint()->GetContentIndex());
2531 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aAdjPaM.GetMark()->GetContentIndex());
2533 CPPUNIT_ASSERT_EQUAL(u"学[がっ]校[こう]に行[い]こう。"_ustr, fnGetCombinedString());
2535 // Operation should be idempotent
2536 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aAdjPaM.GetPoint()->GetContentIndex());
2537 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aAdjPaM.GetMark()->GetContentIndex());
2538 m_pDoc->SetRubyList(aAdjPaM, rList);
2539 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aAdjPaM.GetPoint()->GetContentIndex());
2540 CPPUNIT_ASSERT_EQUAL(sal_Int32(6), aAdjPaM.GetMark()->GetContentIndex());
2542 CPPUNIT_ASSERT_EQUAL(u"学[がっ]校[こう]に行[い]こう。"_ustr, fnGetCombinedString());
2545 // Empty PaM - Should insert
2547 fnAppendJapanese(u"学校"_ustr);
2549 SwPosition aNewPos{ aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent };
2550 const SwTextNode* pTNd = aNewPos.GetNode().GetTextNode();
2551 pTNd->GoNext(aNewPos, SwCursorSkipMode::Chars);
2553 SwPaM aEmptyPaM{ aNewPos };
2554 aEmptyPaM.SetMark();
2556 SwRubyList rList;
2557 fnAppendRuby(&rList, u"森林"_ustr, u"しんりん"_ustr);
2558 fnAppendRuby(&rList, u"海上"_ustr, u"かいじょう"_ustr);
2559 fnAppendRuby(&rList, u"地面"_ustr, u"じめん"_ustr);
2561 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
2562 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetMark()->GetContentIndex());
2563 m_pDoc->SetRubyList(aEmptyPaM, rList);
2564 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
2565 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aEmptyPaM.GetMark()->GetContentIndex());
2567 CPPUNIT_ASSERT_EQUAL(u"学森林[しんりん]海上[かいじょう]地面[じめん]校"_ustr,
2568 fnGetCombinedString());
2570 // Operation should be idempotent
2571 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
2572 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aEmptyPaM.GetMark()->GetContentIndex());
2573 m_pDoc->SetRubyList(aEmptyPaM, rList);
2574 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
2575 CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aEmptyPaM.GetMark()->GetContentIndex());
2577 CPPUNIT_ASSERT_EQUAL(u"学森林[しんりん]海上[かいじょう]地面[じめん]校"_ustr,
2578 fnGetCombinedString());
2582 CPPUNIT_TEST_SUITE_REGISTRATION(SwDocTest);
2584 CPPUNIT_PLUGIN_IMPLEMENT();
2586 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */