LCOV - code coverage report
Current view: top level - sw/qa/core - uwriter.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 949 957 99.2 %
Date: 2015-06-13 12:38:46 Functions: 72 90 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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             :  */
       9             : 
      10             : #include <sal/config.h>
      11             : #include <test/bootstrapfixture.hxx>
      12             : 
      13             : #include <rtl/strbuf.hxx>
      14             : #include <osl/file.hxx>
      15             : 
      16             : #include <com/sun/star/i18n/TransliterationModulesExtra.hpp>
      17             : 
      18             : #include <comphelper/processfactory.hxx>
      19             : #include <comphelper/random.hxx>
      20             : #include <tools/urlobj.hxx>
      21             : #include <unotools/tempfile.hxx>
      22             : #include <unotools/transliterationwrapper.hxx>
      23             : 
      24             : #include <editeng/langitem.hxx>
      25             : #include <editeng/charhiddenitem.hxx>
      26             : 
      27             : #include <sfx2/app.hxx>
      28             : #include <sfx2/docfilt.hxx>
      29             : #include <sfx2/docfile.hxx>
      30             : #include <sfx2/sfxmodelfactory.hxx>
      31             : 
      32             : #include <xmloff/odffields.hxx>
      33             : 
      34             : #include "breakit.hxx"
      35             : #include "doc.hxx"
      36             : #include <IDocumentRedlineAccess.hxx>
      37             : #include <IDocumentFieldsAccess.hxx>
      38             : #include <IDocumentStatistics.hxx>
      39             : #include "cellfml.hxx"
      40             : #include "docsh.hxx"
      41             : #include "docstat.hxx"
      42             : #include "docufld.hxx"
      43             : #include "fmtanchr.hxx"
      44             : #include "init.hxx"
      45             : #include "ndtxt.hxx"
      46             : #include "shellio.hxx"
      47             : #include "shellres.hxx"
      48             : #include "swcrsr.hxx"
      49             : #include "swscanner.hxx"
      50             : #include "swmodule.hxx"
      51             : #include <swdll.hxx>
      52             : #include "swtypes.hxx"
      53             : #include "fmtftn.hxx"
      54             : #include "fmtrfmrk.hxx"
      55             : #include <fmtinfmt.hxx>
      56             : #include <fchrfmt.hxx>
      57             : #include "fmtfld.hxx"
      58             : #include "redline.hxx"
      59             : #include "docary.hxx"
      60             : #include "modeltoviewhelper.hxx"
      61             : #include "scriptinfo.hxx"
      62             : #include "IMark.hxx"
      63             : #include "ring.hxx"
      64             : #include "calbck.hxx"
      65             : #include "pagedesc.hxx"
      66             : 
      67             : typedef tools::SvRef<SwDocShell> SwDocShellRef;
      68             : 
      69             : using namespace ::com::sun::star;
      70             : 
      71             : /* Implementation of Swdoc-Test class */
      72             : 
      73          60 : class SwDocTest : public test::BootstrapFixture
      74             : {
      75             : public:
      76          30 :     SwDocTest()
      77          30 :         : m_pDoc(NULL)
      78             :     {
      79          30 :     }
      80             : 
      81             :     virtual void setUp() SAL_OVERRIDE;
      82             :     virtual void tearDown() SAL_OVERRIDE;
      83             : 
      84             :     void randomTest();
      85             :     void testPageDescName();
      86             :     void testFileNameFields();
      87             :     void testDocStat();
      88             :     void testModelToViewHelperPassthrough();
      89             :     void testModelToViewHelperExpandFieldsExpandFootnote();
      90             :     void testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode();
      91             :     void testModelToViewHelperExpandFields();
      92             :     void testModelToViewHelperExpandFieldsReplaceMode();
      93             :     void testModelToViewHelperExpandFieldsHideInvisible();
      94             :     void testModelToViewHelperExpandFieldsHideRedlined();
      95             :     void testModelToViewHelperExpandFieldsHideInvisibleExpandFootnote();
      96             :     void testModelToViewHelperExpandFieldsHideInvisibleExpandFootnoteReplaceMode();
      97             :     void testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnote();
      98             :     void testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnoteReplaceMode();
      99             :     void testModelToViewHelperHideInvisibleHideRedlined();
     100             :     void testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnote();
     101             :     void testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnoteReplaceMode();
     102             :     void testModelToViewHelperExpandFieldsExpandFootnote2();
     103             :     void testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode2();
     104             :     void testSwScanner();
     105             :     void testUserPerceivedCharCount();
     106             :     void testMergePortionsDeleteNotSorted();
     107             :     void testGraphicAnchorDeletion();
     108             :     void testTransliterate();
     109             :     void testMarkMove();
     110             :     void testFormulas();
     111             :     void testIntrusiveRing();
     112             :     void testClientModify();
     113             :     void test64kPageDescs();
     114             : 
     115           2 :     CPPUNIT_TEST_SUITE(SwDocTest);
     116             : 
     117           1 :     CPPUNIT_TEST(testTransliterate);
     118           1 :     CPPUNIT_TEST(randomTest);
     119           1 :     CPPUNIT_TEST(testPageDescName);
     120           1 :     CPPUNIT_TEST(testFileNameFields);
     121           1 :     CPPUNIT_TEST(testDocStat);
     122           1 :     CPPUNIT_TEST(testModelToViewHelperPassthrough);
     123           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnote);
     124           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode);
     125           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFields);
     126           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsReplaceMode);
     127           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisible);
     128           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideRedlined);
     129           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleExpandFootnote);
     130           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleExpandFootnoteReplaceMode);
     131           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnote);
     132           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnoteReplaceMode);
     133           1 :     CPPUNIT_TEST(testModelToViewHelperHideInvisibleHideRedlined);
     134           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnote);
     135           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnoteReplaceMode);
     136           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnote2);
     137           1 :     CPPUNIT_TEST(testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode2);
     138           1 :     CPPUNIT_TEST(testSwScanner);
     139           1 :     CPPUNIT_TEST(testUserPerceivedCharCount);
     140           1 :     CPPUNIT_TEST(testMergePortionsDeleteNotSorted);
     141           1 :     CPPUNIT_TEST(testGraphicAnchorDeletion);
     142           1 :     CPPUNIT_TEST(testMarkMove);
     143           1 :     CPPUNIT_TEST(testFormulas);
     144           1 :     CPPUNIT_TEST(testIntrusiveRing);
     145           1 :     CPPUNIT_TEST(testClientModify);
     146           1 :     CPPUNIT_TEST(test64kPageDescs);
     147           5 :     CPPUNIT_TEST_SUITE_END();
     148             : 
     149             : private:
     150             :     SwDoc *m_pDoc;
     151             :     SwDocShellRef m_xDocShRef;
     152             : };
     153             : 
     154           1 : void SwDocTest::testPageDescName()
     155             : {
     156           1 :     ShellResource aShellResources;
     157             : 
     158           2 :     std::vector<OUString> aResults;
     159             : 
     160             :     //These names must be unique for each different combination, otherwise
     161             :     //duplicate page description names may exist, which will causes lookup
     162             :     //by name to be incorrect, and so the corresponding export to .odt
     163           1 :     aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::NORMAL_PAGE));
     164           1 :     aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::FIRST_PAGE));
     165           1 :     aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::FOLLOW_PAGE));
     166             : 
     167           1 :     std::sort(aResults.begin(), aResults.end());
     168           1 :     aResults.erase(std::unique(aResults.begin(), aResults.end()), aResults.end());
     169             : 
     170           2 :     CPPUNIT_ASSERT_MESSAGE("GetPageDescName results must be unique", aResults.size() == 3);
     171           1 : }
     172             : 
     173             : //See https://bugs.libreoffice.org/show_bug.cgi?id=32463
     174           1 : void SwDocTest::testFileNameFields()
     175             : {
     176             :     //Here's a file name with some chars in it that will be %% encoded, when expanding
     177             :     //SwFileNameFields we want to restore the original readable filename
     178           1 :     utl::TempFile aTempFile(OUString("demo [name]"));
     179           1 :     aTempFile.EnableKillingFile();
     180             : 
     181           2 :     INetURLObject aTempFileURL(aTempFile.GetURL());
     182           2 :     OUString sFileURL = aTempFileURL.GetMainURL(INetURLObject::NO_DECODE);
     183           2 :     SfxMedium aDstMed(sFileURL, STREAM_STD_READWRITE);
     184             : 
     185             :     SfxFilter aFilter(
     186             :         OUString("Text"),
     187             :         OUString(), SfxFilterFlags::NONE, SotClipboardFormatId::NONE, OUString(), 0, OUString(),
     188           2 :         OUString("TEXT"), OUString() );
     189           1 :     aDstMed.SetFilter(&aFilter);
     190             : 
     191           1 :     m_xDocShRef->DoSaveAs(aDstMed);
     192           1 :     m_xDocShRef->DoSaveCompleted(&aDstMed);
     193             : 
     194           1 :     const INetURLObject &rUrlObj = m_xDocShRef->GetMedium()->GetURLObject();
     195             : 
     196           2 :     SwFileNameFieldType aNameField(m_pDoc);
     197             : 
     198             :     {
     199           1 :         OUString sResult(aNameField.Expand(FF_NAME));
     200             :         OUString sExpected(rUrlObj.getName(INetURLObject::LAST_SEGMENT,
     201           2 :             true,INetURLObject::DECODE_WITH_CHARSET));
     202           2 :         CPPUNIT_ASSERT_MESSAGE("Expected Readable FileName", sResult == sExpected);
     203             :     }
     204             : 
     205             :     {
     206           1 :         OUString sResult(aNameField.Expand(FF_PATHNAME));
     207           2 :         OUString sExpected(rUrlObj.GetFull());
     208           2 :         CPPUNIT_ASSERT_MESSAGE("Expected Readable FileName", sResult == sExpected);
     209             :     }
     210             : 
     211             :     {
     212           1 :         OUString sResult(aNameField.Expand(FF_PATH));
     213           2 :         INetURLObject aTemp(rUrlObj);
     214           1 :         aTemp.removeSegment();
     215           2 :         OUString sExpected(aTemp.PathToFileName());
     216           2 :         CPPUNIT_ASSERT_MESSAGE("Expected Readable FileName", sResult == sExpected);
     217             :     }
     218             : 
     219             :     {
     220           1 :         OUString sResult(aNameField.Expand(FF_NAME_NOEXT));
     221             :         OUString sExpected(rUrlObj.getName(INetURLObject::LAST_SEGMENT,
     222           2 :             true,INetURLObject::DECODE_WITH_CHARSET));
     223             :         //Chop off .tmp
     224           1 :         sExpected = sExpected.copy(0, sExpected.getLength() - 4);
     225           2 :         CPPUNIT_ASSERT_MESSAGE("Expected Readable FileName", sResult == sExpected);
     226             :     }
     227             : 
     228           2 :     m_xDocShRef->DoInitNew(0);
     229           1 : }
     230             : 
     231             : //See http://lists.freedesktop.org/archives/libreoffice/2011-August/016666.html
     232             : //Remove unnecessary parameter to IDocumentStatistics::UpdateDocStat for
     233             : //motivation
     234           1 : void SwDocTest::testDocStat()
     235             : {
     236           1 :     CPPUNIT_ASSERT_MESSAGE("Expected initial 0 count", m_pDoc->getIDocumentStatistics().GetDocStat().nChar == 0);
     237             : 
     238           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
     239           2 :     SwPaM aPaM(aIdx);
     240             : 
     241           2 :     OUString sText("Hello World");
     242           1 :     m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sText);
     243             : 
     244           1 :     CPPUNIT_ASSERT_MESSAGE("Should still be non-updated 0 count", m_pDoc->getIDocumentStatistics().GetDocStat().nChar == 0);
     245             : 
     246           1 :     SwDocStat aDocStat = m_pDoc->getIDocumentStatistics().GetUpdatedDocStat( false, true );
     247           1 :     sal_uLong nLen = static_cast<sal_uLong>(sText.getLength());
     248             : 
     249           1 :     CPPUNIT_ASSERT_MESSAGE("Should now have updated count", aDocStat.nChar == nLen);
     250             : 
     251           2 :     CPPUNIT_ASSERT_MESSAGE("And cache is updated too", m_pDoc->getIDocumentStatistics().GetDocStat().nChar == nLen);
     252           1 : }
     253             : 
     254             : //For UI character counts we should follow UAX#29 and display the user
     255             : //perceived characters, not the number of codepoints, nor the number of code
     256             : //units http://unicode.org/reports/tr29/
     257           1 : void SwDocTest::testUserPerceivedCharCount()
     258             : {
     259           1 :     SwBreakIt *pBreakIter = SwBreakIt::Get();
     260             : 
     261             :     //Grapheme example, two different unicode code-points perceived by the user as a single
     262             :     //glyph
     263           1 :     const sal_Unicode ALEF_QAMATS [] = { 0x05D0, 0x05B8 };
     264           1 :     OUString sALEF_QAMATS(ALEF_QAMATS, SAL_N_ELEMENTS(ALEF_QAMATS));
     265           1 :     sal_Int32 nGraphemeCount = pBreakIter->getGraphemeCount(sALEF_QAMATS);
     266           1 :     CPPUNIT_ASSERT_MESSAGE("Grapheme Count should be 1", nGraphemeCount == 1);
     267             : 
     268             :     //Surrogate pair example, one single unicode code-point (U+1D11E)
     269             :     //represented as two code units in UTF-16
     270           1 :     const sal_Unicode GCLEF[] = { 0xD834, 0xDD1E };
     271           2 :     OUString sGCLEF(GCLEF, SAL_N_ELEMENTS(GCLEF));
     272           1 :     sal_Int32 nCount = pBreakIter->getGraphemeCount(sGCLEF);
     273           2 :     CPPUNIT_ASSERT_MESSAGE("Surrogate Pair should be counted as single character", nCount == 1);
     274           1 : }
     275             : 
     276          16 : SwTextNode* getModelToViewTestDocument(SwDoc *pDoc)
     277             : {
     278          16 :     SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
     279          32 :     SwPaM aPaM(aIdx);
     280             : 
     281          32 :     SwFormatFootnote aFootnote;
     282          16 :     aFootnote.SetNumStr(OUString("foo"));
     283             : 
     284          16 :     pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     285          16 :     pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("AAAAA BBBBB "));
     286          16 :     SwTextNode* pTextNode = aPaM.GetNode().GetTextNode();
     287          16 :     sal_Int32 nPos = aPaM.GetPoint()->nContent.GetIndex();
     288          16 :     pTextNode->InsertItem(aFootnote, nPos, nPos);
     289          16 :     pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(" CCCCC "));
     290          16 :     nPos = aPaM.GetPoint()->nContent.GetIndex();
     291          16 :     pTextNode->InsertItem(aFootnote, nPos, nPos);
     292          16 :     pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(" DDDDD"));
     293          16 :     CPPUNIT_ASSERT(pTextNode->GetText().getLength() == (4*5) + 5 + 2);
     294             : 
     295             :     //set start of selection to first B
     296          16 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 6);
     297          16 :     aPaM.SetMark();
     298             :     //set end of selection to last C
     299          16 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 14);
     300             :     //set character attribute hidden on range
     301          32 :     SvxCharHiddenItem aHidden(true, RES_CHRATR_HIDDEN);
     302          16 :     pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aHidden );
     303          16 :     aPaM.DeleteMark();
     304             : 
     305             :     //turn on red-lining and show changes
     306          16 :     pDoc->getIDocumentRedlineAccess().SetRedlineMode(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_DELETE|nsRedlineMode_t::REDLINE_SHOW_INSERT);
     307          16 :     CPPUNIT_ASSERT_MESSAGE("redlining should be on", pDoc->getIDocumentRedlineAccess().IsRedlineOn());
     308          16 :     CPPUNIT_ASSERT_MESSAGE("redlines should be visible", IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineMode()));
     309             : 
     310             :     //set start of selection to last A
     311          16 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 4);
     312          16 :     aPaM.SetMark();
     313             :     //set end of selection to second last B
     314          16 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 9);
     315          16 :     pDoc->getIDocumentContentOperations().DeleteAndJoin(aPaM);    //redline-aware deletion api
     316          16 :     aPaM.DeleteMark();
     317             : 
     318          32 :     return pTextNode;
     319             : }
     320             : 
     321           2 : SwTextNode* getModelToViewTestDocument2(SwDoc *pDoc)
     322             : {
     323           2 :     SwTextNode* pTextNode = getModelToViewTestDocument(pDoc);
     324             : 
     325           2 :     SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
     326           4 :     SwPaM aPaM(aIdx);
     327             : 
     328           2 :     pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     329           2 :     pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("AAAAA"));
     330           2 :     IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess();
     331             :     sw::mark::IFieldmark *pFieldmark = dynamic_cast<sw::mark::IFieldmark*>(
     332           2 :             pMarksAccess->makeNoTextFieldBookmark(aPaM, "test", ODF_FORMDROPDOWN));
     333           2 :     CPPUNIT_ASSERT(pFieldmark);
     334           4 :     uno::Sequence< OUString > vListEntries(1);
     335           2 :     vListEntries[0] = "BBBBB";
     336           2 :     (*pFieldmark->GetParameters())[ODF_FORMDROPDOWN_LISTENTRY] = uno::makeAny(vListEntries);
     337           2 :     (*pFieldmark->GetParameters())[ODF_FORMDROPDOWN_RESULT] = uno::makeAny(sal_Int32(0));
     338           2 :     pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("CCCCC"));
     339           2 :     pTextNode = aPaM.GetNode().GetTextNode();
     340           4 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11),
     341           2 :             pTextNode->GetText().getLength());
     342             : 
     343           4 :     return pTextNode;
     344             : }
     345             : 
     346           1 : void SwDocTest::testModelToViewHelperPassthrough()
     347             : {
     348           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     349             : 
     350           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::PassThrough);
     351           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     352           2 :     OUString sModelText = pTextNode->GetText();
     353           2 :     CPPUNIT_ASSERT_EQUAL(sModelText, sViewText);
     354           1 : }
     355             : 
     356           1 : void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnote()
     357             : {
     358           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     359             : 
     360           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::ExpandFootnote);
     361           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     362           2 :     CPPUNIT_ASSERT_EQUAL(
     363           2 :         OUString("AAAAA BBBBB foo CCCCC foo DDDDD"), sViewText);
     364           1 : }
     365             : 
     366           1 : void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode()
     367             : {
     368           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     369             : 
     370             :     ModelToViewHelper aModelToViewHelper(*pTextNode,
     371           1 :             ExpandMode::ExpandFields | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
     372           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     373           2 :     CPPUNIT_ASSERT_EQUAL(
     374             :         OUString("AAAAA BBBBB " + OUString(CHAR_ZWSP) + " CCCCC " + OUString(CHAR_ZWSP) + " DDDDD"),
     375           1 :         sViewText);
     376           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2),
     377           1 :         aModelToViewHelper.getFootnotePositions().size());
     378           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12),
     379           1 :         aModelToViewHelper.getFootnotePositions()[0]);
     380           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(20),
     381           1 :         aModelToViewHelper.getFootnotePositions()[1]);
     382           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     383           2 :         aModelToViewHelper.getFieldPositions().size());
     384           1 : }
     385             : 
     386           1 : void SwDocTest::testModelToViewHelperExpandFields()
     387             : {
     388           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     389             : 
     390           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields);
     391           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     392           2 :     CPPUNIT_ASSERT_EQUAL(
     393           2 :         OUString("AAAAA BBBBB  CCCCC  DDDDD"), sViewText);
     394           1 : }
     395             : 
     396           1 : void SwDocTest::testModelToViewHelperExpandFieldsReplaceMode()
     397             : {
     398           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     399             : 
     400             :     ModelToViewHelper aModelToViewHelper(*pTextNode,
     401           1 :         ExpandMode::ExpandFields | ExpandMode::ReplaceMode);
     402           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     403           2 :     CPPUNIT_ASSERT_EQUAL(OUString("AAAAA BBBBB  CCCCC  DDDDD"),
     404           1 :         sViewText);
     405           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     406           1 :         aModelToViewHelper.getFootnotePositions().size());
     407           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     408           2 :         aModelToViewHelper.getFieldPositions().size());
     409           1 : }
     410             : 
     411           1 : void SwDocTest::testModelToViewHelperExpandFieldsHideInvisible()
     412             : {
     413           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     414             : 
     415           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::HideInvisible);
     416           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     417           2 :     CPPUNIT_ASSERT_EQUAL(
     418             :         OUString("AAAAA CCCCC " + OUStringLiteral1<CH_TXTATR_BREAKWORD>() + " DDDDD"),
     419           2 :         sViewText);
     420           1 : }
     421             : 
     422           1 : void SwDocTest::testModelToViewHelperExpandFieldsHideRedlined()
     423             : {
     424           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     425             : 
     426           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::HideDeletions);
     427           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     428           2 :     CPPUNIT_ASSERT_EQUAL(
     429             :         OUString("AAAABB " + OUStringLiteral1<CH_TXTATR_BREAKWORD>() + " CCCCC " + OUStringLiteral1<CH_TXTATR_BREAKWORD>() + " DDDDD"),
     430           2 :         sViewText);
     431           1 : }
     432             : 
     433           1 : void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleExpandFootnote()
     434             : {
     435           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     436             : 
     437           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::ExpandFootnote);
     438           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     439           2 :     CPPUNIT_ASSERT_EQUAL(OUString("AAAAA CCCCC foo DDDDD"), sViewText);
     440           1 : }
     441             : 
     442           1 : void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleExpandFootnoteReplaceMode()
     443             : {
     444           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     445             : 
     446             :     ModelToViewHelper aModelToViewHelper(*pTextNode,
     447           1 :         ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
     448           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     449           2 :     CPPUNIT_ASSERT_EQUAL(
     450             :         OUString("AAAAA CCCCC " + OUString(CHAR_ZWSP) + " DDDDD"),
     451           1 :         sViewText);
     452           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
     453           1 :         aModelToViewHelper.getFootnotePositions().size());
     454           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12),
     455           1 :         aModelToViewHelper.getFootnotePositions()[0]);
     456           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     457           2 :         aModelToViewHelper.getFieldPositions().size());
     458           1 : }
     459             : 
     460           1 : void SwDocTest::testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnote()
     461             : {
     462           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     463             : 
     464           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote);
     465           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     466           2 :     CPPUNIT_ASSERT_EQUAL(
     467           2 :         OUString("AAAABB foo CCCCC foo DDDDD"), sViewText);
     468           1 : }
     469             : 
     470           1 : void SwDocTest::testModelToViewHelperExpandFieldsHideHideRedlinedExpandFootnoteReplaceMode()
     471             : {
     472           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     473             : 
     474             :     ModelToViewHelper aModelToViewHelper(*pTextNode,
     475           1 :         ExpandMode::ExpandFields | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
     476           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     477           2 :     CPPUNIT_ASSERT_EQUAL(
     478             :        OUString("AAAABB " + OUString(CHAR_ZWSP) + " CCCCC " + OUString(CHAR_ZWSP) + " DDDDD"),
     479           1 :        sViewText);
     480           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2),
     481           1 :         aModelToViewHelper.getFootnotePositions().size());
     482           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(7),
     483           1 :         aModelToViewHelper.getFootnotePositions()[0]);
     484           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(15),
     485           1 :         aModelToViewHelper.getFootnotePositions()[1]);
     486           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     487           2 :         aModelToViewHelper.getFieldPositions().size());
     488           1 : }
     489             : 
     490           1 : void SwDocTest::testModelToViewHelperHideInvisibleHideRedlined()
     491             : {
     492           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     493             : 
     494           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::HideInvisible | ExpandMode::HideDeletions);
     495           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     496           2 :     OUStringBuffer aBuffer;
     497           1 :     aBuffer.append("AAAACCCCC ");
     498           1 :     aBuffer.append(CH_TXTATR_BREAKWORD);
     499           1 :     aBuffer.append(" DDDDD");
     500           2 :     CPPUNIT_ASSERT_EQUAL(aBuffer.makeStringAndClear(), sViewText);
     501           1 : }
     502             : 
     503           1 : void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnote()
     504             : {
     505           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     506             : 
     507           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote);
     508           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     509           2 :     CPPUNIT_ASSERT_EQUAL(OUString("AAAACCCCC foo DDDDD"), sViewText);
     510           1 : }
     511             : 
     512           1 : void SwDocTest::testModelToViewHelperExpandFieldsHideInvisibleHideRedlinedExpandFootnoteReplaceMode()
     513             : {
     514           1 :     SwTextNode* pTextNode = getModelToViewTestDocument(m_pDoc);
     515             : 
     516             :     ModelToViewHelper aModelToViewHelper(*pTextNode,
     517           1 :         ExpandMode::ExpandFields | ExpandMode::HideInvisible | ExpandMode::HideDeletions | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
     518           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     519           2 :     CPPUNIT_ASSERT_EQUAL(sViewText,
     520           1 :         OUString("AAAACCCCC " + OUString(CHAR_ZWSP) + " DDDDD"));
     521           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
     522           1 :         aModelToViewHelper.getFootnotePositions().size());
     523           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(10),
     524           1 :         aModelToViewHelper.getFootnotePositions()[0]);
     525           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     526           2 :         aModelToViewHelper.getFieldPositions().size());
     527           1 : }
     528             : 
     529           1 : void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnote2()
     530             : {
     531           1 :     SwTextNode* pTextNode = getModelToViewTestDocument2(m_pDoc);
     532             : 
     533           1 :     ModelToViewHelper aModelToViewHelper(*pTextNode, ExpandMode::ExpandFields | ExpandMode::ExpandFootnote);
     534           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     535           2 :     CPPUNIT_ASSERT_EQUAL(OUString("AAAAABBBBBCCCCC"), sViewText);
     536           1 : }
     537             : 
     538           1 : void SwDocTest::testModelToViewHelperExpandFieldsExpandFootnoteReplaceMode2()
     539             : {
     540           1 :     SwTextNode* pTextNode = getModelToViewTestDocument2(m_pDoc);
     541             : 
     542             :     ModelToViewHelper aModelToViewHelper(*pTextNode,
     543           1 :         ExpandMode::ExpandFields | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode);
     544           2 :     OUString sViewText = aModelToViewHelper.getViewText();
     545           2 :     CPPUNIT_ASSERT_EQUAL(
     546             :         OUString("AAAAA" + OUString(CHAR_ZWSP) + "CCCCC"),
     547           1 :         sViewText);
     548           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     549           1 :         aModelToViewHelper.getFootnotePositions().size());
     550           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
     551           1 :         aModelToViewHelper.getFieldPositions().size());
     552           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5),
     553           2 :         aModelToViewHelper.getFieldPositions()[0]);
     554           1 : }
     555             : 
     556           1 : void SwDocTest::testSwScanner()
     557             : {
     558           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
     559           2 :     SwPaM aPaM(aIdx);
     560             : 
     561           1 :     SwTextNode* pTextNode = aPaM.GetNode().GetTextNode();
     562             : 
     563           1 :     CPPUNIT_ASSERT_MESSAGE("Has Text Node", pTextNode);
     564             : 
     565             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=40449
     566             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=39365
     567             :     //Use a temporary OUString as the arg, as that's the trouble behind
     568             :     //fdo#40449 and fdo#39365
     569             :     {
     570             :         SwScanner aScanner(*pTextNode,
     571             :             OUString("Hello World"),
     572             :             0, ModelToViewHelper(), i18n::WordType::DICTIONARY_WORD, 0,
     573           1 :             RTL_CONSTASCII_LENGTH("Hello World"));
     574             : 
     575           1 :         bool bFirstOk = aScanner.NextWord();
     576           1 :         CPPUNIT_ASSERT_MESSAGE("First Token", bFirstOk);
     577           1 :         const OUString &rHello = aScanner.GetWord();
     578           2 :         CPPUNIT_ASSERT_MESSAGE("Should be Hello",
     579           1 :             rHello == "Hello");
     580             : 
     581           1 :         bool bSecondOk = aScanner.NextWord();
     582           1 :         CPPUNIT_ASSERT_MESSAGE("Second Token", bSecondOk);
     583           1 :         const OUString &rWorld = aScanner.GetWord();
     584           2 :         CPPUNIT_ASSERT_MESSAGE("Should be World",
     585           2 :             rWorld == "World");
     586             :     }
     587             : 
     588             :     //See https://www.libreoffice.org/bugzilla/show_bug.cgi?id=45271
     589             :     {
     590           1 :         const sal_Unicode IDEOGRAPHICFULLSTOP_D[] = { 0x3002, 'D' };
     591             : 
     592           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(IDEOGRAPHICFULLSTOP_D,
     593           1 :             SAL_N_ELEMENTS(IDEOGRAPHICFULLSTOP_D)));
     594             : 
     595           1 :         SvxLanguageItem aCJKLangItem( LANGUAGE_CHINESE_SIMPLIFIED, RES_CHRATR_CJK_LANGUAGE );
     596           2 :         SvxLanguageItem aWestLangItem( LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE );
     597           1 :         m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aCJKLangItem );
     598           1 :         m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aWestLangItem );
     599             : 
     600           1 :         SwDocStat aDocStat;
     601           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     602           1 :         pTextNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(IDEOGRAPHICFULLSTOP_D));
     603             : 
     604           1 :         CPPUNIT_ASSERT_MESSAGE("Should be 2", aDocStat.nChar == 2);
     605           2 :         CPPUNIT_ASSERT_MESSAGE("Should be 2", aDocStat.nCharExcludingSpaces == 2);
     606             :     }
     607             :     {
     608             :         const sal_Unicode test[] =
     609             :         {
     610             :             0x3053, 0x306E, 0x65E5, 0x672C, 0x8A9E, 0x306F, 0x6B63, 0x3057,
     611             :             0x304F, 0x6570, 0x3048, 0x3089, 0x308C, 0x308B, 0x3067, 0x3057,
     612             :             0x3087, 0x3046, 0x304B, 0x3002, 0x0041, 0x006E, 0x0064, 0x0020,
     613             :             0x006C, 0x0065, 0x0074, 0x0027, 0x0073, 0x0020, 0x0074, 0x0068,
     614             :             0x0072, 0x006F, 0x0077, 0x0020, 0x0073, 0x006F, 0x006D, 0x0065,
     615             :             0x0020, 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068,
     616             :             0x0020, 0x0069, 0x006E, 0x0020, 0x0074, 0x006F, 0x0020, 0x006D,
     617             :             0x0061, 0x006B, 0x0065, 0x0020, 0x0069, 0x0074, 0x0020, 0x0069,
     618             :             0x006E, 0x0074, 0x0065, 0x0072, 0x0065, 0x0073, 0x0074, 0x0069,
     619             :             0x006E, 0x0067, 0x002E, 0x0020, 0x0020, 0x305D, 0x3057, 0x3066,
     620             :             0x3001, 0x307E, 0x305F, 0x65E5, 0x672C, 0x8A9E, 0x3000, 0x3000,
     621             :             0x3067, 0x3082, 0x4ECA, 0x56DE, 0x306F, 0x7A7A, 0x767D, 0x3092,
     622             :             0x3000, 0x3000, 0x5165, 0x308C, 0x307E, 0x3057, 0x305F, 0x3002,
     623             :             0x0020, 0x0020, 0x0053, 0x006F, 0x0020, 0x0068, 0x006F, 0x0077,
     624             :             0x0020, 0x0064, 0x006F, 0x0065, 0x0073, 0x0020, 0x0074, 0x0068,
     625             :             0x0069, 0x0073, 0x0020, 0x0064, 0x006F, 0x003F, 0x0020, 0x0020
     626           1 :         };
     627           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     628           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(test,
     629           1 :             SAL_N_ELEMENTS(test)));
     630             : 
     631           1 :         SvxLanguageItem aCJKLangItem( LANGUAGE_JAPANESE, RES_CHRATR_CJK_LANGUAGE );
     632           2 :         SvxLanguageItem aWestLangItem( LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE );
     633           1 :         m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aCJKLangItem );
     634           1 :         m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, aWestLangItem );
     635             : 
     636           1 :         SwDocStat aDocStat;
     637           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     638           1 :         pTextNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(test));
     639           1 :         CPPUNIT_ASSERT_MESSAGE("58 words", aDocStat.nWord == 58);
     640           1 :         CPPUNIT_ASSERT_MESSAGE("43 Asian characters and Korean syllables", aDocStat.nAsianWord == 43);
     641           1 :         CPPUNIT_ASSERT_MESSAGE("105 non-whitespace chars", aDocStat.nCharExcludingSpaces == 105);
     642           2 :         CPPUNIT_ASSERT_MESSAGE("128 characters", aDocStat.nChar == 128);
     643             :     }
     644             : 
     645             :     //See https://bz.apache.org/ooo/show_bug.cgi?id=89042
     646             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=53399
     647             :     {
     648           1 :         SwDocStat aDocStat;
     649             : 
     650             :         const sal_Unicode aShouldBeThree[] = {
     651             :             0x0053, 0x0068, 0x006F, 0x0075, 0x006C, 0x0064, 0x0020,
     652             :             0x2018, 0x0062, 0x0065, 0x0020, 0x0074, 0x0068, 0x0072,
     653             :             0x0065, 0x0065, 0x2019
     654           1 :         };
     655             : 
     656           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     657           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(aShouldBeThree, SAL_N_ELEMENTS(aShouldBeThree)));
     658           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     659           1 :         pTextNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(aShouldBeThree));
     660           1 :         CPPUNIT_ASSERT_MESSAGE("Should be 3", aDocStat.nWord == 3);
     661             : 
     662             :         const sal_Unicode aShouldBeFive[] = {
     663             :             // f    r       e       n       c       h       space
     664             :             0x0046, 0x0072, 0x0065, 0x006E, 0x0063, 0x0068, 0x0020,
     665             :             // <<   nbsp    s       a       v       o       i
     666             :             0x00AB, 0x00A0, 0x0073, 0x0061, 0x0076, 0x006F, 0x0069,
     667             :             // r    nnbsp   c       a       l       c       u
     668             :             0x0072, 0x202f, 0x0063, 0x0061, 0x006C, 0x0063, 0x0075,
     669             :             // l    e       r       idspace >>
     670             :             0x006C, 0x0065, 0x0072, 0x3000, 0x00BB
     671           1 :         };
     672             : 
     673           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     674           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(aShouldBeFive, SAL_N_ELEMENTS(aShouldBeFive)));
     675           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     676           1 :         aDocStat.Reset();
     677           1 :         pTextNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(aShouldBeFive));
     678           1 :         CPPUNIT_ASSERT_MESSAGE("Should be 5", aDocStat.nWord == 5);
     679             :     }
     680             : 
     681             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=49629
     682             :     {
     683           1 :         SwDocStat aDocStat;
     684             : 
     685           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     686           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("Apple"));
     687           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     688           1 :         sal_Int32 nPos = aPaM.GetPoint()->nContent.GetIndex();
     689           1 :         SwFormatFootnote aFootnote;
     690           1 :         aFootnote.SetNumStr(OUString("banana"));
     691           1 :         SwTextAttr* pTA = pTextNode->InsertItem(aFootnote, nPos, nPos);
     692           1 :         CPPUNIT_ASSERT(pTA);
     693           1 :         CPPUNIT_ASSERT(pTextNode->Len() == 6); //Apple + 0x02
     694           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     695           1 :         CPPUNIT_ASSERT(aDocStat.nWord == 1);
     696           1 :         CPPUNIT_ASSERT_MESSAGE("footnote should be expanded", aDocStat.nChar == 11);
     697             : 
     698           1 :         const sal_Int32 nNextPos = aPaM.GetPoint()->nContent.GetIndex();
     699           1 :         CPPUNIT_ASSERT(nNextPos == nPos+1);
     700           2 :         SwFormatRefMark aRef(OUString("refmark"));
     701           1 :         pTA = pTextNode->InsertItem(aRef, nNextPos, nNextPos);
     702           1 :         CPPUNIT_ASSERT(pTA);
     703             : 
     704           1 :         aDocStat.Reset();
     705           1 :         pTextNode->SetWordCountDirty(true);
     706           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     707           1 :         CPPUNIT_ASSERT(aDocStat.nWord == 1);
     708           1 :         CPPUNIT_ASSERT_MESSAGE("refmark anchor should not be counted", aDocStat.nChar == 11);
     709             : 
     710           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     711           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("Apple"));
     712             : 
     713           1 :         DateTime aDate(DateTime::SYSTEM);
     714             :         SwPostItField aPostIt(
     715           1 :             static_cast<SwPostItFieldType*>(m_pDoc->getIDocumentFieldsAccess().GetSysFieldType(RES_POSTITFLD)), OUString("An Author"),
     716           3 :             OUString("Some Text"), OUString("Initials"), OUString("Name"), aDate );
     717           1 :         m_pDoc->getIDocumentContentOperations().InsertPoolItem(aPaM, SwFormatField(aPostIt));
     718             : 
     719           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("Apple"));
     720           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     721           1 :         aDocStat.Reset();
     722           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     723           1 :         CPPUNIT_ASSERT(aDocStat.nWord == 1);
     724           1 :         CPPUNIT_ASSERT_MESSAGE("postit anchor should effectively not exist", aDocStat.nChar == 10);
     725           1 :         CPPUNIT_ASSERT(pTextNode->Len() == 11);
     726             : 
     727           2 :         aDocStat.Reset();
     728             :     }
     729             : 
     730             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=46757
     731             :     {
     732           1 :         SwDocStat aDocStat;
     733             : 
     734           1 :         const char aString[] = "Lorem ipsum";
     735           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     736           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(aString));
     737           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     738           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     739           1 :         CPPUNIT_ASSERT_EQUAL(aDocStat.nWord, static_cast<sal_uLong>(2));
     740             : 
     741             :         //turn on red-lining and show changes
     742           1 :         m_pDoc->getIDocumentRedlineAccess().SetRedlineMode(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_DELETE|nsRedlineMode_t::REDLINE_SHOW_INSERT);
     743           1 :         CPPUNIT_ASSERT_MESSAGE("redlining should be on", m_pDoc->getIDocumentRedlineAccess().IsRedlineOn());
     744           1 :         CPPUNIT_ASSERT_MESSAGE("redlines should be visible", IDocumentRedlineAccess::IsShowChanges(m_pDoc->getIDocumentRedlineAccess().GetRedlineMode()));
     745             : 
     746             :         //delete everything except the first word
     747           1 :         aPaM.SetMark(); //set start of selection to current pos
     748           1 :         aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 5);   //set end of selection to fifth char of current node
     749           1 :         m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aPaM);    //redline-aware deletion api
     750             :         //"real underlying text should be the same"
     751           1 :         CPPUNIT_ASSERT_EQUAL(pTextNode->GetText(), OUString(aString));
     752             : 
     753           1 :         aDocStat.Reset();
     754           1 :         pTextNode->SetWordCountDirty(true);
     755           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len()); //but word-counting the text should only count the non-deleted text
     756           1 :         CPPUNIT_ASSERT_EQUAL(aDocStat.nWord, static_cast<sal_uLong>(1));
     757             : 
     758           1 :         pTextNode->SetWordCountDirty(true);
     759             : 
     760             :         //keep red-lining on but hide changes
     761           1 :         m_pDoc->getIDocumentRedlineAccess().SetRedlineMode(nsRedlineMode_t::REDLINE_ON);
     762           1 :         CPPUNIT_ASSERT_MESSAGE("redlining should be still on", m_pDoc->getIDocumentRedlineAccess().IsRedlineOn());
     763           1 :         CPPUNIT_ASSERT_MESSAGE("redlines should be invisible", !IDocumentRedlineAccess::IsShowChanges(m_pDoc->getIDocumentRedlineAccess().GetRedlineMode()));
     764             : 
     765           1 :         aDocStat.Reset();
     766           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len()); //but word-counting the text should only count the non-deleted text
     767           1 :         CPPUNIT_ASSERT_EQUAL(aDocStat.nWord, static_cast<sal_uLong>(1));
     768             : 
     769           1 :         OUString sLorem = pTextNode->GetText();
     770           1 :         CPPUNIT_ASSERT(sLorem == "Lorem");
     771             : 
     772           1 :         const SwRedlineTable& rTable = m_pDoc->getIDocumentRedlineAccess().GetRedlineTable();
     773             : 
     774           1 :         SwNodes& rNds = m_pDoc->GetNodes();
     775           1 :         CPPUNIT_ASSERT(rTable.size() == 1);
     776             : 
     777           1 :         SwNodeIndex* pNodeIdx = rTable[0]->GetContentIdx();
     778           1 :         CPPUNIT_ASSERT(pNodeIdx);
     779             : 
     780           1 :         pTextNode = rNds[ pNodeIdx->GetIndex() + 1 ]->GetTextNode();        //first deleted txtnode
     781           1 :         CPPUNIT_ASSERT(pTextNode);
     782             : 
     783           2 :         OUString sIpsum = pTextNode->GetText();
     784           1 :         CPPUNIT_ASSERT(sIpsum == " ipsum");
     785             : 
     786           1 :         aDocStat.Reset();
     787           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len()); //word-counting the text should only count the non-deleted text, and this whole chunk should be ignored
     788           1 :         CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), aDocStat.nWord);
     789           1 :         CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), aDocStat.nChar);
     790             : 
     791             :         // https://bugs.libreoffice.org/show_bug.cgi?id=68347 we do want to count
     792             :         // redline *added* text though
     793           1 :         m_pDoc->getIDocumentRedlineAccess().SetRedlineMode(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_DELETE|nsRedlineMode_t::REDLINE_SHOW_INSERT);
     794           1 :         aPaM.DeleteMark();
     795           1 :         aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 0);
     796           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, "redline-new-text ");
     797           1 :         aDocStat.Reset();
     798           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     799           1 :         pTextNode->SetWordCountDirty(true);
     800           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     801           1 :         CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), aDocStat.nWord);
     802             :         //redline-new-text Lorem ipsum
     803             :         //+++++++++++++++++     ------
     804             :         //select start of original text and part of deleted text
     805           1 :         aDocStat.Reset();
     806           1 :         pTextNode->CountWords(aDocStat, 17, 25);
     807           2 :         CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(5), aDocStat.nChar);
     808             :     }
     809             : 
     810             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=38983
     811             :     {
     812           1 :         SwDocStat aDocStat;
     813             : 
     814           1 :         OUString sTemplate("ThisXis a test.");
     815             : 
     816           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     817           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', ' '));
     818           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     819           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     820           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
     821             :                        aDocStat.nCharExcludingSpaces == 12 &&
     822           1 :                        aDocStat.nChar == 15);
     823           1 :         aDocStat.Reset();
     824             : 
     825           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     826           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll(OUString('X'), OUString(" = ")));
     827           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     828           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     829           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 5 &&
     830             :                        aDocStat.nCharExcludingSpaces == 13 &&
     831           1 :                        aDocStat.nChar == 17);
     832           1 :         aDocStat.Reset();
     833             : 
     834           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     835           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll(OUString('X'), OUString(" _ ")));
     836           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     837           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     838           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 5 &&
     839             :                        aDocStat.nCharExcludingSpaces == 13 &&
     840           1 :                        aDocStat.nChar == 17);
     841           1 :         aDocStat.Reset();
     842             : 
     843           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     844           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll(OUString('X'), OUString(" -- ")));
     845           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     846           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     847           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 5 &&
     848             :                        aDocStat.nCharExcludingSpaces == 14 &&
     849           1 :                        aDocStat.nChar == 18);
     850           1 :         aDocStat.Reset();
     851             : 
     852           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     853           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', '_'));
     854           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     855           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     856           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
     857             :                        aDocStat.nCharExcludingSpaces == 13 &&
     858           1 :                        aDocStat.nChar == 15);
     859           1 :         aDocStat.Reset();
     860             : 
     861           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     862           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', '-'));
     863           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     864           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     865           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
     866             :                        aDocStat.nCharExcludingSpaces == 13 &&
     867           1 :                        aDocStat.nChar == 15);
     868           1 :         aDocStat.Reset();
     869             : 
     870           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     871           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2012));
     872           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     873           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     874           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
     875             :                        aDocStat.nCharExcludingSpaces == 13 &&
     876           1 :                        aDocStat.nChar == 15);
     877           1 :         aDocStat.Reset();
     878             : 
     879           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     880           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2015));
     881           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     882           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     883           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
     884             :                        aDocStat.nCharExcludingSpaces == 13 &&
     885           1 :                        aDocStat.nChar == 15);
     886           1 :         aDocStat.Reset();
     887             : 
     888             :         //But default configuration should, msword-alike treak emdash
     889             :         //and endash as word separators for word-counting
     890           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     891           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2013));
     892           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     893           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     894           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
     895             :                        aDocStat.nCharExcludingSpaces == 13 &&
     896           1 :                        aDocStat.nChar == 15);
     897           1 :         aDocStat.Reset();
     898             : 
     899           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     900           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replace('X', 0x2014));
     901           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     902           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     903           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
     904             :                        aDocStat.nCharExcludingSpaces == 13 &&
     905           1 :                        aDocStat.nChar == 15);
     906           1 :         aDocStat.Reset();
     907             : 
     908           1 :         const sal_Unicode aChunk[] = {' ', 0x2013, ' '};
     909           2 :         OUString sChunk(aChunk, SAL_N_ELEMENTS(aChunk));
     910           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     911           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, sTemplate.replaceAll(OUString('X'), sChunk));
     912           1 :         pTextNode = aPaM.GetNode().GetTextNode();
     913           1 :         pTextNode->CountWords(aDocStat, 0, pTextNode->Len());
     914           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
     915             :                        aDocStat.nCharExcludingSpaces == 13 &&
     916           1 :                        aDocStat.nChar == 17);
     917           2 :         aDocStat.Reset();
     918           1 :     }
     919           1 : }
     920             : 
     921           1 : void SwDocTest::testMergePortionsDeleteNotSorted()
     922             : {
     923           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
     924           2 :     SwPaM aPaM(aIdx);
     925           1 :     m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("  AABBCC"));
     926             : 
     927           1 :     SwCharFormat *const pCharFormat(m_pDoc->MakeCharFormat("foo", 0));
     928           2 :     SwFormatCharFormat const charFormat(pCharFormat);
     929             : 
     930           2 :     SwFormatINetFormat const inetFormat("http://example.com", "");
     931             : 
     932           1 :     IDocumentContentOperations & rIDCO(m_pDoc->getIDocumentContentOperations());
     933           1 :     aPaM.SetMark();
     934           1 :     aPaM.GetPoint()->nContent = 2;
     935           1 :     aPaM.GetMark()->nContent = 4;
     936           1 :     rIDCO.InsertPoolItem(aPaM, charFormat);
     937           1 :     aPaM.GetPoint()->nContent = 2;
     938           1 :     aPaM.GetMark()->nContent = 5;
     939           1 :     rIDCO.InsertPoolItem(aPaM, inetFormat);
     940           1 :     aPaM.GetPoint()->nContent = 6;
     941           1 :     aPaM.GetMark()->nContent = 8;
     942           1 :     rIDCO.InsertPoolItem(aPaM, charFormat);
     943           1 :     aPaM.GetPoint()->nContent = 4;
     944           1 :     aPaM.GetMark()->nContent = 6;
     945             :     // this triggered an STL assert in SwpHints::MergePortions()
     946           2 :     rIDCO.InsertPoolItem(aPaM, charFormat);
     947           1 : }
     948             : 
     949             : //See https://bugs.libreoffice.org/show_bug.cgi?id=40599
     950           1 : void SwDocTest::testGraphicAnchorDeletion()
     951             : {
     952           1 :     CPPUNIT_ASSERT_MESSAGE("Expected initial 0 count", m_pDoc->getIDocumentStatistics().GetDocStat().nChar == 0);
     953             : 
     954           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
     955           2 :     SwPaM aPaM(aIdx);
     956             : 
     957           1 :     m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("Paragraph 1"));
     958           1 :     m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     959             : 
     960           1 :     m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("graphic anchor>><<graphic anchor"));
     961           2 :     SwNodeIndex nPara2 = aPaM.GetPoint()->nNode;
     962           1 :     m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
     963             : 
     964           1 :     m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("Paragraph 3"));
     965             : 
     966           1 :     aPaM.GetPoint()->nNode = nPara2;
     967           1 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), RTL_CONSTASCII_LENGTH("graphic anchor>>"));
     968             : 
     969             :     //Insert a graphic at X of >>X<< in paragraph 2
     970           2 :     SfxItemSet aFlySet(m_pDoc->GetAttrPool(), RES_FRMATR_BEGIN, RES_FRMATR_END-1);
     971           2 :     SwFormatAnchor aAnchor(FLY_AS_CHAR);
     972           1 :     aAnchor.SetAnchor(aPaM.GetPoint());
     973           1 :     aFlySet.Put(aAnchor);
     974           1 :     SwFlyFrameFormat *pFrame = m_pDoc->getIDocumentContentOperations().Insert(aPaM, OUString(), OUString(), NULL, &aFlySet, NULL, NULL);
     975           1 :     CPPUNIT_ASSERT_MESSAGE("Expected frame", pFrame != NULL);
     976             : 
     977           1 :     CPPUNIT_ASSERT_MESSAGE("Should be 1 graphic", m_pDoc->GetFlyCount(FLYCNTTYPE_GRF) == 1);
     978             : 
     979             :     //Delete >X<
     980           1 :     aPaM.GetPoint()->nNode = nPara2;
     981           2 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(),
     982           3 :         RTL_CONSTASCII_LENGTH("graphic anchor>><")+1);
     983           1 :     aPaM.SetMark();
     984           1 :     aPaM.GetPoint()->nNode = nPara2;
     985           1 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), RTL_CONSTASCII_LENGTH("graphic anchor>"));
     986           1 :     m_pDoc->getIDocumentContentOperations().DeleteRange(aPaM);
     987             : 
     988             : #ifdef DEBUG_AS_HTML
     989             :     {
     990             :         SvFileStream aPasteDebug(OUString("cppunitDEBUG.html"), StreamMode::WRITE|StreamMode::TRUNC);
     991             :         WriterRef xWrt;
     992             :         GetHTMLWriter( String(), String(), xWrt );
     993             :         SwWriter aDbgWrt( aPasteDebug, *m_pDoc );
     994             :         aDbgWrt.Write( xWrt );
     995             :     }
     996             : #endif
     997             : 
     998           2 :     CPPUNIT_ASSERT_MESSAGE("Should be 0 graphics", m_pDoc->GetFlyCount(FLYCNTTYPE_GRF) == 0);
     999             : 
    1000             :     //Now, if instead we swap FLY_AS_CHAR (inline graphic) to FLY_AT_CHAR (anchored to character)
    1001             :     //and repeat the above, graphic is *not* deleted, i.e. it belongs to the paragraph, not the
    1002             :     //range to which its anchored, which is annoying.
    1003           1 : }
    1004             : 
    1005             : static int
    1006       36624 : getRand(int modulus)
    1007             : {
    1008       36624 :     if (modulus <= 0)
    1009           0 :         return 0;
    1010       36624 :     return comphelper::rng::uniform_int_distribution(0, modulus-1);
    1011             : }
    1012             : 
    1013             : static OUString
    1014        4079 : getRandString()
    1015             : {
    1016        4079 :     OUString aText("AAAAA BBBB CCC DD E \n");
    1017        4079 :     int s = getRand(aText.getLength());
    1018        4079 :     int j = getRand(aText.getLength() - s);
    1019        4079 :     OUString aRet(aText.copy(s, j));
    1020        4079 :     if (!getRand(5))
    1021         828 :         aRet += OUString('\n');
    1022             : //    fprintf (stderr, "rand string '%s'\n", OUStringToOString(aRet, RTL_TEXTENCODING_UTF8).getStr());
    1023        4079 :     return aRet;
    1024             : }
    1025             : 
    1026             : static SwPosition
    1027       18552 : getRandomPosition(SwDoc *pDoc, int /* nOffset */)
    1028             : {
    1029       18552 :     const SwPosition aPos(pDoc->GetNodes().GetEndOfContent());
    1030       18552 :     size_t nNodes = aPos.nNode.GetNode().GetIndex() - aPos.nNode.GetNode().StartOfSectionIndex();
    1031       18552 :     size_t n = comphelper::rng::uniform_size_distribution(0, nNodes);
    1032       37104 :     SwPaM pam(aPos);
    1033       37207 :     for (sal_uLong i = 0; i < n; ++i)
    1034             :     {
    1035       18655 :         pam.Move(fnMoveBackward, fnGoNode);
    1036             :     }
    1037       37104 :     return *pam.GetPoint();
    1038             : }
    1039             : 
    1040           1 : void SwDocTest::randomTest()
    1041             : {
    1042           1 :     CPPUNIT_ASSERT_MESSAGE("SwDoc::IsRedlineOn()", !m_pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    1043             :     RedlineMode_t modes[] = {
    1044             :         nsRedlineMode_t::REDLINE_ON,
    1045             :         nsRedlineMode_t::REDLINE_SHOW_MASK,
    1046             :         nsRedlineMode_t::REDLINE_NONE,
    1047             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_MASK,
    1048             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE,
    1049             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE | nsRedlineMode_t::REDLINE_SHOW_MASK,
    1050             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT,
    1051             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_DELETE
    1052           1 :     };
    1053             :     static const char *authors[] = {
    1054             :         "Jim", "Bob", "JimBobina", "Helga", "Gertrude", "Spagna", "Hurtleweed"
    1055             :     };
    1056             : 
    1057           9 :     for( size_t rlm = 0; rlm < SAL_N_ELEMENTS(modes); rlm++ )
    1058             :     {
    1059           8 :         m_pDoc->ClearDoc();
    1060             : 
    1061             :         // setup redlining
    1062           8 :         m_pDoc->getIDocumentRedlineAccess().SetRedlineMode(modes[rlm]);
    1063           8 :         SW_MOD()->SetRedlineAuthor(OUString::createFromAscii(authors[0]));
    1064             : 
    1065       16008 :         for( int i = 0; i < 2000; i++ )
    1066             :         {
    1067       16000 :             SwPaM aPam(m_pDoc->GetNodes());
    1068       32000 :             SwCursor aCrs(getRandomPosition(m_pDoc, i/20), 0, false);
    1069       16000 :             aCrs.SetMark();
    1070             : 
    1071       16000 :             switch (getRand (i < 50 ? 3 : 6)) {
    1072             :             // insert ops first
    1073             :             case 0: {
    1074        2783 :                 if (!m_pDoc->getIDocumentContentOperations().InsertString(aCrs, getRandString())) {
    1075             : //                    fprintf (stderr, "failed to insert string !\n");
    1076             :                 }
    1077        2783 :                 break;
    1078             :             }
    1079             :             case 1:
    1080        2709 :                 break;
    1081             :             case 2: { // switch author
    1082        2799 :                 int a = getRand(SAL_N_ELEMENTS(authors));
    1083        2799 :                 SW_MOD()->SetRedlineAuthor(OUString::createFromAscii(authors[a]));
    1084        2799 :                 break;
    1085             :             }
    1086             : 
    1087             :             // movement / deletion ops later
    1088             :             case 3: // deletion
    1089        2585 :                 switch (getRand(6)) {
    1090             :                 case 0:
    1091         434 :                     m_pDoc->getIDocumentContentOperations().DelFullPara(aCrs);
    1092         434 :                     break;
    1093             :                 case 1:
    1094         404 :                     m_pDoc->getIDocumentContentOperations().DeleteRange(aCrs);
    1095         404 :                     break;
    1096             :                 case 2:
    1097         451 :                     m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aCrs, !!getRand(1));
    1098         451 :                     break;
    1099             :                 case 3:
    1100             :                 default:
    1101        1296 :                     m_pDoc->getIDocumentContentOperations().Overwrite(aCrs, getRandString());
    1102        1296 :                     break;
    1103             :                 }
    1104        2585 :                 break;
    1105             :             case 4: { // movement
    1106             :                 SwMoveFlags nFlags =
    1107        2552 :                          getRand(1) // FIXME: puterb this more ?
    1108             :                          ? SwMoveFlags::DEFAULT
    1109             :                          : SwMoveFlags::ALLFLYS |
    1110             :                            SwMoveFlags::CREATEUNDOOBJ |
    1111        7656 :                            SwMoveFlags::REDLINES |
    1112        5104 :                            SwMoveFlags::NO_DELFRMS;
    1113        2552 :                 SwPosition aTo(getRandomPosition(m_pDoc, i/10));
    1114        2552 :                 m_pDoc->getIDocumentContentOperations().MoveRange(aCrs, aTo, nFlags);
    1115        2552 :                 break;
    1116             :             }
    1117             : 
    1118             :             case 5:
    1119        2572 :                 break;
    1120             : 
    1121             :             // undo / redo ?
    1122             :             default:
    1123           0 :                 break;
    1124             :             }
    1125       16000 :         }
    1126             : 
    1127             : // Debug / verify the produced document has real content
    1128             : #if 0
    1129             :         OStringBuffer aBuffer("nodes-");
    1130             :         aBuffer.append(sal_Int32(rlm));
    1131             :         aBuffer.append(".xml");
    1132             : 
    1133             :         xmlTextWriterPtr writer;
    1134             :         writer = xmlNewTextWriterFilename( aBuffer.makeStringAndClear().getStr(), 0 );
    1135             :         xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
    1136             :         m_pDoc->dumpAsXml(writer);
    1137             :         xmlTextWriterEndDocument( writer );
    1138             :         xmlFreeTextWriter( writer );
    1139             : #endif
    1140             :     }
    1141           1 : }
    1142             : 
    1143             : static OUString
    1144           6 : translitTest(SwDoc & rDoc, SwPaM & rPaM, sal_uInt32 const nType)
    1145             : {
    1146             :     utl::TransliterationWrapper aTrans(
    1147           6 :             ::comphelper::getProcessComponentContext(), nType);
    1148           6 :     rDoc.getIDocumentContentOperations().TransliterateText(rPaM, aTrans);
    1149           6 :     return rPaM.GetText();
    1150             : }
    1151             : 
    1152           1 : void SwDocTest::testTransliterate()
    1153             : {
    1154             :     // just some simple test to see if it's totally broken
    1155           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
    1156           2 :     SwPaM aPaM(aIdx);
    1157           1 :     m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("foobar"));
    1158           1 :     aPaM.SetMark();
    1159           1 :     aPaM.GetPoint()->nContent = 0;
    1160           1 :     CPPUNIT_ASSERT_EQUAL(OUString("foobar"), aPaM.GetText());
    1161             : 
    1162           2 :     CPPUNIT_ASSERT_EQUAL(OUString("FOOBAR"),
    1163             :             translitTest(*m_pDoc, aPaM,
    1164           1 :                 i18n::TransliterationModules_LOWERCASE_UPPERCASE));
    1165           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Foobar"),
    1166             :             translitTest(*m_pDoc, aPaM,
    1167           1 :                 i18n::TransliterationModulesExtra::TITLE_CASE));
    1168           2 :     CPPUNIT_ASSERT_EQUAL(OUString("fOOBAR"),
    1169             :             translitTest(*m_pDoc, aPaM,
    1170           1 :                 i18n::TransliterationModulesExtra::TOGGLE_CASE));
    1171           2 :     CPPUNIT_ASSERT_EQUAL(OUString("foobar"),
    1172             :             translitTest(*m_pDoc, aPaM,
    1173           1 :                 i18n::TransliterationModules_UPPERCASE_LOWERCASE));
    1174           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Foobar"),
    1175             :             translitTest(*m_pDoc, aPaM,
    1176           1 :                 i18n::TransliterationModulesExtra::SENTENCE_CASE));
    1177           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Foobar"),
    1178             :             translitTest(*m_pDoc, aPaM,
    1179           2 :                 i18n::TransliterationModules_HIRAGANA_KATAKANA));
    1180           1 : }
    1181             : 
    1182             : namespace
    1183             : {
    1184           1 :     class SwTableFormulaTest : public SwTableFormula
    1185             :     {
    1186             :         SwTableNode *m_pNode;
    1187             :     public:
    1188           1 :         SwTableFormulaTest(const OUString &rStr, SwTableNode *pNode)
    1189             :             : SwTableFormula(rStr)
    1190           1 :             , m_pNode(pNode)
    1191             :         {
    1192           1 :             m_eNmType = INTRNL_NAME;
    1193           1 :         }
    1194           0 :         virtual const SwNode* GetNodeOfFormula() const SAL_OVERRIDE
    1195             :         {
    1196           0 :             return m_pNode;
    1197             :         }
    1198             :     };
    1199             : }
    1200             : 
    1201             : //tdf#66353 Expression is faulty
    1202           1 : void SwDocTest::testFormulas()
    1203             : {
    1204           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
    1205           2 :     SwPosition aPos(aIdx);
    1206             : 
    1207             :     const SwTable *pTable = m_pDoc->InsertTable(
    1208           1 :         SwInsertTableOptions(tabopts::HEADLINE_NO_BORDER, 0), aPos, 1, 3, 0);
    1209           1 :     SwTableNode* pTableNode = pTable->GetTableNode();
    1210           2 :     SwTableFormulaTest aFormula("<\x12-1,0>+<Table1.A1>", pTableNode);
    1211             : 
    1212           1 :     aFormula.PtrToBoxNm(pTable);
    1213             : 
    1214           2 :     CPPUNIT_ASSERT_EQUAL(OUString("<?>+<Table1.?>"), aFormula.GetFormula());
    1215           1 : }
    1216             : 
    1217           1 : void SwDocTest::testMarkMove()
    1218             : {
    1219           1 :     IDocumentMarkAccess* pMarksAccess = m_pDoc->getIDocumentMarkAccess();
    1220             : 
    1221             :     {
    1222           1 :         SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
    1223           2 :         SwPaM aPaM(aIdx);
    1224           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("Paragraph 1"));
    1225           1 :         aPaM.SetMark();
    1226           1 :         aPaM.GetMark()->nContent -= aPaM.GetMark()->nContent.GetIndex();
    1227           1 :         pMarksAccess->makeMark(aPaM, OUString("Para1"), IDocumentMarkAccess::MarkType::BOOKMARK);
    1228             : 
    1229           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
    1230           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("Paragraph 2"));
    1231           1 :         aPaM.SetMark();
    1232           1 :         aPaM.GetMark()->nContent -= aPaM.GetMark()->nContent.GetIndex();
    1233           1 :         pMarksAccess->makeMark(aPaM, OUString("Para2"), IDocumentMarkAccess::MarkType::BOOKMARK);
    1234             : 
    1235           1 :         m_pDoc->getIDocumentContentOperations().AppendTextNode(*aPaM.GetPoint());
    1236           1 :         m_pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString("Paragraph 3"));
    1237           1 :         aPaM.SetMark();
    1238           1 :         aPaM.GetMark()->nContent -= aPaM.GetMark()->nContent.GetIndex();
    1239           2 :         pMarksAccess->makeMark(aPaM, OUString("Para3"), IDocumentMarkAccess::MarkType::BOOKMARK);
    1240             :     }
    1241             : 
    1242             :     // join paragraph 2 and 3 and check
    1243             :     {
    1244           1 :         SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -2);
    1245           1 :         SwTextNode& rParaNode2 = dynamic_cast<SwTextNode&>(aIdx.GetNode());
    1246           1 :         rParaNode2.JoinNext();
    1247             :     }
    1248           1 :     ::sw::mark::IMark* pBM1 = pMarksAccess->findMark("Para1")->get();
    1249           1 :     ::sw::mark::IMark* pBM2 = pMarksAccess->findMark("Para2")->get();
    1250           1 :     ::sw::mark::IMark* pBM3 = pMarksAccess->findMark("Para3")->get();
    1251             : 
    1252           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 0 , pBM1->GetMarkStart().nContent.GetIndex());
    1253           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 11, pBM1->GetMarkEnd().nContent.GetIndex());
    1254           2 :     CPPUNIT_ASSERT_EQUAL(
    1255             :         pBM1->GetMarkStart().nNode.GetIndex(),
    1256           1 :         pBM1->GetMarkEnd().nNode.GetIndex());
    1257             : 
    1258           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 0 , pBM2->GetMarkStart().nContent.GetIndex());
    1259           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 11, pBM2->GetMarkEnd().nContent.GetIndex());
    1260           2 :     CPPUNIT_ASSERT_EQUAL(
    1261             :         pBM2->GetMarkStart().nNode.GetIndex(),
    1262           1 :         pBM2->GetMarkEnd().nNode.GetIndex());
    1263             : 
    1264           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 11, pBM3->GetMarkStart().nContent.GetIndex());
    1265           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 22, pBM3->GetMarkEnd().nContent.GetIndex());
    1266           2 :     CPPUNIT_ASSERT_EQUAL(
    1267             :         pBM3->GetMarkStart().nNode.GetIndex(),
    1268           1 :         pBM3->GetMarkEnd().nNode.GetIndex());
    1269             : 
    1270           2 :     CPPUNIT_ASSERT_EQUAL(
    1271             :         pBM1->GetMarkStart().nNode.GetIndex()+1,
    1272           1 :         pBM2->GetMarkStart().nNode.GetIndex());
    1273           2 :     CPPUNIT_ASSERT_EQUAL(
    1274             :         pBM2->GetMarkStart().nNode.GetIndex(),
    1275           1 :         pBM3->GetMarkStart().nNode.GetIndex());
    1276             : 
    1277             :     // cut some text
    1278             :     {
    1279           1 :         SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
    1280           2 :         SwPaM aPaM(aIdx, aIdx, -1);
    1281           1 :         aPaM.GetPoint()->nContent += 5;
    1282           1 :         aPaM.GetMark()->nContent += 6;
    1283           2 :         m_pDoc->getIDocumentContentOperations().DeleteAndJoin(aPaM);
    1284             :     }
    1285           1 :     pBM1 = pMarksAccess->findMark("Para1")->get();
    1286           1 :     pBM2 = pMarksAccess->findMark("Para2")->get();
    1287           1 :     pBM3 = pMarksAccess->findMark("Para3")->get();
    1288             : 
    1289           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 0, pBM1->GetMarkStart().nContent.GetIndex());
    1290           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 6, pBM1->GetMarkEnd().nContent.GetIndex());
    1291           2 :     CPPUNIT_ASSERT_EQUAL(
    1292             :         pBM1->GetMarkStart().nNode.GetIndex(),
    1293           1 :         pBM1->GetMarkEnd().nNode.GetIndex());
    1294             : 
    1295           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 6, pBM2->GetMarkStart().nContent.GetIndex());
    1296           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 12, pBM2->GetMarkEnd().nContent.GetIndex());
    1297           2 :     CPPUNIT_ASSERT_EQUAL(
    1298             :         pBM2->GetMarkStart().nNode.GetIndex(),
    1299           1 :         pBM2->GetMarkEnd().nNode.GetIndex());
    1300             : 
    1301           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 12, pBM3->GetMarkStart().nContent.GetIndex());
    1302           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 23, pBM3->GetMarkEnd().nContent.GetIndex());
    1303           2 :     CPPUNIT_ASSERT_EQUAL(
    1304             :         pBM3->GetMarkStart().nNode.GetIndex(),
    1305           1 :         pBM3->GetMarkEnd().nNode.GetIndex());
    1306             : 
    1307           2 :     CPPUNIT_ASSERT_EQUAL(
    1308             :         pBM1->GetMarkStart().nNode.GetIndex(),
    1309           1 :         pBM2->GetMarkStart().nNode.GetIndex());
    1310           2 :     CPPUNIT_ASSERT_EQUAL(
    1311             :         pBM2->GetMarkStart().nNode.GetIndex(),
    1312           1 :         pBM3->GetMarkStart().nNode.GetIndex());
    1313             : 
    1314             :     // split the paragraph
    1315             :     {
    1316           1 :         SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
    1317           2 :         SwPosition aPos(aIdx);
    1318           1 :         aPos.nContent += 8;
    1319           2 :         m_pDoc->getIDocumentContentOperations().SplitNode(aPos, false);
    1320             :     }
    1321           1 :     pBM1 = pMarksAccess->findMark("Para1")->get();
    1322           1 :     pBM2 = pMarksAccess->findMark("Para2")->get();
    1323           1 :     pBM3 = pMarksAccess->findMark("Para3")->get();
    1324             : 
    1325           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 0, pBM1->GetMarkStart().nContent.GetIndex());
    1326           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 6, pBM1->GetMarkEnd().nContent.GetIndex());
    1327           2 :     CPPUNIT_ASSERT_EQUAL(
    1328             :         pBM1->GetMarkStart().nNode.GetIndex(),
    1329           1 :         pBM1->GetMarkEnd().nNode.GetIndex());
    1330             : 
    1331           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 6, pBM2->GetMarkStart().nContent.GetIndex());
    1332           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 4, pBM2->GetMarkEnd().nContent.GetIndex());
    1333           2 :     CPPUNIT_ASSERT_EQUAL(
    1334             :         pBM2->GetMarkStart().nNode.GetIndex()+1,
    1335           1 :         pBM2->GetMarkEnd().nNode.GetIndex());
    1336             : 
    1337           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 4, pBM3->GetMarkStart().nContent.GetIndex());
    1338           1 :     CPPUNIT_ASSERT_EQUAL((sal_Int32) 15, pBM3->GetMarkEnd().nContent.GetIndex());
    1339           2 :     CPPUNIT_ASSERT_EQUAL(
    1340             :         pBM3->GetMarkStart().nNode.GetIndex(),
    1341           1 :         pBM3->GetMarkEnd().nNode.GetIndex());
    1342             : 
    1343           2 :     CPPUNIT_ASSERT_EQUAL(
    1344             :         pBM1->GetMarkStart().nNode.GetIndex(),
    1345           1 :         pBM2->GetMarkStart().nNode.GetIndex());
    1346           2 :     CPPUNIT_ASSERT_EQUAL(
    1347             :         pBM2->GetMarkEnd().nNode.GetIndex(),
    1348           1 :         pBM3->GetMarkEnd().nNode.GetIndex());
    1349           1 : }
    1350             : 
    1351             : namespace
    1352             : {
    1353           7 :     struct TestRing : public sw::Ring<TestRing>
    1354             :     {
    1355           7 :         TestRing() : sw::Ring<TestRing>() {};
    1356           9 :         TestRing* GetNext()
    1357           9 :             { return GetNextInRing(); }
    1358           9 :         TestRing* GetPrev()
    1359           9 :             { return GetPrevInRing(); }
    1360           6 :         bool lonely() const
    1361           6 :             { return unique(); }
    1362             : #if 0
    1363             :         void debug()
    1364             :         {
    1365             :             SAL_DEBUG("TestRing at: " << this << " prev: " << GetPrev() << " next: " << GetNext());
    1366             :         }
    1367             : #endif
    1368             :     };
    1369             : }
    1370             : 
    1371           1 : void SwDocTest::testIntrusiveRing()
    1372             : {
    1373           2 :     TestRing aRing1, aRing2, aRing3, aRing4, aRing5;
    1374           2 :     std::vector<TestRing*> vRings;
    1375           1 :     vRings.push_back(&aRing1);
    1376           1 :     vRings.push_back(&aRing2);
    1377           1 :     vRings.push_back(&aRing3);
    1378           1 :     vRings.push_back(&aRing4);
    1379           1 :     vRings.push_back(&aRing5);
    1380           1 :     CPPUNIT_ASSERT_EQUAL(aRing1.GetRingContainer().size(), static_cast<size_t>(1));
    1381           1 :     CPPUNIT_ASSERT(aRing1.lonely());
    1382           1 :     CPPUNIT_ASSERT(aRing2.lonely());
    1383           1 :     CPPUNIT_ASSERT(aRing3.lonely());
    1384           1 :     aRing2.MoveTo(&aRing1);
    1385           1 :     aRing3.MoveTo(&aRing1);
    1386           1 :     CPPUNIT_ASSERT_EQUAL(aRing1.GetRingContainer().size(), static_cast<size_t>(3));
    1387           1 :     CPPUNIT_ASSERT_EQUAL(aRing2.GetRingContainer().size(), static_cast<size_t>(3));
    1388           1 :     CPPUNIT_ASSERT_EQUAL(aRing3.GetRingContainer().size(), static_cast<size_t>(3));
    1389           1 :     CPPUNIT_ASSERT(!aRing1.lonely());
    1390           1 :     CPPUNIT_ASSERT(!aRing2.lonely());
    1391           1 :     CPPUNIT_ASSERT(!aRing3.lonely());
    1392           1 :     aRing5.MoveTo(&aRing4);
    1393           1 :     CPPUNIT_ASSERT_EQUAL(aRing4.GetRingContainer().size(), static_cast<size_t>(2));
    1394           1 :     aRing4.GetRingContainer().merge(aRing1.GetRingContainer());
    1395           6 :     for(TestRing* pRing : vRings)
    1396             :     {
    1397           5 :         CPPUNIT_ASSERT_EQUAL(pRing->GetRingContainer().size(), static_cast<size_t>(5));
    1398             :     }
    1399           6 :     for(std::vector<TestRing*>::iterator ppRing = vRings.begin(); ppRing != vRings.end(); ++ppRing)
    1400             :     {
    1401           5 :         std::vector<TestRing*>::iterator ppNext = ppRing+1;
    1402           5 :         if(ppNext==vRings.end())
    1403           1 :             ppNext = vRings.begin();
    1404           5 :         CPPUNIT_ASSERT_EQUAL((*ppRing)->GetNext(), *ppNext);
    1405           5 :         CPPUNIT_ASSERT_EQUAL((*ppNext)->GetPrev(), *ppRing);
    1406             :     }
    1407           6 :     for(TestRing& r: aRing1.GetRingContainer())
    1408             :     {
    1409           5 :         TestRing* pRing = &r;
    1410           5 :         CPPUNIT_ASSERT(pRing);
    1411             :         //pRing->debug();
    1412             :     }
    1413           1 :     const TestRing* pConstRing = &aRing1;
    1414           6 :     for(const TestRing& r: pConstRing->GetRingContainer()) // this should fail without r being const
    1415             :     {
    1416           5 :         const TestRing* pRing = &r;
    1417           5 :         CPPUNIT_ASSERT(pRing);
    1418             :     }
    1419           2 :     TestRing foo, bar;
    1420           1 :     foo.MoveTo(&bar);
    1421           1 :     CPPUNIT_ASSERT_EQUAL(&foo, bar.GetNext());
    1422           1 :     CPPUNIT_ASSERT_EQUAL(&foo, bar.GetPrev());
    1423           1 :     CPPUNIT_ASSERT_EQUAL(&bar, foo.GetNext());
    1424           1 :     CPPUNIT_ASSERT_EQUAL(&bar, foo.GetPrev());
    1425           1 :     foo.MoveTo(&foo);
    1426           1 :     CPPUNIT_ASSERT_EQUAL(&bar, bar.GetNext());
    1427           1 :     CPPUNIT_ASSERT_EQUAL(&bar, bar.GetPrev());
    1428           1 :     CPPUNIT_ASSERT_EQUAL(&foo, foo.GetNext());
    1429           2 :     CPPUNIT_ASSERT_EQUAL(&foo, foo.GetPrev());
    1430           1 : }
    1431             : 
    1432             : namespace
    1433             : {
    1434           1 :     struct TestHint SAL_FINAL : SfxHint {};
    1435           2 :     struct TestModify : SwModify
    1436             :     {
    1437             :         TYPEINFO_OVERRIDE();
    1438             :     };
    1439           0 :     TYPEINIT1( TestModify, SwModify );
    1440           2 :     struct TestClient : SwClient
    1441             :     {
    1442             :         TYPEINFO_OVERRIDE();
    1443             :         int m_nModifyCount;
    1444             :         int m_nNotifyCount;
    1445           2 :         TestClient() : m_nModifyCount(0), m_nNotifyCount(0) {};
    1446           4 :         virtual void Modify( const SfxPoolItem*, const SfxPoolItem*) SAL_OVERRIDE
    1447           4 :         { ++m_nModifyCount; }
    1448           6 :         virtual void SwClientNotify(const SwModify& rModify, const SfxHint& rHint) SAL_OVERRIDE
    1449             :         {
    1450           6 :             if(typeid(TestHint) == typeid(rHint))
    1451           2 :                 ++m_nNotifyCount;
    1452             :             else
    1453           4 :                 SwClient::SwClientNotify(rModify, rHint);
    1454           6 :         }
    1455             :     };
    1456          34 :     TYPEINIT1( TestClient, SwClient );
    1457             :     // sad copypasta as tools/rtti.hxxs little brain cant cope with templates
    1458           2 :     struct OtherTestClient : SwClient
    1459             :     {
    1460             :         TYPEINFO_OVERRIDE();
    1461             :         int m_nModifyCount;
    1462           2 :         OtherTestClient() : m_nModifyCount(0) {};
    1463           0 :         virtual void Modify( const SfxPoolItem*, const SfxPoolItem*) SAL_OVERRIDE
    1464           0 :         { ++m_nModifyCount; }
    1465             :     };
    1466           6 :     TYPEINIT1( OtherTestClient, SwClient );
    1467             : }
    1468           1 : void SwDocTest::testClientModify()
    1469             : {
    1470           1 :     (void) OtherTestClient(); // avoid loplugin:unreffun
    1471           1 :     TestModify aMod;
    1472           2 :     TestClient aClient1, aClient2;
    1473           2 :     OtherTestClient aOtherClient1;
    1474             :     // test client registration
    1475           1 :     CPPUNIT_ASSERT(!aMod.HasWriterListeners());
    1476           1 :     CPPUNIT_ASSERT(!aMod.HasOnlyOneListener());
    1477           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.GetRegisteredIn(),static_cast<SwModify*>(nullptr));
    1478           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(),static_cast<SwModify*>(nullptr));
    1479           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(),static_cast<SwModify*>(nullptr));
    1480           1 :     aMod.Add(&aClient1);
    1481           1 :     CPPUNIT_ASSERT(aMod.HasWriterListeners());
    1482           1 :     CPPUNIT_ASSERT(aMod.HasOnlyOneListener());
    1483           1 :     aMod.Add(&aClient2);
    1484           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.GetRegisteredIn(),static_cast<SwModify*>(&aMod));
    1485           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(),static_cast<SwModify*>(&aMod));
    1486           1 :     CPPUNIT_ASSERT(aMod.HasWriterListeners());
    1487           1 :     CPPUNIT_ASSERT(!aMod.HasOnlyOneListener());
    1488             :     // test broadcast
    1489           1 :     aMod.ModifyBroadcast(nullptr, nullptr);
    1490           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.m_nModifyCount,1);
    1491           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.m_nModifyCount,1);
    1492           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.m_nNotifyCount,0);
    1493           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.m_nNotifyCount,0);
    1494           1 :     aMod.ModifyBroadcast(nullptr, nullptr);
    1495           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.m_nModifyCount,2);
    1496           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.m_nModifyCount,2);
    1497           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.m_nNotifyCount,0);
    1498           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.m_nNotifyCount,0);
    1499             :     // test notify
    1500             :     {
    1501           1 :         TestHint aHint;
    1502           1 :         aMod.CallSwClientNotify(aHint);
    1503           1 :         CPPUNIT_ASSERT_EQUAL(aClient1.m_nModifyCount,2);
    1504           1 :         CPPUNIT_ASSERT_EQUAL(aClient2.m_nModifyCount,2);
    1505           1 :         CPPUNIT_ASSERT_EQUAL(aClient1.m_nNotifyCount,1);
    1506           1 :         CPPUNIT_ASSERT_EQUAL(aClient2.m_nNotifyCount,1);
    1507             :     }
    1508             :     // test typed iteration
    1509           1 :     CPPUNIT_ASSERT(!aClient1.IsA(TYPE(OtherTestClient)));
    1510             :     {
    1511           1 :         SwIterator<OtherTestClient,SwModify> aIter(aMod);
    1512           1 :         for(OtherTestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
    1513           1 :             CPPUNIT_ASSERT(false);
    1514             :     }
    1515             :     {
    1516           1 :         int nCount = 0;
    1517           1 :         SwIterator<TestClient,SwModify> aIter(aMod);
    1518           3 :         for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
    1519             :         {
    1520           2 :             CPPUNIT_ASSERT_EQUAL(pClient->m_nModifyCount,2);
    1521           2 :             ++nCount;
    1522             :         }
    1523           1 :         CPPUNIT_ASSERT_EQUAL(nCount,2);
    1524             :     }
    1525           1 :     aMod.Add(&aOtherClient1);
    1526           1 :     CPPUNIT_ASSERT_EQUAL(aOtherClient1.m_nModifyCount,0);
    1527             :     {
    1528           1 :         int nCount = 0;
    1529           1 :         SwIterator<TestClient,SwModify> aIter(aMod);
    1530           3 :         for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
    1531             :         {
    1532           2 :             CPPUNIT_ASSERT_EQUAL(pClient->m_nModifyCount,2);
    1533           2 :             ++nCount;
    1534             :         }
    1535           1 :         CPPUNIT_ASSERT_EQUAL(nCount,2);
    1536             :     }
    1537           1 :     CPPUNIT_ASSERT_EQUAL(aOtherClient1.m_nModifyCount,0);
    1538           1 :     aMod.Remove(&aOtherClient1);
    1539           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.GetRegisteredIn(),static_cast<SwModify*>(&aMod));
    1540           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(),static_cast<SwModify*>(&aMod));
    1541           1 :     CPPUNIT_ASSERT_EQUAL(aOtherClient1.GetRegisteredIn(),static_cast<SwModify*>(nullptr));
    1542             :     // test client self-deregistration during iteration
    1543             :     {
    1544           1 :         int nCount = 0;
    1545           1 :         SwIterator<TestClient,SwModify> aIter(aMod);
    1546           3 :         for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
    1547             :         {
    1548           2 :             aMod.Remove(pClient);
    1549           2 :             ++nCount;
    1550             :         }
    1551           1 :         CPPUNIT_ASSERT_EQUAL(nCount,2);
    1552             :     }
    1553           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.GetRegisteredIn(), static_cast<SwModify*>(nullptr));
    1554           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.GetRegisteredIn(), static_cast<SwModify*>(nullptr));
    1555             :     {
    1556           1 :         int nCount = 0;
    1557           1 :         SwIterator<TestClient,SwModify> aIter(aMod);
    1558           1 :         for(TestClient* pClient = aIter.First(); pClient ; pClient = aIter.Next())
    1559             :         {
    1560           0 :             CPPUNIT_ASSERT(false);
    1561             :         }
    1562           1 :         CPPUNIT_ASSERT_EQUAL(nCount,0);
    1563             :     }
    1564           1 :     aMod.ModifyBroadcast(nullptr, nullptr);
    1565           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.m_nModifyCount,2);
    1566           1 :     CPPUNIT_ASSERT_EQUAL(aClient2.m_nModifyCount,2);
    1567           1 :     CPPUNIT_ASSERT_EQUAL(aClient1.m_nNotifyCount,1);
    1568           2 :     CPPUNIT_ASSERT_EQUAL(aClient2.m_nNotifyCount,1);
    1569           1 : }
    1570             : 
    1571           1 : void SwDocTest::test64kPageDescs()
    1572             : {
    1573           1 :     size_t nPageDescCount = 65536; // USHRT_MAX + 1
    1574             : 
    1575       65537 :     for (size_t i = 0; i < nPageDescCount; ++i)
    1576             :     {
    1577       65536 :         OUString aName = "Page" + OUString::number(i);
    1578       65536 :         m_pDoc->MakePageDesc( aName );
    1579       65536 :     }
    1580             : 
    1581           1 :     size_t nCount = m_pDoc->GetPageDescCnt();
    1582             :     // +1 because Writer always creates a dummy page desc
    1583             :     // in a new SwDoc
    1584           1 :     CPPUNIT_ASSERT_EQUAL( nPageDescCount + 1, nCount );
    1585             : 
    1586           1 :     const SwPageDesc &rDesc = m_pDoc->GetPageDesc( nPageDescCount );
    1587           1 :     SwPageDesc &rZeroDesc = m_pDoc->GetPageDesc( 0 );
    1588           1 :     CPPUNIT_ASSERT_EQUAL( OUString("Page65535"), rDesc.GetName() );
    1589             : 
    1590           1 :     SwPageDesc aDesc( rDesc );
    1591           2 :     const OUString aChanged("Changed01");
    1592           1 :     aDesc.SetName( aChanged );
    1593           1 :     m_pDoc->ChgPageDesc( nPageDescCount, aDesc );
    1594             : 
    1595             :     size_t nPos;
    1596           1 :     SwPageDesc *pDesc = m_pDoc->FindPageDesc( aChanged, &nPos );
    1597           1 :     CPPUNIT_ASSERT( pDesc != NULL );
    1598           1 :     CPPUNIT_ASSERT( nPos == nPageDescCount );
    1599             : 
    1600             :     // check if we didn't mess up PageDesc at pos 0
    1601             :     // (happens with 16bit int overflow)
    1602           2 :     OUString aZeroName = rZeroDesc.GetName();
    1603           1 :     rZeroDesc = m_pDoc->GetPageDesc( 0 );
    1604           1 :     CPPUNIT_ASSERT_EQUAL( aZeroName, rZeroDesc.GetName() );
    1605             : 
    1606           1 :     m_pDoc->DelPageDesc( aChanged, nPos );
    1607           1 :     pDesc = m_pDoc->FindPageDesc( aChanged, &nPos );
    1608             :     // not there anymore
    1609           1 :     CPPUNIT_ASSERT( pDesc == NULL );
    1610           1 :     CPPUNIT_ASSERT( nPos == SIZE_MAX );
    1611             : 
    1612             :     // check if PageDesc at pos 0 is still there
    1613           1 :     pDesc = m_pDoc->FindPageDesc( aZeroName, &nPos );
    1614           1 :     CPPUNIT_ASSERT( pDesc != NULL );
    1615           2 :     CPPUNIT_ASSERT( nPos == 0 );
    1616           1 : }
    1617             : 
    1618          30 : void SwDocTest::setUp()
    1619             : {
    1620          30 :     BootstrapFixture::setUp();
    1621             : 
    1622          30 :     SwGlobals::ensure();
    1623          30 :     m_pDoc = new SwDoc;
    1624          30 :     m_xDocShRef = new SwDocShell(m_pDoc, SfxObjectCreateMode::EMBEDDED);
    1625          30 :     m_xDocShRef->DoInitNew(0);
    1626          30 : }
    1627             : 
    1628          30 : void SwDocTest::tearDown()
    1629             : {
    1630          30 :     m_pDoc = 0; // deleted by DoClose()
    1631          30 :     m_xDocShRef->DoClose();
    1632          30 :     m_xDocShRef.Clear();
    1633             : 
    1634          30 :     BootstrapFixture::tearDown();
    1635          30 : }
    1636             : 
    1637           1 : CPPUNIT_TEST_SUITE_REGISTRATION(SwDocTest);
    1638             : 
    1639           4 : CPPUNIT_PLUGIN_IMPLEMENT();
    1640             : 
    1641             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11