LCOV - code coverage report
Current view: top level - sw/qa/core - uwriter.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 557 559 99.6 %
Date: 2014-04-11 Functions: 24 25 96.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 <tools/urlobj.hxx>
      20             : #include <unotools/tempfile.hxx>
      21             : #include <unotools/transliterationwrapper.hxx>
      22             : 
      23             : #include <editeng/langitem.hxx>
      24             : #include <editeng/charhiddenitem.hxx>
      25             : 
      26             : #include <sfx2/app.hxx>
      27             : #include <sfx2/docfilt.hxx>
      28             : #include <sfx2/docfile.hxx>
      29             : #include <sfx2/sfxmodelfactory.hxx>
      30             : 
      31             : #include <xmloff/odffields.hxx>
      32             : 
      33             : #include "breakit.hxx"
      34             : #include "doc.hxx"
      35             : #include "docsh.hxx"
      36             : #include "docstat.hxx"
      37             : #include "docufld.hxx"
      38             : #include "fmtanchr.hxx"
      39             : #include "init.hxx"
      40             : #include "ndtxt.hxx"
      41             : #include "shellio.hxx"
      42             : #include "shellres.hxx"
      43             : #include "swcrsr.hxx"
      44             : #include "swscanner.hxx"
      45             : #include "swmodule.hxx"
      46             : #include "swtypes.hxx"
      47             : #include "fmtftn.hxx"
      48             : #include "fmtrfmrk.hxx"
      49             : #include "fmtfld.hxx"
      50             : #include "redline.hxx"
      51             : #include "docary.hxx"
      52             : #include "modeltoviewhelper.hxx"
      53             : #include "scriptinfo.hxx"
      54             : 
      55             : typedef tools::SvRef<SwDocShell> SwDocShellRef;
      56             : 
      57             : using namespace ::com::sun::star;
      58             : 
      59             : /* Implementation of Swdoc-Test class */
      60             : 
      61          27 : class SwDocTest : public test::BootstrapFixture
      62             : {
      63             : public:
      64             :     virtual void setUp() SAL_OVERRIDE;
      65             :     virtual void tearDown() SAL_OVERRIDE;
      66             : 
      67             :     void randomTest();
      68             :     void testPageDescName();
      69             :     void testFileNameFields();
      70             :     void testDocStat();
      71             :     void testModelToViewHelper();
      72             :     void testSwScanner();
      73             :     void testUserPerceivedCharCount();
      74             :     void testGraphicAnchorDeletion();
      75             :     void testTransliterate();
      76             : 
      77           2 :     CPPUNIT_TEST_SUITE(SwDocTest);
      78           1 :     CPPUNIT_TEST(testTransliterate);
      79           1 :     CPPUNIT_TEST(randomTest);
      80           1 :     CPPUNIT_TEST(testPageDescName);
      81           1 :     CPPUNIT_TEST(testFileNameFields);
      82           1 :     CPPUNIT_TEST(testDocStat);
      83           1 :     CPPUNIT_TEST(testModelToViewHelper);
      84           1 :     CPPUNIT_TEST(testSwScanner);
      85           1 :     CPPUNIT_TEST(testUserPerceivedCharCount);
      86           1 :     CPPUNIT_TEST(testGraphicAnchorDeletion);
      87           2 :     CPPUNIT_TEST_SUITE_END();
      88             : 
      89             : private:
      90             :     SwDoc *m_pDoc;
      91             :     SwDocShellRef m_xDocShRef;
      92             : };
      93             : 
      94           1 : void SwDocTest::testPageDescName()
      95             : {
      96           1 :     ShellResource aShellResources;
      97             : 
      98           2 :     std::vector<OUString> aResults;
      99             : 
     100             :     //These names must be unique for each different combination, otherwise
     101             :     //duplicate page description names may exist, which will causes lookup
     102             :     //by name to be incorrect, and so the corresponding export to .odt
     103           1 :     aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::NORMAL_PAGE));
     104           1 :     aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::FIRST_PAGE));
     105           1 :     aResults.push_back(aShellResources.GetPageDescName(1, ShellResource::FOLLOW_PAGE));
     106             : 
     107           1 :     std::sort(aResults.begin(), aResults.end());
     108           1 :     aResults.erase(std::unique(aResults.begin(), aResults.end()), aResults.end());
     109             : 
     110           2 :     CPPUNIT_ASSERT_MESSAGE("GetPageDescName results must be unique", aResults.size() == 3);
     111           1 : }
     112             : 
     113             : //See https://bugs.libreoffice.org/show_bug.cgi?id=32463
     114           1 : void SwDocTest::testFileNameFields()
     115             : {
     116             :     //Here's a file name with some chars in it that will be %% encoded, when expanding
     117             :     //SwFileNameFields we want to restore the original readable filename
     118           1 :     utl::TempFile aTempFile(OUString("demo [name]"));
     119           1 :     aTempFile.EnableKillingFile();
     120             : 
     121           2 :     INetURLObject aTempFileURL(aTempFile.GetURL());
     122           2 :     OUString sFileURL = aTempFileURL.GetMainURL(INetURLObject::NO_DECODE);
     123           2 :     SfxMedium aDstMed(sFileURL, STREAM_STD_READWRITE);
     124             : 
     125             :     SfxFilter aFilter(
     126             :         OUString("Text"),
     127             :         OUString(), 0, 0, OUString(), 0, OUString(),
     128           2 :         OUString("TEXT"), OUString() );
     129           1 :     aDstMed.SetFilter(&aFilter);
     130             : 
     131           1 :     m_xDocShRef->DoSaveAs(aDstMed);
     132           1 :     m_xDocShRef->DoSaveCompleted(&aDstMed);
     133             : 
     134           1 :     const INetURLObject &rUrlObj = m_xDocShRef->GetMedium()->GetURLObject();
     135             : 
     136           2 :     SwFileNameFieldType aNameField(m_pDoc);
     137             : 
     138             :     {
     139           1 :         OUString sResult(aNameField.Expand(FF_NAME));
     140             :         OUString sExpected(rUrlObj.getName(INetURLObject::LAST_SEGMENT,
     141           2 :             true,INetURLObject::DECODE_WITH_CHARSET));
     142           2 :         CPPUNIT_ASSERT_MESSAGE("Expected Readable FileName", sResult == sExpected);
     143             :     }
     144             : 
     145             :     {
     146           1 :         OUString sResult(aNameField.Expand(FF_PATHNAME));
     147           2 :         OUString sExpected(rUrlObj.GetFull());
     148           2 :         CPPUNIT_ASSERT_MESSAGE("Expected Readable FileName", sResult == sExpected);
     149             :     }
     150             : 
     151             :     {
     152           1 :         OUString sResult(aNameField.Expand(FF_PATH));
     153           2 :         INetURLObject aTemp(rUrlObj);
     154           1 :         aTemp.removeSegment();
     155           2 :         OUString sExpected(aTemp.PathToFileName());
     156           2 :         CPPUNIT_ASSERT_MESSAGE("Expected Readable FileName", sResult == sExpected);
     157             :     }
     158             : 
     159             :     {
     160           1 :         OUString sResult(aNameField.Expand(FF_NAME_NOEXT));
     161             :         OUString sExpected(rUrlObj.getName(INetURLObject::LAST_SEGMENT,
     162           2 :             true,INetURLObject::DECODE_WITH_CHARSET));
     163             :         //Chop off .tmp
     164           1 :         sExpected = sExpected.copy(0, sExpected.getLength() - 4);
     165           2 :         CPPUNIT_ASSERT_MESSAGE("Expected Readable FileName", sResult == sExpected);
     166             :     }
     167             : 
     168           2 :     m_xDocShRef->DoInitNew(0);
     169           1 : }
     170             : 
     171             : //See http://lists.freedesktop.org/archives/libreoffice/2011-August/016666.html
     172             : //Remove unnecessary parameter to IDocumentStatistics::UpdateDocStat for
     173             : //motivation
     174           1 : void SwDocTest::testDocStat()
     175             : {
     176           1 :     CPPUNIT_ASSERT_MESSAGE("Expected initial 0 count", m_pDoc->GetDocStat().nChar == 0);
     177             : 
     178           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
     179           2 :     SwPaM aPaM(aIdx);
     180             : 
     181           2 :     OUString sText("Hello World");
     182           1 :     m_pDoc->InsertString(aPaM, sText);
     183             : 
     184           1 :     CPPUNIT_ASSERT_MESSAGE("Should still be non-updated 0 count", m_pDoc->GetDocStat().nChar == 0);
     185             : 
     186           1 :     SwDocStat aDocStat = m_pDoc->GetUpdatedDocStat();
     187           1 :     sal_uLong nLen = static_cast<sal_uLong>(sText.getLength());
     188             : 
     189           1 :     CPPUNIT_ASSERT_MESSAGE("Should now have updated count", aDocStat.nChar == nLen);
     190             : 
     191           2 :     CPPUNIT_ASSERT_MESSAGE("And cache is updated too", m_pDoc->GetDocStat().nChar == nLen);
     192           1 : }
     193             : 
     194             : //For UI character counts we should follow UAX#29 and display the user
     195             : //perceived characters, not the number of codepoints, nor the number of code
     196             : //units http://unicode.org/reports/tr29/
     197           1 : void SwDocTest::testUserPerceivedCharCount()
     198             : {
     199           1 :     SwBreakIt *pBreakIter = SwBreakIt::Get();
     200             : 
     201             :     //Grapheme example, two different unicode code-points perceived by the user as a single
     202             :     //glyph
     203           1 :     const sal_Unicode ALEF_QAMATS [] = { 0x05D0, 0x05B8 };
     204           1 :     OUString sALEF_QAMATS(ALEF_QAMATS, SAL_N_ELEMENTS(ALEF_QAMATS));
     205           1 :     sal_Int32 nGraphemeCount = pBreakIter->getGraphemeCount(sALEF_QAMATS);
     206           1 :     CPPUNIT_ASSERT_MESSAGE("Grapheme Count should be 1", nGraphemeCount == 1);
     207             : 
     208             :     //Surrogate pair example, one single unicode code-point (U+1D11E)
     209             :     //represented as two code units in UTF-16
     210           1 :     const sal_Unicode GCLEF[] = { 0xD834, 0xDD1E };
     211           2 :     OUString sGCLEF(GCLEF, SAL_N_ELEMENTS(GCLEF));
     212           1 :     sal_Int32 nCount = pBreakIter->getGraphemeCount(sGCLEF);
     213           2 :     CPPUNIT_ASSERT_MESSAGE("Surrogate Pair should be counted as single character", nCount == 1);
     214           1 : }
     215             : 
     216           1 : void SwDocTest::testModelToViewHelper()
     217             : {
     218           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
     219           2 :     SwPaM aPaM(aIdx);
     220             : 
     221             :     {
     222           1 :         SwFmtFtn aFtn;
     223           1 :         aFtn.SetNumStr(OUString("foo"));
     224             : 
     225           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     226           1 :         m_pDoc->InsertString(aPaM, OUString("AAAAA BBBBB "));
     227           1 :         SwTxtNode* pTxtNode = aPaM.GetNode()->GetTxtNode();
     228           1 :         sal_Int32 nPos = aPaM.GetPoint()->nContent.GetIndex();
     229           1 :         pTxtNode->InsertItem(aFtn, nPos, nPos);
     230           1 :         m_pDoc->InsertString(aPaM, OUString(" CCCCC "));
     231           1 :         nPos = aPaM.GetPoint()->nContent.GetIndex();
     232           1 :         pTxtNode->InsertItem(aFtn, nPos, nPos);
     233           1 :         m_pDoc->InsertString(aPaM, OUString(" DDDDD"));
     234           1 :         CPPUNIT_ASSERT(pTxtNode->GetTxt().getLength() == (4*5) + 5 + 2);
     235             : 
     236             :         //set start of selection to first B
     237           1 :         aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 6);
     238           1 :         aPaM.SetMark();
     239             :         //set end of selection to last C
     240           1 :         aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 14);
     241             :         //set character attribute hidden on range
     242           2 :         SvxCharHiddenItem aHidden(true, RES_CHRATR_HIDDEN);
     243           1 :         m_pDoc->InsertPoolItem(aPaM, aHidden, 0 );
     244           1 :         aPaM.DeleteMark();
     245             : 
     246             :         //turn on red-lining and show changes
     247           1 :         m_pDoc->SetRedlineMode(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_DELETE|nsRedlineMode_t::REDLINE_SHOW_INSERT);
     248           1 :         CPPUNIT_ASSERT_MESSAGE("redlining should be on", m_pDoc->IsRedlineOn());
     249           1 :         CPPUNIT_ASSERT_MESSAGE("redlines should be visible", IDocumentRedlineAccess::IsShowChanges(m_pDoc->GetRedlineMode()));
     250             : 
     251             :         //set start of selection to last A
     252           1 :         aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 4);
     253           1 :         aPaM.SetMark();
     254             :         //set end of selection to second last B
     255           1 :         aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 9);
     256           1 :         m_pDoc->DeleteAndJoin(aPaM);    //redline-aware deletion api
     257           1 :         aPaM.DeleteMark();
     258             : 
     259             :         {
     260           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, PASSTHROUGH);
     261           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     262           2 :             OUString sModelText = pTxtNode->GetTxt();
     263           2 :             CPPUNIT_ASSERT_EQUAL(sModelText, sViewText);
     264             :         }
     265             : 
     266             :         {
     267           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS | EXPANDFOOTNOTE);
     268           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     269           2 :             CPPUNIT_ASSERT_EQUAL(
     270           2 :                 OUString("AAAAA BBBBB foo CCCCC foo DDDDD"), sViewText);
     271             :         }
     272             :         {
     273             :             ModelToViewHelper aModelToViewHelper(*pTxtNode,
     274           1 :                     EXPANDFIELDS | EXPANDFOOTNOTE | REPLACEMODE);
     275           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     276           2 :             CPPUNIT_ASSERT_EQUAL(
     277             :                 OUString("AAAAA BBBBB " + OUString(CHAR_ZWSP) + " CCCCC " + OUString(CHAR_ZWSP) + " DDDDD"),
     278           1 :                 sViewText);
     279           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2),
     280           1 :                 aModelToViewHelper.getFootnotePositions().size());
     281           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12),
     282           1 :                 aModelToViewHelper.getFootnotePositions()[0]);
     283           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(20),
     284           1 :                 aModelToViewHelper.getFootnotePositions()[1]);
     285           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     286           2 :                 aModelToViewHelper.getFieldPositions().size());
     287             :         }
     288             : 
     289             :         {
     290           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS);
     291           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     292           2 :             CPPUNIT_ASSERT_EQUAL(
     293           2 :                 OUString("AAAAA BBBBB  CCCCC  DDDDD"), sViewText);
     294             :         }
     295             :         {
     296             :             ModelToViewHelper aModelToViewHelper(*pTxtNode,
     297           1 :                 EXPANDFIELDS | REPLACEMODE);
     298           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     299           2 :             CPPUNIT_ASSERT_EQUAL(OUString("AAAAA BBBBB  CCCCC  DDDDD"),
     300           1 :                 sViewText);
     301           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     302           1 :                 aModelToViewHelper.getFootnotePositions().size());
     303           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     304           2 :                 aModelToViewHelper.getFieldPositions().size());
     305             :         }
     306             : 
     307             :         {
     308           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, HIDEINVISIBLE);
     309           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     310           2 :             CPPUNIT_ASSERT_EQUAL(
     311             :                 OUString("AAAAA CCCCC " + OUString(CH_TXTATR_BREAKWORD) + " DDDDD"),
     312           2 :                 sViewText);
     313             :         }
     314             : 
     315             :         {
     316           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, HIDEREDLINED);
     317           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     318           2 :             CPPUNIT_ASSERT_EQUAL(
     319             :                 OUString("AAAABB " + OUString(CH_TXTATR_BREAKWORD) + " CCCCC " + OUString(CH_TXTATR_BREAKWORD) + " DDDDD"),
     320           2 :                 sViewText);
     321             :         }
     322             : 
     323             :         {
     324           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS | HIDEINVISIBLE | EXPANDFOOTNOTE);
     325           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     326           2 :             CPPUNIT_ASSERT_EQUAL(OUString("AAAAA CCCCC foo DDDDD"), sViewText);
     327             :         }
     328             :         {
     329             :             ModelToViewHelper aModelToViewHelper(*pTxtNode,
     330           1 :                 EXPANDFIELDS | HIDEINVISIBLE | EXPANDFOOTNOTE | REPLACEMODE);
     331           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     332           2 :             CPPUNIT_ASSERT_EQUAL(
     333             :                 OUString("AAAAA CCCCC " + OUString(CHAR_ZWSP) + " DDDDD"),
     334           1 :                 sViewText);
     335           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
     336           1 :                 aModelToViewHelper.getFootnotePositions().size());
     337           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12),
     338           1 :                 aModelToViewHelper.getFootnotePositions()[0]);
     339           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     340           2 :                 aModelToViewHelper.getFieldPositions().size());
     341             :         }
     342             : 
     343             :         {
     344           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS | HIDEREDLINED | EXPANDFOOTNOTE);
     345           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     346           2 :             CPPUNIT_ASSERT_EQUAL(
     347           2 :                 OUString("AAAABB foo CCCCC foo DDDDD"), sViewText);
     348             :         }
     349             :         {
     350             :             ModelToViewHelper aModelToViewHelper(*pTxtNode,
     351           1 :                 EXPANDFIELDS | HIDEREDLINED | EXPANDFOOTNOTE | REPLACEMODE);
     352           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     353           2 :             CPPUNIT_ASSERT_EQUAL(
     354             :                OUString("AAAABB " + OUString(CHAR_ZWSP) + " CCCCC " + OUString(CHAR_ZWSP) + " DDDDD"),
     355           1 :                sViewText);
     356           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2),
     357           1 :                 aModelToViewHelper.getFootnotePositions().size());
     358           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(7),
     359           1 :                 aModelToViewHelper.getFootnotePositions()[0]);
     360           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(15),
     361           1 :                 aModelToViewHelper.getFootnotePositions()[1]);
     362           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     363           2 :                 aModelToViewHelper.getFieldPositions().size());
     364             :         }
     365             : 
     366             :         {
     367           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, HIDEINVISIBLE | HIDEREDLINED);
     368           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     369           2 :             OUStringBuffer aBuffer;
     370           1 :             aBuffer.append("AAAACCCCC ");
     371           1 :             aBuffer.append(CH_TXTATR_BREAKWORD);
     372           1 :             aBuffer.append(" DDDDD");
     373           2 :             CPPUNIT_ASSERT_EQUAL(aBuffer.makeStringAndClear(), sViewText);
     374             :         }
     375             : 
     376             :         {
     377           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS | HIDEINVISIBLE | HIDEREDLINED | EXPANDFOOTNOTE);
     378           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     379           2 :             CPPUNIT_ASSERT_EQUAL(OUString("AAAACCCCC foo DDDDD"), sViewText);
     380             :         }
     381             :         {
     382             :             ModelToViewHelper aModelToViewHelper(*pTxtNode,
     383           1 :                 EXPANDFIELDS | HIDEINVISIBLE | HIDEREDLINED | EXPANDFOOTNOTE | REPLACEMODE);
     384           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     385           2 :             CPPUNIT_ASSERT_EQUAL(sViewText,
     386           1 :                 OUString("AAAACCCCC " + OUString(CHAR_ZWSP) + " DDDDD"));
     387           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
     388           1 :                 aModelToViewHelper.getFootnotePositions().size());
     389           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(10),
     390           1 :                 aModelToViewHelper.getFootnotePositions()[0]);
     391           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     392           2 :                 aModelToViewHelper.getFieldPositions().size());
     393             :         }
     394             : 
     395           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     396           1 :         m_pDoc->InsertString(aPaM, OUString("AAAAA"));
     397           1 :         IDocumentMarkAccess* pMarksAccess = m_pDoc->getIDocumentMarkAccess();
     398             :         sw::mark::IFieldmark *pFieldmark = dynamic_cast<sw::mark::IFieldmark*>(
     399           1 :                 pMarksAccess->makeNoTextFieldBookmark(aPaM, "test", ODF_FORMDROPDOWN));
     400           1 :         CPPUNIT_ASSERT(pFieldmark);
     401           2 :         uno::Sequence< OUString > vListEntries(1);
     402           1 :         vListEntries[0] = "BBBBB";
     403           1 :         (*pFieldmark->GetParameters())[ODF_FORMDROPDOWN_LISTENTRY] = uno::makeAny(vListEntries);
     404           1 :         (*pFieldmark->GetParameters())[ODF_FORMDROPDOWN_RESULT] = uno::makeAny(sal_Int32(0));
     405           1 :         m_pDoc->InsertString(aPaM, OUString("CCCCC"));
     406           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     407           2 :         CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(11),
     408           1 :                 pTxtNode->GetTxt().getLength());
     409             : 
     410             :         {
     411           1 :             ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS | EXPANDFOOTNOTE);
     412           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     413           2 :             CPPUNIT_ASSERT_EQUAL(OUString("AAAAABBBBBCCCCC"), sViewText);
     414             :         }
     415             :         {
     416             :             ModelToViewHelper aModelToViewHelper(*pTxtNode,
     417           1 :                 EXPANDFIELDS | EXPANDFOOTNOTE | REPLACEMODE);
     418           2 :             OUString sViewText = aModelToViewHelper.getViewText();
     419           2 :             CPPUNIT_ASSERT_EQUAL(
     420             :                 OUString("AAAAA" + OUString(CHAR_ZWSP) + "CCCCC"),
     421           1 :                 sViewText);
     422           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0),
     423           1 :                 aModelToViewHelper.getFootnotePositions().size());
     424           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1),
     425           1 :                 aModelToViewHelper.getFieldPositions().size());
     426           2 :             CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5),
     427           2 :                 aModelToViewHelper.getFieldPositions()[0]);
     428           1 :         }
     429           1 :     }
     430           1 : }
     431             : 
     432           1 : void SwDocTest::testSwScanner()
     433             : {
     434           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
     435           2 :     SwPaM aPaM(aIdx);
     436             : 
     437           1 :     SwTxtNode* pTxtNode = aPaM.GetNode()->GetTxtNode();
     438             : 
     439           1 :     CPPUNIT_ASSERT_MESSAGE("Has Text Node", pTxtNode);
     440             : 
     441             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=40449
     442             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=39365
     443             :     //Use a temporary OUString as the arg, as that's the trouble behind
     444             :     //fdo#40449 and fdo#39365
     445             :     {
     446             :         SwScanner aScanner(*pTxtNode,
     447             :             OUString("Hello World"),
     448             :             0, ModelToViewHelper(), i18n::WordType::DICTIONARY_WORD, 0,
     449           1 :             RTL_CONSTASCII_LENGTH("Hello World"));
     450             : 
     451           1 :         bool bFirstOk = aScanner.NextWord();
     452           1 :         CPPUNIT_ASSERT_MESSAGE("First Token", bFirstOk);
     453           1 :         const OUString &rHello = aScanner.GetWord();
     454           2 :         CPPUNIT_ASSERT_MESSAGE("Should be Hello",
     455           1 :             rHello == "Hello");
     456             : 
     457           1 :         bool bSecondOk = aScanner.NextWord();
     458           1 :         CPPUNIT_ASSERT_MESSAGE("Second Token", bSecondOk);
     459           1 :         const OUString &rWorld = aScanner.GetWord();
     460           2 :         CPPUNIT_ASSERT_MESSAGE("Should be World",
     461           2 :             rWorld == "World");
     462             :     }
     463             : 
     464             :     //See https://www.libreoffice.org/bugzilla/show_bug.cgi?id=45271
     465             :     {
     466           1 :         const sal_Unicode IDEOGRAPHICFULLSTOP_D[] = { 0x3002, 'D' };
     467             : 
     468             :         m_pDoc->InsertString(aPaM, OUString(IDEOGRAPHICFULLSTOP_D,
     469           1 :             SAL_N_ELEMENTS(IDEOGRAPHICFULLSTOP_D)));
     470             : 
     471           1 :         SvxLanguageItem aCJKLangItem( LANGUAGE_CHINESE_SIMPLIFIED, RES_CHRATR_CJK_LANGUAGE );
     472           2 :         SvxLanguageItem aWestLangItem( LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE );
     473           1 :         m_pDoc->InsertPoolItem(aPaM, aCJKLangItem, 0 );
     474           1 :         m_pDoc->InsertPoolItem(aPaM, aWestLangItem, 0 );
     475             : 
     476           1 :         SwDocStat aDocStat;
     477           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     478           1 :         pTxtNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(IDEOGRAPHICFULLSTOP_D));
     479             : 
     480           1 :         CPPUNIT_ASSERT_MESSAGE("Should be 2", aDocStat.nChar == 2);
     481           2 :         CPPUNIT_ASSERT_MESSAGE("Should be 2", aDocStat.nCharExcludingSpaces == 2);
     482             :     }
     483             :     {
     484             :         const sal_Unicode test[] =
     485             :         {
     486             :             0x3053, 0x306E, 0x65E5, 0x672C, 0x8A9E, 0x306F, 0x6B63, 0x3057,
     487             :             0x304F, 0x6570, 0x3048, 0x3089, 0x308C, 0x308B, 0x3067, 0x3057,
     488             :             0x3087, 0x3046, 0x304B, 0x3002, 0x0041, 0x006E, 0x0064, 0x0020,
     489             :             0x006C, 0x0065, 0x0074, 0x0027, 0x0073, 0x0020, 0x0074, 0x0068,
     490             :             0x0072, 0x006F, 0x0077, 0x0020, 0x0073, 0x006F, 0x006D, 0x0065,
     491             :             0x0020, 0x0045, 0x006E, 0x0067, 0x006C, 0x0069, 0x0073, 0x0068,
     492             :             0x0020, 0x0069, 0x006E, 0x0020, 0x0074, 0x006F, 0x0020, 0x006D,
     493             :             0x0061, 0x006B, 0x0065, 0x0020, 0x0069, 0x0074, 0x0020, 0x0069,
     494             :             0x006E, 0x0074, 0x0065, 0x0072, 0x0065, 0x0073, 0x0074, 0x0069,
     495             :             0x006E, 0x0067, 0x002E, 0x0020, 0x0020, 0x305D, 0x3057, 0x3066,
     496             :             0x3001, 0x307E, 0x305F, 0x65E5, 0x672C, 0x8A9E, 0x3000, 0x3000,
     497             :             0x3067, 0x3082, 0x4ECA, 0x56DE, 0x306F, 0x7A7A, 0x767D, 0x3092,
     498             :             0x3000, 0x3000, 0x5165, 0x308C, 0x307E, 0x3057, 0x305F, 0x3002,
     499             :             0x0020, 0x0020, 0x0053, 0x006F, 0x0020, 0x0068, 0x006F, 0x0077,
     500             :             0x0020, 0x0064, 0x006F, 0x0065, 0x0073, 0x0020, 0x0074, 0x0068,
     501             :             0x0069, 0x0073, 0x0020, 0x0064, 0x006F, 0x003F, 0x0020, 0x0020
     502           1 :         };
     503           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     504             :         m_pDoc->InsertString(aPaM, OUString(test,
     505           1 :             SAL_N_ELEMENTS(test)));
     506             : 
     507           1 :         SvxLanguageItem aCJKLangItem( LANGUAGE_JAPANESE, RES_CHRATR_CJK_LANGUAGE );
     508           2 :         SvxLanguageItem aWestLangItem( LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE );
     509           1 :         m_pDoc->InsertPoolItem(aPaM, aCJKLangItem, 0 );
     510           1 :         m_pDoc->InsertPoolItem(aPaM, aWestLangItem, 0 );
     511             : 
     512           1 :         SwDocStat aDocStat;
     513           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     514           1 :         pTxtNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(test));
     515           1 :         CPPUNIT_ASSERT_MESSAGE("58 words", aDocStat.nWord == 58);
     516           1 :         CPPUNIT_ASSERT_MESSAGE("43 Asian characters and Korean syllables", aDocStat.nAsianWord == 43);
     517           1 :         CPPUNIT_ASSERT_MESSAGE("105 non-whitespace chars", aDocStat.nCharExcludingSpaces == 105);
     518           2 :         CPPUNIT_ASSERT_MESSAGE("128 characters", aDocStat.nChar == 128);
     519             :     }
     520             : 
     521             :     //See https://issues.apache.org/ooo/show_bug.cgi?id=89042
     522             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=53399
     523             :     {
     524           1 :         SwDocStat aDocStat;
     525             : 
     526             :         const sal_Unicode aShouldBeThree[] = {
     527             :             0x0053, 0x0068, 0x006F, 0x0075, 0x006C, 0x0064, 0x0020,
     528             :             0x2018, 0x0062, 0x0065, 0x0020, 0x0074, 0x0068, 0x0072,
     529             :             0x0065, 0x0065, 0x2019
     530           1 :         };
     531             : 
     532           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     533           1 :         m_pDoc->InsertString(aPaM, OUString(aShouldBeThree, SAL_N_ELEMENTS(aShouldBeThree)));
     534           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     535           1 :         pTxtNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(aShouldBeThree));
     536           1 :         CPPUNIT_ASSERT_MESSAGE("Should be 3", aDocStat.nWord == 3);
     537             : 
     538             :         const sal_Unicode aShouldBeFive[] = {
     539             :             // f    r       e       n       c       h       space
     540             :             0x0046, 0x0072, 0x0065, 0x006E, 0x0063, 0x0068, 0x0020,
     541             :             // <<   nbsp    s       a       v       o       i
     542             :             0x00AB, 0x00A0, 0x0073, 0x0061, 0x0076, 0x006F, 0x0069,
     543             :             // r    nnbsp   c       a       l       c       u
     544             :             0x0072, 0x202f, 0x0063, 0x0061, 0x006C, 0x0063, 0x0075,
     545             :             // l    e       r       idspace >>
     546             :             0x006C, 0x0065, 0x0072, 0x3000, 0x00BB
     547           1 :         };
     548             : 
     549           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     550           1 :         m_pDoc->InsertString(aPaM, OUString(aShouldBeFive, SAL_N_ELEMENTS(aShouldBeFive)));
     551           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     552           1 :         aDocStat.Reset();
     553           1 :         pTxtNode->CountWords(aDocStat, 0, SAL_N_ELEMENTS(aShouldBeFive));
     554           1 :         CPPUNIT_ASSERT_MESSAGE("Should be 5", aDocStat.nWord == 5);
     555             :     }
     556             : 
     557             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=49629
     558             :     {
     559           1 :         SwDocStat aDocStat;
     560             : 
     561           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     562           1 :         m_pDoc->InsertString(aPaM, OUString("Apple"));
     563           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     564           1 :         sal_Int32 nPos = aPaM.GetPoint()->nContent.GetIndex();
     565           1 :         SwFmtFtn aFtn;
     566           1 :         aFtn.SetNumStr(OUString("banana"));
     567           1 :         SwTxtAttr* pTA = pTxtNode->InsertItem(aFtn, nPos, nPos);
     568           1 :         CPPUNIT_ASSERT(pTA);
     569           1 :         CPPUNIT_ASSERT(pTxtNode->Len() == 6); //Apple + 0x02
     570           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     571           1 :         CPPUNIT_ASSERT(aDocStat.nWord == 1);
     572           1 :         CPPUNIT_ASSERT_MESSAGE("footnote should be expanded", aDocStat.nChar == 11);
     573             : 
     574           1 :         const sal_Int32 nNextPos = aPaM.GetPoint()->nContent.GetIndex();
     575           1 :         CPPUNIT_ASSERT(nNextPos == nPos+1);
     576           2 :         SwFmtRefMark aRef(OUString("refmark"));
     577           1 :         pTA = pTxtNode->InsertItem(aRef, nNextPos, nNextPos);
     578           1 :         CPPUNIT_ASSERT(pTA);
     579             : 
     580           1 :         aDocStat.Reset();
     581           1 :         pTxtNode->SetWordCountDirty(true);
     582           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     583           1 :         CPPUNIT_ASSERT(aDocStat.nWord == 1);
     584           1 :         CPPUNIT_ASSERT_MESSAGE("refmark anchor should not be counted", aDocStat.nChar == 11);
     585             : 
     586           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     587           1 :         m_pDoc->InsertString(aPaM, OUString("Apple"));
     588             : 
     589           1 :         DateTime aDate(DateTime::SYSTEM);
     590             :         SwPostItField aPostIt(
     591           1 :             (SwPostItFieldType*)m_pDoc->GetSysFldType(RES_POSTITFLD), OUString("An Author"),
     592           3 :             OUString("Some Text"), OUString("Initials"), OUString("Name"), aDate );
     593           1 :         m_pDoc->InsertPoolItem(aPaM, SwFmtFld(aPostIt), 0);
     594             : 
     595           1 :         m_pDoc->InsertString(aPaM, OUString("Apple"));
     596           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     597           1 :         aDocStat.Reset();
     598           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     599           1 :         CPPUNIT_ASSERT(aDocStat.nWord == 1);
     600           1 :         CPPUNIT_ASSERT_MESSAGE("postit anchor should effectively not exist", aDocStat.nChar == 10);
     601           1 :         CPPUNIT_ASSERT(pTxtNode->Len() == 11);
     602             : 
     603           2 :         aDocStat.Reset();
     604             :     }
     605             : 
     606             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=46757
     607             :     {
     608           1 :         SwDocStat aDocStat;
     609             : 
     610           1 :         const char aString[] = "Lorem ipsum";
     611           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     612           1 :         m_pDoc->InsertString(aPaM, OUString(aString));
     613           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     614           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     615           1 :         CPPUNIT_ASSERT_EQUAL(aDocStat.nWord, static_cast<sal_uLong>(2));
     616             : 
     617             :         //turn on red-lining and show changes
     618           1 :         m_pDoc->SetRedlineMode(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_DELETE|nsRedlineMode_t::REDLINE_SHOW_INSERT);
     619           1 :         CPPUNIT_ASSERT_MESSAGE("redlining should be on", m_pDoc->IsRedlineOn());
     620           1 :         CPPUNIT_ASSERT_MESSAGE("redlines should be visible", IDocumentRedlineAccess::IsShowChanges(m_pDoc->GetRedlineMode()));
     621             : 
     622             :         //delete everything except the first word
     623           1 :         aPaM.SetMark(); //set start of selection to current pos
     624           1 :         aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 5);   //set end of selection to fifth char of current node
     625           1 :         m_pDoc->DeleteAndJoin(aPaM);    //redline-aware deletion api
     626             :         //"real underlying text should be the same"
     627           1 :         CPPUNIT_ASSERT_EQUAL(pTxtNode->GetTxt(), OUString(aString));
     628             : 
     629           1 :         aDocStat.Reset();
     630           1 :         pTxtNode->SetWordCountDirty(true);
     631           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len()); //but word-counting the text should only count the non-deleted text
     632           1 :         CPPUNIT_ASSERT_EQUAL(aDocStat.nWord, static_cast<sal_uLong>(1));
     633             : 
     634           1 :         pTxtNode->SetWordCountDirty(true);
     635             : 
     636             :         //keep red-lining on but hide changes
     637           1 :         m_pDoc->SetRedlineMode(nsRedlineMode_t::REDLINE_ON);
     638           1 :         CPPUNIT_ASSERT_MESSAGE("redlining should be still on", m_pDoc->IsRedlineOn());
     639           1 :         CPPUNIT_ASSERT_MESSAGE("redlines should be invisible", !IDocumentRedlineAccess::IsShowChanges(m_pDoc->GetRedlineMode()));
     640             : 
     641           1 :         aDocStat.Reset();
     642           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len()); //but word-counting the text should only count the non-deleted text
     643           1 :         CPPUNIT_ASSERT_EQUAL(aDocStat.nWord, static_cast<sal_uLong>(1));
     644             : 
     645           1 :         OUString sLorem = pTxtNode->GetTxt();
     646           1 :         CPPUNIT_ASSERT(sLorem == "Lorem");
     647             : 
     648           1 :         const SwRedlineTbl& rTbl = m_pDoc->GetRedlineTbl();
     649             : 
     650           1 :         SwNodes& rNds = m_pDoc->GetNodes();
     651           1 :         CPPUNIT_ASSERT(rTbl.size() == 1);
     652             : 
     653           1 :         SwNodeIndex* pNodeIdx = rTbl[0]->GetContentIdx();
     654           1 :         CPPUNIT_ASSERT(pNodeIdx);
     655             : 
     656           1 :         pTxtNode = rNds[ pNodeIdx->GetIndex() + 1 ]->GetTxtNode();        //first deleted txtnode
     657           1 :         CPPUNIT_ASSERT(pTxtNode);
     658             : 
     659           2 :         OUString sIpsum = pTxtNode->GetTxt();
     660           1 :         CPPUNIT_ASSERT(sIpsum == " ipsum");
     661             : 
     662           1 :         aDocStat.Reset();
     663           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len()); //word-counting the text should only count the non-deleted text, and this whole chunk should be ignored
     664           1 :         CPPUNIT_ASSERT_EQUAL(aDocStat.nWord, static_cast<sal_uLong>(0));
     665           2 :         CPPUNIT_ASSERT_EQUAL(aDocStat.nChar, static_cast<sal_uLong>(0));
     666             :     }
     667             : 
     668             :     //See https://bugs.libreoffice.org/show_bug.cgi?id=38983
     669             :     {
     670           1 :         SwDocStat aDocStat;
     671             : 
     672           1 :         OUString sTemplate("ThisXis a test.");
     673             : 
     674           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     675           1 :         m_pDoc->InsertString(aPaM, sTemplate.replace('X', ' '));
     676           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     677           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     678           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
     679             :                        aDocStat.nCharExcludingSpaces == 12 &&
     680           1 :                        aDocStat.nChar == 15);
     681           1 :         aDocStat.Reset();
     682             : 
     683           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     684           1 :         m_pDoc->InsertString(aPaM, sTemplate.replaceAll(OUString('X'), OUString(" = ")));
     685           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     686           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     687           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 5 &&
     688             :                        aDocStat.nCharExcludingSpaces == 13 &&
     689           1 :                        aDocStat.nChar == 17);
     690           1 :         aDocStat.Reset();
     691             : 
     692           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     693           1 :         m_pDoc->InsertString(aPaM, sTemplate.replaceAll(OUString('X'), OUString(" _ ")));
     694           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     695           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     696           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 5 &&
     697             :                        aDocStat.nCharExcludingSpaces == 13 &&
     698           1 :                        aDocStat.nChar == 17);
     699           1 :         aDocStat.Reset();
     700             : 
     701           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     702           1 :         m_pDoc->InsertString(aPaM, sTemplate.replaceAll(OUString('X'), OUString(" -- ")));
     703           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     704           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     705           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 5 &&
     706             :                        aDocStat.nCharExcludingSpaces == 14 &&
     707           1 :                        aDocStat.nChar == 18);
     708           1 :         aDocStat.Reset();
     709             : 
     710           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     711           1 :         m_pDoc->InsertString(aPaM, sTemplate.replace('X', '_'));
     712           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     713           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     714           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
     715             :                        aDocStat.nCharExcludingSpaces == 13 &&
     716           1 :                        aDocStat.nChar == 15);
     717           1 :         aDocStat.Reset();
     718             : 
     719           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     720           1 :         m_pDoc->InsertString(aPaM, sTemplate.replace('X', '-'));
     721           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     722           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     723           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
     724             :                        aDocStat.nCharExcludingSpaces == 13 &&
     725           1 :                        aDocStat.nChar == 15);
     726           1 :         aDocStat.Reset();
     727             : 
     728           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     729           1 :         m_pDoc->InsertString(aPaM, sTemplate.replace('X', 0x2012));
     730           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     731           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     732           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
     733             :                        aDocStat.nCharExcludingSpaces == 13 &&
     734           1 :                        aDocStat.nChar == 15);
     735           1 :         aDocStat.Reset();
     736             : 
     737           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     738           1 :         m_pDoc->InsertString(aPaM, sTemplate.replace('X', 0x2015));
     739           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     740           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     741           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 3 &&
     742             :                        aDocStat.nCharExcludingSpaces == 13 &&
     743           1 :                        aDocStat.nChar == 15);
     744           1 :         aDocStat.Reset();
     745             : 
     746             :         //But default configuration should, msword-alike treak emdash
     747             :         //and endash as word separators for word-counting
     748           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     749           1 :         m_pDoc->InsertString(aPaM, sTemplate.replace('X', 0x2013));
     750           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     751           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     752           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
     753             :                        aDocStat.nCharExcludingSpaces == 13 &&
     754           1 :                        aDocStat.nChar == 15);
     755           1 :         aDocStat.Reset();
     756             : 
     757           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     758           1 :         m_pDoc->InsertString(aPaM, sTemplate.replace('X', 0x2014));
     759           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     760           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     761           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
     762             :                        aDocStat.nCharExcludingSpaces == 13 &&
     763           1 :                        aDocStat.nChar == 15);
     764           1 :         aDocStat.Reset();
     765             : 
     766           1 :         const sal_Unicode aChunk[] = {' ', 0x2013, ' '};
     767           2 :         OUString sChunk(aChunk, SAL_N_ELEMENTS(aChunk));
     768           1 :         m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     769           1 :         m_pDoc->InsertString(aPaM, sTemplate.replaceAll(OUString('X'), sChunk));
     770           1 :         pTxtNode = aPaM.GetNode()->GetTxtNode();
     771           1 :         pTxtNode->CountWords(aDocStat, 0, pTxtNode->Len());
     772           2 :         CPPUNIT_ASSERT(aDocStat.nWord == 4 &&
     773             :                        aDocStat.nCharExcludingSpaces == 13 &&
     774           1 :                        aDocStat.nChar == 17);
     775           2 :         aDocStat.Reset();
     776           1 :     }
     777           1 : }
     778             : 
     779             : //See https://bugs.libreoffice.org/show_bug.cgi?id=40599
     780           1 : void SwDocTest::testGraphicAnchorDeletion()
     781             : {
     782           1 :     CPPUNIT_ASSERT_MESSAGE("Expected initial 0 count", m_pDoc->GetDocStat().nChar == 0);
     783             : 
     784           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
     785           2 :     SwPaM aPaM(aIdx);
     786             : 
     787           1 :     m_pDoc->InsertString(aPaM, OUString("Paragraph 1"));
     788           1 :     m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     789             : 
     790           1 :     m_pDoc->InsertString(aPaM, OUString("graphic anchor>><<graphic anchor"));
     791           2 :     SwNodeIndex nPara2 = aPaM.GetPoint()->nNode;
     792           1 :     m_pDoc->AppendTxtNode(*aPaM.GetPoint());
     793             : 
     794           1 :     m_pDoc->InsertString(aPaM, OUString("Paragraph 3"));
     795             : 
     796           1 :     aPaM.GetPoint()->nNode = nPara2;
     797           1 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), RTL_CONSTASCII_LENGTH("graphic anchor>>"));
     798             : 
     799             :     //Insert a graphic at X of >>X<< in paragraph 2
     800           2 :     SfxItemSet aFlySet(m_pDoc->GetAttrPool(), RES_FRMATR_BEGIN, RES_FRMATR_END-1);
     801           2 :     SwFmtAnchor aAnchor(FLY_AS_CHAR);
     802           1 :     aAnchor.SetAnchor(aPaM.GetPoint());
     803           1 :     aFlySet.Put(aAnchor);
     804           1 :     SwFlyFrmFmt *pFrame = m_pDoc->Insert(aPaM, OUString(), OUString(), NULL, &aFlySet, NULL, NULL);
     805           1 :     CPPUNIT_ASSERT_MESSAGE("Expected frame", pFrame != NULL);
     806             : 
     807           1 :     CPPUNIT_ASSERT_MESSAGE("Should be 1 graphic", m_pDoc->GetFlyCount(FLYCNTTYPE_GRF) == 1);
     808             : 
     809             :     //Delete >X<
     810           1 :     aPaM.GetPoint()->nNode = nPara2;
     811           2 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(),
     812           3 :         RTL_CONSTASCII_LENGTH("graphic anchor>><")+1);
     813           1 :     aPaM.SetMark();
     814           1 :     aPaM.GetPoint()->nNode = nPara2;
     815           1 :     aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), RTL_CONSTASCII_LENGTH("graphic anchor>"));
     816           1 :     m_pDoc->DeleteRange(aPaM);
     817             : 
     818             : #ifdef DEBUG_AS_HTML
     819             :     {
     820             :         SvFileStream aPasteDebug(OUString("cppunitDEBUG.html"), STREAM_WRITE|STREAM_TRUNC);
     821             :         WriterRef xWrt;
     822             :         GetHTMLWriter( String(), String(), xWrt );
     823             :         SwWriter aDbgWrt( aPasteDebug, *m_pDoc );
     824             :         aDbgWrt.Write( xWrt );
     825             :     }
     826             : #endif
     827             : 
     828           2 :     CPPUNIT_ASSERT_MESSAGE("Should be 0 graphics", m_pDoc->GetFlyCount(FLYCNTTYPE_GRF) == 0);
     829             : 
     830             :     //Now, if instead we swap FLY_AS_CHAR (inline graphic) to FLY_AT_CHAR (anchored to character)
     831             :     //and repeat the above, graphic is *not* deleted, i.e. it belongs to the paragraph, not the
     832             :     //range to which its anchored, which is annoying.
     833           1 : }
     834             : 
     835             : static int
     836       36395 : getRand(int modulus)
     837             : {
     838       36395 :     if (modulus <= 0)
     839           0 :         return 0;
     840       36395 :     return rand() % modulus;
     841             : }
     842             : 
     843             : static OUString
     844        4024 : getRandString()
     845             : {
     846        4024 :     OUString aText("AAAAA BBBB CCC DD E \n");
     847        4024 :     int s = getRand(aText.getLength());
     848        4024 :     int j = getRand(aText.getLength() - s);
     849        4024 :     OUString aRet(aText.copy(s, j));
     850        4024 :     if (!getRand(5))
     851         753 :         aRet += OUString('\n');
     852             : //    fprintf (stderr, "rand string '%s'\n", OUStringToOString(aRet, RTL_TEXTENCODING_UTF8).getStr());
     853        4024 :     return aRet;
     854             : }
     855             : 
     856             : static SwPosition
     857       18539 : getRandomPosition(SwDoc *pDoc, int /* nOffset */)
     858             : {
     859       18539 :     const SwPosition aPos(pDoc->GetNodes().GetEndOfContent());
     860       18539 :         sal_uLong nNodes = aPos.nNode.GetNode().GetIndex() - aPos.nNode.GetNode().StartOfSectionIndex();
     861       18539 :         sal_uLong n = (rand() * nNodes) / RAND_MAX;
     862       37078 :         SwPaM pam(aPos);
     863       27815 :         for (sal_uLong i = 0; i < n; ++i) {
     864        9276 :                 pam.Move(fnMoveBackward, fnGoNode);
     865             :         }
     866       37078 :     return *pam.GetPoint();
     867             : }
     868             : 
     869           1 : void SwDocTest::randomTest()
     870             : {
     871           1 :     CPPUNIT_ASSERT_MESSAGE("SwDoc::IsRedlineOn()", !m_pDoc->IsRedlineOn());
     872             :     RedlineMode_t modes[] = {
     873             :         nsRedlineMode_t::REDLINE_ON,
     874             :         nsRedlineMode_t::REDLINE_SHOW_MASK,
     875             :         nsRedlineMode_t::REDLINE_NONE,
     876             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_MASK,
     877             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE,
     878             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE | nsRedlineMode_t::REDLINE_SHOW_MASK,
     879             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT,
     880             :         nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_DELETE
     881           1 :     };
     882             :     static const char *authors[] = {
     883             :         "Jim", "Bob", "JimBobina", "Helga", "Gertrude", "Spagna", "Hurtleweed"
     884             :     };
     885             : 
     886           9 :     for( sal_uInt16 rlm = 0; rlm < SAL_N_ELEMENTS(modes); rlm++ )
     887             :     {
     888           8 :         m_pDoc->ClearDoc();
     889             : 
     890             :         // setup redlining
     891           8 :         m_pDoc->SetRedlineMode(modes[rlm]);
     892           8 :         SW_MOD()->SetRedlineAuthor(OUString::createFromAscii(authors[0]));
     893             : 
     894       16008 :         for( int i = 0; i < 2000; i++ )
     895             :         {
     896       16000 :             SwPaM aPam(m_pDoc->GetNodes());
     897       32000 :             SwCursor aCrs(getRandomPosition(m_pDoc, i/20), 0, false);
     898       16000 :             aCrs.SetMark();
     899             : 
     900       16000 :             switch (getRand (i < 50 ? 3 : 6)) {
     901             :             // insert ops first
     902             :             case 0: {
     903        2682 :                 if (!m_pDoc->InsertString(aCrs, getRandString())) {
     904             : //                    fprintf (stderr, "failed to insert string !\n");
     905             :                 }
     906        2682 :                 break;
     907             :             }
     908             :             case 1:
     909        2825 :                 break;
     910             :             case 2: { // switch author
     911        2690 :                 int a = getRand(SAL_N_ELEMENTS(authors));
     912        2690 :                 SW_MOD()->SetRedlineAuthor(OUString::createFromAscii(authors[a]));
     913        2690 :                 break;
     914             :             }
     915             : 
     916             :             // movement / deletion ops later
     917             :             case 3: // deletion
     918        2665 :                 switch (getRand(6)) {
     919             :                 case 0:
     920         454 :                     m_pDoc->DelFullPara(aCrs);
     921         454 :                     break;
     922             :                 case 1:
     923         440 :                     m_pDoc->DeleteRange(aCrs);
     924         440 :                     break;
     925             :                 case 2:
     926         429 :                     m_pDoc->DeleteAndJoin(aCrs, !!getRand(1));
     927         429 :                     break;
     928             :                 case 3:
     929             :                 default:
     930        1342 :                     m_pDoc->Overwrite(aCrs, getRandString());
     931        1342 :                     break;
     932             :                 }
     933        2665 :                 break;
     934             :             case 4: { // movement
     935             :                 IDocumentContentOperations::SwMoveFlags nFlags =
     936             :                     (IDocumentContentOperations::SwMoveFlags)
     937        2539 :                         (getRand(1) ? // FIXME: puterb this more ?
     938             :                          IDocumentContentOperations::DOC_MOVEDEFAULT :
     939             :                          IDocumentContentOperations::DOC_MOVEALLFLYS |
     940             :                          IDocumentContentOperations::DOC_CREATEUNDOOBJ |
     941             :                          IDocumentContentOperations::DOC_MOVEREDLINES |
     942        2539 :                          IDocumentContentOperations::DOC_NO_DELFRMS);
     943        2539 :                 SwPosition aTo(getRandomPosition(m_pDoc, i/10));
     944        2539 :                 m_pDoc->MoveRange(aCrs, aTo, nFlags);
     945        2539 :                 break;
     946             :             }
     947             : 
     948             :             case 5:
     949        2599 :                 break;
     950             : 
     951             :             // undo / redo ?
     952             :             default:
     953           0 :                 break;
     954             :             }
     955       16000 :         }
     956             : 
     957             : // Debug / verify the produced document has real content
     958             : #if 0
     959             :         OStringBuffer aBuffer("nodes-");
     960             :         aBuffer.append(sal_Int32(rlm));
     961             :         aBuffer.append(".xml");
     962             : 
     963             :         xmlTextWriterPtr writer;
     964             :         writer = xmlNewTextWriterFilename( aBuffer.makeStringAndClear().getStr(), 0 );
     965             :         xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
     966             :         m_pDoc->dumpAsXml(writer);
     967             :         xmlTextWriterEndDocument( writer );
     968             :         xmlFreeTextWriter( writer );
     969             : #endif
     970             :     }
     971           1 : }
     972             : 
     973             : static OUString
     974           6 : translitTest(SwDoc & rDoc, SwPaM & rPaM, sal_uInt32 const nType)
     975             : {
     976             :     utl::TransliterationWrapper aTrans(
     977           6 :             ::comphelper::getProcessComponentContext(), nType);
     978           6 :     rDoc.TransliterateText(rPaM, aTrans);
     979           6 :     return rPaM.GetTxt();
     980             : }
     981             : 
     982           1 : void SwDocTest::testTransliterate()
     983             : {
     984             :     // just some simple test to see if it's totally broken
     985           1 :     SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
     986           2 :     SwPaM aPaM(aIdx);
     987           1 :     m_pDoc->InsertString(aPaM, OUString("foobar"));
     988           1 :     aPaM.SetMark();
     989           1 :     aPaM.GetPoint()->nContent = 0;
     990           1 :     CPPUNIT_ASSERT_EQUAL(OUString("foobar"), aPaM.GetTxt());
     991             : 
     992           2 :     CPPUNIT_ASSERT_EQUAL(OUString("FOOBAR"),
     993             :             translitTest(*m_pDoc, aPaM,
     994           1 :                 i18n::TransliterationModules_LOWERCASE_UPPERCASE));
     995           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Foobar"),
     996             :             translitTest(*m_pDoc, aPaM,
     997           1 :                 i18n::TransliterationModulesExtra::TITLE_CASE));
     998           2 :     CPPUNIT_ASSERT_EQUAL(OUString("fOOBAR"),
     999             :             translitTest(*m_pDoc, aPaM,
    1000           1 :                 i18n::TransliterationModulesExtra::TOGGLE_CASE));
    1001           2 :     CPPUNIT_ASSERT_EQUAL(OUString("foobar"),
    1002             :             translitTest(*m_pDoc, aPaM,
    1003           1 :                 i18n::TransliterationModules_UPPERCASE_LOWERCASE));
    1004           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Foobar"),
    1005             :             translitTest(*m_pDoc, aPaM,
    1006           1 :                 i18n::TransliterationModulesExtra::SENTENCE_CASE));
    1007           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Foobar"),
    1008             :             translitTest(*m_pDoc, aPaM,
    1009           2 :                 i18n::TransliterationModules_HIRAGANA_KATAKANA));
    1010           1 : }
    1011             : 
    1012           9 : void SwDocTest::setUp()
    1013             : {
    1014           9 :     BootstrapFixture::setUp();
    1015             : 
    1016           9 :     SwGlobals::ensure();
    1017           9 :     m_pDoc = new SwDoc;
    1018           9 :     m_xDocShRef = new SwDocShell(m_pDoc, SFX_CREATE_MODE_EMBEDDED);
    1019           9 :     m_xDocShRef->DoInitNew(0);
    1020           9 : }
    1021             : 
    1022           9 : void SwDocTest::tearDown()
    1023             : {
    1024           9 :     m_xDocShRef.Clear();
    1025           9 :     delete m_pDoc;
    1026             : 
    1027           9 :     BootstrapFixture::tearDown();
    1028           9 : }
    1029             : 
    1030           1 : CPPUNIT_TEST_SUITE_REGISTRATION(SwDocTest);
    1031             : 
    1032           4 : CPPUNIT_PLUGIN_IMPLEMENT();
    1033             : 
    1034             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10