Unit tests for tdf#121002 tdf#120013 tdf#123714 tdf#123736

 This is a combination of 4 commits.

Add unit tests for tdf#123736 and related unshared/regrouped listening

Reviewed-on: https://gerrit.libreoffice.org/69372
Tested-by: Jenkins
Reviewed-by: Eike Rathke <erack@redhat.com>
(cherry picked from commit 8925bd2efca8dd07a3ac044ecbc6505bb7bfa0a6)

Unit test for cut copy move into shared formula group reference, tdf#123714

Reviewed-on: https://gerrit.libreoffice.org/69453
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
(cherry picked from commit f81d532648ccbbd08d3cb568eadc9f402dac67ad)

Unit test for cut copy move with a group reference adjusting along, tdf#121002

Reviewed-on: https://gerrit.libreoffice.org/69532
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
(cherry picked from commit 92657eed57548511f26f0c22f1bbc47d554c8b5b)

bcf03f5068630c18eeecf2625cdff7ec1704d292
4f3731e2236f1b8be97a6f5d21e32e678610fecb

Unit test for cut copy move intersecting a formula group run, tdf#120013

Reviewed-on: https://gerrit.libreoffice.org/69568
Tested-by: Jenkins
Reviewed-by: Eike Rathke <erack@redhat.com>
(cherry picked from commit 6280b5c1c62ad40b5b9780a93c7cbee9ca0260f8)

ce7e1e42dba7bfbc2db6a60e4457c3610430b87e

Change-Id: If48e6d75288b42b47c90f3104006b7c52982c9f6
Reviewed-on: https://gerrit.libreoffice.org/69555
Tested-by: Jenkins
Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice@googlemail.com>
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 9f69783..45b46a9 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -407,6 +407,9 @@ public:
    void testSharedFormulaListenerDeleteArea();
    void testSharedFormulaUpdateOnReplacement();
    void testSharedFormulaDeleteTopCell();
    void testSharedFormulaCutCopyMoveIntoRef();
    void testSharedFormulaCutCopyMoveWithRef();
    void testSharedFormulaCutCopyMoveWithinRun();
    void testFormulaPosition();
    void testFormulaWizardSubformula();

@@ -757,6 +760,9 @@ public:
    CPPUNIT_TEST(testSharedFormulaListenerDeleteArea);
    CPPUNIT_TEST(testSharedFormulaUpdateOnReplacement);
    CPPUNIT_TEST(testSharedFormulaDeleteTopCell);
    CPPUNIT_TEST(testSharedFormulaCutCopyMoveIntoRef);
    CPPUNIT_TEST(testSharedFormulaCutCopyMoveWithRef);
    CPPUNIT_TEST(testSharedFormulaCutCopyMoveWithinRun);
    CPPUNIT_TEST(testFormulaPosition);
    CPPUNIT_TEST(testFormulaWizardSubformula);
    CPPUNIT_TEST(testMixData);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index 853f54c..96411b5 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -1668,6 +1668,21 @@ void Test::testSharedFormulaAbsCellListener()
    m_pDoc->DeleteTab(0);
}

static double checkNewValuesNotification( ScDocument* pDoc, const ScAddress& rOrgPos )
{
    ScAddress aPos(rOrgPos);
    aPos.IncCol();
    pDoc->SetValues( aPos, {1024.0, 2048.0, 4096.0, 8192.0, 16384.0});
    aPos = rOrgPos;
    double fVal = 0.0;
    for (SCROW i=0; i < 5; ++i)
    {
        fVal += pDoc->GetValue(aPos);
        aPos.IncRow();
    }
    return fVal;
}

void Test::testSharedFormulaUnshareAreaListeners()
{
    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
@@ -1696,6 +1711,460 @@ void Test::testSharedFormulaUnshareAreaListeners()
    CPPUNIT_ASSERT_EQUAL(17.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    CPPUNIT_ASSERT_EQUAL(40.0, m_pDoc->GetValue(ScAddress(0,2,0)));

    clearRange(m_pDoc, ScRange( 0,0,0, 1,3,0));

    for (int nRun = 0; nRun < 7; ++nRun)
    {
        // Data in A2:C6
        const ScAddress aOrgPos(0,1,0);
        const char* pData2[][3] = {
            { "=SUM(B2:C2)",   "1",   "2" },
            { "=SUM(B3:C3)",   "4",   "8" },
            { "=SUM(B4:C4)",  "16",  "32" },
            { "=SUM(B5:C5)",  "64", "128" },
            { "=SUM(B6:C6)", "256", "512" },
        };
        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Check that A2:A6 is a formula group.
        pFC = m_pDoc->GetFormulaCell(aOrgPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A2", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aOrgPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());

        // Overwrite and thus unshare formula in A3.
        // Check different code paths with different methods.
        ScAddress aPos(aOrgPos);
        aPos.IncRow(2);
        switch (nRun)
        {
            case 0:
                // Directly set a different formula cell, which bypasses
                // ScDocument::SetString(), mimicking formula input in view.
                {
                    ScFormulaCell* pCell = new ScFormulaCell( m_pDoc, aPos, "=B4");
                    ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
                    rDocFunc.SetFormulaCell( aPos, pCell, false);
                }
            break;
            case 1:
                m_pDoc->SetString( aPos, "=B4");    // set formula
            break;
            case 2:
                m_pDoc->SetString( aPos, "x");      // set string
            break;
            case 3:
                m_pDoc->SetString( aPos, "4096");   // set number/numeric
            break;
            case 4:
                m_pDoc->SetValue( aPos, 4096.0);    // set numeric
            break;
            case 5:
                m_pDoc->SetValues( aPos, {4096.0}); // set numeric vector
            break;
            case 6:
                // Set formula cell vector.
                {
                    ScFormulaCell* pCell = new ScFormulaCell( m_pDoc, aPos, "=B4");
                    std::vector<ScFormulaCell*> aCells;
                    aCells.push_back(pCell);
                    m_pDoc->SetFormulaCells( aPos, aCells);
                }
            break;
        }

        // Check that A2:A3 and A5:A6 are two formula groups.
        aPos = aOrgPos;
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A2", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
        aPos.IncRow(3);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A5", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());

        // Check that listeners were set up and formulas are updated when B2:B6
        // get new values input (tdf#123736).
        aPos = aOrgPos;
        aPos.IncCol();
        m_pDoc->SetValues( aPos, {1024.0, 2048.0, 4096.0, 8192.0, 16384.0});

        aPos = aOrgPos;
        CPPUNIT_ASSERT_EQUAL(1026.0, m_pDoc->GetValue(aPos));
        aPos.IncRow();
        CPPUNIT_ASSERT_EQUAL(2056.0, m_pDoc->GetValue(aPos));
        aPos.IncRow();
        if (nRun != 2)  // if not string
            CPPUNIT_ASSERT_EQUAL(4096.0, m_pDoc->GetValue(aPos));
        aPos.IncRow();
        CPPUNIT_ASSERT_EQUAL(8320.0, m_pDoc->GetValue(aPos));
        aPos.IncRow();
        CPPUNIT_ASSERT_EQUAL(16896.0, m_pDoc->GetValue(aPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,5,0));
    }

    // Check detach/regroup combinations of overlapping when setting formula
    // cell vectors.
    {
        // Fixed data in A3:C7, modified formula range A1:A9
        const ScAddress aOrgPos(0,2,0);
        ScAddress aPos( ScAddress::UNINITIALIZED);
        ScFormulaCell* pCell;
        std::vector<ScFormulaCell*> aCells;
        const char* pData2[][3] = {
            { "=SUM(B3:C3)",   "1",   "2" },
            { "=SUM(B4:C4)",   "4",   "8" },
            { "=SUM(B5:C5)",  "16",  "32" },
            { "=SUM(B6:C6)",  "64", "128" },
            { "=SUM(B7:C7)", "256", "512" },
        };

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Add grouping formulas in A1:A2, keep A3:A7
        aPos = ScAddress(0,0,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B1:C1)");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B2:C2)");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check it is one formula group.
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(7), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Add formulas in A1:A2, keep A3:A7
        aPos = ScAddress(0,0,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B1+C1");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B2+C2");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check formula groups.
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
        aPos.IncRow(2);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Add formula in A2, overwrite A3, keep A4:A7
        aPos = ScAddress(0,1,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B2+C2");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B3+C3");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check formula groups.
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A2", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
        aPos.IncRow(2);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A4", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(4), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Overwrite A3:A4, keep A5:A7
        aPos = ScAddress(0,2,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B3+C3");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B4+C4");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check formula groups.
        aPos = aOrgPos;
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
        aPos.IncRow(2);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A5", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(3), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Keep A3, overwrite A4:A5, keep A6:A7
        aPos = ScAddress(0,3,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B4+C4");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B5+C5");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check formula groups.
        aPos = aOrgPos;
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A3", !pFC->IsSharedTop());
        aPos.IncRow(1);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A4", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
        aPos.IncRow(2);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A6", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Keep A3:A4, overwrite A5:A6, keep A7
        aPos = ScAddress(0,4,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B5+C5");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B6+C6");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check formula groups.
        aPos = aOrgPos;
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
        aPos.IncRow(2);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A5", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
        aPos.IncRow(2);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A7", !pFC->IsSharedTop());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Keep A3:A5, overwrite A6:A7
        aPos = ScAddress(0,5,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B6+C6");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B7+C7");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check formula groups.
        aPos = aOrgPos;
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(3), pFC->GetSharedLength());
        aPos.IncRow(3);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A6", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Keep A3:A6, overwrite A7, add A8
        aPos = ScAddress(0,6,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B7+C7");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B8+C8");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check formula groups.
        aPos = aOrgPos;
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(4), pFC->GetSharedLength());
        aPos.IncRow(4);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A7", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Keep A3:A7, add A8:A9
        aPos = ScAddress(0,7,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B8+C8");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=B9+C9");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check formula groups.
        aPos = aOrgPos;
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());
        aPos.IncRow(5);
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A7", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Keep A3:A7, add grouping formulas in A8:A9
        aPos = ScAddress(0,7,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B8:C8)");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B9:C9)");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check it is one formula group.
        aPos = aOrgPos;
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(7), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));

        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));

        // Overwrite grouping formulas in A4:A5
        aPos = ScAddress(0,3,0);
        std::vector<ScFormulaCell*>().swap( aCells);
        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B4:C4)");
        aCells.push_back(pCell);
        aPos.IncRow();
        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B5:C5)");
        aCells.push_back(pCell);
        aPos.IncRow(-1);
        m_pDoc->SetFormulaCells( aPos, aCells);

        // Check it is one formula group.
        aPos = aOrgPos;
        pFC = m_pDoc->GetFormulaCell(aPos);
        CPPUNIT_ASSERT(pFC);
        CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());

        // Check notification of setting new values.
        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));

        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
    }

    m_pDoc->DeleteTab(0);
}

@@ -1940,5 +2409,266 @@ void Test::testSharedFormulaDeleteTopCell()
    m_pDoc->DeleteTab(0);
}

void Test::testSharedFormulaCutCopyMoveIntoRef()
{
    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.

    // tdf#123714 case 1
    {
        m_pDoc->InsertTab(0, "Test");

        // Data in A1:C3
        std::vector<std::vector<const char*>> aData = {
            { "=B1", "", "1" },
            { "=B2", "", "1" },
            { "=B3", "", ""  }
        };
        const ScAddress aOrgPos(0,0,0);
        insertRangeData( m_pDoc, aOrgPos, aData);

        ScMarkData aMark;
        aMark.SelectOneTable(0);

        // Set up clip document.
        ScDocument aClipDoc(SCDOCMODE_CLIP);
        aClipDoc.ResetClip(m_pDoc, &aMark);
        // Cut C1:C2 to clipboard.
        cutToClip( getDocShell(), ScRange(2,0,0, 2,1,0), &aClipDoc, false);

        // Paste to B1:B2
        ScRange aPasteRange(1,0,0, 1,1,0);
        aMark.SetMarkArea(aPasteRange);
        m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);

        // Check data in A1:A2 after Paste.
        ScAddress aPos(aOrgPos);
        CPPUNIT_ASSERT_EQUAL_MESSAGE("A1", 1.0, m_pDoc->GetValue(aPos));
        aPos.IncRow();
        CPPUNIT_ASSERT_EQUAL_MESSAGE("A2", 1.0, m_pDoc->GetValue(aPos));

        m_pDoc->DeleteTab(0);
    }

    // tdf#123714 case 2
    {
        m_pDoc->InsertTab(0, "Test");

        // Data in A1:C3
        std::vector<std::vector<const char*>> aData = {
            {  "1",   "2", "=SUM(A1:B1)" },
            {  "4",   "8", "=SUM(A2:B2)" },
            { "16",  "32", "=SUM(A3:B3)" },
            { "64", "128", "=SUM(A4:B4)" },
        };
        const ScAddress aOrgPos(0,0,0);
        insertRangeData( m_pDoc, aOrgPos, aData);

        ScAddress aPos;
        // Check results in C1:C4
        const double fVec0[] = { 3.0, 12.0, 48.0, 192.0 };
        aPos = ScAddress(2,0,0);
        for (SCROW i=0; i < 4; ++i)
        {
            CPPUNIT_ASSERT_EQUAL( fVec0[i], m_pDoc->GetValue(aPos));
            aPos.IncRow();
        }

        ScMarkData aMark;
        aMark.SelectOneTable(0);

        // Set up clip document.
        ScDocument aClipDoc(SCDOCMODE_CLIP);
        aClipDoc.ResetClip(m_pDoc, &aMark);
        // Cut B1:B2 to clipboard.
        cutToClip( getDocShell(), ScRange(1,0,0, 1,1,0), &aClipDoc, false);

        // Check results in C1:C4 after Cut.
        const double fVec1[] = { 1.0, 4.0, 48.0, 192.0 };
        aPos = ScAddress(2,0,0);
        for (SCROW i=0; i < 4; ++i)
        {
            CPPUNIT_ASSERT_EQUAL( fVec1[i], m_pDoc->GetValue(aPos));
            aPos.IncRow();
        }

        // Paste to B3:B4
        ScRange aPasteRange(1,2,0, 1,3,0);
        aMark.SetMarkArea(aPasteRange);
        m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);

        // Check results in C1:C4 after Paste.
        const double fVec2[] = { 1.0, 4.0, 18.0, 72.0 };
        aPos = ScAddress(2,0,0);
        for (SCROW i=0; i < 4; ++i)
        {
            CPPUNIT_ASSERT_EQUAL( fVec2[i], m_pDoc->GetValue(aPos));
            aPos.IncRow();
        }

        // Paste to B1:B2
        aPasteRange = ScRange(1,0,0, 1,1,0);
        aMark.SetMarkArea(aPasteRange);
        m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);

        // Check results in C1:C4 after Paste.
        const double fVec3[] = { 3.0, 12.0, 18.0, 72.0 };
        aPos = ScAddress(2,0,0);
        for (SCROW i=0; i < 4; ++i)
        {
            CPPUNIT_ASSERT_EQUAL( fVec3[i], m_pDoc->GetValue(aPos));
            aPos.IncRow();
        }

        m_pDoc->DeleteTab(0);
    }
}

// tdf#121002
void Test::testSharedFormulaCutCopyMoveWithRef()
{
    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.

    m_pDoc->InsertTab(0, "Test");

    // Data in A1:C4
    std::vector<std::vector<const char*>> aData = {
        {  "",  "", "=SUM(A1:B1)" },
        {  "",  "", "=SUM(A2:B2)" },
        { "1", "2", "=SUM(A3:B3)" },
        { "4", "8", "=SUM(A4:B4)" }
    };
    const ScAddress aOrgPos(0,0,0);
    insertRangeData( m_pDoc, aOrgPos, aData);

    ScMarkData aMark;
    aMark.SelectOneTable(0);

    ScAddress aPos( ScAddress::UNINITIALIZED);

    // Check results in C1:C4
    const double fVec0[] = { 0.0, 0.0, 3.0, 12.0 };
    aPos = ScAddress(2,0,0);
    for (SCROW i=0; i < 4; ++i)
    {
        CPPUNIT_ASSERT_EQUAL( fVec0[i], m_pDoc->GetValue(aPos));
        aPos.IncRow();
    }

    // Set up clip document.
    ScDocument aClipDoc(SCDOCMODE_CLIP);
    aClipDoc.ResetClip(m_pDoc, &aMark);
    // Cut A3:B3 to clipboard.
    cutToClip( getDocShell(), ScRange(0,2,0, 1,2,0), &aClipDoc, false);

    // Check results in C1:C4 after Cut.
    const double fVec1[] = { 0.0, 0.0, 0.0, 12.0 };
    aPos = ScAddress(2,0,0);
    for (SCROW i=0; i < 4; ++i)
    {
        CPPUNIT_ASSERT_EQUAL( fVec1[i], m_pDoc->GetValue(aPos));
        aPos.IncRow();
    }

    // Paste to A1:B1
    ScRange aPasteRange(0,0,0, 1,0,0);
    aMark.SetMarkArea(aPasteRange);
    m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);

    // Check results in C1:C4 after Paste.
    const double fVec2[] = { 3.0, 0.0, 3.0, 12.0 };
    aPos = ScAddress(2,0,0);
    for (SCROW i=0; i < 4; ++i)
    {
        CPPUNIT_ASSERT_EQUAL( fVec2[i], m_pDoc->GetValue(aPos));
        aPos.IncRow();
    }

    // Check formulas in C1:C4 after Paste.
    const OUStringLiteral sForm[] = { "=SUM(A1:B1)", "=SUM(A2:B2)", "=SUM(A1:B1)", "=SUM(A4:B4)" };
    for (SCROW i=0; i < 4; ++i)
    {
        OUString aFormula;
        m_pDoc->GetFormula( 2,i,0, aFormula);
        CPPUNIT_ASSERT_EQUAL( OUString(sForm[i]), aFormula);
    }

    m_pDoc->DeleteTab(0);
}

// tdf#120013
void Test::testSharedFormulaCutCopyMoveWithinRun()
{
    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.

    m_pDoc->InsertTab(0, "Test");

    // Data in C3:E9
    const std::vector<std::vector<const char*>> aData = {
        { "2200",     "", "=SUM(C$3:C3)-SUM(D$3:D3)" },
        {     "",     "", "=SUM(C$3:C4)-SUM(D$3:D4)" },
        {     "", "1900", "=SUM(C$3:C5)-SUM(D$3:D5)" },
        {     "",     "", "=SUM(C$3:C6)-SUM(D$3:D6)" },
        { "1600",     "", "=SUM(C$3:C7)-SUM(D$3:D7)" },
        {     "", "1000", "=SUM(C$3:C8)-SUM(D$3:D8)" },
        {     "",     "", "=SUM(C$3:C9)-SUM(D$3:D9)" }
    };
    const ScAddress aOrgPos(2,2,0);
    insertRangeData( m_pDoc, aOrgPos, aData);

    // Check that E3:E9 is a formula group.
    const ScAddress aFormulaPos(4,2,0);
    const ScFormulaCell* pFC = m_pDoc->GetFormulaCell( aFormulaPos);
    CPPUNIT_ASSERT(pFC);
    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula top row.", aFormulaPos.Row(), pFC->GetSharedTopRow());
    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula length.", static_cast<SCROW>(7), pFC->GetSharedLength());

    ScAddress aPos( ScAddress::UNINITIALIZED);

    // Check results in E3:E9
    const double fVec0[] = { 2200.0, 2200.0, 300.0, 300.0, 1900.0, 900.0, 900.0 };
    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec0), aData.size());
    aPos = aFormulaPos;
    for (size_t i=0; i < SAL_N_ELEMENTS(fVec0); ++i)
    {
        CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9", fVec0[i], m_pDoc->GetValue(aPos));
        aPos.IncRow();
    }

    ScMarkData aMark;
    aMark.SelectOneTable(0);

    // Set up clip document.
    ScDocument aClipDoc(SCDOCMODE_CLIP);
    aClipDoc.ResetClip(m_pDoc, &aMark);
    // Cut A8:D8 to clipboard.
    cutToClip( getDocShell(), ScRange(0,7,0, 3,7,0), &aClipDoc, false);

    // Check results in E3:E9 after Cut.
    const double fVec1[] = { 2200.0, 2200.0, 300.0, 300.0, 1900.0, 1900.0, 1900.0 };
    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec1), aData.size());
    aPos = aFormulaPos;
    for (size_t i=0; i < SAL_N_ELEMENTS(fVec1); ++i)
    {
        CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9 after Cut.", fVec1[i], m_pDoc->GetValue(aPos));
        aPos.IncRow();
    }

    // Paste to A4:D4
    ScRange aPasteRange(0,3,0, 3,3,0);
    aMark.SetMarkArea(aPasteRange);
    m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);

    // Check results in E3:E9 after Paste.
    const double fVec2[] = { 2200.0, 1200.0, -700.0, -700.0, 900.0, 900.0, 900.0 };
    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec2), aData.size());
    aPos = aFormulaPos;
    for (size_t i=0; i < SAL_N_ELEMENTS(fVec2); ++i)
    {
        CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9 after Paste.", fVec2[i], m_pDoc->GetValue(aPos));
        aPos.IncRow();
    }

    m_pDoc->DeleteTab(0);
}

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