From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- sw/qa/extras/uiwriter/uiwriter.cxx | 1754 ++++++++++++++++++++++++++++++++++++ 1 file changed, 1754 insertions(+) create mode 100644 sw/qa/extras/uiwriter/uiwriter.cxx (limited to 'sw/qa/extras/uiwriter/uiwriter.cxx') diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx new file mode 100644 index 000000000..ddbe5e009 --- /dev/null +++ b/sw/qa/extras/uiwriter/uiwriter.cxx @@ -0,0 +1,1754 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ +constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/extras/uiwriter/data/"; + +void lcl_selectCharacters(SwPaM& rPaM, sal_Int32 first, sal_Int32 end) +{ + rPaM.GetPoint()->nContent.Assign(rPaM.GetContentNode(), first); + rPaM.SetMark(); + rPaM.GetPoint()->nContent.Assign(rPaM.GetContentNode(), end); +} +} //namespace + +class SwUiWriterTest : public SwModelTestBase +{ +public: + std::unique_ptr readDOCXAutotext( + std::u16string_view sFileName, bool bEmpty = false); + void testRedlineFrame(char const*const file); +}; + +std::unique_ptr SwUiWriterTest::readDOCXAutotext(std::u16string_view sFileName, bool bEmpty) +{ + utl::TempFile tmp; + tmp.EnableKillingFile(); + OUString rURL = tmp.GetURL(); + CPPUNIT_ASSERT_EQUAL( + osl::FileBase::E_None, + osl::File::copy(m_directories.getURLFromSrc(DATA_DIRECTORY) + sFileName, rURL)); + + SfxMedium aSrcMed(rURL, StreamMode::STD_READ); + SwDoc* pDoc = createSwDoc(); + + SwReader aReader(aSrcMed, rURL, pDoc); + Reader* pDOCXReader = SwReaderWriter::GetDOCXReader(); + auto pGlossary = std::make_unique(rURL); + + CPPUNIT_ASSERT(pDOCXReader != nullptr); + CPPUNIT_ASSERT_EQUAL(!bEmpty, aReader.ReadGlossaries(*pDOCXReader, *pGlossary, false)); + + return pGlossary; +} + +void SwUiWriterTest::testRedlineFrame(char const*const file) +{ + SwDoc * pDoc(createSwDoc(DATA_DIRECTORY, file)); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + // there is exactly one frame + CPPUNIT_ASSERT_EQUAL(1, getShapes()); + + RedlineFlags nMode = pWrtShell->GetRedlineFlags(); + CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete); + + // hide delete redlines + pWrtShell->SetRedlineFlags(nMode & ~RedlineFlags::ShowDelete); + + // there is still exactly one frame + CPPUNIT_ASSERT_EQUAL(1, getShapes()); + + pWrtShell->SetRedlineFlags(nMode); // show again + + // there is still exactly one frame + CPPUNIT_ASSERT_EQUAL(1, getShapes()); +} + +//Replacement tests + +constexpr OUStringLiteral ORIGINAL_REPLACE_CONTENT(u"toto titi tutu"); +constexpr OUStringLiteral EXPECTED_REPLACE_CONTENT(u"toto toto tutu"); + +// Chinese conversion tests + +const sal_Unicode CHINESE_TRADITIONAL_CONTENT(0x9F8D); +const sal_Unicode CHINESE_SIMPLIFIED_CONTENT(0x9F99); +constexpr OUStringLiteral NON_CHINESE_CONTENT(u"Hippopotamus"); + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testReplaceForward) +{ + SwDoc* pDoc = createSwDoc(); + + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + + SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1); + SwPaM aPaM(aIdx); + + pDoc->getIDocumentContentOperations().InsertString(aPaM, ORIGINAL_REPLACE_CONTENT); + + SwTextNode* pTextNode = aPaM.GetNode().GetTextNode(); + lcl_selectCharacters(aPaM, 5, 9); + pDoc->getIDocumentContentOperations().ReplaceRange(aPaM, "toto", false); + + CPPUNIT_ASSERT_EQUAL(OUString(EXPECTED_REPLACE_CONTENT), pTextNode->GetText()); + + rUndoManager.Undo(); + + CPPUNIT_ASSERT_EQUAL(OUString(ORIGINAL_REPLACE_CONTENT), pTextNode->GetText()); +} + + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtCharStartOutside0) +{ + testRedlineFrame("redlineFrame.fodt"); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtCharStartOutside) +{ + testRedlineFrame("redlineFrame_at_char_start_outside.fodt"); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtCharStartInside) +{ + testRedlineFrame("redlineFrame_at_char_start_inside.fodt"); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtParaStartOutside) +{ + testRedlineFrame("redline_fly_duplication_at_para_start_outside.fodt"); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtParaEndInside) +{ + testRedlineFrame("redline_fly_duplication_at_para_end_inside.fodt"); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtParaOneParagraph) +{ + // test ALLFLYS flag: oddly enough it didn't fail as fodt but failed as odt... + testRedlineFrame("redline_fly_at_para_one_paragraph.odt"); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtPara2ndParagraph) +{ + // lost via the buggy increment in Copy + testRedlineFrame("redline_fly_duplication_at_para_2nd_paragraph.fodt"); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testThreadedException) +{ + SvFileStream aFileStream(m_directories.getURLFromSrc(DATA_DIRECTORY) + "threadedException.fodt", StreamMode::READ); + + //threaded reading only kicks in if there is sufficient buffer to make it worthwhile, so read + //from a SvFileStream to ensure that + bool bRes = TestImportFODT(aFileStream); + + CPPUNIT_ASSERT(!bRes); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf149595) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "demo91.fodt"); + + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + // all 4 shapes are on the 2nd paragraph + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr); + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr); + CPPUNIT_ASSERT_EQUAL(size_t(4), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size()); + + { + pWrtShell->Down(false); + pWrtShell->EndPara(/*bSelect=*/true); + rtl::Reference pTransfer = new SwTransferable(*pWrtShell); + pTransfer->Cut(); + + // one shape is anchored in the middle, others at the start/end/at-para + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr); + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr); + CPPUNIT_ASSERT_EQUAL(size_t(3), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size()); + + pWrtShell->Up(false); + TransferableDataHelper aHelper(pTransfer); + SwTransferable::Paste(*pWrtShell, aHelper); + + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() != nullptr); + CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs()->size()); + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr); + CPPUNIT_ASSERT_EQUAL(size_t(3), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size()); + + pWrtShell->Undo(); + pWrtShell->Undo(); + + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr); + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr); + CPPUNIT_ASSERT_EQUAL(size_t(4), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size()); + } + + // now try the same with redlining enabled - should be the same result + dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {}); + dispatchCommand(mxComponent, ".uno:TrackChanges", {}); + { + pWrtShell->Down(false); + pWrtShell->SttPara(/*bSelect=*/false); + pWrtShell->EndPara(/*bSelect=*/true); + rtl::Reference pTransfer = new SwTransferable(*pWrtShell); + pTransfer->Cut(); + + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr); + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr); + // problem was that this deleted all at-char flys, even at the start/end + CPPUNIT_ASSERT_EQUAL(size_t(3), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size()); + + pWrtShell->Up(false); + TransferableDataHelper aHelper(pTransfer); + SwTransferable::Paste(*pWrtShell, aHelper); + + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() != nullptr); + CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs()->size()); + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr); + CPPUNIT_ASSERT_EQUAL(size_t(3), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size()); + + pWrtShell->Undo(); + pWrtShell->Undo(); + + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr); + CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr); + CPPUNIT_ASSERT_EQUAL(size_t(4), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size()); + } +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testBookmarkCopy) +{ + SwDoc * pDoc(createSwDoc()); + + // add text and bookmark + IDocumentMarkAccess & rIDMA(*pDoc->getIDocumentMarkAccess()); + IDocumentContentOperations & rIDCO(pDoc->getIDocumentContentOperations()); + SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1); + SwCursor aPaM(SwPosition(aIdx), nullptr); + rIDCO.InsertString(aPaM, "foo"); + rIDCO.SplitNode(*aPaM.GetPoint(), false); + rIDCO.InsertString(aPaM, "bar"); + aPaM.SetMark(); + aPaM.MovePara(GoCurrPara, fnParaStart); + rIDMA.makeMark(aPaM, "Mark", IDocumentMarkAccess::MarkType::BOOKMARK, + ::sw::mark::InsertMode::New); + aPaM.Exchange(); + aPaM.DeleteMark(); + rIDCO.SplitNode(*aPaM.GetPoint(), false); + rIDCO.InsertString(aPaM, "baz"); + + // copy range + rIDCO.SplitNode(*aPaM.GetPoint(), false); + SwPosition target(*aPaM.GetPoint()); + aPaM.Move(fnMoveBackward, GoInContent); + aPaM.SetMark(); + aPaM.SttEndDoc(true/*start*/); + aPaM.Move(fnMoveForward, GoInContent); // partially select 1st para + + rIDCO.CopyRange(aPaM, target, SwCopyFlags::CheckPosInFly); + + // check bookmark was copied to correct position + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), rIDMA.getBookmarksCount()); + for (auto it(rIDMA.getBookmarksBegin()); it != rIDMA.getBookmarksEnd(); ++it) + { + OUString markText(SwPaM((*it)->GetMarkPos(), (*it)->GetOtherMarkPos()).GetText()); + CPPUNIT_ASSERT_EQUAL(OUString("bar"), markText); + } + + // copy 2nd time, such that bCanMoveBack is false in CopyImpl + SwPaM aCopyPaM(*aPaM.GetMark(), *aPaM.GetPoint()); + aPaM.SttEndDoc(true/*start*/); + rIDCO.SplitNode(*aPaM.GetPoint(), false); + aPaM.SttEndDoc(true/*start*/); + + rIDCO.CopyRange(aCopyPaM, *aPaM.GetPoint(), SwCopyFlags::CheckPosInFly); + + // check bookmark was copied to correct position + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), rIDMA.getBookmarksCount()); + for (auto it(rIDMA.getBookmarksBegin()); it != rIDMA.getBookmarksEnd(); ++it) + { + OUString markText(SwPaM((*it)->GetMarkPos(), (*it)->GetOtherMarkPos()).GetText()); + CPPUNIT_ASSERT_EQUAL(OUString("bar"), markText); + } +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testInsertFileInInputFieldException) +{ + createSwDoc(); + uno::Reference const xTextDoc(mxComponent, uno::UNO_QUERY); + uno::Reference const xBody(xTextDoc->getText()); + uno::Reference const xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference const xCursor(xBody->createTextCursor()); + uno::Reference const xInsertable(xCursor, uno::UNO_QUERY); + uno::Reference const xContent( + xFactory->createInstance("com.sun.star.text.textfield.Input"), uno::UNO_QUERY); + xBody->insertTextContent(xCursor, xContent, false); + xCursor->goLeft(1, false); + // try to insert some random file + OUString const url(m_directories.getURLFromSrc(DATA_DIRECTORY) + "fdo75110.odt"); + // inserting even asserts in debug builds - document model goes invalid with input field split across 2 nodes + CPPUNIT_ASSERT_THROW(xInsertable->insertDocumentFromURL(url, {}), uno::RuntimeException); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf67238) +{ + //create a new writer document + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + //insert a 3X3 table in the newly created document + SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0); + const SwTable& rTable = pWrtShell->InsertTable(TableOpt, 3, 3); + //checking for the rows and columns + uno::Reference xTable(getParagraphOrTable(1), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable->getRows()->getCount()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable->getColumns()->getCount()); + //selecting the table + pWrtShell->StartOfSection(); + pWrtShell->SelTable(); + //making the table protected + pWrtShell->ProtectCells(); + //checking each cell's protection, it should be protected + CPPUNIT_ASSERT(((rTable.GetTableBox("A1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("A2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("A3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("B1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("B2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("B3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("C1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("C2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("C3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + //undo the changes, make cells [un]protected + rUndoManager.Undo(); + //checking each cell's protection, it should be [un]protected + CPPUNIT_ASSERT(!((rTable.GetTableBox("A1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("A2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("A3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("B1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("B2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("B3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("C1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("C2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("C3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + //redo the changes, make cells protected + rUndoManager.Redo(); + //checking each cell's protection, it should be protected + CPPUNIT_ASSERT(((rTable.GetTableBox("A1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("A2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("A3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("B1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("B2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("B3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("C1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("C2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("C3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + //moving the cursor to the starting of the document + pWrtShell->StartOfSection(); + //making the table [un]protected + pWrtShell->SelTable(); + pWrtShell->UnProtectCells(); + //checking each cell's protection, it should be [un]protected + CPPUNIT_ASSERT(!((rTable.GetTableBox("A1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("A2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("A3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("B1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("B2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("B3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("C1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("C2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("C3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + //undo the changes, make cells protected + rUndoManager.Undo(); + //checking each cell's protection, it should be protected + CPPUNIT_ASSERT(((rTable.GetTableBox("A1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("A2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("A3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("B1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("B2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("B3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("C1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("C2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(((rTable.GetTableBox("C3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + //redo the changes, make cells [un]protected + rUndoManager.Redo(); + //checking each cell's protection, it should be [un]protected + CPPUNIT_ASSERT(!((rTable.GetTableBox("A1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("A2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("A3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("B1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("B2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("B3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("C1"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("C2"))->GetFrameFormat()->GetProtect()).IsContentProtected()); + CPPUNIT_ASSERT(!((rTable.GetTableBox("C3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf147220) +{ + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + pWrtShell->Insert(u"él"); + + // hide and enable + dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {}); + dispatchCommand(mxComponent, ".uno:TrackChanges", {}); + CPPUNIT_ASSERT(pDoc->getIDocumentRedlineAccess().IsRedlineOn()); + CPPUNIT_ASSERT( + IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags())); + CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines()); + + pWrtShell->GoStartSentence(); + pWrtShell->SetMark(); + pWrtShell->GoEndSentence(); + + // this did not remove the original text from the layout + pWrtShell->Replace(u"Él", false); + + // currently the deleted text is before the replacement text, not sure if + // that is really required + CPPUNIT_ASSERT_EQUAL(OUString(u"élÉl"), + pWrtShell->GetCursor()->GetPoint()->nNode.GetNode().GetTextNode()->GetText()); + CPPUNIT_ASSERT_EQUAL(OUString(u"Él"), + static_cast(pWrtShell->GetCursor()->GetPoint()->nNode.GetNode().GetTextNode()->getLayoutFrame(nullptr))->GetText()); + + SwRedlineTable const& rRedlines(pDoc->getIDocumentRedlineAccess().GetRedlineTable()); + CPPUNIT_ASSERT_EQUAL(SwRedlineTable::size_type(2), rRedlines.size()); + CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlines[0]->GetType()); + CPPUNIT_ASSERT_EQUAL(OUString(u"él"), rRedlines[0]->GetText()); + CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rRedlines[1]->GetType()); + CPPUNIT_ASSERT_EQUAL(OUString(u"Él"), rRedlines[1]->GetText()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf135978) +{ + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + pWrtShell->Insert("foobar"); + pWrtShell->SplitNode(); + pWrtShell->Insert("bazquux"); + + CPPUNIT_ASSERT(pWrtShell->IsEndOfDoc()); + + SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR); + anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint()); + SfxItemSet flySet(pDoc->GetAttrPool(), svl::Items); + flySet.Put(anchor); + SwFlyFrameFormat const* pFly = dynamic_cast( + pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true)); + CPPUNIT_ASSERT(pFly != nullptr); + CPPUNIT_ASSERT(pFly->GetFrame() != nullptr); + // move cursor back to body + pWrtShell->SttEndDoc(/*bStt=*/false); + + // hide and enable + dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {}); + dispatchCommand(mxComponent, ".uno:TrackChanges", {}); + + CPPUNIT_ASSERT(pDoc->getIDocumentRedlineAccess().IsRedlineOn()); + CPPUNIT_ASSERT( + IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags())); + CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines()); + + pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 4, /*bBasicCall=*/false); + pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 6, /*bBasicCall=*/false); + pWrtShell->Delete(); + + // now split + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->SplitNode(); + CPPUNIT_ASSERT(pFly->GetFrame() != nullptr); + + // the problem was that undo removed the fly frame from the layout + pWrtShell->Undo(); + CPPUNIT_ASSERT(pFly->GetFrame() != nullptr); + + pWrtShell->Redo(); + CPPUNIT_ASSERT(pFly->GetFrame() != nullptr); + + pWrtShell->Undo(); + CPPUNIT_ASSERT(pFly->GetFrame() != nullptr); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo75110) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "fdo75110.odt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + pWrtShell->SelAll(); + // The problem was that SwEditShell::DeleteSel() what this Delete() invokes took the wrong selection... + pWrtShell->Delete(); + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + // ... so this Undo() call resulted in a crash. + rUndoManager.Undo(); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo75898) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "fdo75898.odt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->SelAll(); + pWrtShell->InsertRow(1, true); + pWrtShell->InsertRow(1, true); + + // Now check if the table has 3 lines. + SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false); + SwTableNode* pTableNode = pShellCursor->Start()->nNode.GetNode().FindTableNode(); + // This was 1, when doing the same using the UI, Writer even crashed. + CPPUNIT_ASSERT_EQUAL(static_cast(3), pTableNode->GetTable().GetTabLines().size()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testReplaceBackward) +{ + //Regression test of fdo#70143 + //EDITING: undo search&replace corrupt text when searching backward + SwDoc* pDoc = createSwDoc(); + + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + + SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1); + SwPaM aPaM(aIdx); + + pDoc->getIDocumentContentOperations().InsertString(aPaM, "toto titi tutu"); + SwTextNode* pTextNode = aPaM.GetNode().GetTextNode(); + lcl_selectCharacters(aPaM, 9, 5); + + pDoc->getIDocumentContentOperations().ReplaceRange(aPaM, "toto", false); + + CPPUNIT_ASSERT_EQUAL(OUString(EXPECTED_REPLACE_CONTENT), pTextNode->GetText()); + + rUndoManager.Undo(); + + CPPUNIT_ASSERT_EQUAL(OUString(ORIGINAL_REPLACE_CONTENT), pTextNode->GetText()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo69893) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "fdo69893.odt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + pWrtShell->SelAll(); // A1 is empty -> selects the whole table. + pWrtShell->SelAll(); // Selects the whole document. + + SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false); + SwTextNode& rEnd = dynamic_cast(pShellCursor->End()->nNode.GetNode()); + // Selection did not include the para after table, this was "B1". + CPPUNIT_ASSERT_EQUAL(OUString("Para after table."), rEnd.GetText()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo70807) +{ + createSwDoc(DATA_DIRECTORY, "fdo70807.odt"); + + uno::Reference xStylesIter(getStyles("PageStyles"), uno::UNO_QUERY); + + for (sal_Int32 i = 0; i < xStylesIter->getCount(); ++i) + { + uno::Reference xStyle(xStylesIter->getByIndex(i), uno::UNO_QUERY); + + bool expectedUsedStyle = false; + bool expectedUserDefined = false; + + OUString styleName(xStyle->getName()); + + // just these styles are user defined styles + if (styleName == "pagestyle1" || styleName == "pagestyle2") + expectedUserDefined = true; + + // just these styles are used in the document + if (styleName == "Right Page" || styleName == "pagestyle1" || styleName == "pagestyle2") + expectedUsedStyle = true; + + CPPUNIT_ASSERT_EQUAL(expectedUserDefined, bool(xStyle->isUserDefined())); + CPPUNIT_ASSERT_EQUAL(expectedUsedStyle, bool(xStyle->isInUse())); + } +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testImportRTF) +{ + // Insert "foobar" and position the cursor between "foo" and "bar". + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert("foobar"); + pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 3, /*bBasicCall=*/false); + + // Insert the RTF at the cursor position. + OString aData = "{\\rtf1 Hello world!\\par}"; + SvMemoryStream aStream(const_cast(aData.getStr()), aData.getLength(), StreamMode::READ); + SwReader aReader(aStream, OUString(), OUString(), *pWrtShell->GetCursor()); + Reader* pRTFReader = SwReaderWriter::GetRtfReader(); + CPPUNIT_ASSERT(pRTFReader != nullptr); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, aReader.Read(*pRTFReader)); + + SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex(); + CPPUNIT_ASSERT_EQUAL(OUString("fooHello world!"), pDoc->GetNodes()[nIndex - 1]->GetTextNode()->GetText()); + CPPUNIT_ASSERT_EQUAL(OUString("bar"), pDoc->GetNodes()[nIndex]->GetTextNode()->GetText()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testExportRTF) +{ + // Insert "aaabbbccc" and select "bbb". + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert("aaabbbccc"); + pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 3, /*bBasicCall=*/false); + pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 3, /*bBasicCall=*/false); + + // Create the clipboard document. + rtl::Reference xClpDoc(new SwDoc()); + xClpDoc->SetClipBoard(true); + pWrtShell->Copy(*xClpDoc); + + // And finally export it as RTF. + WriterRef xWrt; + SwReaderWriter::GetWriter(u"RTF", OUString(), xWrt); + SvMemoryStream aStream; + SwWriter aWrt(aStream, *xClpDoc); + aWrt.Write(xWrt); + + OString aData(static_cast(aStream.GetData()), aStream.GetSize()); + + //Amusingly eventually there was a commit id with "ccc" in it, and so the rtf contained + //{\*\generator LibreOfficeDev/4.4.0.0.alpha0$Linux_X86_64 LibreOffice_project/f70664ccc6837f2cc21a29bb4f44e41e100efe6b} + //so the test fell over. so strip the generator tag + sal_Int32 nGeneratorStart = aData.indexOf("{\\*\\generator "); + CPPUNIT_ASSERT(nGeneratorStart != -1); + sal_Int32 nGeneratorEnd = aData.indexOf('}', nGeneratorStart + 1); + CPPUNIT_ASSERT(nGeneratorEnd != -1); + aData = aData.replaceAt(nGeneratorStart, nGeneratorEnd-nGeneratorStart+1, ""); + + CPPUNIT_ASSERT(aData.startsWith("{\\rtf1")); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), aData.indexOf("aaa")); + CPPUNIT_ASSERT(aData.indexOf("bbb") != -1); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), aData.indexOf("ccc")); + // Ensure there's no extra newline + CPPUNIT_ASSERT(aData.endsWith("bbb}" SAL_NEWLINE_STRING "}")); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDOCXAutoTextEmpty) +{ + // file contains normal content but no AutoText + std::unique_ptr pGlossary = readDOCXAutotext(u"autotext-empty.dotx", true); + CPPUNIT_ASSERT(pGlossary != nullptr); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDOCXAutoTextMultiple) +{ + // file contains three AutoText entries + std::unique_ptr pGlossary = readDOCXAutotext(u"autotext-multiple.dotx"); + + // check entries count + CPPUNIT_ASSERT_EQUAL(sal_uInt16(3), pGlossary->GetCount()); + + // check names of entries, sorted order + CPPUNIT_ASSERT_EQUAL(OUString("Anothercomplex"), pGlossary->GetLongName(0)); + CPPUNIT_ASSERT_EQUAL(OUString("Multiple"), pGlossary->GetLongName(1)); + CPPUNIT_ASSERT_EQUAL(OUString("Second Autotext"), pGlossary->GetLongName(2)); + + // check if previously loaded content is correct (eg. doesn't contain title) + SwDoc* pDoc = pGlossary->GetDoc(); + CPPUNIT_ASSERT(pDoc != nullptr); + + SwNodeIndex aDocEnd(pDoc->GetNodes().GetEndOfContent()); + SwNodeIndex aStart(*aDocEnd.GetNode().StartOfSectionNode(), 1); + + CPPUNIT_ASSERT(aStart < aDocEnd); + + // first line + SwNode& rNode = aStart.GetNode(); + CPPUNIT_ASSERT(rNode.IsTextNode()); + SwTextNode& rTextNode = *rNode.GetTextNode(); + CPPUNIT_ASSERT_EQUAL(OUString("Another "), rTextNode.GetText()); + + // Make sure that autotext does not set a custom page style, leading to an unexpected page break + // on insertion. + // Without the accompanying fix in place, this test would have failed: the text node had an + // attribute set containing a page style item. + CPPUNIT_ASSERT(!rTextNode.HasSwAttrSet() || !rTextNode.GetSwAttrSet().HasItem(RES_PAGEDESC)); + + // last line + SwNodeIndex aLast(*aDocEnd.GetNode().EndOfSectionNode(), -1); + SwNode& rLastNode = aLast.GetNode(); + CPPUNIT_ASSERT_EQUAL(OUString("complex"), rLastNode.GetTextNode()->GetText()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDOTMAutoText) +{ + // this is dotm file difference is that in the dotm + // there are no empty paragraphs at the end of each entry + std::unique_ptr pGlossary = readDOCXAutotext(u"autotext-dotm.dotm"); + + SwDoc* pDoc = pGlossary->GetDoc(); + CPPUNIT_ASSERT(pDoc != nullptr); + + // check if content is correct + SwNodeIndex aDocEnd(pDoc->GetNodes().GetEndOfContent()); + SwNodeIndex aStart(*aDocEnd.GetNode().StartOfSectionNode(), 1); + SwNode& rNode = aStart.GetNode(); + CPPUNIT_ASSERT_EQUAL(OUString("paragraph"), rNode.GetTextNode()->GetText()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDOCXAutoTextGallery) +{ + // this file contains one AutoText entry and other + // entries which are not AutoText (have different "gallery" value) + std::unique_ptr pGlossary = readDOCXAutotext(u"autotext-gallery.dotx"); + + SwDoc* pDoc = pGlossary->GetDoc(); + CPPUNIT_ASSERT(pDoc != nullptr); + + // check entries count + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pGlossary->GetCount()); + + // check entry name (if not contains gallery type) + CPPUNIT_ASSERT_EQUAL(OUString("Multiple"), pGlossary->GetLongName(0)); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testWatermarkDOCX) +{ + SwDoc* const pDoc = createSwDoc(DATA_DIRECTORY, "watermark.docx"); + SwDocShell* pDocShell = pDoc->GetDocShell(); + const SfxWatermarkItem* pWatermark; + SfxItemState eState = pDocShell->GetViewShell()->GetViewFrame()->GetDispatcher()->QueryState(SID_WATERMARK, pWatermark); + + CPPUNIT_ASSERT(eState >= SfxItemState::DEFAULT); + CPPUNIT_ASSERT(pWatermark); + CPPUNIT_ASSERT_EQUAL(static_cast(SID_WATERMARK), pWatermark->Which()); + + CPPUNIT_ASSERT_EQUAL(OUString("CustomWatermark"), pWatermark->GetText()); + CPPUNIT_ASSERT_EQUAL(OUString("DejaVu Sans Light"), pWatermark->GetFont()); + CPPUNIT_ASSERT_EQUAL(sal_Int16(45), pWatermark->GetAngle()); + CPPUNIT_ASSERT_EQUAL(Color(0x548dd4), pWatermark->GetColor()); + CPPUNIT_ASSERT_EQUAL(sal_Int16(50), pWatermark->GetTransparency()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testWatermarkPosition) +{ + // tdf#108494 Watermark inserted in the document with page break was outside the first page + const int aPagesInDocument = 2; + const int aAdditionalPagesCount[] = { 0, 0, 1, 1, 5, 5, 20, 20 }; + const bool aChangeHeader[] = { true, false, true, false, true, false, true, false }; + + for (tools::ULong i = 0; i < sizeof(aAdditionalPagesCount) / sizeof(int); ++i) + { + int aPages = aPagesInDocument + aAdditionalPagesCount[i]; + + // Empty document with one Page Break + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "watermark-position.odt"); + SwEditShell* pEditShell = pDoc->GetEditShell(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + uno::Reference xModel = pDoc->GetDocShell()->GetBaseModel(); + uno::Reference xStyleFamiliesSupplier(xModel, uno::UNO_QUERY); + uno::Reference xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies(); + uno::Reference xStyleFamily(xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY); + uno::Reference xPageStyle(xStyleFamily->getByName("Default Page Style"), uno::UNO_QUERY); + + // 1. Add additional page breaks + for (int j = 0; j < aAdditionalPagesCount[i]; ++j) + pWrtShell->InsertPageBreak(); + + // 2. Change header state (On, Off, On) + if (aChangeHeader[i]) + { + SwPageDesc aDesc(pDoc->GetPageDesc(0)); + SwFrameFormat& rMaster = aDesc.GetMaster(); + rMaster.SetFormatAttr(SwFormatHeader(true)); + pDoc->ChgPageDesc(0, aDesc); + + aDesc = pDoc->GetPageDesc(0); + SwFrameFormat& rMaster2 = aDesc.GetMaster(); + rMaster2.SetFormatAttr(SwFormatHeader(false)); + pDoc->ChgPageDesc(0, aDesc); + + aDesc = pDoc->GetPageDesc(0); + SwFrameFormat& rMaster3 = aDesc.GetMaster(); + rMaster3.SetFormatAttr(SwFormatHeader(true)); + pDoc->ChgPageDesc(0, aDesc); + } + + // 3. Insert Watermark + SfxWatermarkItem aWatermark; + aWatermark.SetText("Watermark"); + aWatermark.SetFont("DejaVu Sans"); + + pEditShell->SetWatermark(aWatermark); + + uno::Reference xShape = getShape(1); + CPPUNIT_ASSERT(xShape.is()); + + SdrPage* pPage = pWrtShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0); + + // Get Watermark object + SdrObject* pObject = pPage->GetObj(0); + pObject->RecalcBoundRect(); + const tools::Rectangle& rRect = pObject->GetSnapRect(); + Size rSize = pPage->GetSize(); + + // Page break, calculate height of a page + const int nPageHeight = rSize.getHeight() / aPages; + + std::stringstream aMessage; + aMessage << "Case: " << i << ", nPageHeight = " << nPageHeight << ", rRect.Bottom = " << rRect.Bottom(); + + // Check if Watermark is inside a page + CPPUNIT_ASSERT_MESSAGE(aMessage.str(), nPageHeight >= rRect.Bottom()); + + // Check if Watermark is centered + CPPUNIT_ASSERT_EQUAL(text::HoriOrientation::CENTER, getProperty(xShape, "HoriOrient")); + CPPUNIT_ASSERT_EQUAL(text::VertOrientation::CENTER, getProperty(xShape, "VertOrient")); + } +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo74981) +{ + // create a document with an input field + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SwInputField aField(static_cast(pWrtShell->GetFieldType(0, SwFieldIds::Input)), "foo", "bar", 0, 0); + pWrtShell->InsertField2(aField); + + { + // expect hints + SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1); + SwTextNode* pTextNode = aIdx.GetNode().GetTextNode(); + CPPUNIT_ASSERT(pTextNode->HasHints()); + } + + // go to the begin of the paragraph and split this node + pWrtShell->Left(CRSR_SKIP_CHARS, false, 100, false); + pWrtShell->SplitNode(); + + { + // expect only the second paragraph to have hints + SwNodeIndex aIdx(SwNodeIndex(pDoc->GetNodes().GetEndOfContent(), -1)); + SwTextNode* pTextNode = aIdx.GetNode().GetTextNode(); + CPPUNIT_ASSERT(pTextNode->HasHints()); + --aIdx; + pTextNode = aIdx.GetNode().GetTextNode(); + CPPUNIT_ASSERT(!pTextNode->HasHints()); + } +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf98512) +{ + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SwInputFieldType *const pType(static_cast( + pWrtShell->GetFieldType(0, SwFieldIds::Input))); + SwInputField aField1(pType, "foo", "bar", INP_TXT, 0); + pWrtShell->InsertField2(aField1); + pWrtShell->SttEndDoc(/*bStt=*/true); + SwInputField aField2(pType, "baz", "quux", INP_TXT, 0); + pWrtShell->InsertField2(aField2); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->SetMark(); + pWrtShell->SttEndDoc(/*bStt=*/false); + OUString const expected1( + OUStringChar(CH_TXT_ATR_INPUTFIELDSTART) + "foo" + OUStringChar(CH_TXT_ATR_INPUTFIELDEND)); + OUString const expected2( + OUStringChar(CH_TXT_ATR_INPUTFIELDSTART) + "baz" + OUStringChar(CH_TXT_ATR_INPUTFIELDEND) + + expected1); + CPPUNIT_ASSERT_EQUAL(expected2, pWrtShell->getShellCursor(false)->GetText()); + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + rUndoManager.Undo(); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->SetMark(); + pWrtShell->SttEndDoc(/*bStt=*/false); + CPPUNIT_ASSERT_EQUAL(expected1, pWrtShell->getShellCursor(false)->GetText()); + rUndoManager.Redo(); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->SetMark(); + pWrtShell->SttEndDoc(/*bStt=*/false); + CPPUNIT_ASSERT_EQUAL(expected2, pWrtShell->getShellCursor(false)->GetText()); + rUndoManager.Undo(); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->SetMark(); + pWrtShell->SttEndDoc(/*bStt=*/false); + CPPUNIT_ASSERT_EQUAL(expected1, pWrtShell->getShellCursor(false)->GetText()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testShapeTextboxSelect) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "shape-textbox.odt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0); + SdrObject* pObject = pPage->GetObj(1); + SwContact* pTextBox = static_cast(pObject->GetUserCall()); + // First, make sure that pTextBox is a fly frame (textbox of a shape). + CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_FLYFRMFMT), pTextBox->GetFormat()->Which()); + + // Then select it. + pWrtShell->SelectObj(Point(), 0, pObject); + const SdrMarkList& rMarkList = pWrtShell->GetDrawView()->GetMarkedObjectList(); + SwDrawContact* pShape = static_cast(rMarkList.GetMark(0)->GetMarkedSdrObj()->GetUserCall()); + // And finally make sure the shape got selected, not just the textbox itself. + CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_DRAWFRMFMT), pShape->GetFormat()->Which()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testShapeTextboxDelete) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "shape-textbox.odt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0); + SdrObject* pObject = pPage->GetObj(0); + pWrtShell->SelectObj(Point(), 0, pObject); + size_t nActual = pPage->GetObjCount(); + // Two objects on the draw page: the shape and its textbox. + CPPUNIT_ASSERT_EQUAL(static_cast(2), nActual); + + pWrtShell->DelSelectedObj(); + nActual = pPage->GetObjCount(); + // Both (not only the shape) should be removed by now (the textbox wasn't removed, so this was 1). + CPPUNIT_ASSERT_EQUAL(static_cast(0), nActual); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testAnchorChangeSelection) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "test_anchor_as_character.odt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0); + SdrObject* pObject = pPage->GetObj(0); + CPPUNIT_ASSERT(pObject); + + // Then select it. + pWrtShell->SelectObj(Point(), 0, pObject); + const SdrMarkList& rMarkList = pWrtShell->GetDrawView()->GetMarkedObjectList(); + CPPUNIT_ASSERT_EQUAL(pObject, rMarkList.GetMark(0)->GetMarkedSdrObj()); + + pWrtShell->ChgAnchor(RndStdIds::FLY_AS_CHAR); + + // tdf#125039 shape must still be selected, extensions depend on that + CPPUNIT_ASSERT_EQUAL(pObject, rMarkList.GetMark(0)->GetMarkedSdrObj()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testCp1000071) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "cp1000071.odt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + const SwRedlineTable& rTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable(); + CPPUNIT_ASSERT_EQUAL( SwRedlineTable::size_type( 2 ), rTable.size()); + SwNodeOffset redlineStart0NodeIndex = rTable[ 0 ]->Start()->nNode.GetIndex(); + sal_Int32 redlineStart0Index = rTable[ 0 ]->Start()->nContent.GetIndex(); + SwNodeOffset redlineEnd0NodeIndex = rTable[ 0 ]->End()->nNode.GetIndex(); + sal_Int32 redlineEnd0Index = rTable[ 0 ]->End()->nContent.GetIndex(); + SwNodeOffset redlineStart1NodeIndex = rTable[ 1 ]->Start()->nNode.GetIndex(); + sal_Int32 redlineStart1Index = rTable[ 1 ]->Start()->nContent.GetIndex(); + SwNodeOffset redlineEnd1NodeIndex = rTable[ 1 ]->End()->nNode.GetIndex(); + sal_Int32 redlineEnd1Index = rTable[ 1 ]->End()->nContent.GetIndex(); + + // Change the document layout to be 2 columns, and then undo. + pWrtShell->SelAll(); + SwSectionData section(SectionType::Content, pWrtShell->GetUniqueSectionName()); + SfxItemSet set( pDoc->GetDocShell()->GetPool(), svl::Items ); + SwFormatCol col; + col.Init( 2, 0, 10000 ); + set.Put( col ); + pWrtShell->InsertSection( section, &set ); + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + rUndoManager.Undo(); + + // Check that redlines are the same like at the beginning. + CPPUNIT_ASSERT_EQUAL( SwRedlineTable::size_type( 2 ), rTable.size()); + CPPUNIT_ASSERT_EQUAL( redlineStart0NodeIndex, rTable[ 0 ]->Start()->nNode.GetIndex()); + CPPUNIT_ASSERT_EQUAL( redlineStart0Index, rTable[ 0 ]->Start()->nContent.GetIndex()); + CPPUNIT_ASSERT_EQUAL( redlineEnd0NodeIndex, rTable[ 0 ]->End()->nNode.GetIndex()); + CPPUNIT_ASSERT_EQUAL( redlineEnd0Index, rTable[ 0 ]->End()->nContent.GetIndex()); + CPPUNIT_ASSERT_EQUAL( redlineStart1NodeIndex, rTable[ 1 ]->Start()->nNode.GetIndex()); + CPPUNIT_ASSERT_EQUAL( redlineStart1Index, rTable[ 1 ]->Start()->nContent.GetIndex()); + CPPUNIT_ASSERT_EQUAL( redlineEnd1NodeIndex, rTable[ 1 ]->End()->nNode.GetIndex()); + CPPUNIT_ASSERT_EQUAL( redlineEnd1Index, rTable[ 1 ]->End()->nContent.GetIndex()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testShapeTextboxVertadjust) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "shape-textbox-vertadjust.odt"); + SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0); + SdrObject* pObject = pPage->GetObj(1); + SwFrameFormat* pFormat = static_cast(pObject->GetUserCall())->GetFormat(); + // This was SDRTEXTVERTADJUST_TOP. + CPPUNIT_ASSERT_EQUAL(SDRTEXTVERTADJUST_CENTER, pFormat->GetTextVertAdjust().GetValue()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testShapeTextboxAutosize) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "shape-textbox-autosize.odt"); + SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0); + // 0-1 is the first UI-visible shape+textbox. + SdrObject* pFirst = pPage->GetObj(0); + CPPUNIT_ASSERT_EQUAL(OUString("1st"), pFirst->GetName()); + + // 2-3 is the second UI-visible shape+textbox. + SdrObject* pSecond = pPage->GetObj(2); + CPPUNIT_ASSERT_EQUAL(OUString("2nd"), pSecond->GetName()); + + // Shape -> textbox synchronization was missing, the second shape had the + // same height as the first, even though the first contained 1 paragraph + // and the other 2 ones. + CPPUNIT_ASSERT(pFirst->GetSnapRect().getHeight() < pSecond->GetSnapRect().getHeight()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo82191) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "fdo82191.odt"); + SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0); + // Make sure we have a single draw shape. + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), SwTextBoxHelper::getCount(pPage)); + + SwDoc aClipboard; + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SdrObject* pObject = pPage->GetObj(0); + // Select it, then copy and paste. + pWrtShell->SelectObj(Point(), 0, pObject); + pWrtShell->Copy(aClipboard); + pWrtShell->Paste(aClipboard); + + // This was one: the textbox of the shape wasn't copied. + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), SwTextBoxHelper::getCount(*pDoc)); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testCommentedWord) +{ + // This word is commented. <- string in document + // 123456789 <- character positions + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "commented-word.odt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + // Move the cursor into the second word. + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 5, /*bBasicCall=*/false); + // Select the word. + pWrtShell->SelWrd(); + + // Make sure that not only the word, but its comment anchor is also selected. + SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false); + // This was 9, only "word", not "word" was selected. + CPPUNIT_ASSERT_EQUAL(sal_Int32(10), pShellCursor->End()->nContent.GetIndex()); + + // Test that getAnchor() points to "word", not to an empty string. + uno::Reference xTextFieldsSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xFieldsAccess(xTextFieldsSupplier->getTextFields()); + uno::Reference xFields(xFieldsAccess->createEnumeration()); + uno::Reference xField(xFields->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("word"), xField->getAnchor()->getString()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTextFieldGetAnchorGetTextInFooter) +{ + createSwDoc(DATA_DIRECTORY, "textfield-getanchor-gettext-in-footer.odt"); + + uno::Reference xTextFieldsSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xFieldsAccess(xTextFieldsSupplier->getTextFields()); + uno::Reference xFields(xFieldsAccess->createEnumeration()); + uno::Reference xField(xFields->nextElement(), uno::UNO_QUERY); + + OUString value = xField->getAnchor()->getText()->getString(); + CPPUNIT_ASSERT_EQUAL(OUString("userfield_in_footer"), value ); +} + +// Tests that a blank document is still blank after conversion +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testChineseConversionBlank) +{ + + // Given + SwDoc* pDoc = createSwDoc(); + SwView* pView = pDoc->GetDocShell()->GetView(); + const uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); + SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1); + SwPaM aPaM(aIdx); + + // When + SwHHCWrapper aWrap( pView, xContext, LANGUAGE_CHINESE_TRADITIONAL, LANGUAGE_CHINESE_SIMPLIFIED, nullptr, + i18n::TextConversionOption::CHARACTER_BY_CHARACTER, false, + true, false, false ); + aWrap.Convert(); + + // Then + SwTextNode* pTextNode = aPaM.GetNode().GetTextNode(); + CPPUNIT_ASSERT_EQUAL(OUString(), pTextNode->GetText()); + +} + +// Tests that non Chinese text is unchanged after conversion +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testChineseConversionNonChineseText) +{ + + // Given + SwDoc* pDoc = createSwDoc(); + SwView* pView = pDoc->GetDocShell()->GetView(); + const uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); + SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1); + SwPaM aPaM(aIdx); + pDoc->getIDocumentContentOperations().InsertString(aPaM, NON_CHINESE_CONTENT); + + // When + SwHHCWrapper aWrap( pView, xContext, LANGUAGE_CHINESE_TRADITIONAL, LANGUAGE_CHINESE_SIMPLIFIED, nullptr, + i18n::TextConversionOption::CHARACTER_BY_CHARACTER, false, + true, false, false ); + aWrap.Convert(); + + // Then + SwTextNode* pTextNode = aPaM.GetNode().GetTextNode(); + CPPUNIT_ASSERT_EQUAL(OUString(NON_CHINESE_CONTENT), pTextNode->GetText()); + +} + +// Tests conversion of traditional Chinese characters to simplified Chinese +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testChineseConversionTraditionalToSimplified) +{ + + // Given + SwDoc* pDoc = createSwDoc(); + SwView* pView = pDoc->GetDocShell()->GetView(); + const uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); + SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1); + SwPaM aPaM(aIdx); + pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(CHINESE_TRADITIONAL_CONTENT)); + + // When + SwHHCWrapper aWrap( pView, xContext, LANGUAGE_CHINESE_TRADITIONAL, LANGUAGE_CHINESE_SIMPLIFIED, nullptr, + i18n::TextConversionOption::CHARACTER_BY_CHARACTER, false, + true, false, false ); + aWrap.Convert(); + + // Then + SwTextNode* pTextNode = aPaM.GetNode().GetTextNode(); + CPPUNIT_ASSERT_EQUAL(OUString(CHINESE_SIMPLIFIED_CONTENT), pTextNode->GetText()); + +} + +// Tests conversion of simplified Chinese characters to traditional Chinese +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testChineseConversionSimplifiedToTraditional) +{ + + // Given + SwDoc* pDoc = createSwDoc(); + SwView* pView = pDoc->GetDocShell()->GetView(); + const uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); + SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1); + SwPaM aPaM(aIdx); + pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(CHINESE_SIMPLIFIED_CONTENT)); + + // When + SwHHCWrapper aWrap( pView, xContext, LANGUAGE_CHINESE_SIMPLIFIED, LANGUAGE_CHINESE_TRADITIONAL, nullptr, + i18n::TextConversionOption::CHARACTER_BY_CHARACTER, false, + true, false, false ); + aWrap.Convert(); + + // Then + SwTextNode* pTextNode = aPaM.GetNode().GetTextNode(); + CPPUNIT_ASSERT_EQUAL(OUString(CHINESE_TRADITIONAL_CONTENT), pTextNode->GetText()); + +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo85554) +{ + // Load the document, it contains one shape with a textbox. + createSwDoc(DATA_DIRECTORY, "fdo85554.odt"); + + // Add a second shape to the document. + uno::Reference xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference xShape(xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setSize(awt::Size(10000, 10000)); + xShape->setPosition(awt::Point(1000, 1000)); + uno::Reference xDrawPageSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); + xDrawPage->add(xShape); + + // Save it and load it back. + reload("writer8", "fdo85554.odt"); + + // This was 1, we lost a shape on export. + CPPUNIT_ASSERT_EQUAL(2, getShapes()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testMergeDoc) +{ + SwDoc* const pDoc1(createSwDoc(DATA_DIRECTORY, "merge-change1.odt")); + + auto xDoc2Component(loadFromDesktop( + m_directories.getURLFromSrc(DATA_DIRECTORY) + "merge-change2.odt", + "com.sun.star.text.TextDocument")); + auto pxDoc2Document( + dynamic_cast(xDoc2Component.get())); + CPPUNIT_ASSERT(pxDoc2Document); + SwDoc* const pDoc2(pxDoc2Document->GetDocShell()->GetDoc()); + + SwEditShell* const pEditShell(pDoc1->GetEditShell()); + pEditShell->MergeDoc(*pDoc2); + + // accept all redlines + while(pEditShell->GetRedlineCount()) + pEditShell->AcceptRedline(0); + + CPPUNIT_ASSERT_EQUAL(7, getParagraphs()); + getParagraph(1, "Para One: Two Three Four Five"); + getParagraph(2, "Para Two: One Three Four Five"); + getParagraph(3, "Para Three: One Two Four Five"); + getParagraph(4, "Para Four: One Two Three Four Five"); + getParagraph(5, "Para Six: One Three Four Five"); + getParagraph(6, ""); + getParagraph(7, ""); + + xDoc2Component->dispose(); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testCreatePortions) +{ + createSwDoc(DATA_DIRECTORY, "uno-cycle.odt"); + uno::Reference xBookmarksSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xText(xBookmarksSupplier->getBookmarks()->getByName("Mark"), uno::UNO_QUERY); + uno::Reference xTextCursor(xText->getAnchor(), uno::UNO_QUERY); + CPPUNIT_ASSERT(xTextCursor.is()); + + uno::Reference xParagraph( + xTextCursor->createEnumeration()->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT(xParagraph.is()); + // This looped forever in lcl_CreatePortions + xParagraph->createEnumeration(); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testBookmarkUndo) +{ + SwDoc* pDoc = createSwDoc(); + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + SwPaM aPaM( SwNodeIndex(pDoc->GetNodes().GetEndOfContent(), -1) ); + + pMarkAccess->makeMark(aPaM, "Mark", IDocumentMarkAccess::MarkType::BOOKMARK, + ::sw::mark::InsertMode::New); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + rUndoManager.Undo(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + rUndoManager.Redo(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + + IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findMark("Mark"); + CPPUNIT_ASSERT(ppBkmk != pMarkAccess->getAllMarksEnd()); + + pMarkAccess->renameMark(*ppBkmk, "Mark_"); + CPPUNIT_ASSERT(bool(pMarkAccess->findMark("Mark") == pMarkAccess->getAllMarksEnd())); + CPPUNIT_ASSERT(pMarkAccess->findMark("Mark_") != pMarkAccess->getAllMarksEnd()); + rUndoManager.Undo(); + CPPUNIT_ASSERT(pMarkAccess->findMark("Mark") != pMarkAccess->getAllMarksEnd()); + CPPUNIT_ASSERT(bool(pMarkAccess->findMark("Mark_") == pMarkAccess->getAllMarksEnd())); + rUndoManager.Redo(); + CPPUNIT_ASSERT(bool(pMarkAccess->findMark("Mark") == pMarkAccess->getAllMarksEnd())); + CPPUNIT_ASSERT(pMarkAccess->findMark("Mark_") != pMarkAccess->getAllMarksEnd()); + + pMarkAccess->deleteMark(pMarkAccess->findMark("Mark_"), false); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + rUndoManager.Undo(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + rUndoManager.Redo(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); +} + +static void lcl_setWeight(SwWrtShell* pWrtShell, FontWeight aWeight) +{ + SvxWeightItem aWeightItem(aWeight, EE_CHAR_WEIGHT); + SvxScriptSetItem aScriptSetItem(SID_ATTR_CHAR_WEIGHT, pWrtShell->GetAttrPool()); + aScriptSetItem.PutItemForScriptType(SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX, aWeightItem); + pWrtShell->SetAttrSet(aScriptSetItem.GetItemSet()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo85876) +{ + SwDoc* const pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + lcl_setWeight(pWrtShell, WEIGHT_BOLD); + pWrtShell->Insert("test"); + lcl_setWeight(pWrtShell, WEIGHT_NORMAL); + pWrtShell->SplitNode(); + pWrtShell->SplitNode(); + pWrtShell->Up(false); + pWrtShell->Insert("test"); + auto xText = getParagraph(1)->getText(); + CPPUNIT_ASSERT(xText.is()); + { + auto xCursor(xText->createTextCursorByRange(getParagraph(1))); + CPPUNIT_ASSERT(xCursor.is()); + xCursor->collapseToStart(); + CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty(xCursor, "CharWeight")); + } + { + auto xCursor(xText->createTextCursorByRange(getParagraph(2))); + CPPUNIT_ASSERT(xCursor.is()); + xCursor->collapseToStart(); + // this used to be BOLD too with fdo#85876 + CPPUNIT_ASSERT_EQUAL(awt::FontWeight::NORMAL, getProperty(xCursor, "CharWeight")); + } +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testCaretPositionMovingUp) +{ + SwDoc* const pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert("after"); + pWrtShell->InsertLineBreak(); + pWrtShell->Up(false); + pWrtShell->Insert("before"); + + CPPUNIT_ASSERT_EQUAL(OUString(u"beforeAfter" + OUStringChar(CH_TXTATR_NEWLINE)), getParagraph(1)->getString()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf93441) +{ + SwDoc* const pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert("Hello"); + pWrtShell->InsertLineBreak(); + pWrtShell->Insert("Hello World"); + pWrtShell->Up(false); + pWrtShell->Insert(" World"); + + // Without the fix in place, this test would have failed with + // - Expected: Hello World\nHello World + // - Actual : WorldHello\nHello World + CPPUNIT_ASSERT_EQUAL(OUString(u"Hello World" + OUStringChar(CH_TXTATR_NEWLINE) + u"Hello World"), getParagraph(1)->getString()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf81226) +{ + SwDoc* const pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert("before"); + pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 4, /*bBasicCall=*/false); + pWrtShell->Down(false); + pWrtShell->Insert("after"); + + // Without the fix in place, this test would have failed with + // - Expected: beforeafter + // - Actual : beafterfore + CPPUNIT_ASSERT_EQUAL(OUString("beforeafter"), getParagraph(1)->getString()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf137532) +{ + SwDoc* const pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert("test"); + + //Select the word and change it to bold + pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 4, /*bBasicCall=*/false); + lcl_setWeight(pWrtShell, WEIGHT_BOLD); + + // Select first character and replace it + pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false); + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false); + pWrtShell->Insert("x"); + + auto xText = getParagraph(1)->getText(); + CPPUNIT_ASSERT(xText.is()); + auto xCursor(xText->createTextCursorByRange(getRun(getParagraph(1), 1))); + + CPPUNIT_ASSERT(xCursor.is()); + CPPUNIT_ASSERT_EQUAL(OUString("xest"), xCursor->getString()); + CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty(xCursor, "CharWeight")); + + dispatchCommand(mxComponent, ".uno:Undo", {}); + Scheduler::ProcessEventsToIdle(); + + xCursor.set(xText->createTextCursorByRange(getRun(getParagraph(1), 1))); + CPPUNIT_ASSERT(xCursor.is()); + CPPUNIT_ASSERT_EQUAL(OUString("test"), xCursor->getString()); + + // Without the fix in place, this test would have failed in + // - Expected: 150 + // - Actual : 100 + CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty(xCursor, "CharWeight")); + + dispatchCommand(mxComponent, ".uno:Undo", {}); + Scheduler::ProcessEventsToIdle(); + + xCursor.set(xText->createTextCursorByRange(getRun(getParagraph(1), 1))); + CPPUNIT_ASSERT(xCursor.is()); + CPPUNIT_ASSERT_EQUAL(OUString("test"), xCursor->getString()); + CPPUNIT_ASSERT_EQUAL(awt::FontWeight::NORMAL, getProperty(xCursor, "CharWeight")); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo87448) +{ + createSwDoc(DATA_DIRECTORY, "fdo87448.odt"); + + // Save the first shape to a metafile. + uno::Reference xGraphicExporter = drawing::GraphicExportFilter::create(comphelper::getProcessComponentContext()); + uno::Reference xSourceDoc(getShape(1), uno::UNO_QUERY); + xGraphicExporter->setSourceDocument(xSourceDoc); + + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + uno::Sequence aDescriptor( comphelper::InitPropertySequence({ + { "OutputStream", uno::Any(xOutputStream) }, + { "FilterName", uno::Any(OUString("SVM")) } + })); + xGraphicExporter->filter(aDescriptor); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Read it back and dump it as an XML file. + Graphic aGraphic; + TypeSerializer aSerializer(aStream); + aSerializer.readGraphic(aGraphic); + const GDIMetaFile& rMetaFile = aGraphic.GetGDIMetaFile(); + MetafileXmlDump dumper; + xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, rMetaFile); + + // The first polyline in the document has a number of points to draw arcs, + // the last one jumps back to the start, so we call "end" the last but one. + sal_Int32 nFirstEnd = getXPath(pXmlDoc, "(//polyline)[1]/point[last()-1]", "x").toInt32(); + // The second polyline has a different start point, but the arc it draws + // should end at the ~same position as the first polyline. + sal_Int32 nSecondEnd = getXPath(pXmlDoc, "(//polyline)[2]/point[last()]", "x").toInt32(); + + // nFirstEnd was 6023 and nSecondEnd was 6648, now they should be much closer, e.g. nFirstEnd = 6550, nSecondEnd = 6548 + OString aMsg = "nFirstEnd is " + OString::number(nFirstEnd) + ", nSecondEnd is " + OString::number(nSecondEnd); + // Assert that the difference is less than half point. + CPPUNIT_ASSERT_MESSAGE(aMsg.getStr(), abs(nFirstEnd - nSecondEnd) < 10); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTextCursorInvalidation) +{ + createSwDoc(); + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + uno::Reference xPageStyle(getStyles("PageStyles")->getByName("Standard"), uno::UNO_QUERY); + CPPUNIT_ASSERT(xPageStyle.is()); + xPageStyle->setPropertyValue("HeaderIsOn", uno::Any(true)); + uno::Reference xHeader(getProperty>(xPageStyle, "HeaderText")); + CPPUNIT_ASSERT(xHeader.is()); + // create cursor inside the header text + uno::Reference xCursor(xHeader->createTextCursor()); + // can't go right in empty header + CPPUNIT_ASSERT(!xCursor->goRight(1, false)); +// this does not actually delete the header: xPageStyle->setPropertyValue("HeaderIsOn", uno::makeAny(false)); + pWrtShell->ChangeHeaderOrFooter(u"Default Page Style", true, false, false); + // must be disposed after deleting header + // cursor ends up in body + // UPDATE: this behaviour has been corrected as a side effect of the fix to tdf#46561: + //CPPUNIT_ASSERT_THROW(xCursor->goRight(1, false), uno::RuntimeException); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf68183) +{ + // First disable RSID and check if indeed no such attribute is inserted. + SwDoc* pDoc = createSwDoc(); + SW_MOD()->GetModuleConfig()->SetStoreRsid(false); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert2("X"); + + SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1); + SwPaM aPaM(aIdx); + SwTextNode* pTextNode = aPaM.GetNode().GetTextNode(); + CPPUNIT_ASSERT_EQUAL(false, pTextNode->GetSwAttrSet().HasItem(RES_PARATR_RSID)); + + // Then enable storing of RSID and make sure that the attribute is inserted. + SW_MOD()->GetModuleConfig()->SetStoreRsid(true); + + pWrtShell->DelToStartOfLine(); + pWrtShell->Insert2("X"); + + CPPUNIT_ASSERT_EQUAL(true, pTextNode->GetSwAttrSet().HasItem(RES_PARATR_RSID)); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testCp1000115) +{ + createSwDoc(DATA_DIRECTORY, "cp1000115.fodt"); + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "/root/page[2]/body/tab/row/cell[2]/txt"); + xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval; + // This was 1: the long paragraph in the B1 cell did flow over to the + // second page, so there was only one paragraph in the second cell of the + // second page. + CPPUNIT_ASSERT_EQUAL(2, xmlXPathNodeSetGetLength(pXmlNodes)); + xmlXPathFreeObject(pXmlObj); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf63214) +{ + //This is a crash test + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + pWrtShell->Insert("V"); + { //limiting the lifetime of SwPaM with a nested scope + //the shell cursor are automatically adjusted when nodes are deleted, but the shell doesn't know about an SwPaM on the stack + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + SwPaM aPaM( SwNodeIndex(pDoc->GetNodes().GetEndOfContent(), -1) ); + aPaM.SetMark(); + aPaM.Move(fnMoveForward, GoInContent); + //Inserting a crossRefBookmark + pMarkAccess->makeMark(aPaM, "Bookmark", + IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK, + ::sw::mark::InsertMode::New); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + } + //moving cursor to the end of paragraph + pWrtShell->EndPara(); + //inserting paragraph break + pWrtShell->SplitNode(); + rUndoManager.Undo(); + rUndoManager.Redo(); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf90003) +{ + createSwDoc(DATA_DIRECTORY, "tdf90003.odt"); + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + CPPUNIT_ASSERT(pXmlDoc); + // This was 1: an unexpected fly portion was created, resulting in too + // large x position for the empty paragraph marker. + assertXPath(pXmlDoc, "//Special[@nType='PortionType::Fly']", 0); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf51741) +{ + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + SwPaM aPaM( SwNodeIndex(pDoc->GetNodes().GetEndOfContent(), -1) ); + //Modification 1 + pMarkAccess->makeMark(aPaM, "Mark", IDocumentMarkAccess::MarkType::BOOKMARK, + ::sw::mark::InsertMode::New); + CPPUNIT_ASSERT(pWrtShell->IsModified()); + pWrtShell->ResetModified(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + //Modification 2 + rUndoManager.Undo(); + CPPUNIT_ASSERT(pWrtShell->IsModified()); + pWrtShell->ResetModified(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + //Modification 3 + rUndoManager.Redo(); + CPPUNIT_ASSERT(pWrtShell->IsModified()); + pWrtShell->ResetModified(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->findMark("Mark"); + CPPUNIT_ASSERT(ppBkmk != pMarkAccess->getAllMarksEnd()); + //Modification 4 + pMarkAccess->renameMark(*ppBkmk, "Mark_"); + CPPUNIT_ASSERT(pWrtShell->IsModified()); + pWrtShell->ResetModified(); + CPPUNIT_ASSERT(bool(pMarkAccess->findMark("Mark") == pMarkAccess->getAllMarksEnd())); + CPPUNIT_ASSERT(pMarkAccess->findMark("Mark_") != pMarkAccess->getAllMarksEnd()); + //Modification 5 + rUndoManager.Undo(); + CPPUNIT_ASSERT(pWrtShell->IsModified()); + pWrtShell->ResetModified(); + CPPUNIT_ASSERT(pMarkAccess->findMark("Mark") != pMarkAccess->getAllMarksEnd()); + CPPUNIT_ASSERT(bool(pMarkAccess->findMark("Mark_") == pMarkAccess->getAllMarksEnd())); + //Modification 6 + rUndoManager.Redo(); + CPPUNIT_ASSERT(pWrtShell->IsModified()); + pWrtShell->ResetModified(); + CPPUNIT_ASSERT(bool(pMarkAccess->findMark("Mark") == pMarkAccess->getAllMarksEnd())); + CPPUNIT_ASSERT(pMarkAccess->findMark("Mark_") != pMarkAccess->getAllMarksEnd()); + //Modification 7 + pMarkAccess->deleteMark(pMarkAccess->findMark("Mark_"), false); + CPPUNIT_ASSERT(pWrtShell->IsModified()); + pWrtShell->ResetModified(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + //Modification 8 + rUndoManager.Undo(); + CPPUNIT_ASSERT(pWrtShell->IsModified()); + pWrtShell->ResetModified(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + //Modification 9 + rUndoManager.Redo(); + CPPUNIT_ASSERT(pWrtShell->IsModified()); + pWrtShell->ResetModified(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDefaultsOfOutlineNumbering) +{ + uno::Reference xDefNum(m_xSFactory->createInstance("com.sun.star.text.DefaultNumberingProvider"), uno::UNO_QUERY); + css::lang::Locale alocale; + alocale.Language = "en"; + alocale.Country = "US"; + const uno::Sequence aPropVal(xDefNum->getDefaultContinuousNumberingLevels(alocale)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPropVal.getLength()); + for(const auto& rPropValues : aPropVal) + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(5), rPropValues.getLength()); + for(const auto& rPropVal : rPropValues) + { + uno::Any aAny = rPropVal.Value; + if(rPropVal.Name == "Prefix" || rPropVal.Name == "Suffix" || rPropVal.Name == "Transliteration") + CPPUNIT_ASSERT_EQUAL(OUString("string"), aAny.getValueTypeName()); + else if(rPropVal.Name == "NumberingType") + CPPUNIT_ASSERT_EQUAL(OUString("short"), aAny.getValueTypeName()); + else if(rPropVal.Name == "NatNum") + CPPUNIT_ASSERT_EQUAL(OUString("short"), aAny.getValueTypeName()); + //It is expected to be long but right now its short !error! + else + CPPUNIT_FAIL("Property Name not matched"); + } + } +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDeleteTableRedlines) +{ + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0); + const SwTable& rTable = pWrtShell->InsertTable(TableOpt, 1, 3); + uno::Reference xTable(getParagraphOrTable(1), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable->getRows()->getCount()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable->getColumns()->getCount()); + uno::Sequence aDescriptor; + SwUnoCursorHelper::makeTableCellRedline((*const_cast(rTable.GetTableBox("A1"))), u"TableCellInsert", aDescriptor); + SwUnoCursorHelper::makeTableCellRedline((*const_cast(rTable.GetTableBox("B1"))), u"TableCellInsert", aDescriptor); + SwUnoCursorHelper::makeTableCellRedline((*const_cast(rTable.GetTableBox("C1"))), u"TableCellInsert", aDescriptor); + IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess(); + SwExtraRedlineTable& rExtras = rIDRA.GetExtraRedlineTable(); + rExtras.DeleteAllTableRedlines(*pDoc, rTable, false, RedlineType::Any); + CPPUNIT_ASSERT_EQUAL(o3tl::narrowing(0), rExtras.GetSize()); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testXFlatParagraph) +{ + SwDoc* pDoc = createSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + //Inserting some text in the document + pWrtShell->Insert("This is sample text"); + pWrtShell->SplitNode(); + pWrtShell->Insert("This is another sample text"); + pWrtShell->SplitNode(); + pWrtShell->Insert("This is yet another sample text"); + //retrieving the XFlatParagraphs + uno::Reference xFPIP(mxComponent, uno::UNO_QUERY); + uno::Reference xFPIterator(xFPIP->getFlatParagraphIterator(sal_Int32(text::TextMarkupType::SPELLCHECK), true)); + uno::Reference xFlatPara(xFPIterator->getFirstPara()); + CPPUNIT_ASSERT_EQUAL(OUString("This is sample text"), xFlatPara->getText()); + //checking modified status + CPPUNIT_ASSERT(!xFlatPara->isModified()); + //checking "checked" status, modifying it and asserting the changes + CPPUNIT_ASSERT(!xFlatPara->isChecked(sal_Int32(text::TextMarkupType::SPELLCHECK))); + xFlatPara->setChecked((sal_Int32(text::TextMarkupType::SPELLCHECK)), true); + CPPUNIT_ASSERT(xFlatPara->isChecked(sal_Int32(text::TextMarkupType::SPELLCHECK))); + //getting other XFlatParagraphs and asserting their contents + uno::Reference xFlatPara2(xFPIterator->getParaAfter(xFlatPara)); + CPPUNIT_ASSERT_EQUAL(OUString("This is another sample text"), xFlatPara2->getText()); + uno::Reference xFlatPara3(xFPIterator->getParaAfter(xFlatPara2)); + CPPUNIT_ASSERT_EQUAL(OUString("This is yet another sample text"), xFlatPara3->getText()); + uno::Reference xFlatPara4(xFPIterator->getParaBefore(xFlatPara3)); + CPPUNIT_ASSERT_EQUAL(xFlatPara2->getText(), xFlatPara4->getText()); + //changing the attributes of last para + uno::Sequence aDescriptor( comphelper::InitPropertySequence({ + { "CharWeight", uno::Any(float(css::awt::FontWeight::BOLD)) } + })); + xFlatPara3->changeAttributes(sal_Int32(0), sal_Int32(5), aDescriptor); + //checking Language Portions + uno::Sequence<::sal_Int32> aLangPortions(xFlatPara4->getLanguagePortions()); + CPPUNIT_ASSERT(!aLangPortions.hasElements()); + //examining Language of text + css::lang::Locale alocale = xFlatPara4->getLanguageOfText(sal_Int32(0), sal_Int32(4)); + CPPUNIT_ASSERT_EQUAL(OUString("en"), alocale.Language); + CPPUNIT_ASSERT_EQUAL(OUString("US"), alocale.Country); + //examining Primary Language of text + css::lang::Locale aprimarylocale = xFlatPara4->getPrimaryLanguageOfText(sal_Int32(0), sal_Int32(20)); + CPPUNIT_ASSERT_EQUAL(OUString("en"), aprimarylocale.Language); + CPPUNIT_ASSERT_EQUAL(OUString("US"), aprimarylocale.Country); +} + +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf81995) +{ + uno::Reference xDefNum(m_xSFactory->createInstance("com.sun.star.text.DefaultNumberingProvider"), uno::UNO_QUERY); + css::lang::Locale alocale; + alocale.Language = "en"; + alocale.Country = "US"; + const uno::Sequence> aIndexAccess(xDefNum->getDefaultOutlineNumberings(alocale)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aIndexAccess.getLength()); + for(const auto& rIndexAccess : aIndexAccess) + { + CPPUNIT_ASSERT_EQUAL(sal_Int32(5), rIndexAccess->getCount()); + for(int j=0;jgetCount();j++) + { + uno::Sequence aProps; + rIndexAccess->getByIndex(j) >>= aProps; + CPPUNIT_ASSERT_EQUAL(sal_Int32(12), aProps.getLength()); + for(const beans::PropertyValue& rProp : std::as_const(aProps)) + { + uno::Any aAny = rProp.Value; + if(rProp.Name == "Prefix" || rProp.Name == "Suffix" || rProp.Name == "BulletChar" || rProp.Name == "BulletFontName" || rProp.Name == "Transliteration") + CPPUNIT_ASSERT_EQUAL(OUString("string"), aAny.getValueTypeName()); + else if(rProp.Name == "NumberingType" || rProp.Name == "ParentNumbering" || rProp.Name == "Adjust") + CPPUNIT_ASSERT_EQUAL(OUString("short"), aAny.getValueTypeName()); + else if(rProp.Name == "LeftMargin" || rProp.Name == "SymbolTextDistance" || rProp.Name == "FirstLineOffset" || rProp.Name == "NatNum") + CPPUNIT_ASSERT_EQUAL(OUString("long"), aAny.getValueTypeName()); + else + CPPUNIT_FAIL("Property Name not matched"); + } + } + } +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3