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

Generated by: LCOV version 1.10