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: */
