Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/editeng/qa/unit/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 108 kB image not shown  

Quelle  core-test.cxx   Sprache: C

 
/* -*- 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 <config_fonts.h>

#include <test/bootstrapfixture.hxx>

#include <cppunit/extensions/HelperMacros.h>

#include <editdoc.hxx>
#include <impedit.hxx>

#include <sfx2/app.hxx>
#include <svl/itempool.hxx>
#include <editeng/adjustitem.hxx>
#include <editeng/editeng.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/lspcitem.hxx>
#include <editeng/svxacorr.hxx>
#include <editeng/unofield.hxx>
#include <editeng/wghtitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/section.hxx>
#include <editeng/editobj.hxx>
#include <editeng/flditem.hxx>
#include <editeng/udlnitem.hxx>
#include <svl/srchitem.hxx>
#include <svl/voiditem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/fhgtitem.hxx>

#include <com/sun/star/text/textfield/Type.hpp>

#include <memory>
#include <vector>
#include <editeng/outliner.hxx>

using namespace com::sun::star;

namespace
{
class Test : public test::BootstrapFixture
{
public:
    Test() {}

    void setUp() override
    {
        test::BootstrapFixture::setUp();
        mpItemPool = new EditEngineItemPool();
        SfxApplication::GetOrCreate();
    }

    void tearDown() override
    {
        mpItemPool.clear();
        test::BootstrapFixture::tearDown();
    }

#if HAVE_MORE_FONTS
    /// Test text portions position when percentage line spacing is set
    void testLineSpacing();
#endif

    void testConstruction();

    /// Test UNO service class that implements text field items.
    void testUnoTextFields();

    /// Test Copy/Paste with hyperlinks in text using Legacy Format
    void testHyperlinkCopyPaste();

    /// Test Copy/Paste using Legacy Format
    void testCopyPaste();

    /// Test Paste using HTML
    void testHTMLPaste();

    /// Test Paste using an HTML fragment
    void testHTMLFragmentPaste();

    /// Test Paste using an RTF
    void testRTFPaste();

    /// Test Paste preference HTML/
    void testRTFHTMLPaste();

    /// Test Copy/Paste with selective selection over multiple paragraphs
    void testMultiParaSelCopyPaste();

    /// Test Copy/Paste with Tabs
    void testTabsCopyPaste();

    /// Test hyperlinks
    void testHyperlinkSearch();

    /// Test Copy/Paste with Bold/Italic text using Legacy Format
    void testBoldItalicCopyPaste();

    /// Test Copy/Paste with Underline text using Legacy Format
    void testUnderlineCopyPaste();

    /// Test Copy/Paste with multiple paragraphs
    void testMultiParaCopyPaste();

    /// Test Copy/Paste with multiple paragraphs having Bold/Italic text
    void testParaBoldItalicCopyPaste();

    void testParaStartCopyPaste();

    void testSectionAttributes();

    void testLargeParaCopyPaste();

    void testTransliterate();

    void testTdf147196();

    void testTdf148148();

    void testSingleLine();
    void testMoveParagraph();
    void testCreateLines();
    void testTdf154248MultilineFieldWrapping();
    void testTdf151748StaleKashidaArray();
    void testTdf162803StaleKashidaArray();

    DECL_STATIC_LINK(Test, CalcFieldValueHdl, EditFieldInfo*, void);

    CPPUNIT_TEST_SUITE(Test);
#if HAVE_MORE_FONTS
    CPPUNIT_TEST(testLineSpacing);
#endif
    CPPUNIT_TEST(testConstruction);
    CPPUNIT_TEST(testUnoTextFields);
    CPPUNIT_TEST(testHyperlinkCopyPaste);
    CPPUNIT_TEST(testCopyPaste);
    CPPUNIT_TEST(testHTMLPaste);
    CPPUNIT_TEST(testHTMLFragmentPaste);
    CPPUNIT_TEST(testRTFPaste);
    CPPUNIT_TEST(testRTFHTMLPaste);
    CPPUNIT_TEST(testMultiParaSelCopyPaste);
    CPPUNIT_TEST(testTabsCopyPaste);
    CPPUNIT_TEST(testHyperlinkSearch);
    CPPUNIT_TEST(testBoldItalicCopyPaste);
    CPPUNIT_TEST(testUnderlineCopyPaste);
    CPPUNIT_TEST(testMultiParaCopyPaste);
    CPPUNIT_TEST(testParaBoldItalicCopyPaste);
    CPPUNIT_TEST(testParaStartCopyPaste);
    CPPUNIT_TEST(testSectionAttributes);
    CPPUNIT_TEST(testLargeParaCopyPaste);
    CPPUNIT_TEST(testTransliterate);
    CPPUNIT_TEST(testTdf147196);
    CPPUNIT_TEST(testTdf148148);
    CPPUNIT_TEST(testSingleLine);
    CPPUNIT_TEST(testMoveParagraph);
    CPPUNIT_TEST(testCreateLines);
    CPPUNIT_TEST(testTdf154248MultilineFieldWrapping);
    CPPUNIT_TEST(testTdf151748StaleKashidaArray);
    CPPUNIT_TEST(testTdf162803StaleKashidaArray);
    CPPUNIT_TEST_SUITE_END();

private:
    rtl::Reference<EditEngineItemPool> mpItemPool;
};

#if HAVE_MORE_FONTS
void Test::testLineSpacing()
{
    // Create EditEngine's instance
    EditEngine aEditEngine(mpItemPool.get());

    if (aEditEngine.GetRefDevice()->GetDPIY() != 96
        || aEditEngine.GetRefDevice()->GetDPIScaleFactor() != 1.0)
        return;

    // Get EditDoc for current EditEngine's instance
    EditDoc& rDoc = aEditEngine.GetEditDoc();

    // Initially no text should be there
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));

    // Set initial text
    OUString aText = u"This is multi-line paragraph"_ustr;

    sal_Int32 aTextLen = aText.getLength();
    aEditEngine.SetText(aText);

    // Assert changes - text insertion
    CPPUNIT_ASSERT_EQUAL(aTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(aText, rDoc.GetParaAsString(sal_Int32(0)));

    // Select all paragraphs
    ESelection aSelection(0, 0, 0, aTextLen);

    auto doTest = [&](sal_uInt16 nSpace, sal_uInt16 nExpMaxAscent, sal_uInt32 nExpLineHeight) {
        std::unique_ptr<SfxItemSet> pSet(new SfxItemSet(aEditEngine.GetEmptyItemSet()));
        SvxLineSpacingItem aLineSpacing(LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL);
        aLineSpacing.SetPropLineSpace(nSpace);
        pSet->Put(aLineSpacing);

        // Set font
        SvxFontItem aFont(EE_CHAR_FONTINFO);
        aFont.SetFamilyName(u"Liberation Sans"_ustr);
        pSet->Put(aFont);
        SvxFontHeightItem aFontSize(240, 100, EE_CHAR_FONTHEIGHT);
        pSet->Put(aFontSize);

        CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(3), pSet->Count());

        aEditEngine.QuickSetAttribs(*pSet, aSelection);

        // Assert changes
        ParaPortion const& rParaPortion = aEditEngine.GetParaPortions().getRef(0);
        ContentNode* const pNode = rParaPortion.GetNode();
        const SvxLineSpacingItem& rLSItem = pNode->GetContentAttribs().GetItem(EE_PARA_SBL);
        CPPUNIT_ASSERT_EQUAL(SvxInterLineSpaceRule::Prop, rLSItem.GetInterLineSpaceRule());
        CPPUNIT_ASSERT_EQUAL(nSpace, rLSItem.GetPropLineSpace());

        // Check the first line
        ParagraphInfos aInfo = aEditEngine.GetParagraphInfos(0);
        CPPUNIT_ASSERT_EQUAL(nExpMaxAscent, aInfo.nFirstLineMaxAscent);
        CPPUNIT_ASSERT_EQUAL(nExpLineHeight, aEditEngine.GetLineHeight(0));
    };

    // Test first case - 60%
    doTest(60, 122, 153);

    // Force multiple lines
    aEditEngine.SetPaperSize(Size(1000, 6000));
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aEditEngine.GetLineCount(0));

    // Test second case - 150%
    doTest(150, 337, 382);

    // Test lower Word limit - 6% (factor 0.06)
    doTest(6, 12, 15);

    // Test upper Word limit - 13200% (factor 132)
    doTest(13200, 33615, 33660);
}
#endif

void Test::testConstruction()
{
    EditEngine aEngine(mpItemPool.get());

    aEngine.SetText(u"I am Edit Engine."_ustr);
}

bool includes(const uno::Sequence<OUString>& rSeq, std::u16string_view rVal)
{
    for (OUString const& s : rSeq)
        if (s == rVal)
            return true;

    return false;
}

void Test::testUnoTextFields()
{
    {
        // DATE
        rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::DATE));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.DateTime");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // URL
        rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::URL));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.URL");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // PAGE
        rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::PAGE));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.PageNumber");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // PAGES
        rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::PAGES));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.PageCount");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // TIME
        rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::TIME));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.DateTime");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // FILE
        rtl::Reference<SvxUnoTextField> xField(
            new SvxUnoTextField(text::textfield::Type::DOCINFO_TITLE));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.docinfo.Title");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // TABLE
        rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::TABLE));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.SheetName");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // EXTENDED TIME
        rtl::Reference<SvxUnoTextField> xField(
            new SvxUnoTextField(text::textfield::Type::EXTENDED_TIME));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.DateTime");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // EXTENDED FILE
        rtl::Reference<SvxUnoTextField> xField(
            new SvxUnoTextField(text::textfield::Type::EXTENDED_FILE));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.FileName");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // AUTHOR
        rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::AUTHOR));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.Author");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // MEASURE
        rtl::Reference<SvxUnoTextField> xField(new SvxUnoTextField(text::textfield::Type::MEASURE));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.text.textfield.Measure");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // PRESENTATION HEADER
        rtl::Reference<SvxUnoTextField> xField(
            new SvxUnoTextField(text::textfield::Type::PRESENTATION_HEADER));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.presentation.textfield.Header");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // PRESENTATION FOOTER
        rtl::Reference<SvxUnoTextField> xField(
            new SvxUnoTextField(text::textfield::Type::PRESENTATION_FOOTER));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.presentation.textfield.Footer");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }

    {
        // PRESENTATION DATE TIME
        rtl::Reference<SvxUnoTextField> xField(
            new SvxUnoTextField(text::textfield::Type::PRESENTATION_DATE_TIME));
        uno::Sequence<OUString> aSvcs = xField->getSupportedServiceNames();
        bool bGood = includes(aSvcs, u"com.sun.star.presentation.textfield.DateTime");
        CPPUNIT_ASSERT_MESSAGE("expected service is not present.", bGood);
    }
}

IMPL_STATIC_LINK(Test, CalcFieldValueHdl, EditFieldInfo*, pInfo, void)
{
    if (!pInfo)
        return;

    const SvxFieldItem& rField = pInfo->GetField();
    const SvxFieldData* pField = rField.GetField();
    if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
    {
        // URLField
        OUString aURL = pURLField->GetURL();
        switch (pURLField->GetFormat())
        {
            case SvxURLFormat::AppDefault:
            case SvxURLFormat::Repr:
            {
                pInfo->SetRepresentation(pURLField->GetRepresentation());
            }
            break;

            case SvxURLFormat::Url:
            {
                pInfo->SetRepresentation(aURL);
            }
            break;
        }
    }
    else
    {
        OSL_FAIL("Unknown Field");
        pInfo->SetRepresentation(OUString('?'));
    }
}

void Test::testHyperlinkCopyPaste()
{
    // Create Outliner instance
    Outliner aOutliner(mpItemPool.get(), OutlinerMode::TextObject);
    aOutliner.SetCalcFieldValueHdl(LINK(nullptr, Test, CalcFieldValueHdl));

    // Create EditEngine's instance
    EditEngine& aEditEngine = const_cast<EditEngine&>(aOutliner.GetEditEngine());

    // Get EditDoc for current EditEngine's instance
    EditDoc& rDoc = aEditEngine.GetEditDoc();

    // New instance must be empty - no initial text
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));

    // Get corresponding Field Item for inserting URLs in text
    // URL 1
    OUString aURL1 = u"mailto:///user@example.com"_ustr;
    OUString aRepres1 = u"user@example.com"_ustr;
    SvxURLField aURLField1( aURL1, aRepres1, SvxURLFormat::Repr );
    SvxFieldItem aField1( aURLField1, EE_FEATURE_FIELD );
    // URL 2
    OUString aURL2 = u"mailto:///example@domain.com"_ustr;
    OUString aRepres2 = u"example@domain.com"_ustr;
    SvxURLField aURLField2( aURL2, aRepres2, SvxURLFormat::Repr );
    SvxFieldItem aField2( aURLField2, EE_FEATURE_FIELD );

    // Insert initial text
    OUString aParaText = u"sampletextfortestingfeaturefields"_ustr;
    // Positions Ref      .............*13....*20..........
    sal_Int32 aTextLen = aParaText.getLength();
    aEditEngine.SetText(aParaText);

    // Assert changes
    CPPUNIT_ASSERT_EQUAL(aTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(aParaText, rDoc.GetParaAsString(sal_Int32(0)));

    // Insert URL 1
    ContentNode* pNode = rDoc.GetObject(0);
    EditSelection aSel1(EditPaM(pNode, 13), EditPaM(pNode, 13));
    aEditEngine.InsertField(aSel1, aField1);

    // Assert Field Count
    CPPUNIT_ASSERT_EQUAL(size_t(1), aEditEngine.GetFieldInfo(0).size());

    // Insert URL 2
    EditSelection aSel2(EditPaM(pNode, 20 + 1), EditPaM(pNode, 20 + 1));
    aEditEngine.InsertField(aSel2, aField2);

    // Assert Field Count
    CPPUNIT_ASSERT_EQUAL(size_t(2), aEditEngine.GetFieldInfo(0).size());

    // Assert URL Fields and text before copy
    // Check text
    CPPUNIT_ASSERT_EQUAL( aTextLen + aRepres1.getLength() + aRepres2.getLength(), rDoc.GetTextLen() );
    CPPUNIT_ASSERT_EQUAL( u"sampletextforuser@example.comtestingexample@domain.comfeaturefields"_ustr, rDoc.GetParaAsString(sal_Int32(0)) );

    // Check Field 1
    EFieldInfo aURLFieldInfo1 = aEditEngine.GetFieldInfo(sal_Int32(0))[0];
    CPPUNIT_ASSERT_EQUAL(sal_Int32(13), aURLFieldInfo1.aPosition.nIndex);
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(EE_FEATURE_FIELD), aURLFieldInfo1.pFieldItem->Which());
    SvxURLField* pURLField1 = dynamic_cast<SvxURLField*>(
        const_cast<SvxFieldData*>(aURLFieldInfo1.pFieldItem->GetField()));
    CPPUNIT_ASSERT(pURLField1);
    CPPUNIT_ASSERT_EQUAL(aURL1, pURLField1->GetURL());
    CPPUNIT_ASSERT_EQUAL(aRepres1, pURLField1->GetRepresentation());

    // Check Field 2
    EFieldInfo aURLFieldInfo2 = aEditEngine.GetFieldInfo(sal_Int32(0))[1];
    CPPUNIT_ASSERT_EQUAL(sal_Int32(21), aURLFieldInfo2.aPosition.nIndex);
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(EE_FEATURE_FIELD), aURLFieldInfo2.pFieldItem->Which());
    SvxURLField* pURLField2 = dynamic_cast<SvxURLField*>(
        const_cast<SvxFieldData*>(aURLFieldInfo2.pFieldItem->GetField()));
    CPPUNIT_ASSERT(pURLField2);
    CPPUNIT_ASSERT_EQUAL(aURL2, pURLField2->GetURL());
    CPPUNIT_ASSERT_EQUAL(aRepres2, pURLField2->GetRepresentation());

    // Copy text using legacy format
    uno::Reference<datatransfer::XTransferable> xData
        = aEditEngine.CreateTransferable(ESelection(0, 10, 0, 21));

    // Paste text at the end
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Assert Changes ACP, ACP: after Copy/Paste

    // Check the fields count
    CPPUNIT_ASSERT_EQUAL(size_t(3), aEditEngine.GetFieldInfo(0).size());

    // Check the updated text length
    CPPUNIT_ASSERT_EQUAL(aTextLen + 10 + aRepres1.getLength() * 2 + aRepres2.getLength(),
                         rDoc.GetTextLen());

    // Check the updated text contents
    CPPUNIT_ASSERT_EQUAL( u"sampletextforuser@example.comtestingexample@domain.comfeaturefieldsforuser@example.comtesting"_ustr, rDoc.GetParaAsString(sal_Int32(0)) );

    // Check the Fields and their values

    // Field 1
    EFieldInfo aACPURLFieldInfo1 = aEditEngine.GetFieldInfo(sal_Int32(0))[0];
    CPPUNIT_ASSERT_EQUAL(sal_Int32(13), aACPURLFieldInfo1.aPosition.nIndex);
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(EE_FEATURE_FIELD), aACPURLFieldInfo1.pFieldItem->Which());
    SvxURLField* pACPURLField1 = dynamic_cast<SvxURLField*>(
        const_cast<SvxFieldData*>(aACPURLFieldInfo1.pFieldItem->GetField()));
    CPPUNIT_ASSERT(pACPURLField1);
    CPPUNIT_ASSERT_EQUAL(aURL1, pACPURLField1->GetURL());
    CPPUNIT_ASSERT_EQUAL(aRepres1, pACPURLField1->GetRepresentation());

    // Field 2
    EFieldInfo aACPURLFieldInfo2 = aEditEngine.GetFieldInfo(sal_Int32(0))[1];
    CPPUNIT_ASSERT_EQUAL(sal_Int32(21), aACPURLFieldInfo2.aPosition.nIndex);
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(EE_FEATURE_FIELD), aACPURLFieldInfo2.pFieldItem->Which());
    SvxURLField* pACPURLField2 = dynamic_cast<SvxURLField*>(
        const_cast<SvxFieldData*>(aACPURLFieldInfo2.pFieldItem->GetField()));
    CPPUNIT_ASSERT(pACPURLField2);
    CPPUNIT_ASSERT_EQUAL(aURL2, pACPURLField2->GetURL());
    CPPUNIT_ASSERT_EQUAL(aRepres2, pACPURLField2->GetRepresentation());

    // Field 3
    EFieldInfo aACPURLFieldInfo3 = aEditEngine.GetFieldInfo(sal_Int32(0))[2];
    CPPUNIT_ASSERT_EQUAL(sal_Int32(38), aACPURLFieldInfo3.aPosition.nIndex);
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(EE_FEATURE_FIELD), aACPURLFieldInfo3.pFieldItem->Which());
    SvxURLField* pACPURLField3 = dynamic_cast<SvxURLField*>(
        const_cast<SvxFieldData*>(aACPURLFieldInfo3.pFieldItem->GetField()));
    CPPUNIT_ASSERT(pACPURLField3);
    CPPUNIT_ASSERT_EQUAL(aURL1, pACPURLField3->GetURL());
    CPPUNIT_ASSERT_EQUAL(aRepres1, pACPURLField3->GetRepresentation());
}

void Test::testCopyPaste()
{
    // Create EditEngine's instance
    EditEngine aEditEngine(mpItemPool.get());

    // Get EditDoc for current EditEngine's instance
    EditDoc& rDoc = aEditEngine.GetEditDoc();

    // Initially no text should be there
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));

    // Set initial text
    OUString aText = u"This is custom initial text"_ustr;
    sal_Int32 aTextLen = aText.getLength();
    aEditEngine.SetText(aText);

    // Assert changes
    CPPUNIT_ASSERT_EQUAL(aTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(aText, rDoc.GetParaAsString(sal_Int32(0)));

    // Copy initial text using legacy format
    uno::Reference<datatransfer::XTransferable> xData
        = aEditEngine.CreateTransferable(ESelection(0, 0, 0, aTextLen));

    // Paste text at the end
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Assert changes
    CPPUNIT_ASSERT_EQUAL(aTextLen + aTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(aText + aText), rDoc.GetParaAsString(sal_Int32(0)));
}

/// XTransferable implementation that provides simple HTML content.
class TestTransferable : public cppu::WeakImplHelper<datatransfer::XTransferable>
{
    std::vector<OString> m_aContent;
    std::vector<OUString> m_aMimeType;

public:
    TestTransferable(std::vector<OString>& rContent, std::vector<OUString>& rMimeType);
    uno::Any SAL_CALL getTransferData(const datatransfer::DataFlavor& rFlavor) override;
    uno::Sequence<datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override;
    sal_Bool SAL_CALL isDataFlavorSupported(const datatransfer::DataFlavor& rFlavor) override;
};

TestTransferable::TestTransferable(std::vector<OString>& rContent, std::vector<OUString>& rMimeType)
    : m_aContent(rContent)
    , m_aMimeType(rMimeType)
{
    CPPUNIT_ASSERT_EQUAL(m_aContent.size(), m_aMimeType.size());
}

uno::Any TestTransferable::getTransferData(const datatransfer::DataFlavor& rFlavor)
{
    for (size_t nType = 0; nType < m_aMimeType.size(); ++nType)
    {
        if (rFlavor.MimeType == m_aMimeType[nType])
        {
            uno::Any aRet;
            SvMemoryStream aStream;
            aStream.WriteOString(m_aContent[nType]);
            aRet <<= uno::Sequence<sal_Int8>(static_cast<const sal_Int8*>(aStream.GetData()),
                                             aStream.GetSize());
            return aRet;
        }
    }
    return {};
}

uno::Sequence<datatransfer::DataFlavor> TestTransferable::getTransferDataFlavors()
{
    std::vector<datatransfer::DataFlavor> aFlavourVac;
    for (size_t nType = 0; nType < m_aMimeType.size(); ++nType)
    {
        datatransfer::DataFlavor aFlavor;
        aFlavor.DataType = cppu::UnoType<uno::Sequence<sal_Int8>>::get();
        aFlavor.MimeType = m_aMimeType[nType];
        aFlavor.HumanPresentableName = aFlavor.MimeType;
        aFlavourVac.push_back(aFlavor);
    }
    uno::Sequence<datatransfer::DataFlavor> aFlavors(aFlavourVac.data(), m_aMimeType.size());
    return aFlavors;
}

sal_Bool TestTransferable::isDataFlavorSupported(const datatransfer::DataFlavor&&nbsp;rFlavor)
{
    for (size_t nType = 0; nType < m_aMimeType.size(); ++nType)
    {
        if (rFlavor.MimeType == m_aMimeType[nType]
            && rFlavor.DataType == cppu::UnoType<uno::Sequence<sal_Int8>>::get())
            return true;
    }
    return false;
}

void Test::testHTMLPaste()
{
    // Given an empty editeng document:
    EditEngine aEditEngine(mpItemPool.get());
    EditDoc& rDoc = aEditEngine.GetEditDoc();
    //OString aHTML("<!DOCTYPE html>\n<html><body>test</body></html>"_ostr);
    std::vector<OString> aContent({ "\ntest"_ostr });
    std::vector<OUString> aMime({ u"text/html"_ustr });

    uno::Reference<datatransfer::XTransferable> xData(new TestTransferable(aContent, aMime));
    // When trying to paste HTML:
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Then make sure the text gets pasted:
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: test
    // - Actual  :
    // i.e. RTF and plain text paste worked, but not HTML.
    CPPUNIT_ASSERT_EQUAL(u"test"_ustr, rDoc.GetParaAsString(static_cast<sal_Int32>(0)));
}

void Test::testHTMLFragmentPaste()
{
    // Given an empty editeng document:
    EditEngine aEditEngine(mpItemPool.get());
    EditDoc& rDoc = aEditEngine.GetEditDoc();
    std::vector<OString> aContent({ "abc"_ostr });
    std::vector<OUString> aMime({ u"text/html"_ustr });

    uno::Reference<datatransfer::XTransferable> xData(new TestTransferable(aContent, aMime));

    // When trying to paste an HTML fragment:
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Then make sure the text gets pasted:
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: abc
    // - Actual  :
    // i.e. a HTML fragment without a proper header was ignored on paste.
    CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, rDoc.GetParaAsString(static_cast<sal_Int32>(0)));
}

void Test::testRTFPaste()
{
    // Given an empty editeng document:
    EditEngine aEditEngine(mpItemPool.get());
    EditDoc& rDoc = aEditEngine.GetEditDoc();
    std::vector<OString> aContent(
        { "{\\rtf1\\adeflang1025\\ansi{\\ul www.libreoffice.org}}"_ostr });
    std::vector<OUString> aMime({ u"text/richtext"_ustr });
    uno::Reference<datatransfer::XTransferable> xData(new TestTransferable(aContent, aMime));

    // When trying to paste HTML:
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Then make sure the text gets pasted:
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: www.libreoffice.org
    // - Actual  :
    // i.e. RTF and plain text paste worked, but not HTML.
    CPPUNIT_ASSERT_EQUAL(u"www.libreoffice.org"_ustr,
                         rDoc.GetParaAsString(static_cast<sal_Int32>(0)));
}

void Test::testRTFHTMLPaste()
{
    // Given an empty editeng document:
    EditEngine aEditEngine(mpItemPool.get());
    EditDoc& rDoc = aEditEngine.GetEditDoc();
    std::vector<OString> aContent(
        { "{\\rtf1\\adeflang1025\\ansi{\\ul www.libreoffice.org}}"_ostr,
          "Version:1.0\nStartHTML:0000000121\n"
          "EndHTML:0000000596\n"
          "StartFragment:0000000519\n"
          "EndFragment:0000000579\n"
          "content-type\" content=\"text/html; "
          "charset=utf-8\"/>"
          "generator\" content=\"LibreOffice 7.4.5.1 (Windows)\"/>"
          ""
          "de-DE\" link=\"#000080\" vlink=\"#800000\" dir=\"ltr\">"
          "

line-height: 100%; margin-bottom: 0cm\">abc

"
_ostr });
    std::vector<OUString> aMime(
        { u"text/richtext"_ustr,
          u"application/x-openoffice-html-simple;windows_formatname=\"HTML Format\""_ustr });
    uno::Reference<datatransfer::XTransferable> xData(new TestTransferable(aContent, aMime));

    // When trying to paste HTML:
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Then make sure the text gets pasted:
    // expected "abc"
    // wrong: www.libreoffice.org
    // i.e. HTML is preferred over HTML.
    CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, rDoc.GetParaAsString(static_cast<sal_Int32>(0)));
}
void Test::testMultiParaSelCopyPaste()
{
    // Create EditEngine's instance
    EditEngine aEditEngine(mpItemPool.get());

    // Get EditDoc for current EditEngine's instance
    EditDoc& rDoc = aEditEngine.GetEditDoc();

    // Initially no text should be there
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));

    // Insert initial text
    OUString aFirstPara = u"This is first paragraph"_ustr;
    // Selection Ref       ........8..............
    OUString aSecondPara = u"This is second paragraph"_ustr;
    // Selection Ref        .............14.........
    OUString aThirdPara = u"This is third paragraph"_ustr;
    OUString aText = aFirstPara + "\n" + aSecondPara + "\n" + aThirdPara;
    sal_Int32 aTextLen = aFirstPara.getLength() + aSecondPara.getLength() + aThirdPara.getLength();
    aEditEngine.SetText( aText );
    OUString aCopyText = u"first paragraphThis is second"_ustr;
    sal_Int32 aCopyTextLen = aCopyText.getLength();

    // Assert changes
    CPPUNIT_ASSERT_EQUAL(aTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(aFirstPara, rDoc.GetParaAsString(sal_Int32(0)));
    CPPUNIT_ASSERT_EQUAL(aSecondPara, rDoc.GetParaAsString(sal_Int32(1)));
    CPPUNIT_ASSERT_EQUAL(aThirdPara, rDoc.GetParaAsString(sal_Int32(2)));

    // Copy initial text using legacy format
    uno::Reference<datatransfer::XTransferable> xData
        = aEditEngine.CreateTransferable(ESelection(0, 8, 1, 14));

    // Paste text at the end
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Assert changes
    OUString aThirdParaAfterCopyPaste = aThirdPara + "first paragraph";
    CPPUNIT_ASSERT_EQUAL( aTextLen + aCopyTextLen, rDoc.GetTextLen() );
    CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
    CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
    CPPUNIT_ASSERT_EQUAL( aThirdParaAfterCopyPaste, rDoc.GetParaAsString(sal_Int32(2)) );
    CPPUNIT_ASSERT_EQUAL( u"This is second"_ustr, rDoc.GetParaAsString(sal_Int32(3)) );
}

void Test::testTabsCopyPaste()
{
    // Create EditEngine's instance
    EditEngine aEditEngine(mpItemPool.get());

    // Get EditDoc for current EditEngine's instance
    EditDoc& rDoc = aEditEngine.GetEditDoc();

    // New instance must be empty - no initial text
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));

    // Get corresponding Item for inserting tabs in the text
    SfxVoidItem aTab(EE_FEATURE_TAB);

    // Insert initial text
    OUString aParaText = u"sampletextfortestingtab"_ustr;
    // Positions Ref      ......*6...............*23
    sal_Int32 aTextLen = aParaText.getLength();
    aEditEngine.SetText(aParaText);

    // Assert changes
    CPPUNIT_ASSERT_EQUAL(aTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(aParaText, rDoc.GetParaAsString(sal_Int32(0)));

    // Insert tab 1 at desired position
    ContentNode* pNode = rDoc.GetObject(0);
    EditSelection aSel1(EditPaM(pNode, 6), EditPaM(pNode, 6));
    aEditEngine.InsertFeature(aSel1, aTab);

    // Assert changes
    CPPUNIT_ASSERT_EQUAL( aTextLen + 1, rDoc.GetTextLen() );
    CPPUNIT_ASSERT_EQUAL( u"sample\ttextfortestingtab"_ustr, rDoc.GetParaAsString(sal_Int32(0)) );

    // Insert tab 2 at desired position
    EditSelection aSel2(EditPaM(pNode, 23 + 1), EditPaM(pNode, 23 + 1));
    aEditEngine.InsertFeature(aSel2, aTab);

    // Assert changes
    CPPUNIT_ASSERT_EQUAL( aTextLen + 2, rDoc.GetTextLen() );
    CPPUNIT_ASSERT_EQUAL( u"sample\ttextfortestingtab\t"_ustr, rDoc.GetParaAsString(sal_Int32(0)) );

    // Copy text using legacy format
    uno::Reference<datatransfer::XTransferable> xData
        = aEditEngine.CreateTransferable(ESelection(0, 6, 0, aTextLen + 2));

    // Paste text at the end
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Assert changes
    CPPUNIT_ASSERT_EQUAL( aTextLen + aTextLen - 6 + 4, rDoc.GetTextLen() );
    CPPUNIT_ASSERT_EQUAL( u"sample\ttextfortestingtab\t\ttextfortestingtab\t"_ustr, rDoc.GetParaAsString(sal_Int32(0)) );
}

class UrlEditEngine : public EditEngine
{
public:
    explicit UrlEditEngine(SfxItemPool* pPool)
        : EditEngine(pPool)
    {
    }

    virtual OUString CalcFieldValue(const SvxFieldItem&, sal_Int32, sal_Int32,
                                    std::optional<Color>&, std::optional<Color>&,
                                    std::optional<FontLineStyle>&) override
    {
        return u"jim@bob.com"_ustr; // a sophisticated view of value:
    }
};

// Odd accounting for hyperlink position & size etc.
// https://bugzilla.novell.com/show_bug.cgi?id=467459
void Test::testHyperlinkSearch()
{
    UrlEditEngine aEngine(mpItemPool.get());
    EditDoc& rDoc = aEngine.GetEditDoc();

    OUString aSampleText = u"Please write email to . if you find a fish(not a dog)."_ustr;
    aEngine.SetText(aSampleText);

    CPPUNIT_ASSERT_EQUAL_MESSAGE("set text", aSampleText, rDoc.GetParaAsString(sal_Int32(0)));

    ContentNode* pNode = rDoc.GetObject(0);
    EditSelection aSel(EditPaM(pNode, 22), EditPaM(pNode, 22));
    SvxURLField aURLField(u"mailto:///jim@bob.com"_ustr, u"jim@bob.com"_ustr,
                          SvxURLFormat::Repr);
    SvxFieldItem aField(aURLField, EE_FEATURE_FIELD);

    aEngine.InsertField(aSel, aField);

    OUString aContent = pNode->GetExpandedText();
    CPPUNIT_ASSERT_EQUAL_MESSAGE("get text", u"Please write email to jim@bob.com. if you find a fish(not a dog)."_ustr,
                           aContent);
    CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong length", aContent.getLength(), rDoc.GetTextLen());

    // Check expansion and positioning re-work
    CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong length", aContent.getLength(), pNode->GetExpandedLen());
    for (sal_Int32 n = 0; n < aContent.getLength(); n++)
    {
        sal_Int32 nStart = n, nEnd = n;
        pNode->UnExpandPositions(nStart, nEnd);
        CPPUNIT_ASSERT_MESSAGE("out of bound start", nStart < pNode->Len());
        CPPUNIT_ASSERT_MESSAGE("out of bound end", nEnd <= pNode->Len());
    }

    static const struct
    {
        sal_Int32 mnStart, mnEnd;
        sal_Int32 mnNewStart, mnNewEnd;
    } aTrickyOnes[] = { { 0, 1, /* -> */ 0, 1 },
                        { 21, 25, /* -> */ 21, 23 }, // the field is really just one char
                        { 25, 27, /* -> */ 22, 23 },
                        { 50, 56, /* -> */ 40, 46 } };
    for (size_t n = 0; n < std::size(aTrickyOnes); n++)
    {
        sal_Int32 nStart = aTrickyOnes[n].mnStart;
        sal_Int32 nEnd = aTrickyOnes[n].mnEnd;
        pNode->UnExpandPositions(nStart, nEnd);

        CPPUNIT_ASSERT_EQUAL_MESSAGE(OString("in row " + OString::number(n)).getStr(),
                                     aTrickyOnes[n].mnNewStart, nStart);
        CPPUNIT_ASSERT_EQUAL_MESSAGE(OString("in row " + OString::number(n)).getStr(),
                                     aTrickyOnes[n].mnNewEnd, nEnd);
    }

    SvxSearchItem aItem(1); //SID_SEARCH_ITEM);
    aItem.SetBackward(false);
    aItem.SetSelection(false);
    aItem.SetSearchString(u"fish"_ustr);
    CPPUNIT_ASSERT_MESSAGE("no fish", aEngine.HasText(aItem));
    aItem.SetSearchString(u"dog"_ustr);
    CPPUNIT_ASSERT_MESSAGE("no dog", aEngine.HasText(aItem));
}

bool hasBold(const editeng::Section& rSecAttr)
{
    return std::any_of(
        rSecAttr.maAttributes.begin(), rSecAttr.maAttributes.end(), [](const SfxPoolItem* p) {
            return p->Which() == EE_CHAR_WEIGHT
                   && static_cast<const SvxWeightItem*>(p)->GetWeight() == WEIGHT_BOLD;
        });
}

bool hasItalic(const editeng::Section& rSecAttr)
{
    return std::any_of(
        rSecAttr.maAttributes.begin(), rSecAttr.maAttributes.end(), [](const SfxPoolItem* p) {
            return p->Which() == EE_CHAR_ITALIC
                   && static_cast<const SvxPostureItem*>(p)->GetPosture() == ITALIC_NORMAL;
        });
}

void Test::testBoldItalicCopyPaste()
{
    // Create EditEngine's instance
    EditEngine aEditEngine(mpItemPool.get());

    // Get EditDoc for current EditEngine's instance
    EditDoc& rDoc = aEditEngine.GetEditDoc();

    // New instance must be empty - no initial text
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));

    // Get corresponding ItemSet for inserting Bold/Italic text
    std::unique_ptr<SfxItemSet> pSet(new SfxItemSet(aEditEngine.GetEmptyItemSet()));
    SvxWeightItem aBold(WEIGHT_BOLD, EE_CHAR_WEIGHT);
    SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);

    // Insert initial text
    OUString aParaText = u"boldeditengineitalic"_ustr;
    // Positions Ref      ..*2....*8...*13.*17
    // Bold Ref           ..[   BOLD   ]......
    // Italic Ref         ........[ ITALIC ]..
    sal_Int32 aTextLen = aParaText.getLength();
    aEditEngine.SetText(aParaText);

    // Assert changes - text insertion
    CPPUNIT_ASSERT_EQUAL(aTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(aParaText, rDoc.GetParaAsString(sal_Int32(0)));

    // Apply Bold to appropriate selection
    pSet->Put(aBold);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pSet->Count());
    aEditEngine.QuickSetAttribs(*pSet, ESelection(0, 2, 0, 14));

    // Assert changes
    std::unique_ptr<EditTextObject> pEditText1(aEditEngine.CreateTextObject());
    std::vector<editeng::Section> aAttrs1;
    pEditText1->GetAllSections(aAttrs1);
    // There should be 3 sections - woBold - wBold - woBold (w - with, wo - without)
    CPPUNIT_ASSERT_EQUAL(size_t(3), aAttrs1.size());

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[0].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[0].mnStart));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs1[0].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[0].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[1].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs1[1].mnStart));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs1[1].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs1[1].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs1[1]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[2].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs1[2].mnStart));
    CPPUNIT_ASSERT_EQUAL(20, static_cast<int>(aAttrs1[2].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[2].maAttributes.size()));

    // Apply Italic to appropriate selection
    pSet.reset(new SfxItemSet(aEditEngine.GetEmptyItemSet()));
    pSet->Put(aItalic);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pSet->Count());
    aEditEngine.QuickSetAttribs(*pSet, ESelection(0, 8, 0, 18));

    // Assert changes
    std::unique_ptr<EditTextObject> pEditText2(aEditEngine.CreateTextObject());
    std::vector<editeng::Section> aAttrs2;
    pEditText2->GetAllSections(aAttrs2);
    // There should be 5 sections - woBold&woItalic - wBold&woItalic - wBold&wItalic - woBold&wItalic - woBold&woItalic&nbsp;(w - with, wo - without)
    CPPUNIT_ASSERT_EQUAL(size_t(5), aAttrs2.size());

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[0].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[0].mnStart));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs2[0].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[0].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[1].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs2[1].mnStart));
    CPPUNIT_ASSERT_EQUAL(8, static_cast<int>(aAttrs2[1].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[1].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs2[1]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[2].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(8, static_cast<int>(aAttrs2[2].mnStart));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs2[2].mnEnd));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs2[2].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(aAttrs2[2]));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasItalic(aAttrs2[2]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[3].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs2[3].mnStart));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs2[3].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[3].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(aAttrs2[3]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[4].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs2[4].mnStart));
    CPPUNIT_ASSERT_EQUAL(20, static_cast<int>(aAttrs2[4].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[4].maAttributes.size()));

    // Copy text using legacy format
    uno::Reference<datatransfer::XTransferable> xData
        = aEditEngine.CreateTransferable(ESelection(0, 1, 0, aTextLen - 1));

    // Paste text at the end
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Assert changes
    CPPUNIT_ASSERT_EQUAL(aTextLen + aTextLen - 2, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(aParaText + "oldeditengineitali"),
                         rDoc.GetParaAsString(sal_Int32(0)));

    // Check updated text for appropriate Bold/Italics
    std::unique_ptr<EditTextObject> pEditText3(aEditEngine.CreateTextObject());
    std::vector<editeng::Section> aAttrs3;
    pEditText3->GetAllSections(aAttrs3);
    // There should be 9 sections - woBold&woItalic - wBold&woItalic - wBold&wItalic - woBold&wItalic - woBold&woItalic&nbsp;- wBold&woItalic
    // - wBold&wItalic - woBold&wItalic - woBold&woItalic(w - with, wo - without)
    CPPUNIT_ASSERT_EQUAL(size_t(9), aAttrs3.size());

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[0].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[0].mnStart));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs3[0].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[0].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[1].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs3[1].mnStart));
    CPPUNIT_ASSERT_EQUAL(8, static_cast<int>(aAttrs3[1].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[1].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs3[1]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[2].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(8, static_cast<int>(aAttrs3[2].mnStart));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs3[2].mnEnd));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs3[2].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(aAttrs3[2]));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasItalic(aAttrs3[2]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[3].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs3[3].mnStart));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs3[3].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[3].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(aAttrs3[3]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[4].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs3[4].mnStart));
    CPPUNIT_ASSERT_EQUAL(21, static_cast<int>(aAttrs3[4].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[4].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[5].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(21, static_cast<int>(aAttrs3[5].mnStart));
    CPPUNIT_ASSERT_EQUAL(27, static_cast<int>(aAttrs3[5].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[5].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs3[5]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[6].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(27, static_cast<int>(aAttrs3[6].mnStart));
    CPPUNIT_ASSERT_EQUAL(33, static_cast<int>(aAttrs3[6].mnEnd));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs3[6].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(aAttrs3[6]));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasItalic(aAttrs3[6]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[7].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(33, static_cast<int>(aAttrs3[7].mnStart));
    CPPUNIT_ASSERT_EQUAL(37, static_cast<int>(aAttrs3[7].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[7].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(aAttrs3[7]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[8].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(37, static_cast<int>(aAttrs3[8].mnStart));
    CPPUNIT_ASSERT_EQUAL(38, static_cast<int>(aAttrs3[8].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[8].maAttributes.size()));
}

// Auxiliary function to test Underline text Copy/Paste using Legacy Format
bool hasUnderline(const editeng::Section& rSecAttr)
{
    return std::any_of(
        rSecAttr.maAttributes.begin(), rSecAttr.maAttributes.end(), [](const SfxPoolItem* p) {
            return p->Which() == EE_CHAR_UNDERLINE
                   && static_cast<const SvxUnderlineItem*>(p)->GetLineStyle() == LINESTYLE_SINGLE;
        });
}

void Test::testUnderlineCopyPaste()
{
    // Create EditEngine's instance
    EditEngine aEditEngine(mpItemPool.get());

    // Get EditDoc for current EditEngine's instance
    EditDoc& rDoc = aEditEngine.GetEditDoc();

    // New instance must be empty - no initial text
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));

    // Get corresponding ItemSet for inserting Underline text
    std::unique_ptr<SfxItemSet> pSet(new SfxItemSet(aEditEngine.GetEmptyItemSet()));
    SvxUnderlineItem aULine(LINESTYLE_SINGLE, EE_CHAR_UNDERLINE);

    // Insert initial text
    OUString aParaText = u"sampletextforunderline"_ustr;
    // Positions Ref      ......*6.........*17..
    // Underline Ref      ......[UNDERLINE ]....
    sal_Int32 aTextLen = aParaText.getLength();
    aEditEngine.SetText(aParaText);

    // Apply Underline style
    pSet->Put(aULine);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pSet->Count());
    aEditEngine.QuickSetAttribs(*pSet, ESelection(0, 6, 0, 18));

    // Assert changes
    std::unique_ptr<EditTextObject> pEditText1(aEditEngine.CreateTextObject());
    std::vector<editeng::Section> aAttrs1;
    pEditText1->GetAllSections(aAttrs1);

    // There should be 3 sections - woUnderline - wUnderline - woUnderline (w - with, wo - without)
    CPPUNIT_ASSERT_EQUAL(size_t(3), aAttrs1.size());

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[0].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[0].mnStart));
    CPPUNIT_ASSERT_EQUAL(6, static_cast<int>(aAttrs1[0].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[0].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[1].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(6, static_cast<int>(aAttrs1[1].mnStart));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs1[1].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs1[1].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be underlined.", hasUnderline(aAttrs1[1]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[2].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs1[2].mnStart));
    CPPUNIT_ASSERT_EQUAL(22, static_cast<int>(aAttrs1[2].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[2].maAttributes.size()));

    // Copy text using legacy format
    uno::Reference<datatransfer::XTransferable> xData
        = aEditEngine.CreateTransferable(ESelection(0, 6, 0, aTextLen - 4));

    // Paste text at the end
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Assert changes
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(aTextLen + strlen("textforunder")),
                         rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(aParaText + "textforunder"), rDoc.GetParaAsString(sal_Int32(0)));

    // Check updated text for appropriate Underline
    std::unique_ptr<EditTextObject> pEditText2(aEditEngine.CreateTextObject());
    std::vector<editeng::Section> aAttrs2;
    pEditText2->GetAllSections(aAttrs2);

    // There should be 4 sections - woUnderline - wUnderline - woUnderline - wUnderline (w - with, wo - without)
    CPPUNIT_ASSERT_EQUAL(size_t(4), aAttrs2.size());

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[0].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[0].mnStart));
    CPPUNIT_ASSERT_EQUAL(6, static_cast<int>(aAttrs2[0].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[0].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[1].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(6, static_cast<int>(aAttrs2[1].mnStart));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs2[1].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[1].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be underlined.", hasUnderline(aAttrs2[1]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[2].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs2[2].mnStart));
    CPPUNIT_ASSERT_EQUAL(22, static_cast<int>(aAttrs2[2].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[2].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[3].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(22, static_cast<int>(aAttrs2[3].mnStart));
    CPPUNIT_ASSERT_EQUAL(34, static_cast<int>(aAttrs2[3].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[3].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be underlined.", hasUnderline(aAttrs2[3]));
}

void Test::testMultiParaCopyPaste()
{
    // Create EditEngine's instance
    EditEngine aEditEngine(mpItemPool.get());

    // Get EditDoc for current EditEngine's instance
    EditDoc& rDoc = aEditEngine.GetEditDoc();

    // Initially no text should be there
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));

    // Insert initial text
    OUString aFirstPara = u"This is first paragraph"_ustr;
    OUString aSecondPara = u"This is second paragraph"_ustr;
    OUString aThirdPara = u"This is third paragraph"_ustr;
    OUString aText = aFirstPara + "\n" + aSecondPara + "\n" + aThirdPara;
    sal_Int32 aTextLen = aFirstPara.getLength() + aSecondPara.getLength() + aThirdPara.getLength();
    aEditEngine.SetText(aText);
    sal_Int32 aCopyTextLen = aFirstPara.getLength() + aSecondPara.getLength();

    // Assert changes
    CPPUNIT_ASSERT_EQUAL(aTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(aFirstPara, rDoc.GetParaAsString(sal_Int32(0)));
    CPPUNIT_ASSERT_EQUAL(aSecondPara, rDoc.GetParaAsString(sal_Int32(1)));
    CPPUNIT_ASSERT_EQUAL(aThirdPara, rDoc.GetParaAsString(sal_Int32(2)));

    // Copy initial text using legacy format
    uno::Reference<datatransfer::XTransferable> xData
        = aEditEngine.CreateTransferable(ESelection(0, 0, 1, aSecondPara.getLength()));

    // Paste text at the end
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Assert changes
    OUString aThirdParaAfterCopyPaste = aThirdPara + aFirstPara;
    CPPUNIT_ASSERT_EQUAL(aTextLen + aCopyTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(aFirstPara, rDoc.GetParaAsString(sal_Int32(0)));
    CPPUNIT_ASSERT_EQUAL(aSecondPara, rDoc.GetParaAsString(sal_Int32(1)));
    CPPUNIT_ASSERT_EQUAL(aThirdParaAfterCopyPaste, rDoc.GetParaAsString(sal_Int32(2)));
    CPPUNIT_ASSERT_EQUAL(aSecondPara, rDoc.GetParaAsString(sal_Int32(3)));
}

void Test::testParaBoldItalicCopyPaste()
{
    // Create EditEngine's instance
    EditEngine aEditEngine(mpItemPool.get());

    // Get EditDoc for current EditEngine's instance
    EditDoc& rDoc = aEditEngine.GetEditDoc();

    // Initially no text should be there
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(OUString(), rDoc.GetParaAsString(sal_Int32(0)));

    // Get corresponding ItemSet for inserting Bold/Italic text
    std::unique_ptr<SfxItemSet> pSet(new SfxItemSet(aEditEngine.GetEmptyItemSet()));
    SvxWeightItem aBold(WEIGHT_BOLD, EE_CHAR_WEIGHT);
    SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);

    // Insert initial text
    OUString aFirstPara = u"This is first paragraph"_ustr;
    // Positions Ref       .....*5.*8....*14*17...
    // Bold Ref            .....[    BOLD   ].....
    // Italic Ref          ..............[     ITA
    // Copy Ref            ........[      Copy Sel
    OUString aSecondPara = u"This is second paragraph"_ustr;
    // Positions Ref        .....*5.*8...*13..*18...
    // Bold Ref             .....[    BOLD    ].....
    // Italic Ref           LIC     ]...............
    // Copy Ref             ection       ]..........
    OUString aThirdPara = u"This is third paragraph"_ustr;
    OUString aText = aFirstPara + "\n" + aSecondPara + "\n" + aThirdPara;
    sal_Int32 aTextLen = aFirstPara.getLength() + aSecondPara.getLength() + aThirdPara.getLength();
    aEditEngine.SetText( aText );
    OUString aCopyText = u"first paragraphThis is second"_ustr;
    sal_Int32 aCopyTextLen = aCopyText.getLength();

    // Assert changes - text insertion
    CPPUNIT_ASSERT_EQUAL(aTextLen, rDoc.GetTextLen());
    CPPUNIT_ASSERT_EQUAL(aFirstPara, rDoc.GetParaAsString(sal_Int32(0)));
    CPPUNIT_ASSERT_EQUAL(aSecondPara, rDoc.GetParaAsString(sal_Int32(1)));
    CPPUNIT_ASSERT_EQUAL(aThirdPara, rDoc.GetParaAsString(sal_Int32(2)));

    // Apply Bold to appropriate selections
    pSet->Put(aBold);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pSet->Count());
    aEditEngine.QuickSetAttribs(*pSet, ESelection(0, 5, 0, 18));
    aEditEngine.QuickSetAttribs(*pSet, ESelection(1, 5, 1, 19));

    // Assert changes
    std::unique_ptr<EditTextObject> pEditText1(aEditEngine.CreateTextObject());
    std::vector<editeng::Section> aAttrs1;
    pEditText1->GetAllSections(aAttrs1);
    // There should be 7 sections - woB - wB - woB -woB -wB -woB -woB (w - with, wo - without, B - Bold, I - Italic)
    CPPUNIT_ASSERT_EQUAL(size_t(7), aAttrs1.size());

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[0].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[0].mnStart));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs1[0].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[0].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[1].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs1[1].mnStart));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs1[1].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs1[1].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs1[1]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[2].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs1[2].mnStart));
    CPPUNIT_ASSERT_EQUAL(23, static_cast<int>(aAttrs1[2].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[2].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs1[3].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[3].mnStart));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs1[3].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[3].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs1[4].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs1[4].mnStart));
    CPPUNIT_ASSERT_EQUAL(19, static_cast<int>(aAttrs1[4].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs1[4].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs1[4]));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs1[5].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(19, static_cast<int>(aAttrs1[5].mnStart));
    CPPUNIT_ASSERT_EQUAL(24, static_cast<int>(aAttrs1[5].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[5].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs1[6].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[6].mnStart));
    CPPUNIT_ASSERT_EQUAL(23, static_cast<int>(aAttrs1[6].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs1[6].maAttributes.size()));

    // Apply Italic to appropriate selection
    pSet.reset(new SfxItemSet(aEditEngine.GetEmptyItemSet()));
    pSet->Put(aItalic);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pSet->Count());
    aEditEngine.QuickSetAttribs(*pSet, ESelection(0, 14, 1, 9));

    // Assert changes
    std::unique_ptr<EditTextObject> pEditText2(aEditEngine.CreateTextObject());
    std::vector<editeng::Section> aAttrs2;
    pEditText2->GetAllSections(aAttrs2);
    // There should be 9 sections - woB&woI - wB&woI - wB&wI -woB&wI - woB&wI - wB&wI - wB&woI&nbsp;- woB&woI - woB&woI (w - with, wo - without, B - Bold, I - Italic)
    CPPUNIT_ASSERT_EQUAL(size_t(9), aAttrs2.size());

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[0].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[0].mnStart));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs2[0].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[0].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[1].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs2[1].mnStart));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs2[1].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[1].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs2[1]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[2].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs2[2].mnStart));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs2[2].mnEnd));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs2[2].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(aAttrs2[2]));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasItalic(aAttrs2[2]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[3].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs2[3].mnStart));
    CPPUNIT_ASSERT_EQUAL(23, static_cast<int>(aAttrs2[3].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[3].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(aAttrs2[3]));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[4].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[4].mnStart));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs2[4].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[4].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(aAttrs2[4]));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[5].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs2[5].mnStart));
    CPPUNIT_ASSERT_EQUAL(9, static_cast<int>(aAttrs2[5].mnEnd));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs2[5].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(aAttrs2[5]));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasItalic(aAttrs2[5]));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[6].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(9, static_cast<int>(aAttrs2[6].mnStart));
    CPPUNIT_ASSERT_EQUAL(19, static_cast<int>(aAttrs2[6].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[6].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs2[6]));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs2[7].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(19, static_cast<int>(aAttrs2[7].mnStart));
    CPPUNIT_ASSERT_EQUAL(24, static_cast<int>(aAttrs2[7].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[7].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs2[8].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[8].mnStart));
    CPPUNIT_ASSERT_EQUAL(23, static_cast<int>(aAttrs2[8].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs2[8].maAttributes.size()));

    // Copy text using legacy format
    uno::Reference<datatransfer::XTransferable> xData
        = aEditEngine.CreateTransferable(ESelection(0, 8, 1, 14));

    // Paste text at the end
    aEditEngine.InsertText(xData, OUString(), rDoc.GetEndPaM(), true);

    // Assert changes
    OUString aThirdParaAfterCopyPaste = aThirdPara + "first paragraph";
    CPPUNIT_ASSERT_EQUAL( aTextLen + aCopyTextLen, rDoc.GetTextLen() );
    CPPUNIT_ASSERT_EQUAL( aFirstPara, rDoc.GetParaAsString(sal_Int32(0)) );
    CPPUNIT_ASSERT_EQUAL( aSecondPara, rDoc.GetParaAsString(sal_Int32(1)) );
    CPPUNIT_ASSERT_EQUAL( aThirdParaAfterCopyPaste, rDoc.GetParaAsString(sal_Int32(2)) );
    CPPUNIT_ASSERT_EQUAL( u"This is second"_ustr, rDoc.GetParaAsString(sal_Int32(3)) );

    // Check updated text for appropriate Bold/Italics
    std::unique_ptr<EditTextObject> pEditText3(aEditEngine.CreateTextObject());
    std::vector<editeng::Section> aAttrs3;
    pEditText3->GetAllSections(aAttrs3);
    // There should be 15 sections - woB&woI - wB&woI - wB&wI -woB&wI - woB&wI - wB&wI - wB&woI&nbsp;- woB&woI - woB&woI
    // - wB&woI - wB&wI - woB&wI - -woB&wI - wB&wI - wB&woI (w - with, wo - without, B - Bold, I - Italic)
    CPPUNIT_ASSERT_EQUAL(size_t(15), aAttrs3.size());

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[0].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[0].mnStart));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs3[0].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[0].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[1].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs3[1].mnStart));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs3[1].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[1].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs3[1]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[2].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(14, static_cast<int>(aAttrs3[2].mnStart));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs3[2].mnEnd));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs3[2].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(aAttrs3[2]));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasItalic(aAttrs3[2]));

    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[3].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(18, static_cast<int>(aAttrs3[3].mnStart));
    CPPUNIT_ASSERT_EQUAL(23, static_cast<int>(aAttrs3[3].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[3].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(aAttrs3[3]));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[4].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[4].mnStart));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs3[4].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[4].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be italic.", hasItalic(aAttrs3[4]));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[5].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(aAttrs3[5].mnStart));
    CPPUNIT_ASSERT_EQUAL(9, static_cast<int>(aAttrs3[5].mnEnd));
    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs3[5].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasBold(aAttrs3[5]));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold and italic.", hasItalic(aAttrs3[5]));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[6].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(9, static_cast<int>(aAttrs3[6].mnStart));
    CPPUNIT_ASSERT_EQUAL(19, static_cast<int>(aAttrs3[6].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[6].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs3[6]));

    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[7].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(19, static_cast<int>(aAttrs3[7].mnStart));
    CPPUNIT_ASSERT_EQUAL(24, static_cast<int>(aAttrs3[7].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[7].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs3[8].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[8].mnStart));
    CPPUNIT_ASSERT_EQUAL(23, static_cast<int>(aAttrs3[8].mnEnd));
    CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(aAttrs3[8].maAttributes.size()));

    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs3[9].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(23, static_cast<int>(aAttrs3[9].mnStart));
    CPPUNIT_ASSERT_EQUAL(29, static_cast<int>(aAttrs3[9].mnEnd));
    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aAttrs3[9].maAttributes.size()));
    CPPUNIT_ASSERT_MESSAGE("This section must be bold.", hasBold(aAttrs3[9]));

    CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(aAttrs3[10].mnParagraph));
    CPPUNIT_ASSERT_EQUAL(29, static_cast<int>(aAttrs3[10].mnStart));
    CPPUNIT_ASSERT_EQUAL(33, static_cast<int>(aAttrs3[10].mnEnd));
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=98 G=95

¤ Dauer der Verarbeitung: 0.25 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.