sc/qa/unit/ucalc_pivottable.cxx |  235 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 235 insertions(+)

New commits:
commit 2e769d65b406dad370f5ad0a5d42e0e2d27482c5
Author:     Tomaž Vajngerl <[email protected]>
AuthorDate: Thu Nov 6 15:50:22 2025 +0900
Commit:     Miklos Vajna <[email protected]>
CommitDate: Fri Dec 5 11:56:43 2025 +0100

    sc: test pivot table undo/redo creation and filter of field
    
    This adds a unit test for undo/redo of pivot table creation and
    filtering (filtering fixed in [1]).
    
    [1] 203922ed789bb87f3cca8ea90c81de72e8919c83
    
    Change-Id: Ied5f9c813c0c2b62c1cf7433b3bc47a3adcb9994
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193513
    Reviewed-by: Tomaž Vajngerl <[email protected]>
    Tested-by: Jenkins
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195043
    Reviewed-by: Miklos Vajna <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/sc/qa/unit/ucalc_pivottable.cxx b/sc/qa/unit/ucalc_pivottable.cxx
index 9517826423bf..23d2c8676b30 100644
--- a/sc/qa/unit/ucalc_pivottable.cxx
+++ b/sc/qa/unit/ucalc_pivottable.cxx
@@ -18,6 +18,7 @@
 #include <dbdocfun.hxx>
 #include <generalfunction.hxx>
 #include <tabprotection.hxx>
+#include <undomanager.hxx>
 
 #include <formula/errorcodes.hxx>
 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
@@ -155,8 +156,31 @@ ScRange refreshGroups(ScDPCollection* pDPs, ScDPObject* 
pDPObj)
     return refresh(pDPObj);
 }
 
+ScDPObject* getDPObject(ScDocument* pDoc, size_t index)
+{
+    ScDPCollection* pDPCollection = pDoc->GetDPCollection();
+    CPPUNIT_ASSERT_MESSAGE("Failed to get pivot table collection.", 
pDPCollection);
+    return &(*pDPCollection)[index];
+}
+
+sal_Int32 getNumberOfPivotTables(ScDocument* pDoc)
+{
+    ScDPCollection* pDPCollection = pDoc->GetDPCollection();
+    if (!pDPCollection)
+        return -1;
+    return pDPCollection->GetCount();
+}
+
+void updatePivotTable(ScDocShellRef const& xDocShell, size_t index)
+{
+    ScDBDocFunc aFunc(*xDocShell);
+    ScDPObject* pDPObject = getDPObject(&xDocShell->GetDocument(), index);
+    CPPUNIT_ASSERT_MESSAGE("Failed to get pivot table object.", pDPObject);
+    aFunc.RefreshPivotTables(pDPObject, true);
 }
 
+} // end anonymous
+
 class TestPivottable : public ScUcalcTestBase
 {
 protected:
@@ -2649,6 +2673,217 @@ CPPUNIT_TEST_FIXTURE(TestPivottable, 
testPivotTableMedianFunc)
     m_pDoc->DeleteTab(0);
 }
 
+CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableUndoCreate)
+{
+    // Test Undo and Redo creating a pivot table
+
+    m_pDoc->InsertTab(0, u"Data"_ustr);
+    m_pDoc->InsertTab(1, u"Table"_ustr);
+
+    bool bSuccess{};
+    ScDBDocFunc aFunc(*m_xDocShell);
+    ScRange aDataRange;
+
+    // Insert data
+    {
+        const std::vector<std::vector<const char*>> aData = {
+            { "Name", "Value" },
+            { "A", "1" },
+            { "B", "2" },
+        };
+
+        static const ScAddress aPosition(1, 1, 0);
+        aDataRange = insertRangeData(m_pDoc, aPosition, aData);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct 
position", aPosition, aDataRange.aStart);
+    }
+
+    // Create pivot table
+    {
+        // Dimension definition
+        static constexpr auto aFields = std::to_array<DPFieldDef>({
+            { "Name", sheet::DataPilotFieldOrientation_ROW, 
ScGeneralFunction::NONE, false },
+            { "Value", sheet::DataPilotFieldOrientation_DATA, 
ScGeneralFunction::COUNT, false },
+        });
+
+        std::unique_ptr<ScDPObject> pDPObject(createDPFromRange(m_pDoc, 
aDataRange, aFields.data(), aFields.size(), false));
+        CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table object.", 
pDPObject);
+
+        // Create a new pivot table output.
+        bSuccess = aFunc.CreatePivotTable(*pDPObject, true, true);
+        CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table output via 
ScDBDocFunc.", bSuccess);
+    }
+
+    // Check output
+    std::function functionCheckNotFiltered = [this, &bSuccess](int nLine)
+    {
+        ScDPObject* pDPObject = getDPObject(m_pDoc, 0);
+
+        ScRange aOutRange = pDPObject->GetOutRange();
+        {
+            std::vector<std::vector<const char*>> aOutputCheck = {
+                { "Name", "Count - Value" },
+                { "A", "1" },
+                { "B", "1" },
+                { "Total Result", "2" },
+            };
+
+            bSuccess = checkDPTableOutput(m_pDoc, aOutRange, aOutputCheck, 
"Unfiltered data not as expected");
+            CPPUNIT_ASSERT_MESSAGE(OString::number(nLine).getStr(), bSuccess);
+        }
+    };
+    functionCheckNotFiltered(__LINE__);
+
+    // Undo
+    m_pDoc->GetUndoManager()->Undo();
+    {
+        ScDPCollection* pDPCollection = m_pDoc->GetDPCollection();
+        CPPUNIT_ASSERT_EQUAL(size_t(0), pDPCollection->GetCount());
+    }
+
+    // Redo
+    m_pDoc->GetUndoManager()->Redo();
+    {
+        ScDPCollection* pDPCollection = m_pDoc->GetDPCollection();
+        CPPUNIT_ASSERT_EQUAL(size_t(1), pDPCollection->GetCount());
+    }
+
+    functionCheckNotFiltered(__LINE__);
+
+    // Remove Pivot Table
+    {
+        ScDPObject* pDPObject = getDPObject(m_pDoc, 0);
+        bSuccess = aFunc.RemovePivotTable(*pDPObject, true, true);
+        CPPUNIT_ASSERT_MESSAGE("Failed to remove pivot table object.", 
bSuccess);
+    }
+
+    m_pDoc->DeleteTab(1);
+    m_pDoc->DeleteTab(0);
+}
+
+CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableFilterValueUndoRedo)
+{
+    // Test Undo and Redo when a value is filtered out
+
+    m_pDoc->InsertTab(0, u"Data"_ustr);
+    m_pDoc->InsertTab(1, u"Table"_ustr);
+
+    bool bSuccess{};
+    ScDBDocFunc aFunc(*m_xDocShell);
+    ScRange aDataRange;
+
+    // Insert data
+    {
+        const std::vector<std::vector<const char*>> aData = {
+            { "Name", "Value" },
+            { "A", "1" },
+            { "B", "2" },
+        };
+
+        static const ScAddress aPosition(1, 1, 0);
+        aDataRange = insertRangeData(m_pDoc, aPosition, aData);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct 
position", aPosition, aDataRange.aStart);
+    }
+
+    // Create pivot table
+    {
+        // Dimension definition
+        static constexpr auto aFields = std::to_array<DPFieldDef>({
+            { "Name", sheet::DataPilotFieldOrientation_ROW, 
ScGeneralFunction::NONE, false },
+            { "Value", sheet::DataPilotFieldOrientation_DATA, 
ScGeneralFunction::COUNT, false },
+        });
+
+        std::unique_ptr<ScDPObject> pDPObject(createDPFromRange(m_pDoc, 
aDataRange, aFields.data(), aFields.size(), false));
+        CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table object.", 
pDPObject);
+
+        // Create a new pivot table output.
+        bSuccess = aFunc.CreatePivotTable(*pDPObject, true, true);
+        CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table output via 
ScDBDocFunc.", bSuccess);
+    }
+
+    // Check output
+    std::function functionCheckNotFiltered = [this, &bSuccess](int nLine)
+    {
+        ScDPObject* pDPObject = getDPObject(m_pDoc, 0);
+
+        ScRange aOutRange = pDPObject->GetOutRange();
+        {
+            std::vector<std::vector<const char*>> aOutputCheck = {
+                { "Name", "Count - Value" },
+                { "A", "1" },
+                { "B", "1" },
+                { "Total Result", "2" },
+            };
+
+            bSuccess = checkDPTableOutput(m_pDoc, aOutRange, aOutputCheck, 
"Unfiltered data not as expected");
+            OString sMessage("Vales don't match. Called at line " + 
OString::number(nLine));
+            CPPUNIT_ASSERT_MESSAGE(sMessage.getStr(), bSuccess);
+        }
+    };
+    functionCheckNotFiltered(__LINE__);
+
+    // Filter value "A" in "Name" Dimension
+    {
+        ScDPObject* pDPObject = getDPObject(m_pDoc, 0);
+        ScDPObject aNewObject(*pDPObject);
+
+        ScDPSaveData* pSaveData = aNewObject.GetSaveData();
+        CPPUNIT_ASSERT_MESSAGE("Save data doesn't exist.", pSaveData);
+        ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(u"Name"_ustr);
+        CPPUNIT_ASSERT_MESSAGE("Name dimension should exist.", pDim);
+        ScDPSaveMember* pMember = pDim->GetMemberByName(u"A"_ustr);
+        CPPUNIT_ASSERT_MESSAGE("Member should exist.", pMember);
+        pMember->SetIsVisible(false);
+
+        aNewObject.SetSaveData(*pSaveData);
+        aNewObject.ReloadGroupTableData();
+        aNewObject.InvalidateData();
+
+        bSuccess = aFunc.DataPilotUpdate(pDPObject, &aNewObject, true, true);
+        //TODO - We need to fix UpdatePivotTable too
+        // bSuccess = aFunc.UpdatePivotTable(aNewObject, true, true);
+        CPPUNIT_ASSERT_MESSAGE("Pivot table should update.", bSuccess);
+    }
+
+    std::function functionCheckFiltered = [this, &bSuccess](int nLine)
+    {
+        ScDPObject* pDPObject = getDPObject(m_pDoc, 0);
+        ScRange aOutRange = pDPObject->GetOutRange();
+        {
+            std::vector<std::vector<const char*>> aOutputCheck = {
+                { "Name", "Count - Value" },
+                { "B", "1" },
+                { "Total Result", "1" },
+            };
+
+            bSuccess = checkDPTableOutput(m_pDoc, aOutRange, aOutputCheck, 
"Filtered data not as expected");
+            OString sMessage("Vales don't match. Called at line " + 
OString::number(nLine));
+            CPPUNIT_ASSERT_MESSAGE(sMessage.getStr(), bSuccess);
+        }
+    };
+    functionCheckFiltered(__LINE__);
+    updatePivotTable(m_xDocShell, 0);
+    functionCheckFiltered(__LINE__);
+
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), getNumberOfPivotTables(m_pDoc));
+
+    // Undo
+    m_pDoc->GetUndoManager()->Undo();
+
+    functionCheckNotFiltered(__LINE__);
+    updatePivotTable(m_xDocShell, 0);
+    functionCheckNotFiltered(__LINE__);
+
+    // Remove Pivot Table
+    {
+        ScDPObject* pDPObject = getDPObject(m_pDoc, 0);
+        bSuccess = aFunc.RemovePivotTable(*pDPObject, true, true);
+        CPPUNIT_ASSERT_MESSAGE("Failed to remove pivot table object.", 
bSuccess);
+    }
+
+    m_pDoc->DeleteTab(1);
+    m_pDoc->DeleteTab(0);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to