LCOV - code coverage report
Current view: top level - sc/qa/unit - ucalc_sharedformula.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 833 984 84.7 %
Date: 2014-11-03 Functions: 20 21 95.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  */
       9             : 
      10             : #include "ucalc.hxx"
      11             : #include "editutil.hxx"
      12             : #include "formulacell.hxx"
      13             : #include "cellvalue.hxx"
      14             : #include "docsh.hxx"
      15             : #include "clipparam.hxx"
      16             : #include "undoblk.hxx"
      17             : #include "scopetools.hxx"
      18             : #include <docfunc.hxx>
      19             : #include <dbdocfun.hxx>
      20             : #include <tokenarray.hxx>
      21             : #include <tokenstringcontext.hxx>
      22             : #include <globalnames.hxx>
      23             : #include <dbdata.hxx>
      24             : 
      25             : #include <svl/sharedstring.hxx>
      26             : 
      27             : #include <formula/grammar.hxx>
      28             : 
      29           2 : void Test::testSharedFormulas()
      30             : {
      31           2 :     m_pDoc->InsertTab(0, "Test");
      32             : 
      33           2 :     ScAddress aPos(1, 9, 0); // B10
      34           2 :     m_pDoc->SetString(aPos, "=A10*2"); // Insert into B10.
      35           2 :     const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
      36           2 :     CPPUNIT_ASSERT_MESSAGE("Expected to be a non-shared cell.", pFC && !pFC->IsShared());
      37             : 
      38           2 :     aPos.SetRow(10); // B11
      39           2 :     m_pDoc->SetString(aPos, "=A11*2");
      40           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
      41           2 :     CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
      42           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedTopRow());
      43           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
      44           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
      45             : 
      46           2 :     aPos.SetRow(8); // B9
      47           2 :     m_pDoc->SetString(aPos, "=A9*2");
      48           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
      49           2 :     CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
      50           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
      51           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
      52           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
      53             : 
      54           2 :     aPos.SetRow(12); // B13
      55           2 :     m_pDoc->SetString(aPos, "=A13*2");
      56           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
      57           2 :     CPPUNIT_ASSERT_MESSAGE("This formula cell shouldn't be shared yet.", pFC && !pFC->IsShared());
      58             : 
      59             :     // Insert a formula to B12, and B9:B13 should be shared.
      60           2 :     aPos.SetRow(11); // B12
      61           2 :     m_pDoc->SetString(aPos, "=A12*2");
      62           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
      63           2 :     CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
      64           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
      65           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedLength());
      66           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
      67             : 
      68             :     // Insert formulas to B15:B16.
      69           2 :     aPos.SetRow(14); // B15
      70           2 :     m_pDoc->SetString(aPos, "=A15*2");
      71           2 :     aPos.SetRow(15); // B16
      72           2 :     m_pDoc->SetString(aPos, "=A16*2");
      73           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
      74           2 :     CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
      75           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow());
      76           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
      77           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
      78             : 
      79             :     // Insert a formula to B14, and B9:B16 should be shared.
      80           2 :     aPos.SetRow(13); // B14
      81           2 :     m_pDoc->SetString(aPos, "=A14*2");
      82           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
      83           2 :     CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
      84           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
      85           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
      86           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
      87             : 
      88             :     // Insert an incompatible formula to B12, to split the shared range to B9:B11 and B13:B16.
      89           2 :     aPos.SetRow(11); // B12
      90           2 :     m_pDoc->SetString(aPos, "=$A$1*4");
      91           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
      92           2 :     CPPUNIT_ASSERT_MESSAGE("This cell shouldn't be shared.", pFC && !pFC->IsShared());
      93             : 
      94           2 :     aPos.SetRow(8); // B9
      95           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
      96           2 :     CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
      97           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
      98           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
      99           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     100             : 
     101           2 :     aPos.SetRow(12); // B13
     102           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     103           2 :     CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
     104           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
     105           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
     106           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     107             : 
     108             :     // Extend B13:B16 to B13:B20.
     109           2 :     aPos.SetRow(16); // B17
     110           2 :     m_pDoc->SetString(aPos, "=A17*2");
     111           2 :     aPos.IncRow();
     112           2 :     m_pDoc->SetString(aPos, "=A18*2");
     113           2 :     aPos.IncRow();
     114           2 :     m_pDoc->SetString(aPos, "=A19*2");
     115           2 :     aPos.IncRow();
     116           2 :     m_pDoc->SetString(aPos, "=A20*2");
     117           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     118           2 :     CPPUNIT_ASSERT_MESSAGE("This cell is expected to be a shared formula cell.", pFC && pFC->IsShared());
     119             :     // B13:B20 shuld be shared.
     120           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
     121           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
     122           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     123             : 
     124             :     // Empty B19. This should split it into B13:B18, and B20 non-shared.
     125           2 :     aPos.SetRow(18);
     126           2 :     m_pDoc->SetEmptyCell(aPos);
     127           2 :     CPPUNIT_ASSERT_MESSAGE("This cell should have been emptied.", m_pDoc->GetCellType(aPos) == CELLTYPE_NONE);
     128           2 :     aPos.SetRow(12); // B13
     129           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     130           2 :     CPPUNIT_ASSERT(pFC);
     131             :     // B13:B18 should be shared.
     132           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(12), pFC->GetSharedTopRow());
     133           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedLength());
     134           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     135             :     // B20 shold be non-shared.
     136           2 :     aPos.SetRow(19); // B20
     137           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     138           2 :     CPPUNIT_ASSERT_MESSAGE("B20 should be a formula cell.", pFC);
     139           2 :     CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared());
     140             : 
     141             :     // Empty B14, to make B13 non-shared and B15:B18 shared.
     142           2 :     aPos.SetRow(13); // B14
     143           2 :     m_pDoc->SetEmptyCell(aPos);
     144           2 :     aPos.SetRow(12); // B13
     145           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     146             :     // B13 should be non-shared.
     147           2 :     CPPUNIT_ASSERT_MESSAGE("B13 should be a formula cell.", pFC);
     148           2 :     CPPUNIT_ASSERT_MESSAGE("This cell should be non-shared.", !pFC->IsShared());
     149             :     // B15:B18 should be shared.
     150           2 :     aPos.SetRow(14); // B15
     151           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     152           2 :     CPPUNIT_ASSERT(pFC);
     153           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(14), pFC->GetSharedTopRow());
     154           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
     155           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     156             : 
     157             :     // Set numeric value to B15, to make B16:B18 shared.
     158           2 :     aPos.SetRow(14);
     159           2 :     m_pDoc->SetValue(aPos, 1.2);
     160           2 :     aPos.SetRow(15);
     161           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     162           2 :     CPPUNIT_ASSERT(pFC);
     163             :     // B16:B18 should be shared.
     164           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(15), pFC->GetSharedTopRow());
     165           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
     166           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     167             : 
     168             :     // Set string value to B16 to make B17:B18 shared.
     169           2 :     aPos.SetRow(15);
     170           2 :     ScCellValue aCell(svl::SharedString("Test"));
     171           2 :     CPPUNIT_ASSERT_MESSAGE("This should be a string value.", aCell.meType == CELLTYPE_STRING);
     172           2 :     aCell.commit(*m_pDoc, aPos);
     173           2 :     CPPUNIT_ASSERT_EQUAL(aCell.mpString->getString(), m_pDoc->GetString(aPos));
     174           2 :     aPos.SetRow(16);
     175           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     176           2 :     CPPUNIT_ASSERT(pFC);
     177             :     // B17:B18 should be shared.
     178           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(16), pFC->GetSharedTopRow());
     179           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
     180           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     181             : 
     182             :     // Set edit text to B17. Now B18 should be non-shared.
     183           2 :     ScFieldEditEngine& rEditEngine = m_pDoc->GetEditEngine();
     184           2 :     rEditEngine.SetText("Edit Text");
     185           2 :     aPos.SetRow(16);
     186           2 :     m_pDoc->SetEditText(aPos, rEditEngine.CreateTextObject());
     187           2 :     CPPUNIT_ASSERT_EQUAL(CELLTYPE_EDIT, m_pDoc->GetCellType(aPos));
     188           2 :     aPos.SetRow(17);
     189           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     190           2 :     CPPUNIT_ASSERT_MESSAGE("B18 should be a formula cell.", pFC);
     191           2 :     CPPUNIT_ASSERT_MESSAGE("B18 should be non-shared.", !pFC->IsShared());
     192             : 
     193             :     // Set up a new group for shared formulas in B2:B10.
     194           2 :     clearRange(m_pDoc, ScRange(0,0,0,2,100,0));
     195             : 
     196           2 :     aPos.SetRow(1);
     197           2 :     m_pDoc->SetString(aPos, "=A2*10");
     198           2 :     aPos.IncRow();
     199           2 :     m_pDoc->SetString(aPos, "=A3*10");
     200           2 :     aPos.IncRow();
     201           2 :     m_pDoc->SetString(aPos, "=A4*10");
     202           2 :     aPos.IncRow();
     203           2 :     m_pDoc->SetString(aPos, "=A5*10");
     204           2 :     aPos.IncRow();
     205           2 :     m_pDoc->SetString(aPos, "=A6*10");
     206           2 :     aPos.IncRow();
     207           2 :     m_pDoc->SetString(aPos, "=A7*10");
     208           2 :     aPos.IncRow();
     209           2 :     m_pDoc->SetString(aPos, "=A8*10");
     210           2 :     aPos.IncRow();
     211           2 :     m_pDoc->SetString(aPos, "=A9*10");
     212           2 :     aPos.IncRow();
     213           2 :     m_pDoc->SetString(aPos, "=A10*10");
     214             : 
     215           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     216           2 :     CPPUNIT_ASSERT_MESSAGE("B10 should be a formula cell.", pFC);
     217           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
     218           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedLength());
     219           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     220             : 
     221             :     // Delete A4:B8. This should splite the grouping to B2:B3 and B9:B10.
     222           2 :     clearRange(m_pDoc, ScRange(0,3,0,1,7,0));
     223           2 :     aPos.SetRow(1);
     224           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     225           2 :     CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
     226           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
     227           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
     228           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     229             : 
     230           2 :     aPos.SetRow(8);
     231           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     232           2 :     CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC);
     233           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
     234           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
     235           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     236             : 
     237             :     // Delete rows 4:8 and shift row 9 and below up to row 4.  This should
     238             :     // re-merge the two into a group of B2:B5.
     239           2 :     m_pDoc->DeleteRow(ScRange(0,3,0,MAXCOL,7,0));
     240           2 :     aPos.SetRow(1);
     241           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     242           2 :     CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
     243           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
     244           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
     245           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     246             : 
     247             :     // Insert 2 rows at row 4, to split it into B2:B3 and B6:B7.
     248           2 :     m_pDoc->InsertRow(ScRange(0,3,0,MAXCOL,4,0));
     249           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     250           2 :     CPPUNIT_ASSERT_MESSAGE("B2 should be a formula cell.", pFC);
     251           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
     252           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
     253           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     254             : 
     255           2 :     aPos.SetRow(5);
     256           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
     257           2 :     CPPUNIT_ASSERT_MESSAGE("B6 should be a formula cell.", pFC);
     258           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedTopRow());
     259           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
     260           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
     261             : 
     262           2 :     m_pDoc->DeleteTab(0);
     263           2 : }
     264             : 
     265           2 : void Test::testSharedFormulasRefUpdate()
     266             : {
     267           2 :     m_pDoc->InsertTab(0, "Test");
     268             : 
     269           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, false); // turn off auto calculation.
     270             : 
     271             :     // Set values to A10:A12.
     272           2 :     m_pDoc->SetValue(ScAddress(0,9,0), 1);
     273           2 :     m_pDoc->SetValue(ScAddress(0,10,0), 2);
     274           2 :     m_pDoc->SetValue(ScAddress(0,11,0), 3);
     275             : 
     276             :     // Insert formulas that reference A10:A12 in B1:B3.
     277           2 :     m_pDoc->SetString(ScAddress(1,0,0), "=A10");
     278           2 :     m_pDoc->SetString(ScAddress(1,1,0), "=A11");
     279           2 :     m_pDoc->SetString(ScAddress(1,2,0), "=A12");
     280             : 
     281           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
     282           0 :         CPPUNIT_FAIL("Wrong formula in B1");
     283           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A11"))
     284           0 :         CPPUNIT_FAIL("Wrong formula in B2");
     285           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12"))
     286           0 :         CPPUNIT_FAIL("Wrong formula in B3");
     287             : 
     288           2 :     const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     289           2 :     CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
     290           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
     291           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
     292             : 
     293             :     // Insert cells over A11:B11 to shift to right. This should split the B1:B3 grouping into 3.
     294           2 :     m_pDoc->InsertCol(ScRange(0,10,0,1,10,0));
     295           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
     296           0 :         CPPUNIT_FAIL("Wrong formula in B1");
     297           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "C11"))
     298           0 :         CPPUNIT_FAIL("Wrong formula in B2");
     299           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12"))
     300           0 :         CPPUNIT_FAIL("Wrong formula in B3");
     301             : 
     302           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     303           2 :     CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC && !pFC->IsShared());
     304           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
     305           2 :     CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", pFC && !pFC->IsShared());
     306           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,0));
     307           2 :     CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", pFC && !pFC->IsShared());
     308             : 
     309             :     // Delelte cells over A11:B11 to bring it back to the previous state.
     310           2 :     m_pDoc->DeleteCol(ScRange(0,10,0,1,10,0));
     311             : 
     312           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
     313           0 :         CPPUNIT_FAIL("Wrong formula in B1");
     314           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A11"))
     315           0 :         CPPUNIT_FAIL("Wrong formula in B2");
     316           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12"))
     317           0 :         CPPUNIT_FAIL("Wrong formula in B3");
     318             : 
     319           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     320           2 :     CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
     321           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
     322           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
     323             : 
     324             :     // Insert cells over A11:A12 and shift down.
     325           2 :     m_pDoc->InsertRow(ScRange(0,10,0,0,11,0));
     326           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
     327           0 :         CPPUNIT_FAIL("Wrong formula in B1");
     328           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A13"))
     329           0 :         CPPUNIT_FAIL("Wrong formula in B2");
     330           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A14"))
     331           0 :         CPPUNIT_FAIL("Wrong formula in B3");
     332             : 
     333           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     334           2 :     CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC && !pFC->IsShared());
     335           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
     336           2 :     CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
     337           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
     338           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
     339             : 
     340             :     // Delete A11:A12 to bring it back to the way it was.
     341           2 :     m_pDoc->DeleteRow(ScRange(0,10,0,0,11,0));
     342             : 
     343           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
     344           0 :         CPPUNIT_FAIL("Wrong formula in B1");
     345           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A11"))
     346           0 :         CPPUNIT_FAIL("Wrong formula in B2");
     347           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12"))
     348           0 :         CPPUNIT_FAIL("Wrong formula in B3");
     349             : 
     350           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     351           2 :     CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
     352           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
     353           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
     354             : 
     355             :     // Insert cells over A11:B11 to shift to right again.
     356           2 :     m_pDoc->InsertCol(ScRange(0,10,0,1,10,0));
     357           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
     358           0 :         CPPUNIT_FAIL("Wrong formula in B1");
     359           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "C11"))
     360           0 :         CPPUNIT_FAIL("Wrong formula in B2");
     361           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12"))
     362           0 :         CPPUNIT_FAIL("Wrong formula in B3");
     363             : 
     364           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     365           2 :     CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC && !pFC->IsShared());
     366           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
     367           2 :     CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", pFC && !pFC->IsShared());
     368           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,0));
     369           2 :     CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", pFC && !pFC->IsShared());
     370             : 
     371             :     // Insert cells over A12:B12 to shift to right.
     372           2 :     m_pDoc->InsertCol(ScRange(0,11,0,1,11,0));
     373           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
     374           0 :         CPPUNIT_FAIL("Wrong formula in B1");
     375           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "C11"))
     376           0 :         CPPUNIT_FAIL("Wrong formula in B2");
     377           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "C12"))
     378           0 :         CPPUNIT_FAIL("Wrong formula in B3");
     379             : 
     380           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     381           2 :     CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC && !pFC->IsShared());
     382             :     // B2 and B3 should be grouped.
     383           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
     384           2 :     CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
     385           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
     386           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
     387             : 
     388             :     // Insert cells over A10:B10 to shift to right.
     389           2 :     m_pDoc->InsertCol(ScRange(0,9,0,1,9,0));
     390           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "C10"))
     391           0 :         CPPUNIT_FAIL("Wrong formula in B1");
     392           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "C11"))
     393           0 :         CPPUNIT_FAIL("Wrong formula in B2");
     394           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "C12"))
     395           0 :         CPPUNIT_FAIL("Wrong formula in B3");
     396             : 
     397             :     // B1:B3 should be now grouped.
     398           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     399           2 :     CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
     400           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
     401           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
     402             : 
     403           2 :     m_pDoc->DeleteTab(0);
     404           2 : }
     405             : 
     406           2 : void Test::testSharedFormulasRefUpdateMove()
     407             : {
     408           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
     409           4 :     FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
     410             : 
     411           2 :     m_pDoc->InsertTab(0, "Test");
     412             : 
     413             :     // Set values in B2:B4.
     414           8 :     for (SCROW i = 1; i <= 3; ++i)
     415           6 :         m_pDoc->SetValue(ScAddress(1,i,0), i);
     416             : 
     417             :     // Make sure the values are really there.
     418           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
     419           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
     420           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,3,0)));
     421             : 
     422             :     // Set formulas in C2:C4 that reference B2:B4 individually.
     423           8 :     for (SCROW i = 1; i <= 3; ++i)
     424           6 :         m_pDoc->SetString(ScAddress(2,i,0), "=RC[-1]");
     425             : 
     426             :     // Check the formula results.
     427           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,1,0)));
     428           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,2,0)));
     429           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,3,0)));
     430             : 
     431             :     // Move B2:B4 to B1:B3.
     432           2 :     bool bMoved = getDocShell().GetDocFunc().MoveBlock(ScRange(1,1,0,1,3,0), ScAddress(1,0,0), true, true, false, true);
     433           2 :     CPPUNIT_ASSERT(bMoved);
     434             : 
     435             :     // Make sure the values have been moved for real.
     436           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
     437           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
     438           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
     439             : 
     440             :     // The formulas should have been adjusted for the move.
     441           2 :     CPPUNIT_ASSERT(checkFormula(*m_pDoc, ScAddress(2,1,0), "R[-1]C[-1]"));
     442           2 :     CPPUNIT_ASSERT(checkFormula(*m_pDoc, ScAddress(2,2,0), "R[-1]C[-1]"));
     443           2 :     CPPUNIT_ASSERT(checkFormula(*m_pDoc, ScAddress(2,3,0), "R[-1]C[-1]"));
     444             : 
     445           2 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
     446           2 :     CPPUNIT_ASSERT(pUndoMgr);
     447           2 :     pUndoMgr->Undo();
     448             : 
     449             :     // The values should have moved back.
     450           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
     451           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
     452           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,3,0)));
     453             : 
     454             :     // And the formulas should have been re-adjusted to their original references.
     455           2 :     CPPUNIT_ASSERT(checkFormula(*m_pDoc, ScAddress(2,1,0), "RC[-1]"));
     456           2 :     CPPUNIT_ASSERT(checkFormula(*m_pDoc, ScAddress(2,2,0), "RC[-1]"));
     457           2 :     CPPUNIT_ASSERT(checkFormula(*m_pDoc, ScAddress(2,3,0), "RC[-1]"));
     458             : 
     459           4 :     m_pDoc->DeleteTab(0);
     460           2 : }
     461             : 
     462           2 : void Test::testSharedFormulasRefUpdateMove2()
     463             : {
     464           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, false); // turn auto calc off this time.
     465           4 :     FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
     466             : 
     467           2 :     m_pDoc->InsertTab(0, "Test");
     468             : 
     469             :     // Set values in B2:B3, and E2:E3.
     470           6 :     for (SCROW i = 1; i <= 2; ++i)
     471             :     {
     472           4 :         m_pDoc->SetValue(ScAddress(1,i,0), i);
     473           4 :         m_pDoc->SetValue(ScAddress(4,i,0), i);
     474             :     }
     475             : 
     476             :     // Make sure the values are really there.
     477           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
     478           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
     479           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(4,1,0)));
     480           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(4,2,0)));
     481             : 
     482             :     // Set formulas in C2:C3 that reference B2:B4 individually, and F2:F3 to E2:E3.
     483           6 :     for (SCROW i = 1; i <= 2; ++i)
     484             :     {
     485           4 :         m_pDoc->SetString(ScAddress(2,i,0), "=RC[-1]");
     486           4 :         m_pDoc->SetString(ScAddress(5,i,0), "=RC[-1]");
     487             :     }
     488             : 
     489           2 :     m_pDoc->CalcFormulaTree(); // calculate manually.
     490             : 
     491             :     // Check the formula results.
     492           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,1,0)));
     493           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,2,0)));
     494           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5,1,0)));
     495           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(5,2,0)));
     496             : 
     497             :     // Move B2:C3 to C3:D4.
     498           2 :     bool bMoved = getDocShell().GetDocFunc().MoveBlock(
     499           4 :         ScRange(1,1,0,2,2,0), ScAddress(2,2,0), true, true, false, true);
     500           2 :     CPPUNIT_ASSERT(bMoved);
     501             : 
     502             :     // Make sure the range has been moved.
     503           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,2,0)));
     504           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,3,0)));
     505             : 
     506             :     // The formula cells should retain their results even with auto calc off
     507             :     // and without recalculation.
     508           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(3,2,0)));
     509           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(3,3,0)));
     510             : 
     511             :     // And these formulas in F2:F3 are unaffected, therefore should not change.
     512           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5,1,0)));
     513           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(5,2,0)));
     514             : 
     515           2 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
     516           2 :     CPPUNIT_ASSERT(pUndoMgr);
     517             : 
     518             :     // Undo the move.
     519           2 :     pUndoMgr->Undo();
     520             : 
     521             :     // Check the formula results.  The results should still be intact.
     522           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,1,0)));
     523           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,2,0)));
     524           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5,1,0)));
     525           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(5,2,0)));
     526             : 
     527           4 :     m_pDoc->DeleteTab(0);
     528           2 : }
     529             : 
     530           2 : void Test::testSharedFormulasRefUpdateRange()
     531             : {
     532           2 :     m_pDoc->InsertTab(0, "Test");
     533             : 
     534             :     // Insert values to A3:A5.
     535           2 :     m_pDoc->SetValue(ScAddress(0,2,0), 1);
     536           2 :     m_pDoc->SetValue(ScAddress(0,3,0), 2);
     537           2 :     m_pDoc->SetValue(ScAddress(0,4,0), 3);
     538             : 
     539             :     // Insert formulas to B3:B5.
     540           2 :     m_pDoc->SetString(ScAddress(1,2,0), "=SUM($A$3:$A$5)");
     541           2 :     m_pDoc->SetString(ScAddress(1,3,0), "=SUM($A$3:$A$5)");
     542           2 :     m_pDoc->SetString(ScAddress(1,4,0), "=SUM($A$3:$A$5)");
     543             : 
     544           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "SUM($A$3:$A$5)"))
     545           0 :         CPPUNIT_FAIL("Wrong formula");
     546           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,3,0), "SUM($A$3:$A$5)"))
     547           0 :         CPPUNIT_FAIL("Wrong formula");
     548           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,4,0), "SUM($A$3:$A$5)"))
     549           0 :         CPPUNIT_FAIL("Wrong formula");
     550             : 
     551             :     // B3:B5 should be shared.
     552           2 :     const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,0));
     553           2 :     CPPUNIT_ASSERT_MESSAGE("B3 should be shared.", pFC && pFC->IsShared());
     554           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,3,0));
     555           2 :     CPPUNIT_ASSERT_MESSAGE("B4 should be shared.", pFC && pFC->IsShared());
     556           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,4,0));
     557           2 :     CPPUNIT_ASSERT_MESSAGE("B3 should be shared.", pFC && pFC->IsShared());
     558             : 
     559             :     // Insert 2 rows at row 1.
     560           2 :     m_pDoc->InsertRow(ScRange(0,0,0,MAXCOL,1,0));
     561             : 
     562             :     // B5:B7 should be shared.
     563           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,4,0));
     564           2 :     CPPUNIT_ASSERT_MESSAGE("B5 should be shared.", pFC && pFC->IsShared());
     565           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,5,0));
     566           2 :     CPPUNIT_ASSERT_MESSAGE("B6 should be shared.", pFC && pFC->IsShared());
     567           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,6,0));
     568           2 :     CPPUNIT_ASSERT_MESSAGE("B7 should be shared.", pFC && pFC->IsShared());
     569             : 
     570           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedTopRow());
     571           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
     572             : 
     573           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,4,0), "SUM($A$5:$A$7)"))
     574           0 :         CPPUNIT_FAIL("Wrong formula");
     575           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,5,0), "SUM($A$5:$A$7)"))
     576           0 :         CPPUNIT_FAIL("Wrong formula");
     577           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,6,0), "SUM($A$5:$A$7)"))
     578           0 :         CPPUNIT_FAIL("Wrong formula");
     579             : 
     580           2 :     m_pDoc->DeleteTab(0);
     581           2 : }
     582             : 
     583           2 : void Test::testSharedFormulasRefUpdateExternal()
     584             : {
     585           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
     586           2 :     m_pDoc->InsertTab(0, "Formula");
     587             : 
     588             :     // Launch an external document shell.
     589           4 :     ScDocShellRef xExtDocSh = new ScDocShell;
     590           4 :     OUString aExtDocName("file:///extdata.fake");
     591             : 
     592           2 :     SfxMedium* pMed = new SfxMedium(aExtDocName, STREAM_STD_READWRITE);
     593           2 :     xExtDocSh->DoInitNew(pMed);
     594           2 :     ScDocument& rExtDoc = xExtDocSh->GetDocument();
     595             : 
     596             :     // Populate A1:A3.
     597           2 :     rExtDoc.InsertTab(0, "Data");
     598           2 :     rExtDoc.SetString(ScAddress(0,0,0), "A");
     599           2 :     rExtDoc.SetString(ScAddress(0,1,0), "B");
     600           2 :     rExtDoc.SetString(ScAddress(0,2,0), "C");
     601             : 
     602             :     // Insert formula cells in A7:A10 of the host document, referencing A1:A3
     603             :     // of the external document.
     604           2 :     m_pDoc->SetString(ScAddress(0,6,0), "='file:///extdata.fake'#$Data.A1");
     605           2 :     m_pDoc->SetString(ScAddress(0,7,0), "='file:///extdata.fake'#$Data.A2");
     606           2 :     m_pDoc->SetString(ScAddress(0,8,0), "='file:///extdata.fake'#$Data.A3");
     607           2 :     m_pDoc->SetString(ScAddress(0,9,0), "=COUNTA('file:///extdata.fake'#$Data.A1:A3)");
     608             : 
     609             :     // Check the formula results.
     610           2 :     CPPUNIT_ASSERT_EQUAL(OUString("A"), m_pDoc->GetString(ScAddress(0,6,0)));
     611           2 :     CPPUNIT_ASSERT_EQUAL(OUString("B"), m_pDoc->GetString(ScAddress(0,7,0)));
     612           2 :     CPPUNIT_ASSERT_EQUAL(OUString("C"), m_pDoc->GetString(ScAddress(0,8,0)));
     613           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,9,0)));
     614             : 
     615             :     // Check the formulas too.
     616           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,6,0), "'file:///extdata.fake'#$Data.A1"))
     617           0 :         CPPUNIT_FAIL("Wrong formula!");
     618           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,7,0), "'file:///extdata.fake'#$Data.A2"))
     619           0 :         CPPUNIT_FAIL("Wrong formula!");
     620           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,8,0), "'file:///extdata.fake'#$Data.A3"))
     621           0 :         CPPUNIT_FAIL("Wrong formula!");
     622           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,9,0), "COUNTA('file:///extdata.fake'#$Data.A1:A3)"))
     623           0 :         CPPUNIT_FAIL("Wrong formula!");
     624             : 
     625             :     // Delete rows 1 and 2. This should not change the references in the formula cells below.
     626           2 :     ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
     627           4 :     ScMarkData aMark;
     628           2 :     aMark.SelectOneTable(0);
     629           2 :     rDocFunc.DeleteCells(ScRange(0,0,0,MAXCOL,1,0), &aMark, DEL_CELLSUP, true, true);
     630             : 
     631             :     // Check the shifted formula cells now in A5:A8.
     632           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,4,0), "'file:///extdata.fake'#$Data.A1"))
     633           0 :         CPPUNIT_FAIL("Wrong formula!");
     634           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,5,0), "'file:///extdata.fake'#$Data.A2"))
     635           0 :         CPPUNIT_FAIL("Wrong formula!");
     636           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,6,0), "'file:///extdata.fake'#$Data.A3"))
     637           0 :         CPPUNIT_FAIL("Wrong formula!");
     638           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,7,0), "COUNTA('file:///extdata.fake'#$Data.A1:A3)"))
     639           0 :         CPPUNIT_FAIL("Wrong formula!");
     640             : 
     641             :     // Undo and check the formulas again.
     642           2 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
     643           2 :     CPPUNIT_ASSERT(pUndoMgr);
     644           2 :     pUndoMgr->Undo();
     645           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,6,0), "'file:///extdata.fake'#$Data.A1"))
     646           0 :         CPPUNIT_FAIL("Wrong formula!");
     647           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,7,0), "'file:///extdata.fake'#$Data.A2"))
     648           0 :         CPPUNIT_FAIL("Wrong formula!");
     649           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,8,0), "'file:///extdata.fake'#$Data.A3"))
     650           0 :         CPPUNIT_FAIL("Wrong formula!");
     651           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,9,0), "COUNTA('file:///extdata.fake'#$Data.A1:A3)"))
     652           0 :         CPPUNIT_FAIL("Wrong formula!");
     653             : 
     654             :     // Redo the row deletion and check the formulas again.
     655           2 :     pUndoMgr->Redo();
     656           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,4,0), "'file:///extdata.fake'#$Data.A1"))
     657           0 :         CPPUNIT_FAIL("Wrong formula!");
     658           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,5,0), "'file:///extdata.fake'#$Data.A2"))
     659           0 :         CPPUNIT_FAIL("Wrong formula!");
     660           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,6,0), "'file:///extdata.fake'#$Data.A3"))
     661           0 :         CPPUNIT_FAIL("Wrong formula!");
     662           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,7,0), "COUNTA('file:///extdata.fake'#$Data.A1:A3)"))
     663           0 :         CPPUNIT_FAIL("Wrong formula!");
     664             : 
     665           2 :     xExtDocSh->DoClose();
     666             : 
     667           4 :     m_pDoc->DeleteTab(0);
     668           2 : }
     669             : 
     670           2 : void Test::testSharedFormulasInsertRow()
     671             : {
     672             :     struct
     673             :     {
     674           4 :         bool checkContent( ScDocument* pDoc )
     675             :         {
     676             :             // B1:B2 and B4:B5 should point to $A$5.
     677           4 :             SCROW pRows[] = { 0, 1, 3, 4 };
     678          20 :             for (size_t i = 0, n = SAL_N_ELEMENTS(pRows); i < n; ++i)
     679             :             {
     680          16 :                 ScAddress aPos(1, pRows[i], 0);
     681          16 :                 if (!checkFormula(*pDoc, aPos, "$A$5"))
     682             :                 {
     683           0 :                     cerr << "Wrong formula!" << endl;
     684           0 :                     return false;
     685             :                 }
     686             :             }
     687             : 
     688             :             // B1:B2 should be grouped.
     689           4 :             ScFormulaCell* pFC = pDoc->GetFormulaCell(ScAddress(1,0,0));
     690           4 :             if (!pFC || pFC->GetSharedTopRow() != 0 || pFC->GetSharedLength() != 2)
     691             :             {
     692           0 :                 cerr << "B1:B2 should be grouped." << endl;
     693           0 :                 return false;
     694             :             }
     695             : 
     696             :             // B4:B5 should be grouped.
     697           4 :             pFC = pDoc->GetFormulaCell(ScAddress(1,3,0));
     698           4 :             if (!pFC || pFC->GetSharedTopRow() != 3 || pFC->GetSharedLength() != 2)
     699             :             {
     700           0 :                 cerr << "B4:B5 should be grouped." << endl;
     701           0 :                 return false;
     702             :             }
     703             : 
     704           4 :             return true;
     705             :         }
     706             : 
     707           2 :         bool checkContentUndo( ScDocument* pDoc )
     708             :         {
     709          10 :             for (SCROW i = 0; i <= 3; ++i)
     710             :             {
     711           8 :                 ScAddress aPos(1,i,0);
     712           8 :                 if (!checkFormula(*pDoc, aPos, "$A$4"))
     713             :                 {
     714           0 :                     cerr << "Wrong formula!" << endl;
     715           0 :                     return false;
     716             :                 }
     717             :             }
     718             : 
     719             :             // Ensure that B5 is empty.
     720           2 :             if (pDoc->GetCellType(ScAddress(1,4,0)) != CELLTYPE_NONE)
     721             :             {
     722           0 :                 cerr << "B5 should be empty." << endl;
     723           0 :                 return false;
     724             :             }
     725             : 
     726             :             // B1:B4 should be grouped.
     727           2 :             ScFormulaCell* pFC = pDoc->GetFormulaCell(ScAddress(1,0,0));
     728           2 :             if (!pFC || pFC->GetSharedTopRow() != 0 || pFC->GetSharedLength() != 4)
     729             :             {
     730           0 :                 cerr << "B1:B4 should be grouped." << endl;
     731           0 :                 return false;
     732             :             }
     733             : 
     734           2 :             return true;
     735             :         }
     736             : 
     737             :     } aCheck;
     738             : 
     739           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
     740           2 :     m_pDoc->InsertTab(0, "Test");
     741             : 
     742             :     // Scenario inspired by fdo#76470.
     743             : 
     744             :     // Set value to A4.
     745           2 :     m_pDoc->SetValue(ScAddress(0,3,0), 4.0);
     746             : 
     747             :     // Set formula cells in B1:B4 all referencing A4 as absolute reference.
     748          10 :     for (SCROW i = 0; i <= 3; ++i)
     749           8 :         m_pDoc->SetString(ScAddress(1,i,0), "=$A$4");
     750             : 
     751             :     // Insert a new row at row 3.
     752           2 :     ScDocFunc& rFunc = getDocShell().GetDocFunc();
     753           4 :     ScMarkData aMark;
     754           2 :     aMark.SelectOneTable(0);
     755           2 :     rFunc.InsertCells(ScRange(0,2,0,MAXCOL,2,0), &aMark, INS_INSROWS, true, true, false);
     756             : 
     757           2 :     bool bResult = aCheck.checkContent(m_pDoc);
     758           2 :     CPPUNIT_ASSERT_MESSAGE("Failed on the initial content check.", bResult);
     759             : 
     760             :     // Undo and check its result.
     761           2 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
     762           2 :     CPPUNIT_ASSERT(pUndoMgr);
     763           2 :     pUndoMgr->Undo();
     764             : 
     765           2 :     bResult = aCheck.checkContentUndo(m_pDoc);
     766           2 :     CPPUNIT_ASSERT_MESSAGE("Failed on the content check after undo.", bResult);
     767             : 
     768             :     // Redo and check its result.
     769           2 :     pUndoMgr->Redo();
     770           2 :     bResult = aCheck.checkContent(m_pDoc);
     771           2 :     CPPUNIT_ASSERT_MESSAGE("Failed on the content check after redo.", bResult);
     772             : 
     773           4 :     m_pDoc->DeleteTab(0);
     774           2 : }
     775             : 
     776           2 : void Test::testSharedFormulasDeleteRows()
     777             : {
     778           2 :     m_pDoc->InsertTab(0, "Test");
     779           2 :     FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
     780             : 
     781             :     // Fill data cells A1:A10 and formula cells B1:B10
     782          22 :     for (SCROW i = 0; i <= 9 ; ++i)
     783             :     {
     784          20 :         m_pDoc->SetValue(0, i, 0, i);
     785          20 :         m_pDoc->SetString(1, i, 0, "=RC[-1]+1");
     786             :     }
     787             :     // Fill data cells A11:A20 and formula cells B11:B20 with a different formula.
     788          22 :     for (SCROW i = 10; i <= 19 ; ++i)
     789             :     {
     790          20 :         m_pDoc->SetValue(0, i, 0, i);
     791          20 :         m_pDoc->SetString(1, i, 0, "=RC[-1]+11");
     792             :     }
     793             : 
     794             :     // B1:B10 should be shared.
     795           2 :     const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     796           2 :     CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC && pFC->IsShared());
     797           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
     798           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
     799             :     // B11:B20 should be shared.
     800           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,10,0));
     801           2 :     CPPUNIT_ASSERT_MESSAGE("1,10 must be a shared formula cell.", pFC && pFC->IsShared());
     802           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedTopRow());
     803           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
     804             : 
     805             :     // Delete rows 9:12
     806           2 :     m_pDoc->DeleteRow(ScRange(0,8,0,MAXCOL,11,0));
     807             : 
     808             :     // B1:B8 should be shared.
     809           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     810           2 :     CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC && pFC->IsShared());
     811           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
     812           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
     813             :     // B9:B16 should be shared.
     814           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,8,0));
     815           2 :     CPPUNIT_ASSERT_MESSAGE("1,8 must be a shared formula cell.", pFC && pFC->IsShared());
     816           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedTopRow());
     817           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
     818             : 
     819             :     // Delete row 3
     820           2 :     m_pDoc->DeleteRow(ScRange(0,2,0,MAXCOL,2,0));
     821             : 
     822             :     // B1:B7 should be shared.
     823           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     824           2 :     CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC && pFC->IsShared());
     825           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
     826           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(7), pFC->GetSharedLength());
     827             :     // B8:B15 should be shared.
     828           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,7,0));
     829           2 :     CPPUNIT_ASSERT_MESSAGE("1,7 must be a shared formula cell.", pFC && pFC->IsShared());
     830           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(7), pFC->GetSharedTopRow());
     831           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
     832             : 
     833             :     // Delete row 5
     834           2 :     m_pDoc->DeleteRow(ScRange(0,4,0,MAXCOL,4,0));
     835             : 
     836             :     // B1:B6 should be shared.
     837           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     838           2 :     CPPUNIT_ASSERT_MESSAGE("1,0 must be a shared formula cell.", pFC && pFC->IsShared());
     839           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
     840           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedLength());
     841             :     // B7:B14 should be shared.
     842           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,6,0));
     843           2 :     CPPUNIT_ASSERT_MESSAGE("1,6 must be a shared formula cell.", pFC && pFC->IsShared());
     844           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedTopRow());
     845           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
     846           2 : }
     847             : 
     848           2 : void Test::testSharedFormulasDeleteColumns()
     849             : {
     850             :     using namespace formula;
     851             : 
     852           2 :     m_pDoc->InsertTab(0, "Test");
     853             : 
     854           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
     855           4 :     FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
     856             : 
     857           2 :     ScDocFunc& rFunc = getDocShell().GetDocFunc();
     858           4 :     ScMarkData aMark;
     859           2 :     aMark.SelectOneTable(0);
     860             : 
     861             :     // First, test a single cell case.  A value in B1 and formula in C1.
     862           2 :     m_pDoc->SetValue(ScAddress(1,0,0), 11.0);
     863           2 :     m_pDoc->SetString(ScAddress(2,0,0), "=RC[-1]");
     864           2 :     CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,0,0)));
     865             : 
     866             :     // Delete column B.
     867           2 :     rFunc.DeleteCells(ScRange(1,0,0,1,MAXROW,0), &aMark, DEL_CELLSLEFT, true, true);
     868           2 :     CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc->GetString(ScAddress(1,0,0)));
     869             : 
     870             :     // The reference should still point to row 1 but the column status should be set to 'deleted'.
     871           2 :     const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
     872           2 :     CPPUNIT_ASSERT(pFC);
     873           2 :     const ScTokenArray* pCode = pFC->GetCode();
     874           2 :     CPPUNIT_ASSERT(pCode && pCode->GetLen() == 1);
     875           2 :     const FormulaToken* pToken = pCode->GetArray()[0];
     876           2 :     CPPUNIT_ASSERT(pToken->GetType() == svSingleRef);
     877           2 :     const ScSingleRefData* pSRef = pToken->GetSingleRef();
     878           2 :     CPPUNIT_ASSERT(pSRef->IsColDeleted());
     879           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pSRef->toAbs(ScAddress(1,0,0)).Row());
     880             : 
     881             :     // The formula string should show #REF! in lieu of the column position (only for Calc A1 syntax).
     882           4 :     sc::CompileFormulaContext aCFCxt(m_pDoc, FormulaGrammar::GRAM_ENGLISH);
     883           2 :     CPPUNIT_ASSERT_EQUAL(OUString("=#REF!1"), pFC->GetFormula(aCFCxt));
     884             : 
     885           2 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
     886           2 :     CPPUNIT_ASSERT(pUndoMgr);
     887             : 
     888             :     // Undo and make sure the deleted flag is gone.
     889           2 :     pUndoMgr->Undo();
     890           2 :     CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,0,0)));
     891           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
     892           2 :     CPPUNIT_ASSERT(pFC);
     893           2 :     CPPUNIT_ASSERT_EQUAL(OUString("=B1"), pFC->GetFormula(aCFCxt));
     894             : 
     895             :     // Clear row 1 and move over to a formula group case.
     896           2 :     clearRange(m_pDoc, ScRange(0,0,0,MAXCOL,0,0));
     897             : 
     898             :     // Fill A1:B2 with numbers, and C1:C2 with formula that reference those numbers.
     899           6 :     for (SCROW i = 0; i <= 1; ++i)
     900             :     {
     901           4 :         m_pDoc->SetValue(ScAddress(0,i,0), (i+1));
     902           4 :         m_pDoc->SetValue(ScAddress(1,i,0), (i+11));
     903           4 :         m_pDoc->SetString(ScAddress(2,i,0), "=RC[-2]+RC[-1]");
     904           4 :         double fCheck = m_pDoc->GetValue(ScAddress(0,i,0));
     905           4 :         fCheck += m_pDoc->GetValue(ScAddress(1,i,0));
     906           4 :         CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i,0)));
     907             :     }
     908             : 
     909             :     // Delete column B.
     910           2 :     rFunc.DeleteCells(ScRange(1,0,0,1,MAXROW,0), &aMark, DEL_CELLSLEFT, true, true);
     911             : 
     912           6 :     for (SCROW i = 0; i <= 1; ++i)
     913             :     {
     914           4 :         ScAddress aPos(1,i,0);
     915           4 :         CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc->GetString(aPos));
     916             :     }
     917             : 
     918           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0)); // B1
     919           2 :     CPPUNIT_ASSERT(pFC);
     920           2 :     CPPUNIT_ASSERT_EQUAL(OUString("=A1+#REF!1"), pFC->GetFormula(aCFCxt));
     921           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0)); // B2
     922           2 :     CPPUNIT_ASSERT(pFC);
     923           2 :     CPPUNIT_ASSERT_EQUAL(OUString("=A2+#REF!2"), pFC->GetFormula(aCFCxt));
     924             : 
     925             :     // Undo deletion of column B and check the results of C1:C2.
     926           2 :     pUndoMgr->Undo();
     927           6 :     for (SCROW i = 0; i <= 1; ++i)
     928             :     {
     929           4 :         double fCheck = m_pDoc->GetValue(ScAddress(0,i,0));
     930           4 :         fCheck += m_pDoc->GetValue(ScAddress(1,i,0));
     931           4 :         CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i,0)));
     932             :     }
     933             : 
     934           4 :     m_pDoc->DeleteTab(0);
     935           2 : }
     936             : 
     937           2 : void Test::testSharedFormulasRefUpdateMoveSheets()
     938             : {
     939           2 :     m_pDoc->InsertTab(0, "Sheet1");
     940           2 :     m_pDoc->InsertTab(1, "Sheet2");
     941           2 :     m_pDoc->InsertTab(2, "Sheet3");
     942             : 
     943           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // make sure auto calc is on.
     944             : 
     945             :     // Switch to R1C1 for ease of repeated formula insertions.
     946           4 :     FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
     947             : 
     948             :     // Fill numbers in A1:A8 on Sheet2.
     949          18 :     for (SCROW i = 0; i <= 7; ++i)
     950          16 :         m_pDoc->SetValue(ScAddress(0,i,1), i+1);
     951             : 
     952             :     // Fill formula cells A1:A8 on Sheet1, to refer to the same cell address on Sheet2.
     953          18 :     for (SCROW i = 0; i <= 7; ++i)
     954          16 :         m_pDoc->SetString(ScAddress(0,i,0), "=Sheet2!RC");
     955             : 
     956             :     // Check the results.
     957          18 :     for (SCROW i = 0; i <= 7; ++i)
     958          16 :         CPPUNIT_ASSERT_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(ScAddress(0,i,0)));
     959             : 
     960             :     // Move Sheet3 to the leftmost position before Sheet1.
     961           2 :     m_pDoc->MoveTab(2, 0);
     962             : 
     963             :     // Check sheet names.
     964           4 :     std::vector<OUString> aTabNames = m_pDoc->GetAllTableNames();
     965           2 :     CPPUNIT_ASSERT_MESSAGE("There should be at least 3 sheets.", aTabNames.size() >= 3);
     966           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet3"), aTabNames[0]);
     967           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aTabNames[1]);
     968           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aTabNames[2]);
     969             : 
     970             :     // Check the results again on Sheet1.
     971          18 :     for (SCROW i = 0; i <= 7; ++i)
     972             :     {
     973          16 :         CPPUNIT_ASSERT_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(ScAddress(0,i,1)));
     974          16 :         if (!checkFormula(*m_pDoc, ScAddress(0,i,1), "Sheet2!RC"))
     975           0 :             CPPUNIT_FAIL("Wrong formula expression.");
     976             :     }
     977             : 
     978             :     // Insert a new sheet at the left end.
     979           2 :     m_pDoc->InsertTab(0, "Sheet4");
     980             : 
     981             :     // Check sheet names.
     982           2 :     aTabNames = m_pDoc->GetAllTableNames();
     983           2 :     CPPUNIT_ASSERT_MESSAGE("There should be at least 4 sheets.", aTabNames.size() >= 4);
     984           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet4"), aTabNames[0]);
     985           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet3"), aTabNames[1]);
     986           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aTabNames[2]);
     987           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aTabNames[3]);
     988             : 
     989             :     // Check the results again on Sheet1.
     990          18 :     for (SCROW i = 0; i <= 7; ++i)
     991             :     {
     992          16 :         CPPUNIT_ASSERT_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(ScAddress(0,i,2)));
     993          16 :         if (!checkFormula(*m_pDoc, ScAddress(0,i,2), "Sheet2!RC"))
     994           0 :             CPPUNIT_FAIL("Wrong formula expression.");
     995             :     }
     996             : 
     997             :     // Delete Sheet4.
     998           2 :     m_pDoc->DeleteTab(0);
     999             : 
    1000             :     // Check sheet names.
    1001           2 :     aTabNames = m_pDoc->GetAllTableNames();
    1002           2 :     CPPUNIT_ASSERT_MESSAGE("There should be at least 3 sheets.", aTabNames.size() >= 3);
    1003           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet3"), aTabNames[0]);
    1004           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aTabNames[1]);
    1005           2 :     CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aTabNames[2]);
    1006             : 
    1007             :     // Check the results again on Sheet1.
    1008          18 :     for (SCROW i = 0; i <= 7; ++i)
    1009             :     {
    1010          16 :         CPPUNIT_ASSERT_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(ScAddress(0,i,1)));
    1011          16 :         if (!checkFormula(*m_pDoc, ScAddress(0,i,1), "Sheet2!RC"))
    1012           0 :             CPPUNIT_FAIL("Wrong formula expression.");
    1013             :     }
    1014             : 
    1015           2 :     m_pDoc->DeleteTab(2);
    1016           2 :     m_pDoc->DeleteTab(1);
    1017           4 :     m_pDoc->DeleteTab(0);
    1018           2 : }
    1019             : 
    1020           2 : void Test::testSharedFormulasRefUpdateCopySheets()
    1021             : {
    1022           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // make sure auto calc is on.
    1023             : 
    1024           2 :     m_pDoc->InsertTab(0, "Sheet1");
    1025           2 :     m_pDoc->InsertTab(1, "Sheet2");
    1026             : 
    1027           2 :     m_pDoc->SetValue(ScAddress(0,0,1), 1.0); // A1 on Sheet2
    1028           2 :     m_pDoc->SetValue(ScAddress(0,1,1), 2.0); // A2 on Sheet2
    1029             : 
    1030             :     // Reference values on Sheet2, but use absolute sheet references.
    1031           2 :     m_pDoc->SetString(ScAddress(0,0,0), "=$Sheet2.A1");
    1032           2 :     m_pDoc->SetString(ScAddress(0,1,0), "=$Sheet2.A2");
    1033             : 
    1034           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    1035           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
    1036             : 
    1037             :     // Copy Sheet1 and insert the copied sheet before the current Sheet1 position.
    1038           2 :     m_pDoc->CopyTab(0, 0);
    1039             : 
    1040           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,0,0), "$Sheet2.A1"))
    1041           0 :         CPPUNIT_FAIL("Wrong formula");
    1042             : 
    1043           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "$Sheet2.A2"))
    1044           0 :         CPPUNIT_FAIL("Wrong formula");
    1045             : 
    1046             :     // Check the values on the copied sheet.
    1047           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    1048           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
    1049             : 
    1050             :     // Check the values on the original sheet.
    1051           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,1)));
    1052           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,1)));
    1053             : 
    1054           2 :     m_pDoc->DeleteTab(2);
    1055           2 :     m_pDoc->DeleteTab(1);
    1056           2 :     m_pDoc->DeleteTab(0);
    1057           2 : }
    1058             : 
    1059           2 : void Test::testSharedFormulasRefUpdateDeleteSheets()
    1060             : {
    1061           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // make sure auto calc is on.
    1062             : 
    1063           2 :     m_pDoc->InsertTab(0, "Sheet1");
    1064           2 :     m_pDoc->InsertTab(1, "Sheet2");
    1065             : 
    1066             :     // Set values to B2:B4 on Sheet2.
    1067           2 :     m_pDoc->SetValue(ScAddress(1,1,1), 1.0);
    1068           2 :     m_pDoc->SetValue(ScAddress(1,2,1), 2.0);
    1069           2 :     m_pDoc->SetValue(ScAddress(1,3,1), 3.0);
    1070             : 
    1071             :     // Set formulas in A1:A3 on Sheet1 that reference B2:B4 on Sheet2.
    1072           2 :     m_pDoc->SetString(ScAddress(0,0,0), "=Sheet2.B2");
    1073           2 :     m_pDoc->SetString(ScAddress(0,1,0), "=Sheet2.B3");
    1074           2 :     m_pDoc->SetString(ScAddress(0,2,0), "=Sheet2.B4");
    1075             : 
    1076             :     // Check the formula results.
    1077           2 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    1078           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
    1079           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,2,0)));
    1080             : 
    1081           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,0,0), "Sheet2.B2"))
    1082           0 :         CPPUNIT_FAIL("Wrong formula");
    1083           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "Sheet2.B3"))
    1084           0 :         CPPUNIT_FAIL("Wrong formula");
    1085           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,2,0), "Sheet2.B4"))
    1086           0 :         CPPUNIT_FAIL("Wrong formula");
    1087             : 
    1088             :     // Delete Sheet2.
    1089           2 :     ScDocFunc& rFunc = getDocShell().GetDocFunc();
    1090           2 :     rFunc.DeleteTable(1, true, true);
    1091             : 
    1092           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,0,0), "#REF!.B2"))
    1093           0 :         CPPUNIT_FAIL("Wrong formula");
    1094           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "#REF!.B3"))
    1095           0 :         CPPUNIT_FAIL("Wrong formula");
    1096           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,2,0), "#REF!.B4"))
    1097           0 :         CPPUNIT_FAIL("Wrong formula");
    1098             : 
    1099             :     // Undo the deletion and make sure the formulas are back to the way they were.
    1100           2 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
    1101           2 :     CPPUNIT_ASSERT(pUndoMgr);
    1102           2 :     pUndoMgr->Undo();
    1103             : 
    1104           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,0,0), "Sheet2.B2"))
    1105           0 :         CPPUNIT_FAIL("Wrong formula");
    1106           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "Sheet2.B3"))
    1107           0 :         CPPUNIT_FAIL("Wrong formula");
    1108           2 :     if (!checkFormula(*m_pDoc, ScAddress(0,2,0), "Sheet2.B4"))
    1109           0 :         CPPUNIT_FAIL("Wrong formula");
    1110             : 
    1111             :     // TODO: We can't test redo yet as ScUndoDeleteTab::Redo() relies on
    1112             :     // view shell to do its thing.
    1113             : 
    1114           2 :     m_pDoc->DeleteTab(1);
    1115           2 :     m_pDoc->DeleteTab(0);
    1116           2 : }
    1117             : 
    1118           2 : void Test::testSharedFormulasCopyPaste()
    1119             : {
    1120           2 :     m_pDoc->InsertTab(0, "Test");
    1121           2 :     FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
    1122             : 
    1123             :     // Fill formula cells B1:B10.
    1124          22 :     for (SCROW i = 0; i <= 9; ++i)
    1125          20 :         m_pDoc->SetString(1, i, 0, "=RC[-1]");
    1126             : 
    1127           2 :     ScAddress aPos(1, 8, 0); // B9
    1128           2 :     ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
    1129           2 :     CPPUNIT_ASSERT_MESSAGE("B9 should be a formula cell.", pFC);
    1130           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
    1131           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
    1132           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
    1133             : 
    1134             :     // Copy formulas in B6:B9 to the clipboard doc.
    1135           2 :     ScRange aSrcRange(1,5,0,1,8,0); // B6:B9
    1136           4 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    1137           2 :     copyToClip(m_pDoc, aSrcRange, &aClipDoc);
    1138           2 :     pFC = aClipDoc.GetFormulaCell(aPos);
    1139           2 :     CPPUNIT_ASSERT_MESSAGE("B9 in the clip doc should be a formula cell.", pFC);
    1140           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), pFC->GetSharedTopRow());
    1141           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(4), pFC->GetSharedLength());
    1142           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
    1143             : 
    1144             :     // Paste them to C2:C10.
    1145           2 :     ScRange aDestRange(2,1,0,2,9,0);
    1146           2 :     pasteFromClip(m_pDoc, aDestRange, &aClipDoc);
    1147           2 :     aPos.SetCol(2);
    1148           2 :     aPos.SetRow(1);
    1149           2 :     pFC = m_pDoc->GetFormulaCell(aPos);
    1150           2 :     CPPUNIT_ASSERT_MESSAGE("C2 should be a formula cell.", pFC);
    1151           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
    1152           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(9), pFC->GetSharedLength());
    1153           2 :     CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
    1154             : 
    1155           2 :     ScRange aRange(1,0,0,1,9,0); // B1:B10
    1156           2 :     ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
    1157           2 :     pUndoDoc->InitUndo(m_pDoc, 0, 0, true, true);
    1158           2 :     m_pDoc->CopyToDocument(aRange, IDF_CONTENTS, false, pUndoDoc);
    1159           4 :     boost::scoped_ptr<ScUndoPaste> pUndo(createUndoPaste(getDocShell(), aRange, pUndoDoc));
    1160             : 
    1161             :     // First, make sure the formula cells are shared in the undo document.
    1162           2 :     aPos.SetCol(1);
    1163          22 :     for (SCROW i = 0; i <= 9; ++i)
    1164             :     {
    1165          20 :         aPos.SetRow(i);
    1166          20 :         pFC = pUndoDoc->GetFormulaCell(aPos);
    1167          20 :         CPPUNIT_ASSERT_MESSAGE("Must be a formula cell.", pFC);
    1168          20 :         CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
    1169          20 :         CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
    1170          20 :         CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
    1171             :     }
    1172             : 
    1173             :     // Overwrite B1:B10.
    1174          22 :     for (SCROW i = 0; i <= 9; ++i)
    1175          20 :         m_pDoc->SetValue(ScAddress(1,i,0), i*10);
    1176             : 
    1177          22 :     for (SCROW i = 0; i <= 9; ++i)
    1178          20 :         CPPUNIT_ASSERT_MESSAGE("Numeric cell was expected.", m_pDoc->GetCellType(ScAddress(1,i,0)) == CELLTYPE_VALUE);
    1179             : 
    1180             :     // Undo the action to fill B1:B10 with formula cells again.
    1181           2 :     pUndo->Undo();
    1182             : 
    1183           2 :     aPos.SetCol(1);
    1184          22 :     for (SCROW i = 0; i <= 9; ++i)
    1185             :     {
    1186          20 :         aPos.SetRow(i);
    1187          20 :         pFC = m_pDoc->GetFormulaCell(aPos);
    1188          20 :         CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
    1189          20 :         CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
    1190          20 :         CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
    1191          20 :         CPPUNIT_ASSERT_MESSAGE("The token is expected to be shared.", pFC->GetCode() == pFC->GetSharedCode());
    1192             :     }
    1193             : 
    1194           4 :     m_pDoc->DeleteTab(0);
    1195           2 : }
    1196             : 
    1197           2 : void Test::testSharedFormulaInsertColumn()
    1198             : {
    1199           2 :     m_pDoc->InsertTab(0, "Test");
    1200             : 
    1201             :     // Set shared formula group over H2:H3.
    1202           2 :     m_pDoc->SetString(ScAddress(7,1,0), "=G3*B3");
    1203           2 :     m_pDoc->SetString(ScAddress(7,2,0), "=G4*B4");
    1204             : 
    1205             :     // Insert a single column at Column F. This used to crash before fdo#74041.
    1206           2 :     m_pDoc->InsertCol(ScRange(5,0,0,5,MAXROW,0));
    1207             : 
    1208           2 :     if (!checkFormula(*m_pDoc, ScAddress(8,1,0), "H3*B3"))
    1209           0 :         CPPUNIT_FAIL("Wrong formula!");
    1210             : 
    1211           2 :     if (!checkFormula(*m_pDoc, ScAddress(8,2,0), "H4*B4"))
    1212           0 :         CPPUNIT_FAIL("Wrong formula!");
    1213             : 
    1214           2 :     m_pDoc->DeleteTab(0);
    1215           2 : }
    1216             : 
    1217           0 : void Test::testSharedFormulaMoveBlock()
    1218             : {
    1219           0 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
    1220           0 :     FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
    1221             : 
    1222           0 :     m_pDoc->InsertTab(0, "Test");
    1223             : 
    1224             :     // Set values to A1:A3.
    1225           0 :     m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
    1226           0 :     m_pDoc->SetValue(ScAddress(0,1,0), 2.0);
    1227           0 :     m_pDoc->SetValue(ScAddress(0,2,0), 3.0);
    1228             : 
    1229             :     // Set formulas in B1:B3 to reference A1:A3.
    1230           0 :     m_pDoc->SetString(ScAddress(1,0,0), "=RC[-1]");
    1231           0 :     m_pDoc->SetString(ScAddress(1,1,0), "=RC[-1]");
    1232           0 :     m_pDoc->SetString(ScAddress(1,2,0), "=RC[-1]");
    1233             : 
    1234           0 :     ScRange aFormulaRange(1,0,0,1,2,0);
    1235             : 
    1236           0 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1237           0 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1238           0 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1239             : 
    1240           0 :     clearFormulaCellChangedFlag(*m_pDoc, aFormulaRange);
    1241             : 
    1242             :     // Move A1:A3 to D1:D3.
    1243           0 :     ScDocFunc& rFunc = getDocShell().GetDocFunc();
    1244           0 :     rFunc.MoveBlock(ScRange(0,0,0,0,2,0), ScAddress(3,0,0), true, true, false, true);
    1245             : 
    1246             :     // The result should stay the same.
    1247           0 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1248           0 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1249           0 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1250             : 
    1251           0 :     clearFormulaCellChangedFlag(*m_pDoc, aFormulaRange);
    1252             : 
    1253             :     // Make sure these formula cells in B1:B3 have correct positions even after the move.
    1254           0 :     std::vector<SCROW> aRows;
    1255           0 :     aRows.push_back(0);
    1256           0 :     aRows.push_back(1);
    1257           0 :     aRows.push_back(2);
    1258           0 :     bool bRes = checkFormulaPositions(*m_pDoc, 0, 1, &aRows[0], aRows.size());
    1259           0 :     CPPUNIT_ASSERT(bRes);
    1260             : 
    1261           0 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
    1262           0 :     CPPUNIT_ASSERT(pUndoMgr);
    1263             : 
    1264             :     // Undo and check the result.
    1265           0 :     pUndoMgr->Undo();
    1266           0 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1267           0 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1268           0 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1269             : 
    1270           0 :     clearFormulaCellChangedFlag(*m_pDoc, aFormulaRange);
    1271             : 
    1272             :     // Redo and check the result.
    1273           0 :     pUndoMgr->Redo();
    1274           0 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1275           0 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1276           0 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1277             : 
    1278             :     // Clear the range and start over.
    1279           0 :     clearRange(m_pDoc, ScRange(0,0,0,MAXCOL,MAXROW,0));
    1280             : 
    1281             :     // Set values 1,2,3,4,5 to A1:A5.
    1282           0 :     for (SCROW i = 0; i <= 4; ++i)
    1283           0 :         m_pDoc->SetValue(ScAddress(0,i,0), (i+1));
    1284             : 
    1285             :     // Set formulas to B1:B5.
    1286           0 :     for (SCROW i = 0; i <= 4; ++i)
    1287           0 :         m_pDoc->SetString(ScAddress(1,i,0), "=RC[-1]");
    1288             : 
    1289             :     // Check the initial formula results.
    1290           0 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1291           0 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1292           0 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1293           0 :     CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,3,0)));
    1294           0 :     CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
    1295             : 
    1296             :     // Move A1:A2 to D2:D3.
    1297           0 :     rFunc.MoveBlock(ScRange(0,0,0,0,1,0), ScAddress(3,1,0), true, true, false, true);
    1298             : 
    1299             :     // Check the formula values again.  They should not change.
    1300           0 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1301           0 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1302           0 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1303           0 :     CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,3,0)));
    1304           0 :     CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
    1305             : 
    1306           0 :     pUndoMgr->Undo();
    1307           0 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1308           0 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1309           0 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1310           0 :     CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,3,0)));
    1311           0 :     CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
    1312             : 
    1313           0 :     pUndoMgr->Redo();
    1314           0 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1315           0 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1316           0 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1317           0 :     CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,3,0)));
    1318           0 :     CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
    1319             : 
    1320           0 :     m_pDoc->DeleteTab(0);
    1321           0 : }
    1322             : 
    1323           2 : void Test::testSharedFormulaUpdateOnNamedRangeChange()
    1324             : {
    1325           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
    1326             : 
    1327           2 :     m_pDoc->InsertTab(0, "Test");
    1328             : 
    1329           2 :     const char* pName = "MyRange";
    1330           2 :     const char* pExpr1 = "$Test.$A$1:$A$3";
    1331           2 :     const char* pExpr2 = "$Test.$A$1:$A$4";
    1332             : 
    1333             :     RangeNameDef aName;
    1334           2 :     aName.mpName = pName;
    1335           2 :     aName.mpExpr = pExpr1;
    1336           2 :     aName.mnIndex = 1;
    1337           2 :     ScRangeName* pNames = new ScRangeName;
    1338           2 :     bool bSuccess = insertRangeNames(m_pDoc, pNames, &aName, &aName + 1);
    1339           2 :     CPPUNIT_ASSERT(bSuccess);
    1340           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pNames->size());
    1341           2 :     m_pDoc->SetRangeName(pNames);
    1342             : 
    1343             :     // Set values to A1:A4.
    1344           2 :     m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
    1345           2 :     m_pDoc->SetValue(ScAddress(0,1,0), 2.0);
    1346           2 :     m_pDoc->SetValue(ScAddress(0,2,0), 3.0);
    1347           2 :     m_pDoc->SetValue(ScAddress(0,3,0), 4.0);
    1348             : 
    1349             :     // Set formula to B1:B3.
    1350           2 :     m_pDoc->SetString(ScAddress(1,0,0), "=SUM(MyRange)");
    1351           2 :     m_pDoc->SetString(ScAddress(1,1,0), "=SUM(MyRange)");
    1352           2 :     m_pDoc->SetString(ScAddress(1,2,0), "=SUM(MyRange)");
    1353             : 
    1354             :     // Set single formula with no named range to B5.
    1355           2 :     m_pDoc->SetString(ScAddress(1,4,0), "=ROW()");
    1356             : 
    1357             :     // Set shared formula with no named range to B7:B8.
    1358           2 :     m_pDoc->SetString(ScAddress(1,6,0), "=ROW()");
    1359           2 :     m_pDoc->SetString(ScAddress(1,7,0), "=ROW()");
    1360             : 
    1361             :     // B1:B3 should be grouped.
    1362           2 :     ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
    1363           2 :     CPPUNIT_ASSERT(pFC);
    1364           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
    1365           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
    1366             : 
    1367             :     // B7:B8 should be grouped.
    1368           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,6,0));
    1369           2 :     CPPUNIT_ASSERT(pFC);
    1370           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), pFC->GetSharedTopRow());
    1371           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
    1372             : 
    1373           2 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1374           2 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1375           2 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1376             : 
    1377           2 :     CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
    1378           2 :     CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(1,6,0)));
    1379           2 :     CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(1,7,0)));
    1380             : 
    1381             :     // Set a single formula to C1.
    1382           2 :     m_pDoc->SetString(ScAddress(2,0,0), "=AVERAGE(MyRange)");
    1383           2 :     pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
    1384           2 :     CPPUNIT_ASSERT(pFC);
    1385           2 :     CPPUNIT_ASSERT_MESSAGE("C1 should not be shared.", !pFC->IsShared());
    1386           2 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
    1387             : 
    1388             :     // Update the range of MyRange.
    1389           2 :     pNames = new ScRangeName;
    1390           2 :     aName.mpExpr = pExpr2;
    1391           2 :     bSuccess = insertRangeNames(m_pDoc, pNames, &aName, &aName + 1);
    1392           2 :     CPPUNIT_ASSERT(bSuccess);
    1393           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pNames->size());
    1394           2 :     ScDocFunc& rFunc = getDocShell().GetDocFunc();
    1395             : 
    1396             :     typedef boost::ptr_map<OUString, ScRangeName> NameMapType;
    1397           4 :     NameMapType aNewNames;
    1398           4 :     OUString aScope(STR_GLOBAL_RANGE_NAME);
    1399           2 :     aNewNames.insert(aScope, pNames);
    1400           2 :     rFunc.ModifyAllRangeNames(aNewNames);
    1401             : 
    1402             :     // Check to make sure all displayed formulas are still good.
    1403           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "SUM(MyRange)"))
    1404           0 :         CPPUNIT_FAIL("Wrong formula!");
    1405           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "SUM(MyRange)"))
    1406           0 :         CPPUNIT_FAIL("Wrong formula!");
    1407           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "SUM(MyRange)"))
    1408           0 :         CPPUNIT_FAIL("Wrong formula!");
    1409           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,4,0), "ROW()"))
    1410           0 :         CPPUNIT_FAIL("Wrong formula!");
    1411           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,6,0), "ROW()"))
    1412           0 :         CPPUNIT_FAIL("Wrong formula!");
    1413           2 :     if (!checkFormula(*m_pDoc, ScAddress(1,7,0), "ROW()"))
    1414           0 :         CPPUNIT_FAIL("Wrong formula!");
    1415           2 :     if (!checkFormula(*m_pDoc, ScAddress(2,0,0), "AVERAGE(MyRange)"))
    1416           0 :         CPPUNIT_FAIL("Wrong formula!");
    1417             : 
    1418             :     // Check the calculation results as well.
    1419           2 :     CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1420           2 :     CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1421           2 :     CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1422           2 :     CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(1,4,0)));
    1423           2 :     CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(1,6,0)));
    1424           2 :     CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(1,7,0)));
    1425           2 :     CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc->GetValue(ScAddress(2,0,0)));
    1426             : 
    1427             :     // Change the value of A4 and make sure the value change gets propagated.
    1428           2 :     m_pDoc->SetValue(ScAddress(0,3,0), 0.0);
    1429           2 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1430           2 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    1431           2 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,2,0)));
    1432             : 
    1433           4 :     m_pDoc->DeleteTab(0);
    1434           2 : }
    1435             : 
    1436           2 : void Test::testSharedFormulaUpdateOnDBChange()
    1437             : {
    1438           2 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
    1439             : 
    1440           2 :     m_pDoc->InsertTab(0, "RangeTest");
    1441             : 
    1442             :     // Put 1, 2, 3, 4 in A1:A4.
    1443          10 :     for (SCROW i = 0; i <= 3; ++i)
    1444           8 :         m_pDoc->SetValue(ScAddress(0,i,0), (i+1));
    1445             : 
    1446           2 :     ScDBCollection* pDBs = m_pDoc->GetDBCollection();
    1447           2 :     CPPUNIT_ASSERT_MESSAGE("Failed to fetch DB collection object.", pDBs);
    1448             : 
    1449             :     // Define database range 'MyRange' for A1:A2.
    1450           2 :     ScDBData* pData = new ScDBData("MyRange", 0, 0, 0, 0, 1);
    1451           2 :     bool bInserted = pDBs->getNamedDBs().insert(pData);
    1452           2 :     if (!bInserted)
    1453           0 :         delete pData;
    1454           2 :     CPPUNIT_ASSERT_MESSAGE("Failed to insert a new database range.", bInserted);
    1455             : 
    1456             :     // Insert in C2:C4 a group of formula cells that reference MyRange.
    1457           8 :     for (SCROW i = 1; i <= 3; ++i)
    1458           6 :         m_pDoc->SetString(ScAddress(2,i,0), "=SUM(MyRange)");
    1459             : 
    1460             :     // Make sure C2:C4 is a formula group.
    1461           2 :     const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(2,1,0));
    1462           2 :     CPPUNIT_ASSERT(pFC);
    1463           2 :     CPPUNIT_ASSERT(pFC->IsSharedTop());
    1464           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
    1465             : 
    1466             :     // Check the initial formula results.
    1467           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,1,0)));
    1468           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,2,0)));
    1469           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,3,0)));
    1470             : 
    1471           4 :     ScDBDocFunc aFunc(getDocShell());
    1472             : 
    1473             :     // Change the range referenced by MyRange to A1:A4.
    1474           4 :     ScDBCollection aNewDBs(m_pDoc);
    1475           2 :     ScDBData* pNewData = new ScDBData("MyRange", 0, 0, 0, 0, 3);
    1476           2 :     bInserted = aNewDBs.getNamedDBs().insert(pNewData);
    1477           2 :     if (!bInserted)
    1478           0 :         delete pNewData;
    1479           2 :     CPPUNIT_ASSERT_MESSAGE("Failed to insert a new database range.", bInserted);
    1480             : 
    1481           4 :     std::vector<ScRange> aDeleted;
    1482           2 :     aFunc.ModifyAllDBData(aNewDBs, aDeleted);
    1483             : 
    1484             :     // Check the updated formula results.
    1485           2 :     CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,1,0)));
    1486           2 :     CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,2,0)));
    1487           2 :     CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,3,0)));
    1488             : 
    1489           2 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
    1490           2 :     CPPUNIT_ASSERT(pUndoMgr);
    1491             : 
    1492             :     // Undo and check the results.
    1493           2 :     pUndoMgr->Undo();
    1494           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,1,0)));
    1495           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,2,0)));
    1496           2 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,3,0)));
    1497             : 
    1498             :     // Redo and check the results.
    1499           2 :     pUndoMgr->Redo();
    1500           2 :     CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,1,0)));
    1501           2 :     CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,2,0)));
    1502           2 :     CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,3,0)));
    1503             : 
    1504           4 :     m_pDoc->DeleteTab(0);
    1505           8 : }
    1506             : 
    1507             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10