[Libreoffice-commits] core.git: Branch 'libreoffice-4-3' - sc/CppunitTest_sc_ucalc.mk sc/qa

Michael Meeks michael.meeks at collabora.com
Fri Oct 17 09:12:02 PDT 2014


 sc/CppunitTest_sc_ucalc.mk |    1 
 sc/qa/unit/ucalc.cxx       |  491 ---------------
 sc/qa/unit/ucalc.hxx       |   21 
 sc/qa/unit/ucalc_sort.cxx  | 1464 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1485 insertions(+), 492 deletions(-)

New commits:
commit f4dabc071f0eaf0e22db9b23c573a380b5e480ff
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Thu Oct 9 17:30:42 2014 +0100

    Back-port Kohei's comprehensive sorting unit tests from master.
    
    As of master commit fab88063281761dbdac7ea550072660fe0f8c863.
    
    Change-Id: I45ee0021c727281ba5590ceead6d8c5848e25169
    Reviewed-on: https://gerrit.libreoffice.org/11903
    Reviewed-by: Muthu Subramanian K <muthusuba at gmail.com>
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Eike Rathke <erack at redhat.com>

diff --git a/sc/CppunitTest_sc_ucalc.mk b/sc/CppunitTest_sc_ucalc.mk
index 9b3c498..2054f19 100644
--- a/sc/CppunitTest_sc_ucalc.mk
+++ b/sc/CppunitTest_sc_ucalc.mk
@@ -17,6 +17,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,sc_ucalc, \
     sc/qa/unit/ucalc_formula \
     sc/qa/unit/ucalc_pivottable \
     sc/qa/unit/ucalc_sharedformula \
+    sc/qa/unit/ucalc_sort \
 ))
 
 $(eval $(call gb_CppunitTest_use_library_objects,sc_ucalc, \
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 8e19f2f..2bb0889 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -4724,497 +4724,6 @@ void Test::testFindAreaPosColRight()
     m_pDoc->DeleteTab(0);
 }
 
-// regression test fo fdo#53814, sorting doens't work as expected
-// if cells in the sort are referenced by formulas
-void Test::testSortWithFormulaRefs()
-{
-    m_pDoc->InsertTab(0, "List1");
-    m_pDoc->InsertTab(1, "List2");
-
-    const char* aFormulaData[6] = {
-        "=IF($List1.A2<>\"\";$List1.A2;\"\")",
-        "=IF($List1.A3<>\"\";$List1.A3;\"\")",
-        "=IF($List1.A4<>\"\";$List1.A4;\"\")",
-        "=IF($List1.A5<>\"\";$List1.A5;\"\")",
-        "=IF($List1.A6<>\"\";$List1.A6;\"\")",
-        "=IF($List1.A7<>\"\";$List1.A7;\"\")",
-    };
-
-    const char* aTextData[4] = {
-        "bob",
-        "tim",
-        "brian",
-        "larry",
-    };
-
-    const char* aResults[6] = {
-        "bob",
-        "brian",
-        "larry",
-        "tim",
-        "",
-        "",
-    };
-
-    // Insert data to sort in A2:A5 on the 1st sheet.
-    for (SCROW i = 1; i <= 4; ++i)
-        m_pDoc->SetString( 0, i, 0, OUString::createFromAscii(aTextData[i-1]) );
-
-    // Insert forumulas in A1:A6 on the 2nd sheet.
-    for (size_t i = 0; i < SAL_N_ELEMENTS(aFormulaData); ++i)
-        m_pDoc->SetString( 0, i, 1, OUString::createFromAscii(aFormulaData[i]) );
-
-    // Sort data in A2:A8 on the 1st sheet. No column header.
-    ScSortParam aSortData;
-    aSortData.nCol1 = 0;
-    aSortData.nCol2 = 0;
-    aSortData.nRow1 = 1;
-    aSortData.nRow2 = 7;
-    aSortData.maKeyState[0].bDoSort = true;
-    aSortData.maKeyState[0].nField = 0;
-
-    m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
-
-    for (size_t i = 0; i < SAL_N_ELEMENTS(aResults); ++i)
-    {
-        OUString sResult = m_pDoc->GetString(0, i + 1, 0);
-        CPPUNIT_ASSERT_EQUAL( OUString::createFromAscii( aResults[i] ), sResult );
-    }
-    m_pDoc->DeleteTab(1);
-    m_pDoc->DeleteTab(0);
-}
-
-void Test::testSortWithStrings()
-{
-    m_pDoc->InsertTab(0, "Test");
-
-    ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
-    rEE.SetText("Val1");
-    m_pDoc->SetString(ScAddress(1,1,0), "Header");
-    m_pDoc->SetString(ScAddress(1,2,0), "Val2");
-    m_pDoc->SetEditText(ScAddress(1,3,0), rEE.CreateTextObject());
-
-    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,2,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,3,0)));
-
-    ScSortParam aParam;
-    aParam.nCol1 = 1;
-    aParam.nCol2 = 1;
-    aParam.nRow1 = 1;
-    aParam.nRow2 = 3;
-    aParam.bHasHeader = true;
-    aParam.maKeyState[0].bDoSort = true;
-    aParam.maKeyState[0].bAscending = true;
-    aParam.maKeyState[0].nField = 1;
-
-    m_pDoc->Sort(0, aParam, false, true, NULL, NULL);
-
-    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,2,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,3,0)));
-
-    aParam.maKeyState[0].bAscending = false;
-
-    m_pDoc->Sort(0, aParam, false, true, NULL, NULL);
-
-    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,2,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,3,0)));
-
-    m_pDoc->DeleteTab(0);
-}
-
-void Test::testSort()
-{
-    m_pDoc->InsertTab(0, "test1");
-
-    ScRange aDataRange;
-    ScAddress aPos(0,0,0);
-    {
-        const char* aData[][2] = {
-            { "2", "4" },
-            { "4", "1" },
-            { "1", "2" },
-            { "1", "23" },
-        };
-
-        clearRange(m_pDoc, ScRange(0, 0, 0, 1, SAL_N_ELEMENTS(aData), 0));
-        aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
-        CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-    }
-
-    // Insert note in cell B2.
-    ScAddress rAddr(1, 1, 0);
-    ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
-    pNote->SetText(rAddr, "Hello");
-    pNote->SetAuthor("Jim Bob");
-
-    ScSortParam aSortData;
-    aSortData.nCol1 = 1;
-    aSortData.nCol2 = 1;
-    aSortData.nRow1 = 0;
-    aSortData.nRow2 = 2;
-    aSortData.maKeyState[0].bDoSort = true;
-    aSortData.maKeyState[0].nField = 1;
-    aSortData.maKeyState[0].bAscending = true;
-
-    m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
-
-    double nVal = m_pDoc->GetValue(1,0,0);
-    ASSERT_DOUBLES_EQUAL(nVal, 1.0);
-
-    // check that note is also moved after sorting
-    pNote = m_pDoc->GetNote(1, 0, 0);
-    CPPUNIT_ASSERT(pNote);
-
-    clearRange(m_pDoc, ScRange(0, 0, 0, 1, 9, 0)); // Clear A1:B10.
-    {
-        // 0 = empty cell
-        const char* aData[][1] = {
-            { "Title" },
-            { 0 },
-            { 0 },
-            { "12" },
-            { "b" },
-            { "1" },
-            { "9" },
-            { "123" }
-        };
-
-        aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
-        CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-    }
-
-    aSortData.nCol1 = aDataRange.aStart.Col();
-    aSortData.nCol2 = aDataRange.aEnd.Col();
-    aSortData.nRow1 = aDataRange.aStart.Row();
-    aSortData.nRow2 = aDataRange.aEnd.Row();
-    aSortData.bHasHeader = true;
-    aSortData.maKeyState[0].nField = 0;
-    m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
-
-    // Title should stay at the top, numbers should be sorted numerically,
-    // numbers always come before strings, and empty cells always occur at the
-    // end.
-    CPPUNIT_ASSERT_EQUAL(OUString("Title"), m_pDoc->GetString(aPos));
-    aPos.IncRow();
-    CPPUNIT_ASSERT_EQUAL(OUString("1"), m_pDoc->GetString(aPos));
-    aPos.IncRow();
-    CPPUNIT_ASSERT_EQUAL(OUString("9"), m_pDoc->GetString(aPos));
-    aPos.IncRow();
-    CPPUNIT_ASSERT_EQUAL(OUString("12"), m_pDoc->GetString(aPos));
-    aPos.IncRow();
-    CPPUNIT_ASSERT_EQUAL(OUString("123"), m_pDoc->GetString(aPos));
-    aPos.IncRow();
-    CPPUNIT_ASSERT_EQUAL(OUString("b"), m_pDoc->GetString(aPos));
-    aPos.IncRow();
-    CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPos));
-
-    m_pDoc->DeleteTab(0);
-}
-
-void Test::testSortHorizontal()
-{
-    ScFormulaOptions aOptions;
-    aOptions.SetFormulaSepArg(";");
-    aOptions.SetFormulaSepArrayCol(";");
-    aOptions.SetFormulaSepArrayRow("|");
-    getDocShell().SetFormulaOptions(aOptions);
-
-    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
-    m_pDoc->InsertTab(0, "Sort");
-
-    // Test case from fdo#78079.
-
-    // 0 = empty cell
-    const char* aData[][4] = {
-        { "table", "has UNIQUE", "Publish to EC2", "flag" },
-        { "w2gi.mobilehit", "Yes", "No", "=CONCATENATE(B2;\"-\";C2)" },
-        { "w2gi.visitors", "No", "No", "=CONCATENATE(B3;\"-\";C3)" },
-        { "w2gi.pagedimension", "Yes", "Yes", "=CONCATENATE(B4;\"-\";C4)" },
-    };
-
-    // Insert raw data into A1:D4.
-    ScRange aDataRange = insertRangeData(m_pDoc, ScAddress(0,0,0), aData, SAL_N_ELEMENTS(aData));
-    CPPUNIT_ASSERT_EQUAL(OUString("A1:D4"), aDataRange.Format(SCA_VALID));
-
-    // Check the formula values.
-    CPPUNIT_ASSERT_EQUAL(OUString("Yes-No"), m_pDoc->GetString(ScAddress(3,1,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("No-No"), m_pDoc->GetString(ScAddress(3,2,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Yes-Yes"), m_pDoc->GetString(ScAddress(3,3,0)));
-
-    // Define A1:D4 as sheet-local anonymous database range.
-    m_pDoc->SetAnonymousDBData(
-        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 3, 3));
-
-    // Sort A1:D4 horizontally, ascending by row 1.
-    ScDBDocFunc aFunc(getDocShell());
-
-    ScSortParam aSortData;
-    aSortData.nCol1 = 0;
-    aSortData.nCol2 = 3;
-    aSortData.nRow1 = 0;
-    aSortData.nRow2 = 3;
-    aSortData.bHasHeader = true;
-    aSortData.bByRow = false; // Sort by column (in horizontal direction).
-    aSortData.bIncludePattern = true;
-    aSortData.maKeyState[0].bDoSort = true;
-    aSortData.maKeyState[0].nField = 0;
-    aSortData.maKeyState[0].bAscending = true;
-    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
-    CPPUNIT_ASSERT(bSorted);
-
-    {
-        // Expected output table content.  0 = empty cell
-        const char* aOutputCheck[][4] = {
-            { "table", "flag", "has UNIQUE", "Publish to EC2" },
-            { "w2gi.mobilehit",     "Yes-No",  "Yes", "No" },
-            { "w2gi.visitors",      "No-No",   "No",  "No" },
-            { "w2gi.pagedimension", "Yes-Yes", "Yes", "Yes" },
-        };
-
-        bool bSuccess = checkOutput<4>(m_pDoc, aDataRange, aOutputCheck, "Sorted by column with formula");
-        CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
-    }
-
-    if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "CONCATENATE(C2;\"-\";D2)"))
-        CPPUNIT_FAIL("Wrong formula!");
-    if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "CONCATENATE(C3;\"-\";D3)"))
-        CPPUNIT_FAIL("Wrong formula!");
-    if (!checkFormula(*m_pDoc, ScAddress(1,3,0), "CONCATENATE(C4;\"-\";D4)"))
-        CPPUNIT_FAIL("Wrong formula!");
-
-    m_pDoc->DeleteTab(0);
-}
-
-void Test::testSortInFormulaGroup()
-{
-    static struct {
-        SCCOL nCol;
-        SCROW nRow;
-        const char *pData;
-    } aEntries[] = {
-        { 0, 0, "3" },   { 1, 0, "=A1" },
-        { 0, 1, "1" },   { 1, 1, "=A2" },
-        { 0, 2, "20" },  { 1, 2, "=A3" },
-        { 0, 3, "10" },  { 1, 3, "=A4+1" }, // swap across groups
-        { 0, 4, "2"  },  { 1, 4, "=A5+1" },
-        { 0, 5, "101" }, { 1, 5, "=A6" }, // swap inside contiguious group
-        { 0, 6, "100" }, { 1, 6, "=A7" },
-        { 0, 7, "102" }, { 1, 7, "=A8" },
-        { 0, 8, "104" }, { 1, 8, "=A9" },
-        { 0, 9, "103" }, { 1, 9, "=A10" },
-    };
-
-    m_pDoc->InsertTab(0, "sorttest");
-
-    for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
-        m_pDoc->SetString( aEntries[i].nCol, aEntries[i].nRow, 0,
-                           OUString::createFromAscii( aEntries[i].pData) );
-
-    ScSortParam aSortData;
-    aSortData.nCol1 = 0;
-    aSortData.nCol2 = 1;
-    aSortData.nRow1 = 0;
-    aSortData.nRow2 = 9;
-    aSortData.maKeyState[0].bDoSort = true;
-    aSortData.maKeyState[0].nField = 0;
-    aSortData.maKeyState[0].bAscending = true;
-
-    m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
-
-    static struct {
-        SCCOL nCol;
-        SCROW nRow;
-        double fValue;
-    } aResults[] = {
-        { 0, 0, 1.0 },   { 1, 0, 1.0 },
-        { 0, 1, 2.0 },   { 1, 1, 3.0 },
-        { 0, 2, 3.0 },   { 1, 2, 3.0 },
-        { 0, 3, 10.0 },  { 1, 3, 11.0 },
-        { 0, 4, 20.0 },  { 1, 4, 20.0 },
-        { 0, 5, 100.0 }, { 1, 5, 100.0 },
-        { 0, 6, 101.0 }, { 1, 6, 101.0 },
-        { 0, 7, 102.0 }, { 1, 7, 102.0 },
-        { 0, 8, 103.0 }, { 1, 8, 103.0 },
-        { 0, 9, 104.0 }, { 1, 9, 104.0 },
-    };
-
-    for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
-    {
-        double val = m_pDoc->GetValue( aEntries[i].nCol, aEntries[i].nRow, 0 );
-//        fprintf(stderr, "value at %d %d is %g = %g\n",
-//                (int)aResults[i].nRow, (int)aResults[i].nCol,
-//                val, aResults[i].fValue);
-        CPPUNIT_ASSERT_MESSAGE("Mis-matching value after sort.",
-                               rtl::math::approxEqual(val, aResults[i].fValue));
-    }
-
-    m_pDoc->DeleteTab( 0 );
-}
-
-void Test::testSortWithCellFormats()
-{
-    struct
-    {
-        bool isBold( const ScPatternAttr* pPat ) const
-        {
-            if (!pPat)
-            {
-                cerr << "Pattern is NULL!" << endl;
-                return false;
-            }
-
-            const SfxPoolItem* pItem = NULL;
-            if (!pPat->GetItemSet().HasItem(ATTR_FONT_WEIGHT, &pItem))
-            {
-                cerr << "Pattern does not have a font weight item, but it should." << endl;
-                return false;
-            }
-
-            if (static_cast<const SvxWeightItem*>(pItem)->GetEnumValue() != WEIGHT_BOLD)
-            {
-                cerr << "Font weight should be bold." << endl;
-                return false;
-            }
-
-            return true;
-        }
-
-        bool isItalic( const ScPatternAttr* pPat ) const
-        {
-            if (!pPat)
-            {
-                cerr << "Pattern is NULL!" << endl;
-                return false;
-            }
-
-            const SfxPoolItem* pItem = NULL;
-            if (!pPat->GetItemSet().HasItem(ATTR_FONT_POSTURE, &pItem))
-            {
-                cerr << "Pattern does not have a font posture item, but it should." << endl;
-                return false;
-            }
-
-            if (static_cast<const SvxPostureItem*>(pItem)->GetEnumValue() != ITALIC_NORMAL)
-            {
-                cerr << "Italic should be applied.." << endl;
-                return false;
-            }
-
-            return true;
-        }
-
-        bool isNormal( const ScPatternAttr* pPat ) const
-        {
-            if (!pPat)
-            {
-                cerr << "Pattern is NULL!" << endl;
-                return false;
-            }
-
-            const SfxPoolItem* pItem = NULL;
-            if (pPat->GetItemSet().HasItem(ATTR_FONT_WEIGHT))
-            {
-                // Check if the font weight is applied.
-                if (static_cast<const SvxWeightItem*>(pItem)->GetEnumValue() == WEIGHT_BOLD)
-                {
-                    cerr << "This cell is bold, but shouldn't." << endl;
-                    return false;
-                }
-            }
-
-            if (pPat->GetItemSet().HasItem(ATTR_FONT_POSTURE))
-            {
-                // Check if the italics is applied.
-                if (static_cast<const SvxPostureItem*>(pItem)->GetEnumValue() == ITALIC_NORMAL)
-                {
-                    cerr << "This cell is bold, but shouldn't." << endl;
-                    return false;
-                }
-            }
-
-            return true;
-        }
-
-    } aCheck;
-
-    m_pDoc->InsertTab(0, "Test");
-
-    // Insert some values into A1:A4.
-    m_pDoc->SetString(ScAddress(0,0,0), "Header");
-    m_pDoc->SetString(ScAddress(0,1,0), "Normal");
-    m_pDoc->SetString(ScAddress(0,2,0), "Bold");
-    m_pDoc->SetString(ScAddress(0,3,0), "Italic");
-
-    // Set A3 bold and A4 italic.
-    const ScPatternAttr* pPat = m_pDoc->GetPattern(ScAddress(0,2,0));
-    CPPUNIT_ASSERT(pPat);
-    {
-        ScPatternAttr aNewPat(*pPat);
-        SfxItemSet& rSet = aNewPat.GetItemSet();
-        rSet.Put(SvxWeightItem(WEIGHT_BOLD, ATTR_FONT_WEIGHT));
-        m_pDoc->ApplyPattern(0, 2, 0, aNewPat);
-
-        // Make sure it's really in.
-        bool bGood = aCheck.isBold(m_pDoc->GetPattern(ScAddress(0,2,0)));
-        CPPUNIT_ASSERT_MESSAGE("A3 is not bold but it should.", bGood);
-    }
-
-    pPat = m_pDoc->GetPattern(ScAddress(0,3,0));
-    CPPUNIT_ASSERT(pPat);
-    {
-        ScPatternAttr aNewPat(*pPat);
-        SfxItemSet& rSet = aNewPat.GetItemSet();
-        rSet.Put(SvxPostureItem(ITALIC_NORMAL, ATTR_FONT_POSTURE));
-        m_pDoc->ApplyPattern(0, 3, 0, aNewPat);
-
-        bool bGood = aCheck.isItalic(m_pDoc->GetPattern(ScAddress(0,3,0)));
-        CPPUNIT_ASSERT_MESSAGE("A4 is not italic but it should.", bGood);
-    }
-
-    // Define A1:A4 as sheet-local anonymous database range, else sort wouldn't run.
-    m_pDoc->SetAnonymousDBData(
-        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 3));
-
-    // Sort A1:A4 ascending with cell formats.
-    ScDBDocFunc aFunc(getDocShell());
-
-    ScSortParam aSortData;
-    aSortData.nCol1 = 0;
-    aSortData.nCol2 = 0;
-    aSortData.nRow1 = 0;
-    aSortData.nRow2 = 3;
-    aSortData.bHasHeader = true;
-    aSortData.bIncludePattern = true;
-    aSortData.maKeyState[0].bDoSort = true;
-    aSortData.maKeyState[0].nField = 0;
-    aSortData.maKeyState[0].bAscending = true;
-    bool bSorted = aFunc.Sort(0, aSortData, true, false, true);
-    CPPUNIT_ASSERT(bSorted);
-
-    // Check the sort result.
-    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Bold"),   m_pDoc->GetString(ScAddress(0,1,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Italic"), m_pDoc->GetString(ScAddress(0,2,0)));
-    CPPUNIT_ASSERT_EQUAL(OUString("Normal"), m_pDoc->GetString(ScAddress(0,3,0)));
-
-    // A2 should be bold now.
-    bool bBold = aCheck.isBold(m_pDoc->GetPattern(ScAddress(0,1,0)));
-    CPPUNIT_ASSERT_MESSAGE("A2 should be bold after the sort.", bBold);
-
-    // and A3 should be italic.
-    bool bItalic = aCheck.isItalic(m_pDoc->GetPattern(ScAddress(0,2,0)));
-    CPPUNIT_ASSERT_MESSAGE("A3 should be italic.", bItalic);
-
-    // A4 should have neither bold nor italic.
-    bool bNormal = aCheck.isNormal(m_pDoc->GetPattern(ScAddress(0,3,0)));
-    CPPUNIT_ASSERT_MESSAGE("A4 should be neither bold nor italic.", bNormal);
-
-    m_pDoc->DeleteTab(0);
-}
-
 void Test::testShiftCells()
 {
     m_pDoc->InsertTab(0, "foo");
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 39862ee..a1688f7 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -338,13 +338,23 @@ public:
 
     void testFindAreaPosVertical();
     void testFindAreaPosColRight();
+    void testShiftCells();
+
     void testSort();
     void testSortHorizontal();
+    void testSortHorizontalWholeColumn();
+    void testSortSingleRow();
     void testSortWithFormulaRefs();
     void testSortWithStrings();
     void testSortInFormulaGroup();
     void testSortWithCellFormats();
-    void testShiftCells();
+    void testSortRefUpdate();
+    void testSortRefUpdate2();
+    void testSortRefUpdate3();
+    void testSortRefUpdate4();
+    void testSortRefUpdate5();
+    void testSortOutOfPlaceResult();
+    void testSortPartialFormulaGroup();
 
     void testNoteBasic();
     void testNoteDeleteRow();
@@ -507,10 +517,19 @@ public:
     CPPUNIT_TEST(testFindAreaPosColRight);
     CPPUNIT_TEST(testSort);
     CPPUNIT_TEST(testSortHorizontal);
+    CPPUNIT_TEST(testSortHorizontalWholeColumn);
+    CPPUNIT_TEST(testSortSingleRow);
     CPPUNIT_TEST(testSortWithFormulaRefs);
     CPPUNIT_TEST(testSortWithStrings);
     CPPUNIT_TEST(testSortInFormulaGroup);
     CPPUNIT_TEST(testSortWithCellFormats);
+    CPPUNIT_TEST(testSortRefUpdate);
+    CPPUNIT_TEST(testSortRefUpdate2);
+    CPPUNIT_TEST(testSortRefUpdate3);
+    CPPUNIT_TEST(testSortRefUpdate4);
+    CPPUNIT_TEST(testSortRefUpdate5);
+    CPPUNIT_TEST(testSortOutOfPlaceResult);
+    CPPUNIT_TEST(testSortPartialFormulaGroup);
     CPPUNIT_TEST(testShiftCells);
     CPPUNIT_TEST(testNoteBasic);
     CPPUNIT_TEST(testNoteDeleteRow);
diff --git a/sc/qa/unit/ucalc_sort.cxx b/sc/qa/unit/ucalc_sort.cxx
new file mode 100644
index 0000000..f81a394
--- /dev/null
+++ b/sc/qa/unit/ucalc_sort.cxx
@@ -0,0 +1,1464 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ucalc.hxx"
+
+#include <postit.hxx>
+#include <sortparam.hxx>
+#include <dbdata.hxx>
+#include <patattr.hxx>
+#include <formulacell.hxx>
+#include <scopetools.hxx>
+#include <globalnames.hxx>
+#include <dbdocfun.hxx>
+#include <scitems.hxx>
+#include <inputopt.hxx>
+#include <editutil.hxx>
+
+#include <sal/config.h>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <test/bootstrapfixture.hxx>
+
+void Test::testSort()
+{
+    m_pDoc->InsertTab(0, "test1");
+
+    ScRange aDataRange;
+    ScAddress aPos(0,0,0);
+    {
+        const char* aData[][2] = {
+            { "2", "4" },
+            { "4", "1" },
+            { "1", "2" },
+            { "1", "23" },
+        };
+
+        clearRange(m_pDoc, ScRange(0, 0, 0, 1, SAL_N_ELEMENTS(aData), 0));
+        aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+        CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+    }
+
+    // Insert note in cell B2.
+    ScAddress rAddr(1, 1, 0);
+    ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
+    pNote->SetText(rAddr, "Hello");
+    pNote->SetAuthor("Jim Bob");
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 1;
+    aSortData.nCol2 = 1;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 2;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 1;
+    aSortData.maKeyState[0].bAscending = true;
+
+    m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
+
+    double nVal = m_pDoc->GetValue(1,0,0);
+    ASSERT_DOUBLES_EQUAL(nVal, 1.0);
+
+    // check that note is also moved after sorting
+    pNote = m_pDoc->GetNote(1, 0, 0);
+    CPPUNIT_ASSERT(pNote);
+
+    clearRange(m_pDoc, ScRange(0, 0, 0, 1, 9, 0)); // Clear A1:B10.
+    {
+        // 0 = empty cell
+        const char* aData[][1] = {
+            { "Title" },
+            { 0 },
+            { 0 },
+            { "12" },
+            { "b" },
+            { "1" },
+            { "9" },
+            { "123" }
+        };
+
+        aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+        CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+    }
+
+    aSortData.nCol1 = aDataRange.aStart.Col();
+    aSortData.nCol2 = aDataRange.aEnd.Col();
+    aSortData.nRow1 = aDataRange.aStart.Row();
+    aSortData.nRow2 = aDataRange.aEnd.Row();
+    aSortData.bHasHeader = true;
+    aSortData.maKeyState[0].nField = 0;
+    m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
+
+    // Title should stay at the top, numbers should be sorted numerically,
+    // numbers always come before strings, and empty cells always occur at the
+    // end.
+    CPPUNIT_ASSERT_EQUAL(OUString("Title"), m_pDoc->GetString(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL(OUString("1"), m_pDoc->GetString(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL(OUString("9"), m_pDoc->GetString(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL(OUString("12"), m_pDoc->GetString(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL(OUString("123"), m_pDoc->GetString(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL(OUString("b"), m_pDoc->GetString(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPos));
+
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortHorizontal()
+{
+    ScFormulaOptions aOptions;
+    aOptions.SetFormulaSepArg(";");
+    aOptions.SetFormulaSepArrayCol(";");
+    aOptions.SetFormulaSepArrayRow("|");
+    getDocShell().SetFormulaOptions(aOptions);
+
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
+    m_pDoc->InsertTab(0, "Sort");
+
+    // Test case from fdo#78079.
+
+    // 0 = empty cell
+    const char* aData[][4] = {
+        { "table", "has UNIQUE", "Publish to EC2", "flag" },
+        { "w2gi.mobilehit", "Yes", "No", "=CONCATENATE(B2;\"-\";C2)" },
+        { "w2gi.visitors", "No", "No", "=CONCATENATE(B3;\"-\";C3)" },
+        { "w2gi.pagedimension", "Yes", "Yes", "=CONCATENATE(B4;\"-\";C4)" },
+    };
+
+    // Insert raw data into A1:D4.
+    ScRange aDataRange = insertRangeData(m_pDoc, ScAddress(0,0,0), aData, SAL_N_ELEMENTS(aData));
+    CPPUNIT_ASSERT_EQUAL(OUString("A1:D4"), aDataRange.Format(SCA_VALID));
+
+    // Check the formula values.
+    CPPUNIT_ASSERT_EQUAL(OUString("Yes-No"), m_pDoc->GetString(ScAddress(3,1,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("No-No"), m_pDoc->GetString(ScAddress(3,2,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Yes-Yes"), m_pDoc->GetString(ScAddress(3,3,0)));
+
+    // Define A1:D4 as sheet-local anonymous database range.
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 3, 3));
+
+    // Sort A1:D4 horizontally, ascending by row 1.
+    ScDBDocFunc aFunc(getDocShell());
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 3;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 3;
+    aSortData.bHasHeader = true;
+    aSortData.bByRow = false; // Sort by column (in horizontal direction).
+    aSortData.bIncludePattern = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    {
+        // Expected output table content.  0 = empty cell
+        const char* aOutputCheck[][4] = {
+            { "table", "flag", "has UNIQUE", "Publish to EC2" },
+            { "w2gi.mobilehit",     "Yes-No",  "Yes", "No" },
+            { "w2gi.visitors",      "No-No",   "No",  "No" },
+            { "w2gi.pagedimension", "Yes-Yes", "Yes", "Yes" },
+        };
+
+        bool bSuccess = checkOutput<4>(m_pDoc, aDataRange, aOutputCheck, "Sorted by column with formula");
+        CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+    }
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "CONCATENATE(C2;\"-\";D2)"))
+        CPPUNIT_FAIL("Wrong formula!");
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "CONCATENATE(C3;\"-\";D3)"))
+        CPPUNIT_FAIL("Wrong formula!");
+    if (!checkFormula(*m_pDoc, ScAddress(1,3,0), "CONCATENATE(C4;\"-\";D4)"))
+        CPPUNIT_FAIL("Wrong formula!");
+
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortHorizontalWholeColumn()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
+    m_pDoc->InsertTab(0, "Sort");
+
+    // 0 = empty cell
+    const char* aData[][5] = {
+        { "4", "2", "47", "a", "9" }
+    };
+
+    // Insert row data to C1:G1.
+    ScRange aSortRange = insertRangeData(m_pDoc, ScAddress(2,0,0), aData, SAL_N_ELEMENTS(aData));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(3,0,0)));
+    CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(4,0,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("a"), m_pDoc->GetString(ScAddress(5,0,0)));
+    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(6,0,0)));
+
+    // Extend the sort range to whole column.
+    aSortRange.aEnd.SetRow(MAXROW);
+
+    SCCOL nCol1 = aSortRange.aStart.Col();
+    SCCOL nCol2 = aSortRange.aEnd.Col();
+    SCROW nRow1 = aSortRange.aStart.Row();
+    SCROW nRow2 = aSortRange.aEnd.Row();
+
+    // Define C:G as sheet-local anonymous database range.
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, nCol1, nRow1, nCol2, nRow2, false, false));
+
+    // Sort C:G horizontally ascending by row 1.
+    ScDBDocFunc aFunc(getDocShell());
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = nCol1;
+    aSortData.nCol2 = nCol2;
+    aSortData.nRow1 = nRow1;
+    aSortData.nRow2 = nRow2;
+    aSortData.bHasHeader = false;
+    aSortData.bByRow = false; // Sort by column (in horizontal direction).
+    aSortData.bIncludePattern = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Check the sort result.
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(3,0,0)));
+    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
+    CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(5,0,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("a"), m_pDoc->GetString(ScAddress(6,0,0)));
+
+    // Undo and check.
+
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    CPPUNIT_ASSERT(pUndoMgr);
+
+    pUndoMgr->Undo();
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(3,0,0)));
+    CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(4,0,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("a"), m_pDoc->GetString(ScAddress(5,0,0)));
+    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(6,0,0)));
+
+    // Redo and check.
+    pUndoMgr->Redo();
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(3,0,0)));
+    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
+    CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(5,0,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("a"), m_pDoc->GetString(ScAddress(6,0,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortSingleRow()
+{
+    // This test case is from fdo#80462.
+
+    m_pDoc->InsertTab(0, "Test");
+
+    // Sort range consists of only one row.
+    m_pDoc->SetString(ScAddress(0,0,0), "X");
+    m_pDoc->SetString(ScAddress(1,0,0), "Y");
+
+    // Define A1:B1 as sheet-local anonymous database range.
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 1, 0));
+
+    // Sort A1:B1 horizontally, ascending by row 1.
+    ScDBDocFunc aFunc(getDocShell());
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 1;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 0;
+    aSortData.bHasHeader = true;
+    aSortData.bByRow = true;
+    aSortData.bIncludePattern = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+
+    // Do the sorting.  This should not crash.
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Another test case - single row horizontal sort with header column.
+    clearSheet(m_pDoc, 0);
+
+    // A1:G1
+    m_pDoc->SetString(ScAddress(0,0,0), "Header");
+    m_pDoc->SetValue(ScAddress(1,0,0),  1.0);
+    m_pDoc->SetValue(ScAddress(2,0,0), 10.0);
+    m_pDoc->SetValue(ScAddress(3,0,0),  3.0);
+    m_pDoc->SetValue(ScAddress(4,0,0),  9.0);
+    m_pDoc->SetValue(ScAddress(5,0,0), 12.0);
+    m_pDoc->SetValue(ScAddress(6,0,0),  2.0);
+
+    // Define A1:G1 as sheet-local anonymous database range.
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 6, 0, false, true));
+
+    // Update the sort data.
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 6;
+    aSortData.bByRow = false;
+    bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Check the result.
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
+    CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(5,0,0)));
+    CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(6,0,0)));
+
+    // Undo and check.
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    CPPUNIT_ASSERT(pUndoMgr);
+    pUndoMgr->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
+    CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
+    CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(5,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(6,0,0)));
+
+    // Redo and check.
+    pUndoMgr->Redo();
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
+    CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(5,0,0)));
+    CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(6,0,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
+// regression test fo fdo#53814, sorting doens't work as expected
+// if cells in the sort are referenced by formulas
+void Test::testSortWithFormulaRefs()
+{
+    m_pDoc->InsertTab(0, "List1");
+    m_pDoc->InsertTab(1, "List2");
+
+    const char* aFormulaData[6] = {
+        "=IF($List1.A2<>\"\";$List1.A2;\"\")",
+        "=IF($List1.A3<>\"\";$List1.A3;\"\")",
+        "=IF($List1.A4<>\"\";$List1.A4;\"\")",
+        "=IF($List1.A5<>\"\";$List1.A5;\"\")",
+        "=IF($List1.A6<>\"\";$List1.A6;\"\")",
+        "=IF($List1.A7<>\"\";$List1.A7;\"\")",
+    };
+
+    const char* aTextData[4] = {
+        "bob",
+        "tim",
+        "brian",
+        "larry",
+    };
+
+    const char* aResults[6] = {
+        "bob",
+        "brian",
+        "larry",
+        "tim",
+        "",
+        "",
+    };
+
+    // Insert data to sort in A2:A5 on the 1st sheet.
+    for (SCROW i = 1; i <= 4; ++i)
+        m_pDoc->SetString( 0, i, 0, OUString::createFromAscii(aTextData[i-1]) );
+
+    // Insert forumulas in A1:A6 on the 2nd sheet.
+    for (size_t i = 0; i < SAL_N_ELEMENTS(aFormulaData); ++i)
+        m_pDoc->SetString( 0, i, 1, OUString::createFromAscii(aFormulaData[i]) );
+
+    // Sort data in A2:A8 on the 1st sheet. No column header.
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 0;
+    aSortData.nRow1 = 1;
+    aSortData.nRow2 = 7;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+
+    m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
+
+    for (size_t i = 0; i < SAL_N_ELEMENTS(aResults); ++i)
+    {
+        OUString sResult = m_pDoc->GetString(0, i + 1, 0);
+        CPPUNIT_ASSERT_EQUAL( OUString::createFromAscii( aResults[i] ), sResult );
+    }
+    m_pDoc->DeleteTab(1);
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortWithStrings()
+{
+    m_pDoc->InsertTab(0, "Test");
+
+    ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
+    rEE.SetText("Val1");
+    m_pDoc->SetString(ScAddress(1,1,0), "Header");
+    m_pDoc->SetString(ScAddress(1,2,0), "Val2");
+    m_pDoc->SetEditText(ScAddress(1,3,0), rEE.CreateTextObject());
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,3,0)));
+
+    ScSortParam aParam;
+    aParam.nCol1 = 1;
+    aParam.nCol2 = 1;
+    aParam.nRow1 = 1;
+    aParam.nRow2 = 3;
+    aParam.bHasHeader = true;
+    aParam.maKeyState[0].bDoSort = true;
+    aParam.maKeyState[0].bAscending = true;
+    aParam.maKeyState[0].nField = 1;
+
+    m_pDoc->Sort(0, aParam, false, true, NULL, NULL);
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,3,0)));
+
+    aParam.maKeyState[0].bAscending = false;
+
+    m_pDoc->Sort(0, aParam, false, true, NULL, NULL);
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,3,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortInFormulaGroup()
+{
+    static struct {
+        SCCOL nCol;
+        SCROW nRow;
+        const char *pData;
+    } aEntries[] = {
+        { 0, 0, "3" },   { 1, 0, "=A1" },
+        { 0, 1, "1" },   { 1, 1, "=A2" },
+        { 0, 2, "20" },  { 1, 2, "=A3" },
+        { 0, 3, "10" },  { 1, 3, "=A4+1" }, // swap across groups
+        { 0, 4, "2"  },  { 1, 4, "=A5+1" },
+        { 0, 5, "101" }, { 1, 5, "=A6" }, // swap inside contiguious group
+        { 0, 6, "100" }, { 1, 6, "=A7" },
+        { 0, 7, "102" }, { 1, 7, "=A8" },
+        { 0, 8, "104" }, { 1, 8, "=A9" },
+        { 0, 9, "103" }, { 1, 9, "=A10" },
+    };
+
+    m_pDoc->InsertTab(0, "sorttest");
+
+    for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
+        m_pDoc->SetString( aEntries[i].nCol, aEntries[i].nRow, 0,
+                           OUString::createFromAscii( aEntries[i].pData) );
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 1;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 9;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+
+    m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
+
+    static struct {
+        SCCOL nCol;
+        SCROW nRow;
+        double fValue;
+    } aResults[] = {
+        { 0, 0, 1.0 },   { 1, 0, 1.0 },
+        { 0, 1, 2.0 },   { 1, 1, 3.0 },
+        { 0, 2, 3.0 },   { 1, 2, 3.0 },
+        { 0, 3, 10.0 },  { 1, 3, 11.0 },
+        { 0, 4, 20.0 },  { 1, 4, 20.0 },
+        { 0, 5, 100.0 }, { 1, 5, 100.0 },
+        { 0, 6, 101.0 }, { 1, 6, 101.0 },
+        { 0, 7, 102.0 }, { 1, 7, 102.0 },
+        { 0, 8, 103.0 }, { 1, 8, 103.0 },
+        { 0, 9, 104.0 }, { 1, 9, 104.0 },
+    };
+
+    for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
+    {
+        double val = m_pDoc->GetValue( aEntries[i].nCol, aEntries[i].nRow, 0 );
+//        fprintf(stderr, "value at %d %d is %g = %g\n",
+//                (int)aResults[i].nRow, (int)aResults[i].nCol,
+//                val, aResults[i].fValue);
+        CPPUNIT_ASSERT_MESSAGE("Mis-matching value after sort.",
+                               rtl::math::approxEqual(val, aResults[i].fValue));
+    }
+
+    m_pDoc->DeleteTab( 0 );
+}
+
+void Test::testSortWithCellFormats()
+{
+    struct
+    {
+        bool isBold( const ScPatternAttr* pPat ) const
+        {
+            if (!pPat)
+            {
+                cerr << "Pattern is NULL!" << endl;
+                return false;
+            }
+
+            const SfxPoolItem* pItem = NULL;
+            if (!pPat->GetItemSet().HasItem(ATTR_FONT_WEIGHT, &pItem))
+            {
+                cerr << "Pattern does not have a font weight item, but it should." << endl;
+                return false;
+            }
+
+            CPPUNIT_ASSERT(pItem);
+
+            if (static_cast<const SvxWeightItem*>(pItem)->GetEnumValue() != WEIGHT_BOLD)
+            {
+                cerr << "Font weight should be bold." << endl;
+                return false;
+            }
+
+            return true;
+        }
+
+        bool isItalic( const ScPatternAttr* pPat ) const
+        {
+            if (!pPat)
+            {
+                cerr << "Pattern is NULL!" << endl;
+                return false;
+            }
+
+            const SfxPoolItem* pItem = NULL;
+            if (!pPat->GetItemSet().HasItem(ATTR_FONT_POSTURE, &pItem))
+            {
+                cerr << "Pattern does not have a font posture item, but it should." << endl;
+                return false;
+            }
+
+            CPPUNIT_ASSERT(pItem);
+
+            if (static_cast<const SvxPostureItem*>(pItem)->GetEnumValue() != ITALIC_NORMAL)
+            {
+                cerr << "Italic should be applied.." << endl;
+                return false;
+            }
+
+            return true;
+        }
+
+        bool isNormal( const ScPatternAttr* pPat ) const
+        {
+            if (!pPat)
+            {
+                cerr << "Pattern is NULL!" << endl;
+                return false;
+            }
+
+            const SfxPoolItem* pItem = NULL;
+            if (pPat->GetItemSet().HasItem(ATTR_FONT_WEIGHT, &pItem))
+            {
+                // Check if the font weight is applied.
+                if (static_cast<const SvxWeightItem*>(pItem)->GetEnumValue() == WEIGHT_BOLD)
+                {
+                    cerr << "This cell is bold, but shouldn't." << endl;
+                    return false;
+                }
+            }
+
+            if (pPat->GetItemSet().HasItem(ATTR_FONT_POSTURE, &pItem))
+            {
+                // Check if the italics is applied.
+                if (static_cast<const SvxPostureItem*>(pItem)->GetEnumValue() == ITALIC_NORMAL)
+                {
+                    cerr << "This cell is bold, but shouldn't." << endl;
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+    } aCheck;
+
+    m_pDoc->InsertTab(0, "Test");
+
+    // Insert some values into A1:A4.
+    m_pDoc->SetString(ScAddress(0,0,0), "Header");
+    m_pDoc->SetString(ScAddress(0,1,0), "Normal");
+    m_pDoc->SetString(ScAddress(0,2,0), "Bold");
+    m_pDoc->SetString(ScAddress(0,3,0), "Italic");
+
+    // Set A3 bold and A4 italic.
+    const ScPatternAttr* pPat = m_pDoc->GetPattern(ScAddress(0,2,0));
+    CPPUNIT_ASSERT(pPat);
+    {
+        ScPatternAttr aNewPat(*pPat);
+        SfxItemSet& rSet = aNewPat.GetItemSet();
+        rSet.Put(SvxWeightItem(WEIGHT_BOLD, ATTR_FONT_WEIGHT));
+        m_pDoc->ApplyPattern(0, 2, 0, aNewPat);
+
+        // Make sure it's really in.
+        bool bGood = aCheck.isBold(m_pDoc->GetPattern(ScAddress(0,2,0)));
+        CPPUNIT_ASSERT_MESSAGE("A3 is not bold but it should.", bGood);
+    }
+
+    pPat = m_pDoc->GetPattern(ScAddress(0,3,0));
+    CPPUNIT_ASSERT(pPat);
+    {
+        ScPatternAttr aNewPat(*pPat);
+        SfxItemSet& rSet = aNewPat.GetItemSet();
+        rSet.Put(SvxPostureItem(ITALIC_NORMAL, ATTR_FONT_POSTURE));
+        m_pDoc->ApplyPattern(0, 3, 0, aNewPat);
+
+        bool bGood = aCheck.isItalic(m_pDoc->GetPattern(ScAddress(0,3,0)));
+        CPPUNIT_ASSERT_MESSAGE("A4 is not italic but it should.", bGood);
+    }
+
+    // Define A1:A4 as sheet-local anonymous database range, else sort wouldn't run.
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 3));
+
+    // Sort A1:A4 ascending with cell formats.
+    ScDBDocFunc aFunc(getDocShell());
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 0;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 3;
+    aSortData.bHasHeader = true;
+    aSortData.bIncludePattern = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+    bool bSorted = aFunc.Sort(0, aSortData, true, false, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Check the sort result.
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Bold"),   m_pDoc->GetString(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Italic"), m_pDoc->GetString(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL(OUString("Normal"), m_pDoc->GetString(ScAddress(0,3,0)));
+
+    // A2 should be bold now.
+    bool bBold = aCheck.isBold(m_pDoc->GetPattern(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_MESSAGE("A2 should be bold after the sort.", bBold);
+
+    // and A3 should be italic.
+    bool bItalic = aCheck.isItalic(m_pDoc->GetPattern(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_MESSAGE("A3 should be italic.", bItalic);
+
+    // A4 should have neither bold nor italic.
+    bool bNormal = aCheck.isNormal(m_pDoc->GetPattern(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_MESSAGE("A4 should be neither bold nor italic.", bNormal);
+
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortRefUpdate()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+    FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
+
+    m_pDoc->InsertTab(0, "Sort");
+
+    // Set values to sort in column A.
+    m_pDoc->SetString(ScAddress(0,0,0), "Header");
+
+    double aValues[] = { 4.0, 36.0, 14.0, 29.0, 98.0, 78.0, 0.0, 99.0, 1.0 };
+    size_t nCount = SAL_N_ELEMENTS(aValues);
+    for (size_t i = 0; i < nCount; ++i)
+        m_pDoc->SetValue(ScAddress(0,i+1,0), aValues[i]);
+
+    // Set formulas to reference these values in column C.
+    m_pDoc->SetString(ScAddress(2,0,0), "Formula");
+    for (size_t i = 0; i < nCount; ++i)
+        m_pDoc->SetString(ScAddress(2,1+i,0), "=RC[-2]");
+
+    // Check the values in column C.
+    for (size_t i = 0; i < nCount; ++i)
+    {
+        double fCheck = aValues[i];
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0)));
+    }
+
+    ScDBDocFunc aFunc(getDocShell());
+
+    // Define A1:A10 as sheet-local anonymous database range, else sort wouldn't run.
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 9));
+
+    // Sort A1:A10 (with a header row).
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 0;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 9;
+    aSortData.bHasHeader = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    double aSorted[] = { 0.0, 1.0, 4.0, 14.0, 29.0, 36.0, 78.0, 98.0, 99.0 };
+
+    // Check the sort result.
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    for (size_t i = 0; i < nCount; ++i)
+    {
+        double fCheck = aSorted[i];
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(0,i+1,0)));
+    }
+
+    // Sorting should not alter the values in column C.
+    m_pDoc->CalcAll(); // just in case...
+    for (size_t i = 0; i < nCount; ++i)
+    {
+        double fCheck = aValues[i];
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0)));
+    }
+
+    // C2 should now point to A4.
+    if (!checkFormula(*m_pDoc, ScAddress(2,1,0), "R[2]C[-2]"))
+        CPPUNIT_FAIL("Wrong formula in C2!");
+
+    // Undo the sort.
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    pUndoMgr->Undo();
+
+    // Check the undo result.
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    for (size_t i = 0; i < nCount; ++i)
+    {
+        double fCheck = aValues[i];
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(0,i+1,0)));
+    }
+
+    // Values in column C should still be unaltered.
+    m_pDoc->CalcAll(); // just in case...
+    for (size_t i = 0; i < nCount; ++i)
+    {
+        double fCheck = aValues[i];
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0)));
+    }
+
+    // C2 should now point to A2.
+    if (!checkFormula(*m_pDoc, ScAddress(2,1,0), "RC[-2]"))
+        CPPUNIT_FAIL("Wrong formula in C2!");
+
+    // Redo.
+    pUndoMgr->Redo();
+
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    for (size_t i = 0; i < nCount; ++i)
+    {
+        double fCheck = aSorted[i];
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(0,i+1,0)));
+    }
+
+    // Sorting should not alter the values in column C.
+    m_pDoc->CalcAll(); // just in case...
+    for (size_t i = 0; i < nCount; ++i)
+    {
+        double fCheck = aValues[i];
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0)));
+    }
+
+    // C2 should now point to A4.
+    if (!checkFormula(*m_pDoc, ScAddress(2,1,0), "R[2]C[-2]"))
+        CPPUNIT_FAIL("Wrong formula in C2!");
+
+    // Undo again.
+    pUndoMgr->Undo();
+
+    // Formulas in column C should all be "RC[-2]" again.
+    for (size_t i = 0; i < nCount; ++i)
+        m_pDoc->SetString(ScAddress(2,1+i,0), "=RC[-2]");
+
+    // Turn off reference update on sort.
+    ScInputOptions aInputOption = SC_MOD()->GetInputOptions();
+    aInputOption.SetSortRefUpdate(false);
+
+    bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Check the sort result again.
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    for (size_t i = 0; i < nCount; ++i)
+    {
+        double fCheck = aSorted[i];
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(0,i+1,0)));
+    }
+
+    // Formulas in column C should all remain "RC[-2]".
+    for (size_t i = 0; i < nCount; ++i)
+        m_pDoc->SetString(ScAddress(2,1+i,0), "=RC[-2]");
+
+    // The values in column C should now be the same as sorted values in column A.
+    m_pDoc->CalcAll(); // just in case...
+    for (size_t i = 0; i < nCount; ++i)
+    {
+        double fCheck = aSorted[i];
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0))); // column C
+    }
+
+    // Turn it back on.
+    aInputOption.SetSortRefUpdate(true);
+
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortRefUpdate2()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+    FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
+
+    m_pDoc->InsertTab(0, "Sort");
+
+    // Set up the sheet.
+    const char* aData[][2] = {
+        { "F1", "F2" },
+        { "9", "=RC[-1]" },
+        { "2", "=RC[-1]" },
+        { "6", "=RC[-1]" },
+        { "4", "=RC[-1]" },
+        { 0, 0 } // terminator
+    };
+
+    for (SCROW i = 0; aData[i][0]; ++i)
+    {
+        m_pDoc->SetString(0, i, 0, OUString::createFromAscii(aData[i][0]));
+        m_pDoc->SetString(1, i, 0, OUString::createFromAscii(aData[i][1]));
+    }
+
+    // Check the values in B2:B5.
+    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,3,0)));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,4,0)));
+
+    ScDBDocFunc aFunc(getDocShell());
+
+    // Define A1:B5 as sheet-local anonymous database range, else sort wouldn't run.
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 1, 4));
+
+    // Sort A1:B5 by column A (with a row header).
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 1;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 4;
+    aSortData.bHasHeader = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Check the sort result in column A.
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(0,4,0)));
+
+    // and column B.
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,3,0)));
+    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(1,4,0)));
+
+    // Formulas in column B should still point to their respective left neighbor cell.
+    for (SCROW i = 1; i <= 4; ++i)
+    {
+        if (!checkFormula(*m_pDoc, ScAddress(1,i,0), "RC[-1]"))
+            CPPUNIT_FAIL("Wrong formula!");
+    }
+
+    // Undo and check the result in column B.
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    pUndoMgr->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,3,0)));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,4,0)));
+
+    // and redo.
+    pUndoMgr->Redo();
+
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,3,0)));
+    CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(1,4,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortRefUpdate3()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+    m_pDoc->InsertTab(0, "Sort");
+
+    const char* pData[] = {
+        "Header",
+        "1",
+        "=A2+10",
+        "2",
+        "=A4+10",
+        "=A2+A4",
+        0 // terminator
+    };
+
+    for (SCROW i = 0; pData[i]; ++i)
+        m_pDoc->SetString(ScAddress(0,i,0), OUString::createFromAscii(pData[i]));
+
+    // Check the initial values.
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,4,0)));
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+
+    ScDBDocFunc aFunc(getDocShell());
+
+    // Sort A1:A6.
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 5));
+
+    // Sort A1:A6 by column A (with a row header).
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 0;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 5;
+    aSortData.bHasHeader = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Check the sorted values.
+    m_pDoc->CalcAll();
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(0,4,0)));
+    CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+
+    // Make sure the formula cells have been adjusted correctly.
+    if (!checkFormula(*m_pDoc, ScAddress(0,3,0), "A2+A3"))
+        CPPUNIT_FAIL("Wrong formula in A4.");
+    if (!checkFormula(*m_pDoc, ScAddress(0,4,0), "A2+10"))
+        CPPUNIT_FAIL("Wrong formula in A5.");
+    if (!checkFormula(*m_pDoc, ScAddress(0,5,0), "A3+10"))
+        CPPUNIT_FAIL("Wrong formula in A6.");
+
+    // Undo and check the result.
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    pUndoMgr->Undo();
+    m_pDoc->CalcAll();
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,4,0)));
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+
+    // Redo and check the result.
+    pUndoMgr->Redo();
+    m_pDoc->CalcAll();
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(0,4,0)));
+    CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
+// Derived from fdo#79441 https://bugs.freedesktop.org/attachment.cgi?id=100144
+// testRefInterne.ods
+void Test::testSortRefUpdate4()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+    m_pDoc->InsertTab(0, "Sort");
+    m_pDoc->InsertTab(1, "Lesson1");
+    m_pDoc->InsertTab(2, "Lesson2");
+
+    ScRange aLesson1Range;
+    {
+        const char* aData[][2] = {
+            { "Name", "Note" },
+            { "Student1", "1" },
+            { "Student2", "2" },
+            { "Student3", "3" },
+            { "Student4", "4" },
+            { "Student5", "5" },
+        };
+
+        SCTAB nTab = 1;
+        ScAddress aPos(0,0,nTab);
+        clearRange(m_pDoc, ScRange(0, 0, nTab, 1, SAL_N_ELEMENTS(aData), nTab));
+        aLesson1Range = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+        CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aLesson1Range.aStart == aPos);
+    }
+
+    ScRange aLesson2Range;
+    {
+        const char* aData[][2] = {
+            { "Name", "Note" },
+            { "=Lesson1.A2", "3" },
+            { "=Lesson1.A3", "4" },
+            { "=Lesson1.A4", "9" },
+            { "=Lesson1.A5", "6" },
+            { "=Lesson1.A6", "3" },
+        };
+
+        SCTAB nTab = 2;
+        ScAddress aPos(0,0,nTab);
+        clearRange(m_pDoc, ScRange(0, 0, nTab, 1, SAL_N_ELEMENTS(aData), nTab));
+        aLesson2Range = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+        CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aLesson2Range.aStart == aPos);
+    }
+
+    ScRange aSortRange;
+    {
+        const char* aData[][4] = {
+            { "Name", "Lesson1", "Lesson2", "Average" },
+            { "=Lesson1.A2", "=Lesson1.B2", "=Lesson2.B2", "=AVERAGE(B2:C2)" },
+            { "=Lesson1.A3", "=Lesson1.B3", "=Lesson2.B3", "=AVERAGE(B3:C3)" },
+            { "=Lesson1.A4", "=Lesson1.B4", "=Lesson2.B4", "=AVERAGE(B4:C4)" },
+            { "=Lesson1.A5", "=Lesson1.B5", "=Lesson2.B5", "=AVERAGE(B5:C5)" },
+            { "=Lesson1.A6", "=Lesson1.B6", "=Lesson2.B6", "=AVERAGE(B6:C6)" },
+        };
+
+        SCTAB nTab = 0;
+        ScAddress aPos(0,0,nTab);
+        clearRange(m_pDoc, ScRange(0, 0, nTab, 1, SAL_N_ELEMENTS(aData), nTab));
+        aSortRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+        CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aSortRange.aStart == aPos);
+    }
+
+    ScDBDocFunc aFunc(getDocShell());
+
+    // Sort A1:D6 by column D (Average, with a row header).
+    {
+        ScSortParam aSortData;
+        aSortData.nCol1 = aSortRange.aStart.Col();
+        aSortData.nCol2 = aSortRange.aEnd.Col();
+        aSortData.nRow1 = aSortRange.aStart.Row();
+        aSortData.nRow2 = aSortRange.aEnd.Row();
+        aSortData.bHasHeader = true;
+        aSortData.maKeyState[0].bDoSort = true;         // sort on
+        aSortData.maKeyState[0].nField = 3;             // Average
+        aSortData.maKeyState[0].bAscending = false;     // descending
+
+        m_pDoc->SetAnonymousDBData( 0, new ScDBData( STR_DB_LOCAL_NONAME, aSortRange.aStart.Tab(),
+                    aSortData.nCol1, aSortData.nRow1, aSortData.nCol2, aSortData.nRow2));
+
+        bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+        CPPUNIT_ASSERT(bSorted);
+
+        // Check the sorted values.
+        m_pDoc->CalcAll();
+        CPPUNIT_ASSERT_EQUAL(OUString("Name"), m_pDoc->GetString(ScAddress(0,0,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student3"), m_pDoc->GetString(ScAddress(0,1,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student4"), m_pDoc->GetString(ScAddress(0,2,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student5"), m_pDoc->GetString(ScAddress(0,3,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student2"), m_pDoc->GetString(ScAddress(0,4,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student1"), m_pDoc->GetString(ScAddress(0,5,0)));
+        CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue(ScAddress(3,1,0)));
+        CPPUNIT_ASSERT_EQUAL( 5.0, m_pDoc->GetValue(ScAddress(3,2,0)));
+        CPPUNIT_ASSERT_EQUAL( 4.0, m_pDoc->GetValue(ScAddress(3,3,0)));
+        CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,4,0)));
+        CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(3,5,0)));
+
+        // Make sure the formula cells have been adjusted correctly.
+        const char* aCheck[][4] = {
+            // Name          Lesson1       Lesson2       Average
+            { "Lesson1.A4", "Lesson1.B4", "Lesson2.B4", "AVERAGE(B2:C2)" },
+            { "Lesson1.A5", "Lesson1.B5", "Lesson2.B5", "AVERAGE(B3:C3)" },
+            { "Lesson1.A6", "Lesson1.B6", "Lesson2.B6", "AVERAGE(B4:C4)" },
+            { "Lesson1.A3", "Lesson1.B3", "Lesson2.B3", "AVERAGE(B5:C5)" },
+            { "Lesson1.A2", "Lesson1.B2", "Lesson2.B2", "AVERAGE(B6:C6)" },
+        };
+        for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aCheck)); ++nRow)
+        {
+            for (SCCOL nCol=0; nCol < 4; ++nCol)
+            {
+                if (!checkFormula(*m_pDoc, ScAddress(nCol,nRow+1,0), aCheck[nRow][nCol]))
+                    CPPUNIT_FAIL(OString("Wrong formula in " + OString('A'+nCol) + OString::number(nRow+2) + ".").getStr());
+            }
+        }
+
+        // Undo and check the result.
+        SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+        pUndoMgr->Undo();
+        m_pDoc->CalcAll();
+        CPPUNIT_ASSERT_EQUAL(OUString("Name"), m_pDoc->GetString(ScAddress(0,0,0)));
+        CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(3,1,0)));
+        CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,2,0)));
+        CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue(ScAddress(3,3,0)));
+        CPPUNIT_ASSERT_EQUAL( 5.0, m_pDoc->GetValue(ScAddress(3,4,0)));
+        CPPUNIT_ASSERT_EQUAL( 4.0, m_pDoc->GetValue(ScAddress(3,5,0)));
+
+        // Redo and check the result.
+        pUndoMgr->Redo();
+        m_pDoc->CalcAll();
+        CPPUNIT_ASSERT_EQUAL(OUString("Name"), m_pDoc->GetString(ScAddress(0,0,0)));
+        CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue(ScAddress(3,1,0)));
+        CPPUNIT_ASSERT_EQUAL( 5.0, m_pDoc->GetValue(ScAddress(3,2,0)));
+        CPPUNIT_ASSERT_EQUAL( 4.0, m_pDoc->GetValue(ScAddress(3,3,0)));
+        CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,4,0)));
+        CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(3,5,0)));
+    }
+
+    // Sort A2:AMJ6 by column A (Name, without header).
+    {
+        ScSortParam aSortData;
+        aSortData.nCol1 = 0;
+        aSortData.nCol2 = MAXCOL;
+        aSortData.nRow1 = aSortRange.aStart.Row()+1;
+        aSortData.nRow2 = aSortRange.aEnd.Row();
+        aSortData.bHasHeader = false;
+        aSortData.maKeyState[0].bDoSort = true;         // sort on
+        aSortData.maKeyState[0].nField = 0;             // Name
+        aSortData.maKeyState[0].bAscending = false;     // descending
+
+        m_pDoc->SetAnonymousDBData( 0, new ScDBData( STR_DB_LOCAL_NONAME, aSortRange.aStart.Tab(),
+                    aSortData.nCol1, aSortData.nRow1, aSortData.nCol2, aSortData.nRow2));
+
+        bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+        CPPUNIT_ASSERT(bSorted);
+
+        // Check the sorted values.
+        m_pDoc->CalcAll();
+        CPPUNIT_ASSERT_EQUAL(OUString("Name"), m_pDoc->GetString(ScAddress(0,0,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student5"), m_pDoc->GetString(ScAddress(0,1,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student4"), m_pDoc->GetString(ScAddress(0,2,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student3"), m_pDoc->GetString(ScAddress(0,3,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student2"), m_pDoc->GetString(ScAddress(0,4,0)));
+        CPPUNIT_ASSERT_EQUAL(OUString("Student1"), m_pDoc->GetString(ScAddress(0,5,0)));
+        CPPUNIT_ASSERT_EQUAL( 4.0, m_pDoc->GetValue(ScAddress(3,1,0)));
+        CPPUNIT_ASSERT_EQUAL( 5.0, m_pDoc->GetValue(ScAddress(3,2,0)));
+        CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue(ScAddress(3,3,0)));
+        CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,4,0)));
+        CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(3,5,0)));
+
+        // Make sure the formula cells have been adjusted correctly.
+        const char* aCheck[][4] = {
+            // Name          Lesson1       Lesson2       Average
+            { "Lesson1.A6", "Lesson1.B6", "Lesson2.B6", "AVERAGE(B2:C2)" },
+            { "Lesson1.A5", "Lesson1.B5", "Lesson2.B5", "AVERAGE(B3:C3)" },
+            { "Lesson1.A4", "Lesson1.B4", "Lesson2.B4", "AVERAGE(B4:C4)" },
+            { "Lesson1.A3", "Lesson1.B3", "Lesson2.B3", "AVERAGE(B5:C5)" },
+            { "Lesson1.A2", "Lesson1.B2", "Lesson2.B2", "AVERAGE(B6:C6)" },
+        };
+        for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aCheck)); ++nRow)
+        {
+            for (SCCOL nCol=0; nCol < 4; ++nCol)
+            {
+                if (!checkFormula(*m_pDoc, ScAddress(nCol,nRow+1,0), aCheck[nRow][nCol]))
+                    CPPUNIT_FAIL(OString("Wrong formula in " + OString('A'+nCol) + OString::number(nRow+2) + ".").getStr());
+            }
+        }
+    }
+
+    m_pDoc->DeleteTab(2);
+    m_pDoc->DeleteTab(1);
+    m_pDoc->DeleteTab(0);
+}
+
+// Make sure the refupdate works also with volatile cells, see fdo#83067
+/* FIXME: this test is not roll-over-midnight safe and will fail then! We may
+ * want to have something different, but due to the nature of volatile
+ * functions it's not that easy to come up with something reproducible staying
+ * stable over sorts.. ;-)  Check for time and don't run test a few seconds
+ * before midnight, ermm.. */
+void Test::testSortRefUpdate5()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+    m_pDoc->InsertTab(0, "Sort");
+
+    double aValCheck[][3] = {
+        // Result, Unsorted order, Sorted result.
+        { 0, 4, 0 },
+        { 0, 1, 0 },
+        { 0, 3, 0 },
+        { 0, 2, 0 },
+    };
+    ScRange aSortRange;
+    {
+        const char* aData[][3] = {
+            { "Date", "Volatile", "Order" },
+            { "1999-05-05", "=TODAY()-$A2", "4" },
+            { "1994-10-18", "=TODAY()-$A3", "1" },
+            { "1996-06-30", "=TODAY()-$A4", "3" },
+            { "1995-11-21", "=TODAY()-$A5", "2" },
+        };
+
+        SCTAB nTab = 0;
+        ScAddress aPos(0,0,nTab);
+        clearRange(m_pDoc, ScRange(0, 0, nTab, 2, SAL_N_ELEMENTS(aData), nTab));
+        aSortRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+        CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aSortRange.aStart == aPos);
+
+        // Actual results and expected sorted results.
+        for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aValCheck)); ++nRow)
+        {
+            double fVal = m_pDoc->GetValue(ScAddress(1,nRow+1,0));
+            aValCheck[nRow][0] = fVal;
+            aValCheck[static_cast<size_t>(aValCheck[nRow][1])-1][2] = fVal;
+        }
+    }
+
+    ScDBDocFunc aFunc(getDocShell());
+
+    // Sort A1:B5.
+    m_pDoc->SetAnonymousDBData( 0, new ScDBData( STR_DB_LOCAL_NONAME, aSortRange.aStart.Tab(),
+                aSortRange.aStart.Col(), aSortRange.aStart.Row(), aSortRange.aEnd.Col(), aSortRange.aEnd.Row()));
+
+    // Sort by column A.
+    ScSortParam aSortData;
+    aSortData.nCol1 = aSortRange.aStart.Col();
+    aSortData.nCol2 = aSortRange.aEnd.Col();
+    aSortData.nRow1 = aSortRange.aStart.Row();
+    aSortData.nRow2 = aSortRange.aEnd.Row();
+    aSortData.bHasHeader = true;
+    aSortData.maKeyState[0].bDoSort = true;         // sort on
+    aSortData.maKeyState[0].nField = 0;             // Date
+    aSortData.maKeyState[0].bAscending = true;      // ascending
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Check the sorted values.
+    m_pDoc->CalcAll();
+    for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aValCheck)); ++nRow)
+    {
+        size_t i = static_cast<size_t>(m_pDoc->GetValue(ScAddress(2,nRow+1,0)));    // order 1..4
+        CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(nRow+1), i);
+        CPPUNIT_ASSERT_EQUAL( aValCheck[i-1][2], m_pDoc->GetValue(ScAddress(1,nRow+1,0)));
+    }
+
+    // Make sure the formula cells have been adjusted correctly.
+    const char* aFormulaCheck[] = {
+        // Volatile
+        "TODAY()-$A2",
+        "TODAY()-$A3",
+        "TODAY()-$A4",
+        "TODAY()-$A5",
+    };
+    for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aFormulaCheck)); ++nRow)
+    {
+        if (!checkFormula(*m_pDoc, ScAddress(1,nRow+1,0), aFormulaCheck[nRow]))
+            CPPUNIT_FAIL(OString("Wrong formula in B" + OString::number(nRow+2) + ".").getStr());
+    }
+
+    // Undo and check the result.
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    pUndoMgr->Undo();
+    m_pDoc->CalcAll();
+    for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aValCheck)); ++nRow)
+    {
+        CPPUNIT_ASSERT_EQUAL( aValCheck[nRow][0], m_pDoc->GetValue(ScAddress(1,nRow+1,0)));
+        CPPUNIT_ASSERT_EQUAL( aValCheck[nRow][1], m_pDoc->GetValue(ScAddress(2,nRow+1,0)));
+    }
+
+    // Redo and check the result.
+    pUndoMgr->Redo();
+    m_pDoc->CalcAll();
+    for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aValCheck)); ++nRow)
+    {
+        size_t i = static_cast<size_t>(m_pDoc->GetValue(ScAddress(2,nRow+1,0)));    // order 1..4
+        CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(nRow+1), i);
+        CPPUNIT_ASSERT_EQUAL( aValCheck[i-1][2], m_pDoc->GetValue(ScAddress(1,nRow+1,0)));
+    }
+
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortOutOfPlaceResult()
+{
+    m_pDoc->InsertTab(0, "Sort");
+    m_pDoc->InsertTab(1, "Result");
+
+    const char* pData[] = {
+        "Header",
+        "1",
+        "23",
+        "2",
+        "9",
+        "-2",
+        0 // terminator
+    };
+
+    // source data in A1:A6.
+    for (SCROW i = 0; pData[i]; ++i)
+        m_pDoc->SetString(ScAddress(0,i,0), OUString::createFromAscii(pData[i]));
+
+    // Check the initial values.
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL(23.0, m_pDoc->GetValue(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(0,4,0)));
+    CPPUNIT_ASSERT_EQUAL(-2.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+
+    ScDBDocFunc aFunc(getDocShell());
+
+    // Sort A1:A6, and set the result to C2:C7
+    m_pDoc->SetAnonymousDBData(
+        0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 5));
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 0;
+    aSortData.nCol2 = 0;
+    aSortData.nRow1 = 0;
+    aSortData.nRow2 = 5;
+    aSortData.bHasHeader = true;
+    aSortData.bInplace = false;
+    aSortData.nDestTab = 1;
+    aSortData.nDestCol = 2;
+    aSortData.nDestRow = 1;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    // Source data still intact.
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL(23.0, m_pDoc->GetValue(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(0,4,0)));
+    CPPUNIT_ASSERT_EQUAL(-2.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+
+    // Sort result in C2:C7 on sheet "Result".
+    CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(2,1,1)));
+    CPPUNIT_ASSERT_EQUAL(-2.0, m_pDoc->GetValue(ScAddress(2,2,1)));
+    CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(2,3,1)));
+    CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(2,4,1)));
+    CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(2,5,1)));
+    CPPUNIT_ASSERT_EQUAL(23.0, m_pDoc->GetValue(ScAddress(2,6,1)));
+
+    m_pDoc->DeleteTab(1);
+    m_pDoc->DeleteTab(0);
+}
+
+void Test::testSortPartialFormulaGroup()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+    FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
+
+    m_pDoc->InsertTab(0, "Sort");
+
+    // Set up the sheet.
+    const char* aData[][2] = {
+        { "F1", "F2" },
+        { "43", "=RC[-1]" },
+        { "50", "=RC[-1]" },
+        {  "8", "=RC[-1]" },
+        { "47", "=RC[-1]" },
+        { "28", "=RC[-1]" },
+        { 0, 0 } // terminator
+    };
+
+    // A1:B6.
+    for (SCROW i = 0; aData[i][0]; ++i)
+    {
+        m_pDoc->SetString(0, i, 0, OUString::createFromAscii(aData[i][0]));
+        m_pDoc->SetString(1, i, 0, OUString::createFromAscii(aData[i][1]));
+    }
+
+    // Check the initial condition.
+    for (SCROW i = 1; i <= 5; ++i)
+        // A2:A6 should equal B2:B6.
+        CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(0,i,0)), m_pDoc->GetValue(ScAddress(1,i,0)));
+
+    const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_MESSAGE("This formula cell should be the first in a group.", pFC->IsSharedTop());
+    CPPUNIT_ASSERT_MESSAGE("Incorrect formula group length.", pFC->GetSharedLength() == 5);
+
+    ScDBDocFunc aFunc(getDocShell());
+
+    // Sort only B2:B4.  This caused crash at one point (c.f. fdo#81617).
+
+    m_pDoc->SetAnonymousDBData(0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 1, 1, 1, 3));
+
+    ScSortParam aSortData;
+    aSortData.nCol1 = 1;
+    aSortData.nCol2 = 1;
+    aSortData.nRow1 = 1;
+    aSortData.nRow2 = 3;
+    aSortData.bHasHeader = false;
+    aSortData.bInplace = true;
+    aSortData.maKeyState[0].bDoSort = true;
+    aSortData.maKeyState[0].nField = 0;
+    aSortData.maKeyState[0].bAscending = true;
+    bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
+    CPPUNIT_ASSERT(bSorted);
+
+    m_pDoc->CalcAll(); // just in case...
+
+    // Check the cell values after the partial sort.
+
+    // Column A
+    CPPUNIT_ASSERT_EQUAL(43.0, m_pDoc->GetValue(ScAddress(0,1,0)));
+    CPPUNIT_ASSERT_EQUAL(50.0, m_pDoc->GetValue(ScAddress(0,2,0)));
+    CPPUNIT_ASSERT_EQUAL( 8.0, m_pDoc->GetValue(ScAddress(0,3,0)));
+    CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(0,4,0)));
+    CPPUNIT_ASSERT_EQUAL(28.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+
+    // Column B
+    CPPUNIT_ASSERT_EQUAL( 8.0, m_pDoc->GetValue(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(43.0, m_pDoc->GetValue(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(50.0, m_pDoc->GetValue(ScAddress(1,3,0)));
+    CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(1,4,0)));
+    CPPUNIT_ASSERT_EQUAL(28.0, m_pDoc->GetValue(ScAddress(1,5,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list