/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the Collabora Office 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 <swmodeltestbase.hxx>
#include <COKit/COKit.hxx>
#include <vcl/filter/PDFiumLibrary.hxx>
#include <vcl/scheduler.hxx>
#include <vcl/TypeSerializer.hxx>
#include <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/style/ParagraphAdjust.hpp>
#include <com/sun/star/drawing/GraphicExportFilter.hpp>
#include <IDocumentDrawModelAccess.hxx>
#include <com/sun/star/text/XTextFrame.hpp>
#include <com/sun/star/text/XTextTable.hpp>
#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
#include <com/sun/star/text/XPageCursor.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>
#include <comphelper/kit.hxx>
#include <comphelper/propertysequence.hxx>
#include <boost/property_tree/json_parser.hpp>
#include <frameformats.hxx>
#include <i18nlangtag/languagetag.hxx>
#include <tools/json_writer.hxx>
#include <unotools/streamwrap.hxx>
#include <editeng/adjustitem.hxx>
#include <editeng/lrspitem.hxx>
#include <sfx2/linkmgr.hxx>

#include <wrtsh.hxx>
#include <UndoManager.hxx>
#include <unotxdoc.hxx>
#include <drawdoc.hxx>
#include <dcontact.hxx>
#include <svx/svdpage.hxx>
#include <ndtxt.hxx>
#include <txtfld.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentLinksAdministration.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <rootfrm.hxx>
#include <redline.hxx>
#include <itabenum.hxx>
#include <officecfg/Office/Common.hxx>

using namespace css;
using namespace css::uno;

namespace
{
/// 8th set of tests asserting the behavior of Writer user interface shells.
class SwUiWriterTest8 : public SwModelTestBase
{
public:
    SwUiWriterTest8()
        : SwModelTestBase(u"/sw/qa/extras/uiwriter/data/"_ustr)
    {
        // $(vlang) names the autotext directory, and no view is here to set the Kit's language
        comphelper::COKit::setLanguageTag(LanguageTag(LANGUAGE_ENGLISH_US));
    }
};

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf131684)
{
    createSwDoc("tdf131684.docx");

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    //Use selectAll 3 times in a row
    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xIndexAccess->getCount());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    // without the fix, it crashes
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    // check that the text frame has the correct upper
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    OUString const sectionId = getXPath(pXmlDoc, "/root/page[1]/body/section[7]", "id");
    OUString const sectionLower = getXPath(pXmlDoc, "/root/page[1]/body/section[7]", "lower");
    OUString const textId = getXPath(pXmlDoc, "/root/page[1]/body/section[7]/txt[1]", "id");
    OUString const textUpper = getXPath(pXmlDoc, "/root/page[1]/body/section[7]/txt[1]", "upper");
    CPPUNIT_ASSERT_EQUAL(textId, sectionLower);
    CPPUNIT_ASSERT_EQUAL(sectionId, textUpper);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf132420)
{
    createSwDoc("tdf132420.odt");

    CPPUNIT_ASSERT_EQUAL(12, getShapes());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(0, getShapes());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    //Without the fix in place, 1 frame and 1 image would be gone and getShapes would return 10
    CPPUNIT_ASSERT_EQUAL(12, getShapes());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf132744)
{
    createSwDoc("tdf132744.odt");
    SwDoc* pDoc = getSwDoc();

    // disable change tracking to cut the table
    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::ShowDelete
                                                      | RedlineFlags::ShowInsert);

    CPPUNIT_ASSERT_MESSAGE("redlining should be off",
                           !pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(0, getShapes());

    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    //Without the fix in place, the image wouldn't be pasted
    CPPUNIT_ASSERT_EQUAL(1, getShapes());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf146622)
{
    createSwDoc("TC-table-del-add.docx");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTables->getCount());
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());

    dispatchCommand(mxComponent, u".uno:DeleteRows"_ustr, {});

    // This was 3 (deleting the already deleted row with change tracking)
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:DeleteRows"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:DeleteRows"_ustr, {});
    // This was 2 (deleting the already deleted table with change tracking)
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTables->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());

    // check that the first table was deleted with change tracking
    dispatchCommand(mxComponent, u".uno:AcceptAllTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());

    // Undo AcceptAllTrackedChanges and DeleteRows
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    // now only the second table deleted by AcceptAllTrackedChanges
    dispatchCommand(mxComponent, u".uno:AcceptAllTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf146962)
{
    // load a 2-row table, set Hide Changes mode and delete the first row with change tracking
    createSwDoc("tdf116789.fodt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    // hide changes
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    dispatchCommand(mxComponent, u".uno:DeleteRows"_ustr, {});

    // Without the fix in place, the deleted row would be visible

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // This was 2
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 1);

    // check it in Show Changes mode

    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(!pWrtShell->GetLayout()->IsHideRedlines());

    pXmlDoc = parseLayoutDump();
    // 2 rows are visible now
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);

    // check it in Hide Changes mode again

    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    pXmlDoc = parseLayoutDump();
    // only a single row is visible again
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 1);

    // tdf#148227 check Undo of tracked table row deletion

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    pXmlDoc = parseLayoutDump();
    // This was 1
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf159026)
{
    // load a floating table (tables in DOCX footnotes
    // imported as floating tables in Writer)
    createSwDoc("tdf159026.docx");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    // hide changes
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    // select table with SelectionSupplier
    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
    uno::Reference<view::XSelectionSupplier> xSelSupplier(xModel->getCurrentController(),
                                                          uno::UNO_QUERY_THROW);
    // select floating table (table in a frame)
    xSelSupplier->select(xIndexAccess->getByIndex(0));

    // delete table with track changes
    dispatchCommand(mxComponent, u".uno:DeleteTable"_ustr, {});

    // tracked table deletion
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    // hidden table
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "//tab", 0);

    // delete frame
    uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess2(xTextFramesSupplier->getTextFrames(),
                                                          uno::UNO_QUERY);
    xSelSupplier->select(xIndexAccess2->getByIndex(0));
    dispatchCommand(mxComponent, u".uno:Delete"_ustr, {});

    // undo frame deletion
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    // undo tracked table deletion

    // This resulted crashing
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf147347)
{
    // load a 2-row table, set Hide Changes mode and delete the table with change tracking
    createSwDoc("tdf116789.fodt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    // hide changes
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    dispatchCommand(mxComponent, u".uno:DeleteTable"_ustr, {});

    // Without the fix in place, the deleted row would be visible

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // This was 1
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 0);

    // check it in Show Changes mode

    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(!pWrtShell->GetLayout()->IsHideRedlines());

    pXmlDoc = parseLayoutDump();
    // 2 rows are visible now
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);

    // check it in Hide Changes mode again

    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    pXmlDoc = parseLayoutDump();
    // no visible row again
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 0);

    // tdf#148228 check Undo of tracked table deletion

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    pXmlDoc = parseLayoutDump();
    // This was 0
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf153819)
{
    // copy a table before a deleted table in Hide Changes mode
    createSwDoc("tdf153819.fodt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // hide changes
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    dispatchCommand(mxComponent, u".uno:SelectTable"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
    dispatchCommand(mxComponent, u".uno:GoDown"_ustr, {});

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    // FIXME: Show Changes, otherwise ~SwTableNode() would have crashed
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf148345)
{
    // load a 2-row table, set Hide Changes mode and delete the first row with change tracking
    createSwDoc("tdf116789.fodt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    // hide changes
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    dispatchCommand(mxComponent, u".uno:DeleteRows"_ustr, {});

    // Without the fix in place, the deleted row would be visible

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // This was 2
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 1);

    // check it in Show Changes mode

    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(!pWrtShell->GetLayout()->IsHideRedlines());

    pXmlDoc = parseLayoutDump();
    // 2 rows are visible now
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);

    // check it in Hide Changes mode again

    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    pXmlDoc = parseLayoutDump();
    // only a single row is visible again
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 1);

    // tdf#148227 check Reject All of tracked table row deletion

    dispatchCommand(mxComponent, u".uno:RejectAllTrackedChanges"_ustr, {});
    pXmlDoc = parseLayoutDump();
    // This was 1
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf141391)
{
    // table insertion in the first paragraph of the cell
    // overwrites the row content, instead of inserting a nested table

    // load a 2-row table
    createSwDoc("tdf116789.fodt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // select the table, and copy it into at paragraph start of cell "A2"

    dispatchCommand(mxComponent, u".uno:SelectTable"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
    // remove the selection and positionate the cursor at beginning of A2
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // 3-row, overwriting cells of the second row and inserting a new row
    // with the 2-row clipboard table content
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 3);
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout",
                "portion", u"hello");

    // Undo

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    pXmlDoc = parseLayoutDump();
    // 2 rows again, no copied text content
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[1]/SwParaPortion", 0);

    // insert the 2-row table into the second paragraph of cell "A2" as a nested table
    // For this it's enough to positionate the text cursor not in the first paragraph

    // insert some text and an empty paragraph
    pWrtShell->Insert(u"Some text..."_ustr);
    pWrtShell->SplitNode();
    Scheduler::ProcessEventsToIdle();
    pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[1]/txt", 2);
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[1]/txt[1]/SwParaPortion/SwLineLayout",
                "portion", u"Some text...");
    // the empty paragraph in A2
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[1]/txt[2]/SwParaPortion", 0);

    // insert the table, as a nested one in cell "A2"
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
    pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[1]/tab", 1);
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[1]/tab/row", 2);

    // Undo

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    pXmlDoc = parseLayoutDump();
    // 2 rows again, no copied text content
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[1]/txt[1]/SwParaPortion/SwLineLayout",
                "portion", u"Some text...");

    // copy the 2-row table into the first paragraph of cell "A2",
    // but not at paragraph start (changed behaviour)

    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
    pWrtShell->Insert(u"and some text again in the first paragraph to be sure..."_ustr);
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    pXmlDoc = parseLayoutDump();

    // 3-row, overwriting cells of the second row and inserting a new row
    // with the 2-row clipboard table content

    // This was 2 (nested table)
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 3);
    // This was "Some text..." with a nested table
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout",
                "portion", u"hello");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf148791)
{
    // test Paste as Rows Above with centered table alignment

    // load a 2-row table
    createSwDoc("tdf116789.fodt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // select and copy the table, and Paste As Rows Above

    dispatchCommand(mxComponent, u".uno:SelectTable"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
    // remove the selection and positionate the cursor at beginning of A2
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
    pWrtShell->Up(/*bSelect=*/false);
    dispatchCommand(mxComponent, u".uno:PasteRowsBefore"_ustr, {});

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // Paste as Rows Above results 4-row table with default table alignment
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 4);
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[1]/cell[1]/txt/SwParaPortion/SwLineLayout",
                "portion", u"hello");
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[3]/cell[1]/txt/SwParaPortion/SwLineLayout",
                "portion", u"hello");

    // set table alignment to center, select and copy the table again
    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);

    // Default table alignment
    CPPUNIT_ASSERT_EQUAL(text::HoriOrientation::FULL,
                         getProperty<sal_Int16>(xTextTable, u"HoriOrient"_ustr));

    //CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xTextTable, "TableTemplateName"));
    uno::Reference<beans::XPropertySet> xTableProps(xTextTable, uno::UNO_QUERY_THROW);

    xTableProps->setPropertyValue(u"HoriOrient"_ustr, cpo::uno::Any(text::HoriOrientation::CENTER));

    CPPUNIT_ASSERT_EQUAL(text::HoriOrientation::CENTER,
                         getProperty<sal_Int16>(xTextTable, u"HoriOrient"_ustr));

    dispatchCommand(mxComponent, u".uno:SelectTable"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
    // remove the selection and positionate the cursor at beginning of A2
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
    pWrtShell->Up(/*bSelect=*/false);
    pWrtShell->Up(/*bSelect=*/false);
    pWrtShell->Up(/*bSelect=*/false);
    dispatchCommand(mxComponent, u".uno:PasteRowsBefore"_ustr, {});

    pXmlDoc = parseLayoutDump();
    // This was 5 (inserting only a single row for the 4-row clipboard content, and
    // overwriting 3 existing rows)
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 8);
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[1]/cell[1]/txt/SwParaPortion/SwLineLayout",
                "portion", u"hello");
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[3]/cell[1]/txt/SwParaPortion/SwLineLayout",
                "portion", u"hello");
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[5]/cell[1]/txt/SwParaPortion/SwLineLayout",
                "portion", u"hello");
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row[7]/cell[1]/txt/SwParaPortion/SwLineLayout",
                "portion", u"hello");

    // tdf#64902 add a test case for nested tables

    // insert a nested table, and copy as paste as rows above the whole table with it
    dispatchCommand(mxComponent, u".uno:PasteNestedTable"_ustr, {});
    dispatchCommand(mxComponent, u".uno:SelectTable"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
    // remove the selection and positionate the cursor at beginning of A2
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
    // skip 7 table rows plus 4 rows of the nested table
    for (int i = 0; i < 7 + 4; ++i)
        pWrtShell->Up(/*bSelect=*/false);
    dispatchCommand(mxComponent, u".uno:PasteRowsBefore"_ustr, {});

    pXmlDoc = parseLayoutDump();
    // rows of the nested table doesn't effect row number of the main table
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 16);
    // there are two nested tables after the paste
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/tab", 2);

    // tdf#64902 add a test case for repeated table headings

    xTableProps->setPropertyValue(u"RepeatHeadline"_ustr, cpo::uno::Any(true));
    CPPUNIT_ASSERT(getProperty<bool>(xTextTable, u"RepeatHeadline"_ustr));

    xTableProps->setPropertyValue(u"HeaderRowCount"_ustr, cpo::uno::Any(sal_Int32(3)));
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), getProperty<sal_Int32>(xTextTable, u"HeaderRowCount"_ustr));

    dispatchCommand(mxComponent, u".uno:SelectTable"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
    // remove the selection and positionate the cursor at beginning of A2
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
    // skip 15 table rows plus 4 * 2 rows of the nested tables
    for (int i = 0; i < 15 + 4 * 2; ++i)
        pWrtShell->Up(/*bSelect=*/false);
    dispatchCommand(mxComponent, u".uno:PasteRowsBefore"_ustr, {});

    pXmlDoc = parseLayoutDump();
    // repeating table header (and its thead/tbody indentation) doesn't effect row number
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 32);
    // there are two nested tables after the paste
    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/tab", 4);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf135014)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(
        comphelper::InitPropertySequence({ { "KeyModifier", cpo::uno::Any(sal_Int32(0)) } }));

    // Toggle Numbering List
    dispatchCommand(mxComponent, u".uno:DefaultBullet"_ustr, aArgs);

    cpo::uno::Sequence<beans::PropertyValue> aArgs2(comphelper::InitPropertySequence(
        { { "Param", cpo::uno::Any(u"NewNumberingStyle"_ustr) },
          { "Family", cpo::uno::Any(static_cast<sal_Int16>(SfxStyleFamily::Pseudo)) } }));

    // New Style from selection
    dispatchCommand(mxComponent, u".uno:StyleNewByExample"_ustr, aArgs2);

    // Without the fix in place, this test would have failed here
    saveAndReload(TestFilter::DOCX);

    xmlDocUniquePtr pXmlStyles = parseExport(u"word/styles.xml"_ustr);
    assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='NewNumberingStyle']/w:qFormat", 1);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf130629)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(
        comphelper::InitPropertySequence({ { "KeyModifier", cpo::uno::Any(KEY_MOD1) } }));

    dispatchCommand(mxComponent, u".uno:BasicShapes.diamond"_ustr, aArgs);

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    // Undo twice
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(0, getShapes());

    // Shape toolbar is active, use ESC before inserting a new shape
    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_ESCAPE);
    Scheduler::ProcessEventsToIdle();

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:BasicShapes.diamond"_ustr, aArgs);

    CPPUNIT_ASSERT_EQUAL(1, getShapes());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf145584)
{
    std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
    if (!pPDFium)
    {
        return;
    }
    createSwDoc();
    SwWrtShell* const pWrtSh = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtSh);

    pWrtSh->Insert(u"Hello World"_ustr);

    // Select 'World'
    pWrtSh->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 5, /*bBasicCall=*/false);

    // Save as PDF.
    cpo::uno::Sequence<beans::PropertyValue> aFilterData(
        comphelper::InitPropertySequence({ { "Selection", cpo::uno::Any(true) } }));

    cpo::uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
        { { "FilterName", cpo::uno::Any(u"writer_pdf_Export"_ustr) },
          { "FilterData", cpo::uno::Any(aFilterData) },
          { "URL", cpo::uno::Any(maTempFile.GetURL()) } }));

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:ExportToPDF"_ustr, aDescriptor);

    std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
    CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount());
    std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0);
    CPPUNIT_ASSERT(pPdfPage);
    CPPUNIT_ASSERT_EQUAL(1, pPdfPage->getObjectCount());
    std::unique_ptr<vcl::pdf::PDFiumTextPage> pPdfTextPage = pPdfPage->getTextPage();
    CPPUNIT_ASSERT(pPdfTextPage);

    std::unique_ptr<vcl::pdf::PDFiumPageObject> pPageObject = pPdfPage->getObject(0);
    OUString sText = pPageObject->getText(pPdfTextPage);
    CPPUNIT_ASSERT_EQUAL(u"World"_ustr, sText);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf131728)
{
    std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
    if (!pPDFium)
    {
        return;
    }
    createSwDoc("tdf131728.docx");
    SwDoc* const pDoc = getSwDoc();
    SwWrtShell* const pWrtSh = pDoc->GetDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtSh);

    // Save as PDF.
    cpo::uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence(
        { { "ExportBookmarksToPDFDestination", cpo::uno::Any(true) } }));

    cpo::uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
        { { "FilterName", cpo::uno::Any(u"writer_pdf_Export"_ustr) },
          { "FilterData", cpo::uno::Any(aFilterData) },
          { "URL", cpo::uno::Any(maTempFile.GetURL()) } }));

    dispatchCommand(mxComponent, u".uno:ExportToPDF"_ustr, aDescriptor);

    std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
    CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount());

    std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0);
    CPPUNIT_ASSERT(pPdfPage);

    // Without the fix in place, this test would have bad order
    // (starting with the outlines of text frames)
    CPPUNIT_ASSERT_EQUAL(u"Article 1. Definitions\n"
                         " Apple\n"
                         " Bread\n"
                         " Cable\n"
                         " Cable\n" // ???
                         "Article 2. Three style separators in one line!\n"
                         " Heading 2\n"
                         " Heading 2 Again\n"_ustr,
                         pPdfDocument->getBookmarks());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf95239)
{
    std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
    if (!pPDFium)
    {
        return;
    }
    createSwDoc("tdf95239.fodt");
    SwDoc* const pDoc = getSwDoc();
    SwWrtShell* const pWrtSh = pDoc->GetDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtSh);

    // Save as PDF.
    cpo::uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence(
        { { "ExportBookmarksToPDFDestination", cpo::uno::Any(true) } }));

    cpo::uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
        { { "FilterName", cpo::uno::Any(u"writer_pdf_Export"_ustr) },
          { "FilterData", cpo::uno::Any(aFilterData) },
          { "URL", cpo::uno::Any(maTempFile.GetURL()) } }));

    dispatchCommand(mxComponent, u".uno:ExportToPDF"_ustr, aDescriptor);

    std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
    CPPUNIT_ASSERT_EQUAL(2, pPdfDocument->getPageCount());

    std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0);
    CPPUNIT_ASSERT(pPdfPage);

    // Without the fix in place, this test would have bad order
    // (starting with the outlines of text frames)
    CPPUNIT_ASSERT_EQUAL(u"H1\n"
                         " H2\n"
                         "  H3\n"
                         "   Lorem\n"
                         "    Vestibulum\n"
                         "    Integer\n"
                         "   Aliquam\n"
                         "    Donec\n"
                         "    Praesent\n"
                         "  H3\n"
                         "   Lorem\n"
                         "    Vestibulum\n"
                         "    Integer\n"
                         "   Aliquam\n"
                         "    Donec\n"
                         "    Praesent\n"
                         "H1\n"
                         " H2\n"
                         "  H3\n"
                         "   Lorem\n"
                         "    Vestibulum\n"
                         "    Integer\n"
                         "   Aliquam\n"
                         "    Donec\n"
                         "    Praesent\n"_ustr,
                         pPdfDocument->getBookmarks());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf152575)
{
    std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
    if (!pPDFium)
        return;

    createSwDoc("152575.fodt");

    // Save as PDF.
    cpo::uno::Sequence<beans::PropertyValue> aFilterData(
        comphelper::InitPropertySequence({ { "ExportNotesInMargin", cpo::uno::Any(true) } }));

    cpo::uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence(
        { { "FilterName", cpo::uno::Any(u"writer_pdf_Export"_ustr) },
          { "FilterData", cpo::uno::Any(aFilterData) },
          { "URL", cpo::uno::Any(maTempFile.GetURL()) } }));

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:ExportToPDF"_ustr, aDescriptor);

    std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport();
    CPPUNIT_ASSERT_EQUAL(3, pPdfDocument->getPageCount());
    std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/1);
    CPPUNIT_ASSERT(pPdfPage);
    // Without the fix for tdf#152575 this would be only 44 objects
    CPPUNIT_ASSERT_EQUAL(53, pPdfPage->getObjectCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf140731)
{
    createSwDoc();
    SwDoc* const pDoc = getSwDoc();
    SwWrtShell* const pWrtSh = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtSh);

    pWrtSh->Insert(u"Lorem"_ustr);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_F3);
    Scheduler::ProcessEventsToIdle();

    // generating a big text with ~60k words and several paragraphs
    for (sal_Int32 i = 0; i < 8; ++i)
    {
        dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

        dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});

        dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

        dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
    }

    dispatchCommand(mxComponent, u".uno:GoToStartOfDoc"_ustr, {});

    // Format->Text operations on small selections (which would generate <~500 redlines)
    // changetracking still working
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});

    SwCursorShell* pShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pShell);

    pShell->SelectTextModel(1, 500);

    dispatchCommand(mxComponent, u".uno:ChangeCaseToTitleCase"_ustr, {});

    SwEditShell* const pEditShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pEditShell);
    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(120),
                         pEditShell->GetRedlineCount());

    //Removing all the redlines.
    dispatchCommand(mxComponent, u".uno:RejectAllTrackedChanges"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(0), pEditShell->GetRedlineCount());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:ChangeCaseToTitleCase"_ustr, {});

    // Without the fix in place, on big selections writer would freeze. Now it ignores change tracking.
    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(0), pEditShell->GetRedlineCount());

    // The patch has no effects on the Format->Text operations
    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Lorem Ipsum Dolor Sit Amet"));

    dispatchCommand(mxComponent, u".uno:ChangeCaseToUpper"_ustr, {});

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("LOREM IPSUM DOLOR SIT AMET"));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf116315)
{
    createSwDoc();
    SwWrtShell* const pWrtSh = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtSh);

    pWrtSh->Insert(u"This is a test"_ustr);
    pWrtSh->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 4, /*bBasicCall=*/false);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    for (sal_Int32 i = 0; i < 5; ++i)
    {
        pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_SHIFT | KEY_F3);
        Scheduler::ProcessEventsToIdle();

        // Title Case
        CPPUNIT_ASSERT_EQUAL(u"This is a Test"_ustr, getParagraph(1)->getString());

        pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_SHIFT | KEY_F3);
        Scheduler::ProcessEventsToIdle();

        // Upper Case
        CPPUNIT_ASSERT_EQUAL(u"This is a TEST"_ustr, getParagraph(1)->getString());

        pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_SHIFT | KEY_F3);
        Scheduler::ProcessEventsToIdle();

        // Lower Case
        CPPUNIT_ASSERT_EQUAL(u"This is a test"_ustr, getParagraph(1)->getString());
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testInsertAutoTextIntoListFromParaStyle)
{
    createSwDoc("stylewithlistandindents.fodt");
    SwWrtShell* const pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    pWrtShell->FwdPara();
    pWrtShell->EndPara(/*bSelect=*/false);
    // expands autotext (via F3)
    pWrtShell->Insert(u" jacr"_ustr);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_F3);
    Scheduler::ProcessEventsToIdle();

    pWrtShell->SttEndDoc(/*bStt=*/true);
    pWrtShell->FwdPara();

    SwNumRule* pNumRule;
    SvxTextLeftMarginItem const* pTextLeftMargin;
    SvxFirstLineIndentItem const* pFirstLineIndent;

    {
        SwTextNode& rNode{ *pWrtShell->GetCursor()->GetPoint()->GetNode().GetTextNode() };
        // numrule from paragraph style, but not from direct formatting
        auto pSet{ rNode.GetpSwAttrSet() };
        CPPUNIT_ASSERT(pSet);
        // list id was set
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_LIST_ID, false));
        // the numrule is set on the paragraph style, not on the paragraph
        CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, pSet->GetItemState(RES_PARATR_NUMRULE, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_NUMRULE, true));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT,
                             pSet->GetItemState(RES_MARGIN_FIRSTLINE, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_FIRSTLINE, true));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, pSet->GetItemState(RES_MARGIN_TEXTLEFT, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_TEXTLEFT, true));
        CPPUNIT_ASSERT_EQUAL(u"ListAndIndents"_ustr, rNode.GetTextColl()->GetName().toString());
        CPPUNIT_ASSERT_EQUAL(u"Item We confirm receipt of your application material."_ustr,
                             rNode.GetText());
        pNumRule = rNode.GetNumRule();
        pTextLeftMargin = &rNode.GetAttr(RES_MARGIN_TEXTLEFT);
        pFirstLineIndent = &rNode.GetAttr(RES_MARGIN_FIRSTLINE);
    }

    pWrtShell->FwdPara();

    {
        SwTextNode& rNode{ *pWrtShell->GetCursor()->GetPoint()->GetNode().GetTextNode() };
        auto pSet{ rNode.GetpSwAttrSet() };
        CPPUNIT_ASSERT(pSet);
        // list id was set
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_LIST_ID, false));
        // middle paragraph was pasted - has numrule and indents applied directly
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_NUMRULE, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_FIRSTLINE, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_TEXTLEFT, false));
        CPPUNIT_ASSERT_EQUAL(u"Default Paragraph Style"_ustr,
                             rNode.GetTextColl()->GetName().toString());
        CPPUNIT_ASSERT(rNode.GetText().startsWith("As more applicants applied"));
        CPPUNIT_ASSERT_EQUAL(pNumRule, rNode.GetNumRule());
        CPPUNIT_ASSERT_EQUAL(pTextLeftMargin->ResolveTextLeft({}),
                             rNode.GetAttr(RES_MARGIN_TEXTLEFT).ResolveTextLeft({}));
        CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->ResolveTextFirstLineOffset({}),
                             rNode.GetAttr(RES_MARGIN_FIRSTLINE).ResolveTextFirstLineOffset({}));
    }

    pWrtShell->FwdPara();

    {
        SwTextNode& rNode{ *pWrtShell->GetCursor()->GetPoint()->GetNode().GetTextNode() };
        // numrule from paragraph style, but not from direct formatting
        auto pSet{ rNode.GetpSwAttrSet() };
        CPPUNIT_ASSERT(pSet);
        // list id was set
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_LIST_ID, false));
        // the numrule is set on the paragraph style, not on the paragraph
        CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, pSet->GetItemState(RES_PARATR_NUMRULE, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_NUMRULE, true));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT,
                             pSet->GetItemState(RES_MARGIN_FIRSTLINE, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_FIRSTLINE, true));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, pSet->GetItemState(RES_MARGIN_TEXTLEFT, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_TEXTLEFT, true));
        CPPUNIT_ASSERT_EQUAL(u"ListAndIndents"_ustr, rNode.GetTextColl()->GetName().toString());
        CPPUNIT_ASSERT(rNode.GetText().endsWith("as soon as we have come to a decision."));
        CPPUNIT_ASSERT_EQUAL(pNumRule, rNode.GetNumRule());
        CPPUNIT_ASSERT_EQUAL(pTextLeftMargin->ResolveTextLeft({}),
                             rNode.GetAttr(RES_MARGIN_TEXTLEFT).ResolveTextLeft({}));
        CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->ResolveTextFirstLineOffset({}),
                             rNode.GetAttr(RES_MARGIN_FIRSTLINE).ResolveTextFirstLineOffset({}));
    }

    pWrtShell->FwdPara();

    {
        SwTextNode& rNode{ *pWrtShell->GetCursor()->GetPoint()->GetNode().GetTextNode() };
        // numrule from paragraph style, but not from direct formatting
        auto pSet{ rNode.GetpSwAttrSet() };
        CPPUNIT_ASSERT(pSet);
        // list id was set
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_LIST_ID, false));
        // the numrule is set on the paragraph style, not on the paragraph
        CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, pSet->GetItemState(RES_PARATR_NUMRULE, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_NUMRULE, true));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT,
                             pSet->GetItemState(RES_MARGIN_FIRSTLINE, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_FIRSTLINE, true));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, pSet->GetItemState(RES_MARGIN_TEXTLEFT, false));
        CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_TEXTLEFT, true));
        CPPUNIT_ASSERT_EQUAL(u"ListAndIndents"_ustr, rNode.GetTextColl()->GetName().toString());
        CPPUNIT_ASSERT_EQUAL(u"more"_ustr, rNode.GetText()); // pre-existing list item
        CPPUNIT_ASSERT_EQUAL(pNumRule, rNode.GetNumRule());
        CPPUNIT_ASSERT_EQUAL(pTextLeftMargin->ResolveTextLeft({}),
                             rNode.GetAttr(RES_MARGIN_TEXTLEFT).ResolveTextLeft({}));
        CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->ResolveTextFirstLineOffset({}),
                             rNode.GetAttr(RES_MARGIN_FIRSTLINE).ResolveTextFirstLineOffset({}));
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf144364)
{
    createSwDoc();
    SwWrtShell* const pWrtSh = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtSh);

    // expands autotext (via F3)
    pWrtSh->Insert(u"AR"_ustr);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_F3);
    Scheduler::ProcessEventsToIdle();

    // was ...'letter of <placeholder:"November 21, 2004":"Click placeholder and overwrite">'
    CPPUNIT_ASSERT_EQUAL(
        u"We hereby acknowledge the receipt of your letter of <November 21, 2004>."_ustr,
        getParagraph(1)->getString());
}

// Test that <field:company> in autotext is converted to an ExtendedUser field.
// Uses en-US "JARL" autotext (Job Application: Rejection Letter) which contains
// <field:company> in its content.xml.
CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testGlossaryFieldUserDataConversion)
{
    createSwDoc();
    SwWrtShell* pWrtSh = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtSh);

    pWrtSh->Insert(u"JARL"_ustr);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_F3);
    Scheduler::ProcessEventsToIdle();

    // JARL contains "Thank you for your interest in <field:company>."
    // The <field:company> must be converted to an ExtendedUser field.
    bool bFieldFound = false;
    sal_Int32 nParas = getParagraphs();
    for (sal_Int32 i = 1; i <= nParas; ++i)
    {
        OUString sText = getParagraph(i)->getString();
        if (sText.indexOf("Thank you for your interest in") != -1)
        {
            CPPUNIT_ASSERT_EQUAL_MESSAGE("<field:company> was not converted", sal_Int32(-1),
                                         sText.indexOf("<field:company>"));
            bFieldFound = true;
            break;
        }
    }
    CPPUNIT_ASSERT_MESSAGE("JARL autotext paragraph not found", bFieldFound);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf146248)
{
    createSwDoc("tdf146248.docx");

    uno::Reference<beans::XPropertySet> xPageStyle(
        getStyles(u"PageStyles"_ustr)->getByName(u"Standard"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));

    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // Delete the header
    pWrtShell->ChangeHeaderOrFooter(UIName(u"Default Page Style"_ustr), true, false, false);

    CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf161741)
{
    // Redo of header change causes LO to crash
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    sw::UndoManager& rUndoManager = pDoc->GetUndoManager();

    uno::Reference<beans::XPropertySet> xPageStyle(
        getStyles(u"PageStyles"_ustr)->getByName(u"Standard"_ustr), uno::UNO_QUERY);

    // sanity checks: verify baseline status
    CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rUndoManager.GetUndoActionCount());

    // Create a header
    pWrtShell->ChangeHeaderOrFooter(UIName(u"Default Page Style"_ustr), /*header*/ true,
                                    /*on*/ true, false);
    CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));

    // create an additional non-header undo point
    pWrtShell->Insert(u"crash_test"_ustr); // three undo points
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rUndoManager.GetUndoActionCount());

    // undo all the changes in one pass
    cpo::uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence({
        { "Undo", cpo::uno::Any(sal_Int32(4)) },
    }));
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, aPropertyValues); // undo all 4 actions
    CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rUndoManager.GetUndoActionCount());

    // Crash avoided by clearing the entire redo stack. This redo request will do nothing.
    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:Redo"_ustr, {}); // redo first (Header) change
    // Since Redo is "cleared", the redo did nothing, thus the Header remains off
    CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf152964)
{
    createSwDoc();

    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});

    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(2)) }, { "Columns", cpo::uno::Any(sal_Int32(2)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getColumns()->getCount());

    SwDoc* pDoc = getSwDoc();
    SwEditShell* const pEditShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pEditShell);
    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), pEditShell->GetRedlineCount());
    dispatchCommand(mxComponent, u".uno:GoDown"_ustr, {});
    dispatchCommand(mxComponent, u".uno:DeleteRows"_ustr, {});
    dispatchCommand(mxComponent, u".uno:DeleteRows"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(2), pEditShell->GetRedlineCount());

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), pEditShell->GetRedlineCount());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(0), pEditShell->GetRedlineCount());

    dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), pEditShell->GetRedlineCount());
    dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(2), pEditShell->GetRedlineCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf107427)
{
    createSwDoc();

    dispatchCommand(
        mxComponent,
        u".uno:InsertPageHeader?PageStyle:string=Default%20Page%20Style&On:bool=true"_ustr, {});
    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(2)) }, { "Columns", cpo::uno::Any(sal_Int32(2)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    xmlDocUniquePtr pLayout = parseLayoutDump();
    assertXPath(pLayout, "/root/page[1]/header/tab/row", 2);

    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    // Delete the header
    pWrtShell->ChangeHeaderOrFooter(UIName(u"Default Page Style"_ustr), true, false, false);

    pLayout = parseLayoutDump();
    assertXPath(pLayout, "/root/page[1]/header", 0);

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    pLayout = parseLayoutDump();
    assertXPath(pLayout, "/root/page[1]/header/tab/row", 2);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf141613)
{
    createSwDoc();
    SwWrtShell* const pWrtSh = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtSh);

    pWrtSh->Insert(u"Test"_ustr);

    dispatchCommand(
        mxComponent,
        u".uno:InsertPageHeader?PageStyle:string=Default%20Page%20Style&On:bool=true"_ustr, {});

    uno::Reference<beans::XPropertySet> xPageStyle(
        getStyles(u"PageStyles"_ustr)->getByName(u"Standard"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));
    CPPUNIT_ASSERT_EQUAL(u"Test"_ustr, getParagraph(1)->getString());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));
    CPPUNIT_ASSERT_EQUAL(u"Test"_ustr, getParagraph(1)->getString());

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(u""_ustr, getParagraph(1)->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf107494)
{
    createSwDoc();

    // Create a graphic object, but don't insert it yet.
    uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
    uno::Reference<beans::XPropertySet> xTextGraphic(
        xFactory->createInstance(u"com.sun.star.text.TextGraphicObject"_ustr), uno::UNO_QUERY);

    uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY);

    uno::Reference<beans::XPropertySet> xPageStyle(
        getStyles(u"PageStyles"_ustr)->getByName(u"Standard"_ustr), uno::UNO_QUERY);

    xPageStyle->setPropertyValue(u"HeaderIsOn"_ustr, cpo::uno::Any(true));

    uno::Reference<text::XText> xHeader(
        getProperty<uno::Reference<text::XText>>(xPageStyle, u"HeaderText"_ustr));
    CPPUNIT_ASSERT(xHeader.is());
    uno::Reference<text::XTextCursor> xHeaderCursor(xHeader->createTextCursor());

    xHeader->insertTextContent(xHeaderCursor, xTextContent, false);

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    xPageStyle->setPropertyValue(u"HeaderIsOn"_ustr, cpo::uno::Any(false));

    CPPUNIT_ASSERT_EQUAL(0, getShapes());

    xPageStyle->setPropertyValue(u"FooterIsOn"_ustr, cpo::uno::Any(true));

    uno::Reference<text::XText> xFooter(
        getProperty<uno::Reference<text::XText>>(xPageStyle, u"FooterText"_ustr));
    CPPUNIT_ASSERT(xFooter.is());
    uno::Reference<text::XTextCursor> xFooterCursor(xFooter->createTextCursor());

    xTextGraphic.set(xFactory->createInstance(u"com.sun.star.text.TextGraphicObject"_ustr),
                     uno::UNO_QUERY);

    xTextContent.set(xTextGraphic, uno::UNO_QUERY);

    xFooter->insertTextContent(xFooterCursor, xTextContent, false);

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    xPageStyle->setPropertyValue(u"FooterIsOn"_ustr, cpo::uno::Any(false));

    CPPUNIT_ASSERT_EQUAL(0, getShapes());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf133358)
{
    createSwDoc();
    SwWrtShell* const pWrtSh = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtSh);

    pWrtSh->Insert(u"Test"_ustr);

    CPPUNIT_ASSERT_EQUAL(u"Test"_ustr, getParagraph(1)->getString());

    uno::Reference<beans::XPropertyState> xParagraph(getParagraph(1), uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xParagraph, u"ParaLeftMargin"_ustr));

    dispatchCommand(mxComponent, u".uno:IncrementIndent"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1251),
                         getProperty<sal_Int32>(xParagraph, u"ParaLeftMargin"_ustr));

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xParagraph, u"ParaLeftMargin"_ustr));

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1251),
                         getProperty<sal_Int32>(xParagraph, u"ParaLeftMargin"_ustr));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf131771)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(2)) }, { "Columns", cpo::uno::Any(sal_Int32(2)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(u""_ustr, getProperty<OUString>(xTextTable, u"TableTemplateName"_ustr));
    uno::Reference<beans::XPropertySet> xTableProps(xTextTable, uno::UNO_QUERY_THROW);
    xTableProps->setPropertyValue(u"TableTemplateName"_ustr, cpo::uno::Any(u"Default Style"_ustr));

    CPPUNIT_ASSERT_EQUAL(u"Default Style"_ustr,
                         getProperty<OUString>(xTextTable, u"TableTemplateName"_ustr));

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
    dispatchCommand(mxComponent, u".uno:GoDown"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess->getCount());

    CPPUNIT_ASSERT_EQUAL(u"Default Style"_ustr,
                         getProperty<OUString>(xTextTable, u"TableTemplateName"_ustr));

    uno::Reference<text::XTextTable> xTextTable2(xIndexAccess->getByIndex(1), uno::UNO_QUERY);

    // Without the fix in place, this test would have failed with
    // - Expected: Default Style
    // - Actual  :
    CPPUNIT_ASSERT_EQUAL(u"Default Style"_ustr,
                         getProperty<OUString>(xTextTable2, u"TableTemplateName"_ustr));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf156546)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(2)) }, { "Columns", cpo::uno::Any(sal_Int32(2)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    uno::Reference<text::XTextTablesSupplier> xTableSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTableSupplier->getTextTables(),
                                                    uno::UNO_QUERY);

    // check that table was created and inserted into the document
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});

    // create another document
    createSwDoc();
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    uno::Reference<text::XTextTablesSupplier> xTableSupplier2(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables2(xTableSupplier2->getTextTables(),
                                                     uno::UNO_QUERY);

    // check table exists after paste/undo
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables2->getCount());
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables2->getCount());

    // without the test, writer freezes on redo table paste into new doc
    dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables2->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf80663)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(2)) }, { "Columns", cpo::uno::Any(sal_Int32(2)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getColumns()->getCount());

    dispatchCommand(mxComponent, u".uno:DeleteRows"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getColumns()->getCount());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getColumns()->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf130805)
{
    createSwDoc("tdf130805.odt");
    SwDoc* pDoc = getSwDoc();

    const auto& rFrmFormats = *pDoc->GetSpzFrameFormats();
    CPPUNIT_ASSERT(rFrmFormats.size() >= size_t(o3tl::make_unsigned(1)));
    auto pShape = rFrmFormats.front();
    CPPUNIT_ASSERT(pShape);

    SwTextBoxHelper::create(pShape, pShape->FindRealSdrObject());
    auto pTxBxFrm = SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));
    CPPUNIT_ASSERT(pTxBxFrm);

    const SwNode* pTxAnch = pTxBxFrm->GetAnchor().GetAnchorNode();
    const SwNode* pShpAnch = pShape->GetAnchor().GetAnchorNode();
    CPPUNIT_ASSERT(pTxAnch);
    CPPUNIT_ASSERT(pShpAnch);

    CPPUNIT_ASSERT_EQUAL_MESSAGE("The textbox got apart!", pTxAnch->GetIndex(),
                                 pShpAnch->GetIndex());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf107893)
{
    //Open the sample doc
    createSwDoc("tdf107893.odt");
    SwDoc* pDoc = getSwDoc();

    //Get the format of the shape
    const auto& rFrmFormats = *pDoc->GetSpzFrameFormats();
    CPPUNIT_ASSERT(rFrmFormats.size() >= size_t(o3tl::make_unsigned(1)));
    auto pShape = rFrmFormats.front();
    CPPUNIT_ASSERT(pShape);

    //Add a textbox
    SwTextBoxHelper::create(pShape, pShape->FindRealSdrObject());
    SwFrameFormat* pTxBxFrm = SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));
    CPPUNIT_ASSERT(pTxBxFrm);

    //Remove the textbox using Undo
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    //Add again
    SwTextBoxHelper::create(pShape, pShape->FindRealSdrObject());
    pTxBxFrm = SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));

    //This was nullptr because of unsuccessful re-adding
    CPPUNIT_ASSERT_MESSAGE("Textbox cannot be readd after Undo!", pTxBxFrm);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf121031)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(3)) }, { "Columns", cpo::uno::Any(sal_Int32(3)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    dispatchCommand(mxComponent, u".uno:DeleteTable"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xIndexAccess->getCount());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());

    // Without the fix in place, the table would be hidden
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "/root/page[1]/body/tab", 1);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, TestTextBoxCrashAfterLineDel)
{
    // Open the desired file
    createSwDoc("txbx_crash.odt");
    SwDoc* pDoc = getSwDoc();

    // Get the format of the shape
    const auto& rFrmFormats = *pDoc->GetSpzFrameFormats();
    CPPUNIT_ASSERT(rFrmFormats.size() >= size_t(o3tl::make_unsigned(1)));
    auto pShape = rFrmFormats.front();
    CPPUNIT_ASSERT(pShape);

    // Add a textbox
    SwTextBoxHelper::create(pShape, pShape->FindRealSdrObject());
    SwFrameFormat* pTxBxFrm = SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));
    CPPUNIT_ASSERT(pTxBxFrm);

    // remove the last paragraph
    auto xCursor = getParagraph(1)->getText()->createTextCursor();
    xCursor->gotoEnd(false);
    xCursor->goLeft(3, true);

    // This caused crash before, now it should pass with the patch.
    xCursor->setString(OUString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf146356)
{
    createSwDoc("tdf146356.odt");

    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_MOD2 | awt::Key::RETURN);
    Scheduler::ProcessEventsToIdle();

    emulateTyping(u"Some Text");

    // Without the fix in place, this test would have failed with
    // - Expected: Some Text
    // - Actual  : Table of Contents
    CPPUNIT_ASSERT_EQUAL(u"Some Text"_ustr, getParagraph(1)->getString());

    // tdf#160095: Without the fix in place, this test would have crashed here
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_MOD2 | awt::Key::RETURN);
    Scheduler::ProcessEventsToIdle();

    CPPUNIT_ASSERT_EQUAL(u"Some Text"_ustr, getParagraph(1)->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf121546)
{
    createSwDoc("tdf121546.odt");

    CPPUNIT_ASSERT_EQUAL(u"xxxxxxxxxxxxxxxxxxxx"_ustr, getParagraph(2)->getString());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(1, getParagraphs());

    // Create a new document
    createSwDoc();

    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(u"xxxxxxxxxxxxxxxxxxxx"_ustr, getParagraph(2)->getString());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(1, getParagraphs());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(u"xxxxxxxxxxxxxxxxxxxx"_ustr, getParagraph(2)->getString());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    // Without the fix in place, this test would have crashed here
    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_RETURN);
    Scheduler::ProcessEventsToIdle();

    CPPUNIT_ASSERT_EQUAL(2, getParagraphs());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf145621)
{
    createSwDoc("tdf145621.odt");

    CPPUNIT_ASSERT_EQUAL(u"AAAAAA"_ustr, getParagraph(1)->getString());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(u""_ustr, getParagraph(1)->getString());

    // Without the fix in place, this test would have crashed
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(u"AAAAAA"_ustr, getParagraph(1)->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf134626)
{
    createSwDoc("tdf134626.odt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    CPPUNIT_ASSERT_EQUAL(u"Apple"_ustr, getParagraph(1)->getString());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});

    // Create a new document
    createSwDoc();
    pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // Without the fix in place, this test would have crashed here
    for (sal_Int32 i = 0; i < 5; ++i)
    {
        dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

        CPPUNIT_ASSERT_EQUAL(u"Apple"_ustr, getParagraph(1)->getString());

        dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

        CPPUNIT_ASSERT_EQUAL(u"AppleApple"_ustr, getParagraph(1)->getString());

        dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

        CPPUNIT_ASSERT_EQUAL(u"Apple"_ustr, getParagraph(1)->getString());

        dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

        CPPUNIT_ASSERT_EQUAL(u""_ustr, getParagraph(1)->getString());
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf139566)
{
    createSwDoc();
    SwWrtShell* pWrtSh = getSwDocShell()->GetWrtShell();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(1)) }, { "Columns", cpo::uno::Any(sal_Int32(1)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    // Move the cursor outside the table
    pWrtSh->Down(/*bSelect=*/false);

    pWrtSh->Insert(u"Test"_ustr);

    CPPUNIT_ASSERT_EQUAL(u"Test"_ustr, getParagraph(2)->getString());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    uno::Reference<frame::XFrames> xFrames = mxDesktop->getFrames();
    sal_Int32 nFrames = xFrames->getCount();

    // Create a second window so the first window looses focus
    dispatchCommand(mxComponent, u".uno:NewWindow"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(nFrames + 1, xFrames->getCount());

    dispatchCommand(mxComponent, u".uno:CloseWin"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(nFrames, xFrames->getCount());

    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xSelections(xModel->getCurrentSelection(),
                                                        uno::UNO_QUERY);

    // Without the fix in place, this test would have failed here
    CPPUNIT_ASSERT(xSelections.is());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf96067)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(3)) }, { "Columns", cpo::uno::Any(sal_Int32(3)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTextTable->getColumns()->getCount());

    dispatchCommand(mxComponent, u".uno:SelectTable"_ustr, {});
    dispatchCommand(mxComponent, u".uno:InsertRowsBefore"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(6), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTextTable->getColumns()->getCount());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTextTable->getColumns()->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf87199)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(2)) }, { "Columns", cpo::uno::Any(sal_Int32(1)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTextTable->getColumns()->getCount());

    uno::Reference<text::XTextRange> xCellA1(xTextTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    xCellA1->setString(u"test1"_ustr);

    uno::Reference<text::XTextRange> xCellA2(xTextTable->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
    xCellA2->setString(u"test2"_ustr);

    dispatchCommand(mxComponent, u".uno:EntireColumn"_ustr, {});
    dispatchCommand(mxComponent, u".uno:MergeCells"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTextTable->getColumns()->getCount());

    CPPUNIT_ASSERT(xCellA1->getString().endsWith("test2"));

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTextTable->getColumns()->getCount());

    xCellA1.set(xTextTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);

    CPPUNIT_ASSERT(xCellA1->getString().endsWith("test1"));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf39828)
{
    createSwDoc("tdf39828.fodt");
    SwDoc* pDoc = getSwDoc();

    // show changes
    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::ShowDelete
                                                      | RedlineFlags::ShowInsert);
    CPPUNIT_ASSERT_MESSAGE("redlining should be off",
                           !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    CPPUNIT_ASSERT_MESSAGE(
        "redlines should be visible",
        IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTextTable->getRows()->getCount());

    uno::Reference<text::XTextRange> xCellA1(xTextTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    // deleted "1", inserted "2"
    CPPUNIT_ASSERT_EQUAL(u"12"_ustr, xCellA1->getString());
    uno::Reference<text::XTextRange> xCellA3(xTextTable->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
    // This was 14 (bad sum: 2 + A1, where A1 was 12 instead of the correct 2)
    CPPUNIT_ASSERT_EQUAL(u"4"_ustr, xCellA3->getString());
    uno::Reference<text::XTextRange> xCellA4(xTextTable->getCellByName(u"A4"_ustr), uno::UNO_QUERY);
    // This was 28 (bad sum: 2 + A1 + A3, where A1 was 12 and A3 was 14)
    CPPUNIT_ASSERT_EQUAL(u"8"_ustr, xCellA4->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf146573)
{
    createSwDoc("tdf39828.fodt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // remove redlines, add a footnote, and change the value
    // of the cell with the footnote
    dispatchCommand(mxComponent, u".uno:AcceptAllTrackedChanges"_ustr, {});
    pWrtShell->Right(SwCursorSkipMode::Cells, /*bSelect=*/false, /*nCount=*/1,
                     /*bBasicCall=*/false);
    dispatchCommand(mxComponent, u".uno:InsertFootnote"_ustr, {});
    dispatchCommand(mxComponent, u".uno:PageUp"_ustr, {}); // leave footnote
    pWrtShell->Left(SwCursorSkipMode::Cells, /*bSelect=*/false, /*nCount=*/1, /*bBasicCall=*/false);
    pWrtShell->Left(SwCursorSkipMode::Cells, /*bSelect=*/true, /*nCount=*/1, /*bBasicCall=*/false);
    pWrtShell->Insert(u"100"_ustr);

    // trigger recalculation by leaving the cell
    pWrtShell->Down(/*bSelect=*/false, /*nCount=*/1);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTextTable->getRows()->getCount());

    uno::Reference<text::XTextRange> xCellA1(xTextTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    // value "100" and footnote index "1"
    CPPUNIT_ASSERT_EQUAL(u"1001"_ustr, xCellA1->getString());
    uno::Reference<text::XTextRange> xCellA3(xTextTable->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
    // This was 4 (missing recalculation)
    CPPUNIT_ASSERT_EQUAL(u"102"_ustr, xCellA3->getString());
    uno::Reference<text::XTextRange> xCellA4(xTextTable->getCellByName(u"A4"_ustr), uno::UNO_QUERY);
    // This was 8 (missing recalculation)
    CPPUNIT_ASSERT_EQUAL(u"204"_ustr, xCellA4->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf157132)
{
    createSwDoc("tdf157132.odt");

    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // Go to cell A2
    pWrtShell->Down(/*bSelect=*/false, /*nCount=*/1);

    // Select A2 and A3 and copy
    pWrtShell->Down(/*bSelect=*/true, /*nCount=*/1);

    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});

    // Go to A4 and paste
    pWrtShell->Down(/*bSelect=*/false, /*nCount=*/1);

    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());

    uno::Reference<text::XTextTable> xTextTable(xTables->getByIndex(0), uno::UNO_QUERY);

    uno::Reference<text::XTextRange> xCellA2(xTextTable->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"2"_ustr, xCellA2->getString());
    uno::Reference<text::XTextRange> xCellA3(xTextTable->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"3"_ustr, xCellA3->getString());
    uno::Reference<text::XTextRange> xCellA4(xTextTable->getCellByName(u"A4"_ustr), uno::UNO_QUERY);

    // Without the fix in place, this test would have failed with
    // - Expected: 6
    // - Actual  : 2
    CPPUNIT_ASSERT_EQUAL(u"6"_ustr, xCellA4->getString());
    uno::Reference<text::XTextRange> xCellA5(xTextTable->getCellByName(u"A5"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"7"_ustr, xCellA5->getString());

    xTextTable.set(xTables->getByIndex(1), uno::UNO_QUERY);

    xCellA2.set(xTextTable->getCellByName(u"A2"_ustr), uno::UNO_QUERY);

    // tdf#158336: Without the fix in place, this test would have failed with
    // - Expected: 2
    // - Actual  : ** Expression is faulty **
    CPPUNIT_ASSERT_EQUAL(u"2"_ustr, xCellA2->getString());
    xCellA3.set(xTextTable->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"3"_ustr, xCellA3->getString());
    xCellA4.set(xTextTable->getCellByName(u"A4"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"6"_ustr, xCellA4->getString());
    xCellA5.set(xTextTable->getCellByName(u"A5"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"7"_ustr, xCellA5->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf147938)
{
    createSwDoc("tdf147938.fodt");

    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->getIDocumentRedlineAccess().GetRedlineTable().size());
    CPPUNIT_ASSERT_EQUAL(u"Bar\nbaz "_ustr,
                         pDoc->getIDocumentRedlineAccess().GetRedlineTable()[0]->GetText());

    pWrtShell->Down(/*bSelect=*/false, /*nCount=*/1);
    pWrtShell->TableToText('\t');

    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->getIDocumentRedlineAccess().GetRedlineTable().size());
    CPPUNIT_ASSERT_EQUAL(u"Bar\nbaz "_ustr,
                         pDoc->getIDocumentRedlineAccess().GetRedlineTable()[0]->GetText());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    SwInsertTableOptions const opts(SwInsertTableFlags::NONE, 0);
    pWrtShell->TextToTable(opts, '\t', nullptr);

    pWrtShell->Undo();

    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->getIDocumentRedlineAccess().GetRedlineTable().size());
    CPPUNIT_ASSERT_EQUAL(u"Bar\nbaz "_ustr,
                         pDoc->getIDocumentRedlineAccess().GetRedlineTable()[0]->GetText());

    pWrtShell->Undo();

    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->getIDocumentRedlineAccess().GetRedlineTable().size());
    CPPUNIT_ASSERT_EQUAL(u"Bar\nbaz "_ustr,
                         pDoc->getIDocumentRedlineAccess().GetRedlineTable()[0]->GetText());

    pWrtShell->Redo();

    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->getIDocumentRedlineAccess().GetRedlineTable().size());
    CPPUNIT_ASSERT_EQUAL(u"Bar\nbaz "_ustr,
                         pDoc->getIDocumentRedlineAccess().GetRedlineTable()[0]->GetText());

    pWrtShell->Redo();

    pWrtShell->Undo();

    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->getIDocumentRedlineAccess().GetRedlineTable().size());
    CPPUNIT_ASSERT_EQUAL(u"Bar\nbaz "_ustr,
                         pDoc->getIDocumentRedlineAccess().GetRedlineTable()[0]->GetText());

    pWrtShell->Undo();

    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->getIDocumentRedlineAccess().GetRedlineTable().size());
    CPPUNIT_ASSERT_EQUAL(u"Bar\nbaz "_ustr,
                         pDoc->getIDocumentRedlineAccess().GetRedlineTable()[0]->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf148799)
{
    // load a document with table formulas with comma delimiter,
    // but with a document language with default point delimiter
    createSwDoc("tdf148799.docx");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // check formula update

    // put cursor in the first table row
    pWrtShell->Down(/*bSelect=*/false, /*nCount=*/1);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());

    uno::Reference<text::XTextTable> xTextTable(xTables->getByIndex(0), uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTextTable->getRows()->getCount());

    // These were "** Expression is faulty **"

    uno::Reference<text::XTextRange> xCellA1(xTextTable->getCellByName(u"D3"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"2.3"_ustr, xCellA1->getString());
    uno::Reference<text::XTextRange> xCellA3(xTextTable->getCellByName(u"D4"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"2345"_ustr, xCellA3->getString());
    uno::Reference<text::XTextRange> xCellA4(xTextTable->getCellByName(u"D5"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"23684.5"_ustr, xCellA4->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf151993)
{
    // load a document with table formulas with comma delimiter
    // (with a document language with default comma delimiter)
    createSwDoc("tdf151993.docx");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // check formula update

    // put cursor in the first table row
    pWrtShell->Down(/*bSelect=*/false, /*nCount=*/1);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());

    uno::Reference<text::XTextTable> xTextTable(xTables->getByIndex(0), uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getRows()->getCount());

    // This was 0
    uno::Reference<text::XTextRange> xCellA1(xTextTable->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"30"_ustr, xCellA1->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf148849)
{
    // load a document with a table and an empty paragraph before the table
    createSwDoc("tdf148849.fodt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // record changes
    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete
                                                      | RedlineFlags::ShowInsert);
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    // hide changes
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());

    // put cursor in the first table row
    pWrtShell->Down(/*bSelect=*/false, /*nCount=*/1);

    // delete a table row
    pWrtShell->DeleteRow();

    // check cursor position

    // This was "", because the text cursor jumped to the start of the document
    // after deleting a table row instead of remaining in the next table row
    SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
    CPPUNIT_ASSERT_EQUAL(u"Row 2"_ustr, rNode.GetTextNode()->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf150576)
{
    // load a document with a table and an empty paragraph before the table
    createSwDoc("tdf148849.fodt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // record changes
    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete
                                                      | RedlineFlags::ShowInsert);
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    // hide changes
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());

    // Check deletion of the first row, if the second row deleted already

    // put cursor in the second table row
    pWrtShell->Down(/*bSelect=*/false, /*nCount=*/2);
    SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->GetNode();
    CPPUNIT_ASSERT_EQUAL(u"Row 2"_ustr, rNode.GetTextNode()->GetText());

    // delete the second table row
    pWrtShell->DeleteRow();

    // check cursor position (row 3)
    SwNode& rNode2 = pWrtShell->GetCursor()->GetPoint()->GetNode();
    CPPUNIT_ASSERT_EQUAL(u"Row 3"_ustr, rNode2.GetTextNode()->GetText());

    // put cursor in the first row
    pWrtShell->Up(/*bSelect=*/false, /*nCount=*/1);
    SwNode& rNode3 = pWrtShell->GetCursor()->GetPoint()->GetNode();
    CPPUNIT_ASSERT_EQUAL(u"12"_ustr, rNode3.GetTextNode()->GetText());

    // delete the first row
    pWrtShell->DeleteRow();

    // This was empty (cursor jumped in the start of the document instead of
    // the next not deleted row)
    SwNode& rNode4 = pWrtShell->GetCursor()->GetPoint()->GetNode();
    CPPUNIT_ASSERT_EQUAL(u"Row 3"_ustr, rNode4.GetTextNode()->GetText());

    // Check skipping previous lines

    // restore deleted rows
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    SwNode& rNode5 = pWrtShell->GetCursor()->GetPoint()->GetNode();
    CPPUNIT_ASSERT_EQUAL(u"Row 2"_ustr, rNode5.GetTextNode()->GetText());

    // delete the second row
    pWrtShell->DeleteRow();
    SwNode& rNode7 = pWrtShell->GetCursor()->GetPoint()->GetNode();
    CPPUNIT_ASSERT_EQUAL(u"Row 3"_ustr, rNode7.GetTextNode()->GetText());

    // delete the third, i.e. last row
    pWrtShell->DeleteRow();
    SwNode& rNode8 = pWrtShell->GetCursor()->GetPoint()->GetNode();

    // This was empty (cursor jumped in the start of the document instead of
    // the previous not deleted row)
    CPPUNIT_ASSERT_EQUAL(u"12"_ustr, rNode8.GetTextNode()->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf132603)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aPropertyValues
        = comphelper::InitPropertySequence({ { "Text", cpo::uno::Any(u"Comment"_ustr) } });

    dispatchCommand(mxComponent, u".uno:InsertAnnotation"_ustr, aPropertyValues);

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    // Without the fix in place, it would crash here
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});

    tools::JsonWriter aJsonWriter;
    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->getPostIts(aJsonWriter);
    OString pChar = aJsonWriter.finishAndGetAsOString();
    std::stringstream aStream((std::string(pChar)));
    boost::property_tree::ptree aTree;
    boost::property_tree::read_json(aStream, aTree);
    for (const boost::property_tree::ptree::value_type& rValue : aTree.get_child("comments"))
    {
        const boost::property_tree::ptree& rComment = rValue.second;

        OString aText(rComment.get<std::string>("html"));
        CPPUNIT_ASSERT_EQUAL("<div>Comment</div>"_ostr, aText);
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf117601)
{
    createSwDoc();

    cpo::uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
        { { "Rows", cpo::uno::Any(sal_Int32(5)) }, { "Columns", cpo::uno::Any(sal_Int32(3)) } }));

    dispatchCommand(mxComponent, u".uno:InsertTable"_ustr, aArgs);

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTextTable->getColumns()->getCount());

    uno::Reference<text::XTextRange> xCellB1(xTextTable->getCellByName(u"B1"_ustr), uno::UNO_QUERY);
    xCellB1->setString(u"test1"_ustr);

    uno::Reference<text::XTextRange> xCellB2(xTextTable->getCellByName(u"B2"_ustr), uno::UNO_QUERY);
    xCellB2->setString(u"test2"_ustr);

    //go to middle row
    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_UP);
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_RIGHT);
    Scheduler::ProcessEventsToIdle();

    dispatchCommand(mxComponent, u".uno:EntireColumn"_ustr, {});
    dispatchCommand(mxComponent, u".uno:MergeCells"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTextTable->getColumns()->getCount());

    CPPUNIT_ASSERT(xCellB1->getString().endsWith("test2"));

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTextTable->getColumns()->getCount());

    CPPUNIT_ASSERT(xCellB1->getString().endsWith("test1"));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf138130)
{
    createSwDoc("tdf138130.docx");

    CPPUNIT_ASSERT_EQUAL(1, getShapes());
    uno::Reference<drawing::XShape> xShape = getShape(1);

    awt::Point aPos = xShape->getPosition();

    //select shape and change the anchor
    selectShape(1);

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:SetAnchorToPage"_ustr, {});

    //position has changed
    CPPUNIT_ASSERT(aPos.X < xShape->getPosition().X);
    CPPUNIT_ASSERT(aPos.Y < xShape->getPosition().Y);

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(aPos.X, xShape->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos.Y, xShape->getPosition().Y);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf136385)
{
    createSwDoc("tdf136385.odt");

    CPPUNIT_ASSERT_EQUAL(1, getShapes());
    uno::Reference<drawing::XShape> xShape = getShape(1);

    awt::Point aPos = xShape->getPosition();

    //select shape and change the anchor
    selectShape(1);

    dispatchCommand(mxComponent, u".uno:SetAnchorToPage"_ustr, {});

    //position has changed
    CPPUNIT_ASSERT(aPos.X < xShape->getPosition().X);
    CPPUNIT_ASSERT(aPos.Y < xShape->getPosition().Y);

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    //Without the fix in place, this test would have failed with
    //- Expected: 2447
    //- Actual  : 446
    CPPUNIT_ASSERT_EQUAL(aPos.X, xShape->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos.Y, xShape->getPosition().Y);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf145207)
{
    createSwDoc("tdf145207.odt");

    CPPUNIT_ASSERT_EQUAL(1, getPages());
    CPPUNIT_ASSERT_EQUAL(3, getShapes());

    //select one shape and use the TAB key to iterate over the different shapes
    selectShape(1);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    for (sal_Int32 i = 0; i < 10; ++i)
    {
        // Without the fix in place, this test would have crashed here
        pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_TAB);
        Scheduler::ProcessEventsToIdle();
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf128782)
{
    createSwDoc("tdf128782.odt");

    CPPUNIT_ASSERT_EQUAL(2, getShapes());
    uno::Reference<drawing::XShape> xShape1 = getShape(1);
    uno::Reference<drawing::XShape> xShape2 = getShape(2);

    awt::Point aPos[2];
    aPos[0] = xShape1->getPosition();
    aPos[1] = xShape2->getPosition();

    //select shape 2 and move it down
    selectShape(2);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_DOWN);
    Scheduler::ProcessEventsToIdle();

    CPPUNIT_ASSERT_EQUAL(aPos[0].X, xShape1->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos[0].Y, xShape1->getPosition().Y);
    CPPUNIT_ASSERT_EQUAL(aPos[1].X, xShape2->getPosition().X);
    //Y position in shape 2 has changed
    CPPUNIT_ASSERT(aPos[1].Y < xShape2->getPosition().Y);

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(aPos[0].X, xShape1->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos[0].Y, xShape1->getPosition().Y);
    CPPUNIT_ASSERT_EQUAL(aPos[1].X, xShape2->getPosition().X);
    // Shape2 has come back to the original position
    // without the fix in place, it would have failed
    CPPUNIT_ASSERT_EQUAL(aPos[1].Y, xShape2->getPosition().Y);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf135623)
{
    createSwDoc("tdf135623.docx");

    CPPUNIT_ASSERT_EQUAL(2, getShapes());
    CPPUNIT_ASSERT_EQUAL(2, getPages());

    uno::Reference<drawing::XShape> xShape1 = getShape(1);
    uno::Reference<drawing::XShape> xShape2 = getShape(2);

    awt::Point aPos[2];
    aPos[0] = xShape1->getPosition();
    aPos[1] = xShape2->getPosition();

    //select shape 1 and move it down
    selectShape(1);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_DOWN);
    Scheduler::ProcessEventsToIdle();

    CPPUNIT_ASSERT_EQUAL(aPos[0].X, xShape1->getPosition().X);
    //Y position in shape 1 has changed
    CPPUNIT_ASSERT(aPos[0].Y < xShape1->getPosition().Y);
    CPPUNIT_ASSERT_EQUAL(aPos[1].X, xShape2->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos[1].Y, xShape2->getPosition().Y);

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(aPos[0].X, xShape1->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos[0].Y, xShape1->getPosition().Y);
    CPPUNIT_ASSERT_EQUAL(aPos[1].X, xShape2->getPosition().X);

    // Without the fix in place, this test would have failed here
    // - Expected: 1351
    // - Actual  : 2233
    CPPUNIT_ASSERT_EQUAL(aPos[1].Y, xShape2->getPosition().Y);

    CPPUNIT_ASSERT_EQUAL(2, getPages());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf133490)
{
    createSwDoc("tdf133490.odt");

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});

    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(0, getShapes());

    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(2, getShapes());

    uno::Reference<drawing::XShape> xShape1 = getShape(1);
    uno::Reference<drawing::XShape> xShape2 = getShape(2);

    awt::Point aPos[2];
    aPos[0] = xShape1->getPosition();
    aPos[1] = xShape2->getPosition();

    //select shape 2 and move it to the right
    selectShape(2);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    for (sal_Int32 i = 0; i < 5; ++i)
    {
        pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_RIGHT);
        Scheduler::ProcessEventsToIdle();
    }

    CPPUNIT_ASSERT_EQUAL(aPos[0].X, xShape1->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos[0].Y, xShape1->getPosition().Y);
    //X position in shape 2 has changed
    CPPUNIT_ASSERT(aPos[1].X < xShape2->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos[1].Y, xShape2->getPosition().Y);

    for (sal_Int32 i = 0; i < 4; ++i)
    {
        dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

        // Without the fix in place, undo action would have changed shape1's position
        // and this test would have failed with
        // - Expected: -139
        // - Actual  : 1194
        CPPUNIT_ASSERT_EQUAL(aPos[0].X, xShape1->getPosition().X);
        CPPUNIT_ASSERT_EQUAL(aPos[0].Y, xShape1->getPosition().Y);
        CPPUNIT_ASSERT(aPos[1].X < xShape2->getPosition().X);
        CPPUNIT_ASSERT_EQUAL(aPos[1].Y, xShape2->getPosition().Y);
    }

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(aPos[0].X, xShape1->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos[0].Y, xShape1->getPosition().Y);
    // Shape 2 has come back to the original position
    CPPUNIT_ASSERT_EQUAL(aPos[1].X, xShape2->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(aPos[1].Y, xShape2->getPosition().Y);

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(0, getShapes());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(1, getShapes());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf132637_protectTrackChanges)
{
    createSwDoc("tdf132637_protectTrackChanges.doc");

    // The password should only prevent turning off track changes, not open as read-only
    CPPUNIT_ASSERT(!getSwDocShell()->IsReadOnly());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf127652)
{
    createSwDoc("tdf127652.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* const pWrtShell = getSwDocShell()->GetWrtShell();

    // get a page cursor
    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
    uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
        xModel->getCurrentController(), uno::UNO_QUERY);
    uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(),
                                              uno::UNO_QUERY);

    // go to the start of page 4
    xCursor->jumpToPage(4);
    xCursor->jumpToStartOfPage();

    // mark a section that overlaps multiple pages
    pWrtShell->Down(false, 2);
    pWrtShell->Up(true, 5);

    // delete the marked section
    pWrtShell->DelRight();

    // go to the start of page 4
    xCursor->jumpToPage(4);
    xCursor->jumpToStartOfPage();

    // move up to page 3
    pWrtShell->Up(false, 5);

    // check that we are on the third page
    // in the bug one issue was that the cursor was placed incorrectly, so
    // moving up to the previous page would not work any more
    sal_uInt16 assertPage = 3;
    SwCursorShell* pShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pShell);
    sal_uInt16 currentPage = pShell->GetPageNumSeqNonEmpty();
    CPPUNIT_ASSERT_EQUAL_MESSAGE("We are on the wrong page!", assertPage, currentPage);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, AtPageTextBoxCrash)
{
    // Load sample file
    createSwDoc("AtPageTextBoxCrash.odt");
    SwDoc* pDoc = getSwDoc();

    // Get the format of the shape
    const auto& rFrmFormats = *pDoc->GetSpzFrameFormats();
    CPPUNIT_ASSERT(rFrmFormats.size() >= size_t(o3tl::make_unsigned(1)));
    auto pShape = rFrmFormats.front();
    CPPUNIT_ASSERT(pShape);

    // Add a textbox to the shape
    SwTextBoxHelper::create(pShape, pShape->FindRealSdrObject());
    auto pTxBxFrm = SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));
    CPPUNIT_ASSERT(pTxBxFrm);

    // Change its anchor to page
    uno::Reference<beans::XPropertySet> xShpProps(getShape(1), uno::UNO_QUERY_THROW);
    xShpProps->setPropertyValue(
        u"AnchorType"_ustr,
        cpo::uno::Any(text::TextContentAnchorType::TextContentAnchorType_AT_PAGE));

    // The page anchored objects must not have content anchor
    // unless this will lead to crash later, for example on
    // removing the paragraph where it is anchored to...
    CPPUNIT_ASSERT_EQUAL(RndStdIds::FLY_AT_PAGE, pTxBxFrm->GetAnchor().GetAnchorId());
    CPPUNIT_ASSERT(!pTxBxFrm->GetAnchor().GetAnchorNode());

    // Remove the paragraph where the textframe should be anchored
    // before. Now with the patch it must not crash...
    auto xPara = getParagraph(1);
    xPara->getText()->setString(OUString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf135661)
{
    createSwDoc("tdf135661.odt");

    CPPUNIT_ASSERT_EQUAL(1, getShapes());
    uno::Reference<drawing::XShape> xShape(getShape(1), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3424), xShape->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1545), xShape->getPosition().Y);

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(0, getShapes());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    xShape.set(getShape(1), uno::UNO_QUERY);

    //Without the fix in place, the shape position would have been 0,0
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3424), xShape->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1545), xShape->getPosition().Y);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf133477)
{
    if (getDefaultDeviceBitCount() < 24)
        return;
    createSwDoc("tdf133477.fodt");

    // Save the shape to a BMP.
    uno::Reference<drawing::XGraphicExportFilter> xGraphicExporter
        = drawing::GraphicExportFilter::create(m_xContext);
    uno::Reference<lang::XComponent> xSourceDoc(getShape(1), uno::UNO_QUERY);
    xGraphicExporter->setSourceDocument(xSourceDoc);

    SvMemoryStream aStream;
    uno::Reference<io::XOutputStream> xOutputStream(new utl::OStreamWrapper(aStream));
    cpo::uno::Sequence<beans::PropertyValue> aDescriptor(
        comphelper::InitPropertySequence({ { "OutputStream", cpo::uno::Any(xOutputStream) },
                                           { "FilterName", cpo::uno::Any(u"BMP"_ustr) } }));
    xGraphicExporter->filter(aDescriptor);
    aStream.Seek(STREAM_SEEK_TO_BEGIN);

    // Read it back and check the color of the first pixel.
    // (Actually check at one-pixel offset, because imprecise shape positioning may
    // result in blending with background for the first pixel).
    Graphic aGraphic;
    TypeSerializer aSerializer(aStream);
    aSerializer.readGraphic(aGraphic);

    Bitmap aBitmap = aGraphic.GetBitmap();
    CPPUNIT_ASSERT_EQUAL(Color(0, 102, 204), aBitmap.GetPixelColor(1, 1));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf137964)
{
    createSwDoc("tdf137964.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    CPPUNIT_ASSERT_EQUAL(1, getShapes());
    uno::Reference<drawing::XShape> xShape(getShape(1), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3579), xShape->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4090), xShape->getPosition().Y);

    SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
    SdrObject* pObject = pPage->GetObj(1);
    SwContact* pTextBox = static_cast<SwContact*>(pObject->GetUserCall());
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_FLYFRMFMT), pTextBox->GetFormat()->Which());

    pWrtShell->SelectObj(Point(), 0, pObject);

    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_SHIFT | KEY_UP);
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_SHIFT | KEY_LEFT);
    Scheduler::ProcessEventsToIdle();

    // Without the fix in place, the shape would have stayed where it was
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2579), xShape->getPosition().X);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3090), xShape->getPosition().Y);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf143244)
{
    createSwDoc("tdf143244.odt");

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(6), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getColumns()->getCount());

    uno::Reference<text::XTextRange> xCell(xTextTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(Color(0x009353), getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(COL_AUTO, getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(Color(0xdddddd), getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A4"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(COL_AUTO, getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A5"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(Color(0xdddddd), getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A6"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(Color(0xbee3d3), getProperty<Color>(xCell, u"BackColor"_ustr));

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xIndexAccess->getCount());

    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    xTextTable.set(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(6), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getColumns()->getCount());

    dispatchCommand(mxComponent, u".uno:GoUp"_ustr, {});

    SwXTextDocument* pTextDoc = getSwTextDoc();
    for (sal_Int32 i = 0; i < 6; ++i)
    {
        pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_TAB);
        Scheduler::ProcessEventsToIdle();
    }

    for (sal_Int32 i = 0; i < 5; ++i)
    {
        dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    }

    xTextTable.set(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(6), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getColumns()->getCount());

    for (sal_Int32 i = 0; i < 5; ++i)
    {
        dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
    }

    xTextTable.set(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(9), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getColumns()->getCount());

    xCell.set(xTextTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(Color(0x009353), getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(COL_AUTO, getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(Color(0xdddddd), getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A4"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(COL_AUTO, getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A5"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(Color(0xdddddd), getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A6"_ustr), uno::UNO_QUERY);

    // Without the fix in place, this test would have failed with
    // - Expected: Color: R:255 G:255 B:255 A:255
    // - Actual  : Color: R:190 G:227 B:211 A:0
    CPPUNIT_ASSERT_EQUAL(COL_AUTO, getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A7"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(Color(0xdddddd), getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A8"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(COL_AUTO, getProperty<Color>(xCell, u"BackColor"_ustr));

    xCell.set(xTextTable->getCellByName(u"A9"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(Color(0xbee3d3), getProperty<Color>(xCell, u"BackColor"_ustr));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf136715)
{
    createSwDoc("tdf136715.odt");

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTextTable->getColumns()->getCount());

    uno::Reference<text::XTextRange> xCell(xTextTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xCell->getText(), uno::UNO_QUERY);
    uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
    uno::Reference<text::XTextRange> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xPara, u"CharWeight"_ustr));

    xCell.set(xTextTable->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
    xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
    xParaEnum.set(xParaEnumAccess->createEnumeration());
    xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::NORMAL, getProperty<float>(xPara, u"CharWeight"_ustr));

    xCell.set(xTextTable->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
    xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
    xParaEnum.set(xParaEnumAccess->createEnumeration());
    xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::NORMAL, getProperty<float>(xPara, u"CharWeight"_ustr));

    xCell.set(xTextTable->getCellByName(u"A4"_ustr), uno::UNO_QUERY);
    xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
    xParaEnum.set(xParaEnumAccess->createEnumeration());
    xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xPara, u"CharWeight"_ustr));

    dispatchCommand(mxComponent, u".uno:GoDown"_ustr, {});
    dispatchCommand(mxComponent, u".uno:GoDown"_ustr, {});
    dispatchCommand(mxComponent, u".uno:LineDownSel"_ustr, {});
    dispatchCommand(mxComponent, u".uno:DeleteRows"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTextTable->getColumns()->getCount());

    xCell.set(xTextTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
    xParaEnum.set(xParaEnumAccess->createEnumeration());
    xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xPara, u"CharWeight"_ustr));

    xCell.set(xTextTable->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
    xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
    xParaEnum.set(xParaEnumAccess->createEnumeration());
    xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xPara, u"CharWeight"_ustr));

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTextTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTextTable->getColumns()->getCount());

    xCell.set(xTextTable->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
    xParaEnum.set(xParaEnumAccess->createEnumeration());
    xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xPara, u"CharWeight"_ustr));

    xCell.set(xTextTable->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
    xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
    xParaEnum.set(xParaEnumAccess->createEnumeration());
    xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);

    // Without the fix in place, this test would have failed with
    // - Expected: 100
    // - Actual  : 150
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::NORMAL, getProperty<float>(xPara, u"CharWeight"_ustr));

    xCell.set(xTextTable->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
    xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
    xParaEnum.set(xParaEnumAccess->createEnumeration());
    xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::NORMAL, getProperty<float>(xPara, u"CharWeight"_ustr));

    xCell.set(xTextTable->getCellByName(u"A4"_ustr), uno::UNO_QUERY);
    xParaEnumAccess.set(xCell->getText(), uno::UNO_QUERY);
    xParaEnum.set(xParaEnumAccess->createEnumeration());
    xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xPara, u"CharWeight"_ustr));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf138897)
{
    createSwDoc("tdf100018-1.odt");

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
    // this was crashing
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf136740)
{
    createSwDoc();
    css::uno::Reference<css::lang::XMultiServiceFactory> xFact(mxComponent,
                                                               css::uno::UNO_QUERY_THROW);
    css::uno::Reference<css::beans::XPropertySet> xTextDefaults(
        xFact->createInstance(u"com.sun.star.text.Defaults"_ustr), css::uno::UNO_QUERY_THROW);
    const cpo::uno::Any aOrig = xTextDefaults->getPropertyValue(u"TabStopDistance"_ustr);
    sal_Int32 nDefTab = aOrig.get<sal_Int32>();
    CPPUNIT_ASSERT(nDefTab != 0);

    css::uno::Reference<css::text::XTextRange> const xParagraph(getParagraphOrTable(1),
                                                                css::uno::UNO_QUERY_THROW);
    xParagraph->setString(u"Foo"_ustr);

    CPPUNIT_ASSERT_EQUAL(1, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"Foo"_ustr, xParagraph->getString());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
    dispatchCommand(mxComponent, u".uno:GoToEndOfDoc"_ustr, {});

    const cpo::uno::Any aNew(nDefTab * 2);
    xTextDefaults->setPropertyValue(u"TabStopDistance"_ustr, aNew);
    // it may become slightly different because of conversions, so get the actual value
    const cpo::uno::Any aNewCorrected = xTextDefaults->getPropertyValue(u"TabStopDistance"_ustr);
    CPPUNIT_ASSERT_DOUBLES_EQUAL(nDefTab * 2, aNewCorrected.get<sal_Int32>(), 1);

    // Paste special as RTF
    const auto aPropertyValues = comphelper::InitPropertySequence(
        { { "SelectedFormat",
            cpo::uno::Any(static_cast<sal_uInt32>(SotClipboardFormatId::RTF)) } });
    dispatchCommand(mxComponent, u".uno:ClipboardFormatItems"_ustr, aPropertyValues);

    CPPUNIT_ASSERT_EQUAL(1, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"FooFoo"_ustr, xParagraph->getString());

    // Without the fix in place, this would fail with
    //     equality assertion failed
    //     - Expected: <Any: (long) 2501>
    //     - Actual  : <Any: (long) 1251>
    // i.e., pasting RTF would reset the modified default tab stop distance to hardcoded default
    CPPUNIT_ASSERT_EQUAL(aNewCorrected, xTextDefaults->getPropertyValue(u"TabStopDistance"_ustr));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf128106)
{
    createSwDoc("cross_reference_demo_bmk.odt");

    const auto aPropertyValues
        = comphelper::InitPropertySequence({ { "FileName", cpo::uno::Any(maTempFile.GetURL()) } });
    dispatchCommand(mxComponent, u".uno:NewGlobalDoc"_ustr, aPropertyValues);

    // Use loadFromDesktop instead of loadFromURL to avoid calling mxComponent->dispose()
    // Otherwise it fails with 'DeInitVCL: some top Windows are still alive'
    mxComponent = loadFromDesktop(maTempFile.GetURL());

    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    SwDoc* const pMasterDoc(pWrtShell->GetDoc());
    CPPUNIT_ASSERT_EQUAL(
        size_t(2),
        pMasterDoc->getIDocumentLinksAdministration().GetLinkManager().GetLinks().size());
    // no way to set SwDocShell::m_nUpdateDocMode away from NO_UPDATE ?
    // pMasterDoc->getIDocumentLinksAdministration().UpdateLinks();
    pMasterDoc->getIDocumentLinksAdministration().GetLinkManager().UpdateAllLinks(false, nullptr,
                                                                                  u""_ustr);
    // note: this has called SwGetRefFieldType::UpdateGetReferences()
    SwFieldType const* const pType(
        pMasterDoc->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef));
    std::vector<SwFormatField*> fields;
    pType->GatherFields(fields);
    CPPUNIT_ASSERT_EQUAL(size_t(6), fields.size());
    std::sort(fields.begin(), fields.end(), [](auto const* const pA, auto const* const pB) {
        SwTextField const* const pHintA(pA->GetTextField());
        SwTextField const* const pHintB(pB->GetTextField());
        // in this document: only 1 field per node
        CPPUNIT_ASSERT(pA == pB || &pHintA->GetTextNode() != &pHintB->GetTextNode());
        return pHintA->GetTextNode().GetIndex() < pHintB->GetTextNode().GetIndex();
    });
    CPPUNIT_ASSERT_EQUAL(ReferencesSubtype::Bookmark,
                         static_cast<SwGetRefField*>(fields[0]->GetField())->GetSubType());
    CPPUNIT_ASSERT_EQUAL(
        u"bookmarkchapter1_text"_ustr,
        static_cast<SwGetRefField const*>(fields[0]->GetField())->GetSetRefName().toString());
    CPPUNIT_ASSERT_EQUAL(u"Text"_ustr,
                         static_cast<SwGetRefField const*>(fields[0]->GetField())
                             ->GetExpandedTextOfReferencedTextNode(*pWrtShell->GetLayout()));
    CPPUNIT_ASSERT_EQUAL(ReferencesSubtype::Bookmark,
                         static_cast<SwGetRefField*>(fields[1]->GetField())->GetSubType());
    CPPUNIT_ASSERT(
        static_cast<SwGetRefField const*>(fields[1]->GetField())->IsRefToHeadingCrossRefBookmark());
    CPPUNIT_ASSERT_EQUAL(u"Chapter 2"_ustr,
                         static_cast<SwGetRefField const*>(fields[1]->GetField())->GetPar2());
    CPPUNIT_ASSERT_EQUAL(ReferencesSubtype::Bookmark,
                         static_cast<SwGetRefField*>(fields[2]->GetField())->GetSubType());
    CPPUNIT_ASSERT_EQUAL(
        u"Bookmarkchapter1"_ustr,
        static_cast<SwGetRefField const*>(fields[2]->GetField())->GetSetRefName().toString());
    CPPUNIT_ASSERT_EQUAL(u"Chapter 1"_ustr,
                         static_cast<SwGetRefField const*>(fields[2]->GetField())->GetPar2());
    CPPUNIT_ASSERT_EQUAL(ReferencesSubtype::Bookmark,
                         static_cast<SwGetRefField*>(fields[3]->GetField())->GetSubType());
    CPPUNIT_ASSERT_EQUAL(
        u"bookmarkchapter1_text"_ustr,
        static_cast<SwGetRefField const*>(fields[3]->GetField())->GetSetRefName().toString());
    CPPUNIT_ASSERT_EQUAL(u"Text"_ustr,
                         static_cast<SwGetRefField const*>(fields[3]->GetField())->GetPar2());
    CPPUNIT_ASSERT_EQUAL(ReferencesSubtype::Bookmark,
                         static_cast<SwGetRefField*>(fields[4]->GetField())->GetSubType());
    CPPUNIT_ASSERT(
        static_cast<SwGetRefField const*>(fields[4]->GetField())->IsRefToHeadingCrossRefBookmark());
    CPPUNIT_ASSERT_EQUAL(u"Chapter 1.1"_ustr,
                         static_cast<SwGetRefField const*>(fields[4]->GetField())->GetPar2());
    CPPUNIT_ASSERT_EQUAL(ReferencesSubtype::Bookmark,
                         static_cast<SwGetRefField*>(fields[5]->GetField())->GetSubType());
    CPPUNIT_ASSERT(
        static_cast<SwGetRefField const*>(fields[5]->GetField())->IsRefToHeadingCrossRefBookmark());
    CPPUNIT_ASSERT_EQUAL(u"Chapter 2"_ustr,
                         static_cast<SwGetRefField const*>(fields[5]->GetField())->GetPar2());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf103612)
{
    createSwGlobalDoc("DUMMY.odm");
    SwDoc* pDoc = getSwDoc();
    CPPUNIT_ASSERT_EQUAL(
        size_t(1), pDoc->getIDocumentLinksAdministration().GetLinkManager().GetLinks().size());
    pDoc->getIDocumentLinksAdministration().GetLinkManager().UpdateAllLinks(false, nullptr,
                                                                            u""_ustr);

    xmlDocUniquePtr pLayout = parseLayoutDump();

    assertXPath(pLayout, "/root/page[1]/body/section[1]/txt[1]/SwParaPortion/SwLineLayout[1]",
                "portion", u"Text before section");
    // the inner section and its content was hidden
    assertXPath(pLayout, "/root/page[1]/body/section[2]/txt[1]/SwParaPortion/SwLineLayout[1]",
                "portion", u"Text inside section before ToC");
    assertXPath(pLayout, "/root/page[1]/body/section[3]/txt[1]/SwParaPortion/SwLineLayout[1]",
                "portion", u"Table of Contents");
    assertXPath(pLayout, "/root/page[1]/body/section[4]/txt[1]/SwParaPortion/SwLineLayout[1]",
                "portion", u"First header*1");
    assertXPath(pLayout, "/root/page[1]/body/section[4]/txt[2]/SwParaPortion/SwLineLayout[1]",
                "portion", u"Second header*1");
    assertXPath(pLayout, "/root/page[1]/body/section[5]/txt[2]/SwParaPortion/SwLineLayout[1]",
                "portion", u"Text inside section after ToC");
    assertXPath(pLayout, "/root/page[1]/body/section[6]/txt[1]/SwParaPortion/SwLineLayout[1]",
                "portion", u"Text after section");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf121119)
{
    createSwGlobalDoc("tdf121119.odm");
    SwDoc* pDoc = getSwDoc();
    CPPUNIT_ASSERT_EQUAL(
        size_t(2), pDoc->getIDocumentLinksAdministration().GetLinkManager().GetLinks().size());
    pDoc->getIDocumentLinksAdministration().GetLinkManager().UpdateAllLinks(false, nullptr,
                                                                            u""_ustr);

    uno::Reference<text::XTextGraphicObjectsSupplier> xTextGraphicObjectsSupplier(mxComponent,
                                                                                  uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(
        xTextGraphicObjectsSupplier->getGraphicObjects(), uno::UNO_QUERY);

    // This was 0 (missing images anchored at page)
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xIndexAccess->getCount());

    uno::Reference<drawing::XShape> xShape(xIndexAccess->getByIndex(0), uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_PAGE,
                         getProperty<text::TextContentAnchorType>(xShape, u"AnchorType"_ustr));

    xmlDocUniquePtr pLayout = parseLayoutDump();
    // check page numbers of the objects anchored at page
    assertXPath(pLayout, "/root/page[2]/anchored/fly/SwAnchoredObject", 1);
    assertXPath(pLayout, "/root/page[4]/anchored/fly/SwAnchoredObject", 1);
    assertXPath(pLayout, "/root/page[7]/anchored/fly/SwAnchoredObject", 1);
    assertXPath(pLayout, "/root/page[9]/anchored/fly/SwAnchoredObject", 1);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf97899)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    SwCursorShell* pShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pShell);
    SwPaM* pCursor = pShell->GetCursor();

    IDocumentContentOperations& rIDCO(pDoc->getIDocumentContentOperations());

    // Create an Ordered List
    rIDCO.InsertString(*pCursor, u"\ta"_ustr);
    pWrtShell->SplitNode();
    rIDCO.InsertString(*pCursor, u"   b"_ustr);
    pWrtShell->SplitNode();
    rIDCO.InsertString(*pCursor, u"  \t  c"_ustr);

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:DefaultNumbering"_ustr, {});

    // tdf#109285: RemoveLeadingWhiteSpace from all numbered paragraphs
    getParagraph(1, u"a"_ustr);
    getParagraph(2, u"b"_ustr);
    getParagraph(3, u"c"_ustr);

    // Save it as DOCX & load it again
    saveAndReload(TestFilter::DOCX);
    uno::Reference<container::XIndexAccess> xNumberingRules
        = getProperty<uno::Reference<container::XIndexAccess>>(getParagraph(1),
                                                               u"NumberingRules"_ustr);
    CPPUNIT_ASSERT(xNumberingRules->getCount());
    cpo::uno::Sequence<beans::PropertyValue> aNumbering;
    xNumberingRules->getByIndex(0) >>= aNumbering;
    OUString sCharStyleName;
    for (const auto& prop : aNumbering)
    {
        if (prop.Name == "CharStyleName")
        {
            prop.Value >>= sCharStyleName;
            break;
        }
    }
    CPPUNIT_ASSERT(!sCharStyleName.isEmpty());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf40142)
{
    createSwDoc("tdf40142.odt");
    dispatchCommand(mxComponent, u".uno:UpdateAllIndexes"_ustr, {});

    xmlDocUniquePtr pLayout = parseLayoutDump();
    // Without the fix in place, this test would have failed with
    // - Expected: 2
    // - Actual  : 4
    assertXPath(pLayout, "/root/page[1]/body/section[2]/txt", 2);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf151462)
{
    createSwDoc("tdf151462.odt");
    dispatchCommand(mxComponent, u".uno:UpdateAllIndexes"_ustr, {});

    xmlDocUniquePtr pLayout = parseLayoutDump();
    // Without the fix in place, there would be just the first index entry
    assertXPath(pLayout,
                "/root/page[1]/body/txt[2]/anchored/fly/section/txt[1]/SwParaPortion/"
                "SwLineLayout[1]/SwLinePortion[1]",
                "portion", u"sub one");
    assertXPath(pLayout,
                "/root/page[1]/body/txt[2]/anchored/fly/section/txt[2]/SwParaPortion/"
                "SwLineLayout[1]/SwLinePortion[1]",
                "portion", u"sub two");
    assertXPath(pLayout,
                "/root/page[1]/body/txt[2]/anchored/fly/section/txt[3]/SwParaPortion/"
                "SwLineLayout[1]/SwLinePortion[1]",
                "portion", u"sub three");

    // Without the fix in place, there would be just the first index entry
    assertXPath(pLayout,
                "/root/page[1]/body/txt[6]/anchored/fly/section/txt[1]/SwParaPortion/"
                "SwLineLayout[1]/SwLinePortion[1]",
                "portion", u"another sub one");
    assertXPath(pLayout,
                "/root/page[1]/body/txt[6]/anchored/fly/section/txt[2]/SwParaPortion/"
                "SwLineLayout[1]/SwLinePortion[1]",
                "portion", u"another sub two");
    assertXPath(pLayout,
                "/root/page[1]/body/txt[6]/anchored/fly/section/txt[3]/SwParaPortion/"
                "SwLineLayout[1]/SwLinePortion[1]",
                "portion", u"another sub three");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf153636)
{
    createSwDoc("tdf153636.odt");
    dispatchCommand(mxComponent, u".uno:UpdateAllIndexes"_ustr, {});
    saveAndReload(TestFilter::ODT);

    xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
    CPPUNIT_ASSERT(pXmlDoc);

    for (int i = 1; i <= 3; i += 2)
    {
        const OUString frameStyleName
            = getXPath(pXmlDoc,
                       "/office:document-content/office:body/office:text/"
                       "text:user-index[@text:name='User-Defined1']/text:index-body/text:p["
                           + OString::number(i) + "]",
                       "style-name");
        const OUString tableStyleName
            = getXPath(pXmlDoc,
                       "/office:document-content/office:body/office:text/"
                       "text:user-index[@text:name='User-Defined1']/text:index-body/text:p["
                           + OString::number(i + 1) + "]",
                       "style-name");

        // Without the fix in place, the frame and table indentation would differ
        CPPUNIT_ASSERT_EQUAL(frameStyleName, tableStyleName);
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf168157_crash_after_pasting_and_undoing)
{
    createSwDoc("tdf168157.docx");

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});

    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(2, getShapes());

    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    // Without the fix in place, this test would have crashed here
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    CPPUNIT_ASSERT_EQUAL(1, getShapes());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf157129)
{
    // Unit test for tdf#157129
    // Test to see if cursor moves to the end after paste

    // First document containing test data
    createSwDoc("tdf157129.doc");
    CPPUNIT_ASSERT_EQUAL(5, getParagraphs());
    // Copy data from first document
    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});

    // Create a new document
    createSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    CPPUNIT_ASSERT_EQUAL(1, getParagraphs());

    // Paste data from first document
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
    CPPUNIT_ASSERT_EQUAL(5, getParagraphs());

    // Save cursor position after paste occurs
    SwPosition aCursorPosPaste(*pWrtShell->GetCursor()->GetPoint());

    // Move cursor position to the end
    pWrtShell->SttEndDoc(false); //bStart = false

    // Save cursor position at end
    SwPosition aCursorPosEnd(*pWrtShell->GetCursor()->GetPoint());

    // Assert the cursor position after paste is at the end
    // Without the test in place, the cursor position is at the beginning of the document
    // - Expected : SwPosition (node 18, offset 0)
    // - Actual : SwPosition (node 6, offset 0)
    CPPUNIT_ASSERT_EQUAL(aCursorPosEnd, aCursorPosPaste);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testCursorPositionAfterUndo)
{
    createSwDoc("cursor_position_after_undo.odt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // switch on "Outline Folding" mode
    dispatchCommand(mxComponent, u".uno:ShowOutlineContentVisibilityButton"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton());

    // move the cursor to the beginning of the 3rd word in the 3rd paragraph, "tincidunt"
    pWrtShell->FwdPara();
    pWrtShell->FwdPara();
    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 16, /*bBasicCall=*/false);

    // select the word
    dispatchCommand(mxComponent, u".uno:SelectWord"_ustr, {});

    // check the word is select
    SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
    CPPUNIT_ASSERT_EQUAL(u"tincidunt"_ustr, pShellCursor->GetText());

    // remember the cursor position for comparison
    SwPosition aCursorPos(*pWrtShell->GetCursor()->GetPoint());

    // delete the selected word
    pWrtShell->Delete();

    // undo delete
    dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});

    // without the fix in place, the cursor would have been set to the start of the outline node
    // - Expected: SwPosition (node 11, offset 25)
    // - Actual  : SwPosition (node 9, offset 0)
    CPPUNIT_ASSERT_EQUAL(aCursorPos, *pWrtShell->GetCursor()->GetPoint());

    // switch off "Outline Folding" mode
    dispatchCommand(mxComponent, u".uno:ShowOutlineContentVisibilityButton"_ustr, {});
    CPPUNIT_ASSERT(!pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testCrashOutlineFoldingPressingReturn)
{
    createSwDoc("tdf166713.odt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // switch on "Outline Folding" mode
    dispatchCommand(mxComponent, u".uno:ShowOutlineContentVisibilityButton"_ustr, {});
    CPPUNIT_ASSERT(pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton());

    // Without the fix in place, this test would have crashed here
    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_RETURN);
    Scheduler::ProcessEventsToIdle();

    // switch off "Outline Folding" mode
    dispatchCommand(mxComponent, u".uno:ShowOutlineContentVisibilityButton"_ustr, {});
    CPPUNIT_ASSERT(!pWrtShell->GetViewOptions()->IsShowOutlineContentVisibilityButton());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf73483)
{
    // Given a document with a first paragraph having a manually set page break with page style
    createSwDoc("pageBreakWithPageStyle.fodt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    CPPUNIT_ASSERT_EQUAL(u"Right Page"_ustr, pWrtShell->GetCurPageStyle().toString());

    dispatchCommand(mxComponent, u".uno:ResetAttributes"_ustr,
                    {}); // Ctrl+M "Clear Direct Formatting"
    // Make sure that clearing direct formatting doesn't clear the page style
    CPPUNIT_ASSERT_EQUAL(u"Right Page"_ustr, pWrtShell->GetCurPageStyle().toString());

    // Make sure that the page break with page style survives ODF save-and-reload
    saveAndReload(TestFilter::ODT);

    xmlDocUniquePtr pXml = parseExport(u"content.xml"_ustr);
    CPPUNIT_ASSERT(pXml);
    OUString para_style_name
        = getXPath(pXml, "/office:document-content/office:body/office:text/text:p", "style-name");
    // Without the fix in place, this would fail
    CPPUNIT_ASSERT(!para_style_name.equalsIgnoreAsciiCase("Standard"));

    OString para_style_path
        = "/office:document-content/office:automatic-styles/style:style[@style:name='"
          + para_style_name.toUtf8() + "']";
    assertXPath(pXml, para_style_path, "family", u"paragraph");
    // Without the fix in place, the autostyle had no parent
    assertXPath(pXml, para_style_path, "parent-style-name", u"Standard");
    assertXPath(pXml, para_style_path, "master-page-name", u"Right_20_Page");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf62032ApplyStyle)
{
    createSwDoc("tdf62032_apply_style.odt");
    SwWrtShell* pWrtSh = getSwDocShell()->GetWrtShell();

    pWrtSh->Down(/*bSelect=*/false);

    cpo::uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
        { "Style", cpo::uno::Any(u"A 2"_ustr) },
        { "FamilyName", cpo::uno::Any(u"ParagraphStyles"_ustr) },
    });
    dispatchCommand(mxComponent, u".uno:StyleApply"_ustr, aPropertyValues);

    // Without the fix in place, it fails with:
    // - Expected: 1.1
    // - Actual  : 2
    CPPUNIT_ASSERT_EQUAL(u"1.1"_ustr,
                         getProperty<OUString>(getParagraph(2), u"ListLabelString"_ustr).trim());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf156560)
{
    createSwDoc("tdf156560.docx");

    uno::Reference<beans::XPropertySet> xPageStyle(
        getStyles(u"PageStyles"_ustr)->getByName(u"Standard"_ustr), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xPageStyle, u"HeaderIsOn"_ustr));

    SwXTextDocument* pTextDoc = getSwTextDoc();
    pTextDoc->postKeyEvent(COKitKeyEventType::DOWN, 0, KEY_MOD1 | KEY_PAGEUP);

    // Insert header
    // Without the fix in place, this test would have got SIGABRT here
    dispatchCommand(mxComponent, u".uno:InsertHeader"_ustr, {});
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testTdf158459)
{
    createSwDoc("tdf158459_tracked_changes_across_nodes.fodt");
    SwDoc* pDoc = getSwDoc();

    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);
    pWrtShell->FwdPara(); // Skip first paragraph
    pWrtShell->EndOfSection(true); // Select everything to the end

    SwDoc aClipboard;
    pWrtShell->Copy(aClipboard); // This must not crash

    pWrtShell->SelAll();
    pWrtShell->Delete();
    pWrtShell->Paste(aClipboard); // Replace everything with the copied stuff

    SwNodes& rNodes = pDoc->GetNodes();
    SwNodeIndex aIdx(rNodes.GetEndOfExtras());
    SwContentNode* pContentNode = SwNodes::GoNext(&aIdx);
    CPPUNIT_ASSERT(pContentNode);
    SwTextNode* pTextNode = pContentNode->GetTextNode();
    CPPUNIT_ASSERT(pTextNode);
    // Check that deleted parts (paragraph break, "c", "e") haven't been pasted
    CPPUNIT_ASSERT_EQUAL(u"abdf"_ustr, pTextNode->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testCopyPasteParaFormatting)
{
    // Given a document with three paragraphs:
    // - paragraphs 1-2: justified text "Hello" and "World" (multi-node source)
    // - paragraph 3: just a newline character "\n" (destination)
    // Copying multiple paragraphs triggers the multi-node path in CopyImplImpl
    // where bEmptyDestNd is false for "\n", so CopyCollFormat is skipped.
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);

    {
        SwPaM aPaM(aIdx);

        // Build two formatted paragraphs as copy source: first justified, second right-aligned
        pDoc->getIDocumentContentOperations().InsertString(aPaM, u"Hello"_ustr);
        aPaM.GetPointNode().GetTextNode()->SetAttr(
            SvxAdjustItem(SvxAdjust::Block, RES_PARATR_ADJUST));
        pDoc->getIDocumentContentOperations().SplitNode(*aPaM.GetPoint(), false);
        pDoc->getIDocumentContentOperations().InsertString(aPaM, u"World"_ustr);
        aPaM.GetPointNode().GetTextNode()->SetAttr(
            SvxAdjustItem(SvxAdjust::Right, RES_PARATR_ADJUST));

        // Third paragraph: destination with "\n" content and default (left) alignment
        pDoc->getIDocumentContentOperations().SplitNode(*aPaM.GetPoint(), false);
        pDoc->getIDocumentContentOperations().InsertString(aPaM, u"\n"_ustr);
        aPaM.GetPointNode().GetTextNode()->SetAttr(
            SvxAdjustItem(SvxAdjust::Left, RES_PARATR_ADJUST));
    }

    CPPUNIT_ASSERT_EQUAL(3, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"\n"_ustr, getParagraph(3)->getString());

    // Use CopyRange directly to exercise CopyImplImpl
    // Walk forward from start of body to find the three paragraphs
    SwNodeIndex aNodeIdx(pDoc->GetNodes().GetEndOfExtras());
    SwContentNode* pSttNode = SwNodes::GoNext(&aNodeIdx);
    ++aNodeIdx;
    SwContentNode* pEndNode = aNodeIdx.GetNode().GetContentNode();
    ++aNodeIdx;
    SwContentNode* pDestNode = aNodeIdx.GetNode().GetContentNode();
    CPPUNIT_ASSERT_EQUAL(u"Hello"_ustr, pSttNode->GetTextNode()->GetText());
    CPPUNIT_ASSERT_EQUAL(u"World"_ustr, pEndNode->GetTextNode()->GetText());

    {
        SwPaM aCopyPaM(*pSttNode, 0, *pEndNode, pEndNode->GetTextNode()->GetText().getLength());
        SwPosition aDestPos(*pDestNode, 0);

        pDoc->getIDocumentContentOperations().CopyRange(aCopyPaM, aDestPos, SwCopyFlags::Default);
    }

    // The last pasted paragraph should preserve right alignment from source.
    // In CopyImplImpl, bEmptyDestNd is false for "\n" content, so
    // CopyCollFormat is skipped in the multi-node path (line ~5419).
    auto xLastPara = getParagraph(getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"World\n"_ustr, xLastPara->getString());
    CPPUNIT_ASSERT_EQUAL(
        style::ParagraphAdjust_RIGHT,
        static_cast<style::ParagraphAdjust>(getProperty<sal_Int16>(xLastPara, u"ParaAdjust"_ustr)));

    // Undo and verify we're back to the original state
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->Undo();
    CPPUNIT_ASSERT_EQUAL(3, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"\n"_ustr, getParagraph(3)->getString());
    CPPUNIT_ASSERT_EQUAL(style::ParagraphAdjust_LEFT,
                         static_cast<style::ParagraphAdjust>(
                             getProperty<sal_Int16>(getParagraph(3), u"ParaAdjust"_ustr)));

    // Redo and verify formatting is restored
    pWrtShell->Redo();
    xLastPara = getParagraph(getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"World\n"_ustr, xLastPara->getString());
    CPPUNIT_ASSERT_EQUAL(
        style::ParagraphAdjust_RIGHT,
        static_cast<style::ParagraphAdjust>(getProperty<sal_Int16>(xLastPara, u"ParaAdjust"_ustr)));
}

} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
