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 974bf22680b702b9474d4a91dbf1d06a785ff774
Author:     Kohei Yoshida <ko...@libreoffice.org>
AuthorDate: Thu Feb 24 23:17:09 2022 -0500
Commit:     Kohei Yoshida <ko...@libreoffice.org>
CommitDate: Sat Feb 26 01:43:32 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>

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 2e1f0df49bdb..e23eac0fdab1 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -719,6 +719,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 b0557751ae22..344e99e130f8 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -2229,6 +2229,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 08624a937172..4a8654a67344 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -1108,6 +1108,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 eb400e68acba..e1b1ee6c65f9 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 ffb8d2fbe4eb..1d02913dab9c 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -222,6 +222,8 @@ public:
     void testProtectedSheetEditByRow();
     void testProtectedSheetEditByColumn();
 
+    void testInsertColumnsWithFormulaCells();
+
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testCollator);
     CPPUNIT_TEST(testSharedStringPool);
@@ -311,6 +313,7 @@ public:
     CPPUNIT_TEST(testPrecisionAsShown);
     CPPUNIT_TEST(testProtectedSheetEditByRow);
     CPPUNIT_TEST(testProtectedSheetEditByColumn);
+    CPPUNIT_TEST(testInsertColumnsWithFormulaCells);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -6645,6 +6648,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 5d5728844e56..2e839d80dba4 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -1069,4 +1069,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 f5c27323090c..dc3a8c045dd9 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: */

Reply via email to