sc/inc/column.hxx | 2 + sc/inc/document.hxx | 10 +++++++ sc/inc/mtvelements.hxx | 2 + sc/inc/table.hxx | 4 +++ sc/qa/unit/helper/qahelper.hxx | 1 sc/qa/unit/ucalc.cxx | 46 ++++++++++++++++++++++++++++++++++++ sc/source/core/data/column4.cxx | 15 +++++++++++ sc/source/core/data/document10.cxx | 18 ++++++++++++++ sc/source/core/data/mtvelements.cxx | 5 +++ sc/source/core/data/table7.cxx | 19 ++++++++++++++ 10 files changed, 122 insertions(+)
New commits: commit d54dfc3d3d241b7430accf17a249406bc9cbfb6c Author: Kohei Yoshida <ko...@libreoffice.org> AuthorDate: Thu Feb 24 23:17:09 2022 -0500 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Mon Feb 28 12:20:26 2022 +0100 tdf#147298: Add a simple test case for formula cell tracking by column. Change-Id: Ibdd72c08f8660ade511fdce8b3fb7cd3ed97f4b7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130511 Tested-by: Jenkins Reviewed-by: Kohei Yoshida <ko...@libreoffice.org> (cherry picked from commit 974bf22680b702b9474d4a91dbf1d06a785ff774) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130554 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 480e691366c2..35c4b3eb0d3b 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -717,6 +717,8 @@ public: SCSIZE GetPatternCount( SCROW nRow1, SCROW nRow2 ) const; bool ReservePatternCount( SCSIZE nReserve ); + void CheckIntegrity() const; + private: sc::CellStoreType::iterator GetPositionToInsert( SCROW nRow, std::vector<SCROW>& rNewSharedRows, diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index fec085a32733..029a339f94a7 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -2219,6 +2219,16 @@ public: std::set<Color> GetDocColors(); sc::IconSetBitmapMap& GetIconSetBitmapMap(); + std::set<SCCOL> QueryColumnsWithFormulaCells( SCTAB nTab ) const; + + /** + * Check the integrity of the internal table state. Useful from testing + * code. It throws an exception upon first failure. + * + * Feel free to add more checks as needed. + */ + void CheckIntegrity( SCTAB nTab ) const; + private: ScDocument(const ScDocument& r) = delete; diff --git a/sc/inc/mtvelements.hxx b/sc/inc/mtvelements.hxx index 75cdea9483bd..c74e1bc7d91b 100644 --- a/sc/inc/mtvelements.hxx +++ b/sc/inc/mtvelements.hxx @@ -100,6 +100,8 @@ public: void stop(); void swap(CellStoreEvent& other); + + const ScColumn* getColumn() const; }; struct CellStoreTrait diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index e61f2f717d89..5602d6dcacfe 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -1106,6 +1106,10 @@ public: */ OString dumpSheetGeomData(bool bColumns, SheetGeomType eGeomType); + std::set<SCCOL> QueryColumnsWithFormulaCells() const; + + void CheckIntegrity() const; + private: void FillFormulaVertical( diff --git a/sc/qa/unit/helper/qahelper.hxx b/sc/qa/unit/helper/qahelper.hxx index 0435ef021651..9aea7a203805 100644 --- a/sc/qa/unit/helper/qahelper.hxx +++ b/sc/qa/unit/helper/qahelper.hxx @@ -29,6 +29,7 @@ #include <sal/types.h> #include <memory> +#include <tuple> namespace utl { class TempFile; } diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index 9cfe59ac27d3..1e7cde76d9f0 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -254,6 +254,8 @@ public: void testProtectedSheetEditByRow(); void testProtectedSheetEditByColumn(); + void testInsertColumnsWithFormulaCells(); + CPPUNIT_TEST_SUITE(Test); CPPUNIT_TEST(testCollator); CPPUNIT_TEST(testSharedStringPool); @@ -343,6 +345,7 @@ public: CPPUNIT_TEST(testPrecisionAsShown); CPPUNIT_TEST(testProtectedSheetEditByRow); CPPUNIT_TEST(testProtectedSheetEditByColumn); + CPPUNIT_TEST(testInsertColumnsWithFormulaCells); CPPUNIT_TEST_SUITE_END(); private: @@ -6677,6 +6680,49 @@ void Test::testProtectedSheetEditByColumn() m_pDoc->DeleteTab(0); } +void Test::testInsertColumnsWithFormulaCells() +{ + m_pDoc->InsertTab(0, "Tab1"); + + std::set<SCCOL> aCols = m_pDoc->QueryColumnsWithFormulaCells(0); + CPPUNIT_ASSERT_MESSAGE("empty sheet should contain no formula cells.", aCols.empty()); + + auto equals = [](const std::set<SCCOL>& left, const std::set<SCCOL>& right) + { + return left == right; + }; + + // insert formula cells in columns 2, 4 and 6. + m_pDoc->SetFormula(ScAddress(2, 2, 0), "=1", m_pDoc->GetGrammar()); + m_pDoc->SetFormula(ScAddress(4, 2, 0), "=1", m_pDoc->GetGrammar()); + m_pDoc->SetFormula(ScAddress(6, 2, 0), "=1", m_pDoc->GetGrammar()); + + aCols = m_pDoc->QueryColumnsWithFormulaCells(0); + + std::set<SCCOL> aExpected = { 2, 4, 6 }; + CPPUNIT_ASSERT_MESSAGE("Columns 2, 4 and 6 should contain formula cells.", equals(aExpected, aCols)); + + // Insert 2 columns at column A to shift everything to right by 2. + m_pDoc->InsertCol(0, 0, MAXROW, 0, 0, 2); + + aExpected = { 4, 6, 8 }; + aCols = m_pDoc->QueryColumnsWithFormulaCells(0); + CPPUNIT_ASSERT_MESSAGE("Columns 4, 6 and 8 should contain formula cells.", equals(aExpected, aCols)); + + try + { + m_pDoc->CheckIntegrity(0); + } + catch (const std::exception& e) + { + std::ostringstream os; + os << "document integrity check failed: " << e.what(); + CPPUNIT_FAIL(os.str()); + } + + m_pDoc->DeleteTab(0); +} + CPPUNIT_TEST_SUITE_REGISTRATION(Test); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx index 980ceb5ac3a2..22bd15cb271c 100644 --- a/sc/source/core/data/column4.cxx +++ b/sc/source/core/data/column4.cxx @@ -2138,4 +2138,19 @@ void ScColumn::RestoreFromCache(SvStream& rStrm) } } +void ScColumn::CheckIntegrity() const +{ + const ScColumn* pColTest = maCells.event_handler().getColumn(); + + if (pColTest != this) + { + std::ostringstream os; + os << "cell store's event handler references wrong column instance (this=" << this + << "; stored=" << pColTest << ")"; + throw std::runtime_error(os.str()); + } + + // Add more integrity checks as needed. +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index f2c8ef5be794..722419fadc06 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -1068,4 +1068,22 @@ bool ScDocument::SetLOKFreezeRow(SCROW nFreezeRow, SCTAB nTab) return pTab->SetLOKFreezeRow(nFreezeRow); } +std::set<SCCOL> ScDocument::QueryColumnsWithFormulaCells( SCTAB nTab ) const +{ + const ScTable* pTab = FetchTable(nTab); + if (!pTab) + return std::set<SCCOL>{}; + + return pTab->QueryColumnsWithFormulaCells(); +} + +void ScDocument::CheckIntegrity( SCTAB nTab ) const +{ + const ScTable* pTab = FetchTable(nTab); + if (!pTab) + return; + + pTab->CheckIntegrity(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/mtvelements.cxx b/sc/source/core/data/mtvelements.cxx index a06e86dcae16..2c2c8daa64fb 100644 --- a/sc/source/core/data/mtvelements.cxx +++ b/sc/source/core/data/mtvelements.cxx @@ -61,6 +61,11 @@ void CellStoreEvent::swap(CellStoreEvent& other) std::swap(mpCol, other.mpCol); } +const ScColumn* CellStoreEvent::getColumn() const +{ + return mpCol; +} + ColumnBlockPositionSet::ColumnBlockPositionSet(ScDocument& rDoc) : mrDoc(rDoc) {} ColumnBlockPosition* ColumnBlockPositionSet::getBlockPosition(SCTAB nTab, SCCOL nCol) diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx index b66b9d88eb3a..3b9c872fb87a 100644 --- a/sc/source/core/data/table7.cxx +++ b/sc/source/core/data/table7.cxx @@ -630,4 +630,23 @@ bool ScTable::SetLOKFreezeRow(SCROW nFreezeRow) return false; } +std::set<SCCOL> ScTable::QueryColumnsWithFormulaCells() const +{ + std::set<SCCOL> aColIndices; + + for (const auto& pCol : aCol) + { + if (pCol->HasFormulaCell()) + aColIndices.insert(pCol->GetCol()); + } + + return aColIndices; +} + +void ScTable::CheckIntegrity() const +{ + for (const auto& pCol : aCol) + pCol->CheckIntegrity(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */