LCOV - code coverage report
Current view: top level - sc/qa/unit - ucalc.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 2926 3178 92.1 %
Date: 2014-04-11 Functions: 111 117 94.9 %
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             : 
      12             : #include <sal/config.h>
      13             : #include <test/bootstrapfixture.hxx>
      14             : 
      15             : #include <rtl/strbuf.hxx>
      16             : #include <osl/file.hxx>
      17             : #include <osl/time.h>
      18             : 
      19             : #include "scdll.hxx"
      20             : #include "formulacell.hxx"
      21             : #include "stringutil.hxx"
      22             : #include "scmatrix.hxx"
      23             : #include "drwlayer.hxx"
      24             : #include "scitems.hxx"
      25             : #include "reffind.hxx"
      26             : #include "markdata.hxx"
      27             : #include "clipparam.hxx"
      28             : #include "refundo.hxx"
      29             : #include "undoblk.hxx"
      30             : #include "undotab.hxx"
      31             : #include "queryentry.hxx"
      32             : #include "postit.hxx"
      33             : #include "attrib.hxx"
      34             : #include "dbdata.hxx"
      35             : #include "reftokenhelper.hxx"
      36             : #include "userdat.hxx"
      37             : 
      38             : #include "docsh.hxx"
      39             : #include "docfunc.hxx"
      40             : #include "dbdocfun.hxx"
      41             : #include "funcdesc.hxx"
      42             : #include "externalrefmgr.hxx"
      43             : 
      44             : #include "calcconfig.hxx"
      45             : #include "interpre.hxx"
      46             : #include "columniterator.hxx"
      47             : #include "types.hxx"
      48             : #include "conditio.hxx"
      49             : #include "globstr.hrc"
      50             : #include "tokenarray.hxx"
      51             : #include "scopetools.hxx"
      52             : #include "dociter.hxx"
      53             : #include "queryparam.hxx"
      54             : #include "edittextiterator.hxx"
      55             : #include "editutil.hxx"
      56             : #include <asciiopt.hxx>
      57             : #include <impex.hxx>
      58             : #include <columnspanset.hxx>
      59             : #include <docoptio.hxx>
      60             : #include <patattr.hxx>
      61             : #include <docpool.hxx>
      62             : 
      63             : #include "formula/IFunctionDescription.hxx"
      64             : 
      65             : #include <basegfx/polygon/b2dpolygon.hxx>
      66             : #include <editeng/boxitem.hxx>
      67             : #include <editeng/brushitem.hxx>
      68             : #include "editeng/wghtitem.hxx"
      69             : #include "editeng/postitem.hxx"
      70             : 
      71             : #include <svx/svdograf.hxx>
      72             : #include <svx/svdpage.hxx>
      73             : #include <svx/svdocirc.hxx>
      74             : #include <svx/svdopath.hxx>
      75             : #include <svx/svdocapt.hxx>
      76             : #include "svl/srchitem.hxx"
      77             : #include "svl/sharedstringpool.hxx"
      78             : 
      79             : #include <sfx2/docfile.hxx>
      80             : 
      81             : #include <iostream>
      82             : #include <sstream>
      83             : #include <vector>
      84             : 
      85             : #include <com/sun/star/i18n/TransliterationModules.hpp>
      86             : 
      87         282 : struct TestImpl
      88             : {
      89             :     ScDocShellRef m_xDocShell;
      90             : };
      91             : 
      92           8 : FormulaGrammarSwitch::FormulaGrammarSwitch(ScDocument* pDoc, formula::FormulaGrammar::Grammar eGrammar) :
      93           8 :     mpDoc(pDoc), meOldGrammar(pDoc->GetGrammar())
      94             : {
      95           8 :     mpDoc->SetGrammar(eGrammar);
      96           8 : }
      97             : 
      98           8 : FormulaGrammarSwitch::~FormulaGrammarSwitch()
      99             : {
     100           8 :     mpDoc->SetGrammar(meOldGrammar);
     101           8 : }
     102             : 
     103             : class MeasureTimeSwitch
     104             : {
     105             :     double& mrDiff;
     106             :     TimeValue maTimeBefore;
     107             : public:
     108           0 :     MeasureTimeSwitch(double& rDiff) : mrDiff(rDiff)
     109             :     {
     110           0 :         mrDiff = 9999.0;
     111           0 :         osl_getSystemTime(&maTimeBefore);
     112           0 :     }
     113             : 
     114           0 :     ~MeasureTimeSwitch()
     115             :     {
     116             :         TimeValue aTimeAfter;
     117           0 :         osl_getSystemTime(&aTimeAfter);
     118           0 :         mrDiff = getTimeDiff(aTimeAfter, maTimeBefore);
     119           0 :     }
     120             : 
     121           0 :     double getTimeDiff(const TimeValue& t1, const TimeValue& t2) const
     122             :     {
     123           0 :         double tv1 = t1.Seconds;
     124           0 :         double tv2 = t2.Seconds;
     125           0 :         tv1 += t1.Nanosec / 1000000000.0;
     126           0 :         tv2 += t2.Nanosec / 1000000000.0;
     127             : 
     128           0 :         return tv1 - tv2;
     129             :     }
     130             : };
     131             : 
     132         141 : Test::Test() :
     133         141 :     m_pImpl(new TestImpl),
     134         282 :     m_pDoc(0)
     135             : {
     136         141 : }
     137             : 
     138         423 : Test::~Test()
     139             : {
     140         141 :     delete m_pImpl;
     141         282 : }
     142             : 
     143          37 : ScDocShell& Test::getDocShell()
     144             : {
     145          37 :     return *m_pImpl->m_xDocShell;
     146             : }
     147             : 
     148         141 : void Test::setUp()
     149             : {
     150         141 :     BootstrapFixture::setUp();
     151             : 
     152         141 :     ScDLL::Init();
     153         423 :     m_pImpl->m_xDocShell = new ScDocShell(
     154             :         SFXMODEL_STANDARD |
     155             :         SFXMODEL_DISABLE_EMBEDDED_SCRIPTS |
     156         282 :         SFXMODEL_DISABLE_DOCUMENT_RECOVERY);
     157             : 
     158         141 :     m_pImpl->m_xDocShell->DoInitUnitTest();
     159         141 :     m_pDoc = m_pImpl->m_xDocShell->GetDocument();
     160         141 : }
     161             : 
     162         141 : void Test::tearDown()
     163             : {
     164         141 :     m_pImpl->m_xDocShell.Clear();
     165         141 :     BootstrapFixture::tearDown();
     166         141 : }
     167             : 
     168             : #define PERF_ASSERT(df,scale,time,message) \
     169             :     do { \
     170             :         double dfscaled = df / scale; \
     171             :         if ((dfscaled) >= (time)) \
     172             :         { \
     173             :             std::ostringstream os; \
     174             :             os << message << " took " << dfscaled << " pseudo-cycles (" << df << " real-time seconds), expected: " << time << " pseudo-cycles."; \
     175             :             CPPUNIT_FAIL(os.str().c_str()); \
     176             :         } \
     177             :     } while (false)
     178             : 
     179           0 : void Test::testPerf()
     180             : {
     181           0 :     CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "foo"));
     182             : 
     183             :     // First do a set of simple operations to try to work out
     184             :     // how fast (or not) this particular machine is:
     185             :     double scale;
     186             :     {
     187           0 :         MeasureTimeSwitch aTime(scale);
     188           0 :         for (int i = 0; i < 10000000; ++i)
     189             :         {
     190             :             // Bang on the allocator
     191           0 :             volatile ScRange *pRange = new ScRange (ScAddress (0,0,0));
     192             :             // Calc does quite a bit of string conversion
     193           0 :             volatile double it = OUString::number ((double)i/253.0).toDouble();
     194             :             // Do we have floating point math ?
     195           0 :             volatile double another = rtl::math::sin (it);
     196           0 :             (void)another;
     197           0 :             delete pRange;
     198           0 :         }
     199             :     }
     200           0 :     printf("CPU scale factor %g\n", scale);
     201             : 
     202             :     // FIXME: we should check if this already took too long
     203             :     // and if so not run the perf. tests to have pity on some
     204             :     // slow ARM machines - I think.
     205             : 
     206             :     // to make the numbers more round and helpful,
     207             :     // but the calculation of scale reasonably precise.
     208           0 :     scale /= 100000.0;
     209             : 
     210             :     double diff;
     211             : 
     212             :     // Clearing an already empty sheet should finish in a fraction of a
     213             :     // second.  Flag failure if it takes more than one second.  Clearing 100
     214             :     // columns should be large enough to flag if something goes wrong.
     215             :     {
     216           0 :         MeasureTimeSwitch aTime(diff);
     217           0 :         clearRange(m_pDoc, ScRange(0,0,0,99,MAXROW,0));
     218             :     }
     219           0 :     PERF_ASSERT(diff, scale, 1.0, "Clearing an empty sheet");
     220             : 
     221             :     {
     222             :         // Switch to R1C1 to make it easier to input relative references in multiple cells.
     223           0 :         FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
     224             : 
     225             :         // Insert formulas in B1:B100000. This shouldn't take long, but may take
     226             :         // close to a second on a slower machine. We don't measure this yet, for
     227             :         // now.
     228           0 :         for (SCROW i = 0; i < 100000; ++i)
     229           0 :             m_pDoc->SetString(ScAddress(1,i,0), "=RC[-1]");
     230             : 
     231             :         // Now, Delete B2:B100000. This should complete in a fraction of a second
     232             :         // (0.06 sec on my machine).
     233             :         {
     234           0 :             MeasureTimeSwitch aTime(diff);
     235           0 :             clearRange(m_pDoc, ScRange(1,1,0,1,99999,0));
     236             :         }
     237           0 :         PERF_ASSERT(diff, scale, 2000, "Removal of a large array of formula cells");
     238             :     }
     239             : 
     240           0 :     clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
     241           0 :     CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
     242           0 :     CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
     243             : 
     244             :     {
     245             :         // Measure the performance of repeat-pasting a single cell to a large
     246             :         // cell range, undoing it, and redoing it.
     247             : 
     248           0 :         ScAddress aPos(0,0,0);
     249           0 :         m_pDoc->SetString(aPos, "test");
     250           0 :         ScMarkData aMark;
     251           0 :         aMark.SelectOneTable(0);
     252             : 
     253             :         // Copy cell A1 to clipboard.
     254           0 :         ScDocument aClipDoc(SCDOCMODE_CLIP);
     255           0 :         ScClipParam aParam(aPos, false);
     256           0 :         m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
     257           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
     258             : 
     259           0 :         ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
     260           0 :         pUndoDoc->InitUndo(m_pDoc, 0, 0);
     261           0 :         m_pDoc->CopyToDocument(ScRange(aPos), IDF_CONTENTS, false, pUndoDoc, &aMark);
     262             : 
     263             :         // Paste it to A2:A100000, and measure its duration.
     264           0 :         ScRange aPasteRange(0,1,0,0,99999,0);
     265           0 :         aMark.SetMarkArea(aPasteRange);
     266             : 
     267             :         {
     268           0 :             MeasureTimeSwitch aTime(diff);
     269           0 :             m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
     270             :         }
     271           0 :         PERF_ASSERT(diff, scale, 1500.0, "Pasting a single cell to A2:A100000");
     272             : 
     273           0 :         ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
     274           0 :         pRedoDoc->InitUndo(m_pDoc, 0, 0);
     275           0 :         m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
     276             : 
     277             :         // Create an undo object for this.
     278           0 :         ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
     279           0 :         ScUndoPaste aUndo(&getDocShell(), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
     280             : 
     281             :         // Make sure it did what it's supposed to do.
     282           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
     283           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
     284             : 
     285             :         {
     286           0 :             MeasureTimeSwitch aTime(diff);
     287           0 :             aUndo.Undo();
     288             :         }
     289           0 :         PERF_ASSERT(diff, scale, 500.0, "Undoing a pasting of a cell to A2:A100000");
     290             : 
     291             :         // Make sure it's really undone.
     292           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, m_pDoc->GetCellType(aPos));
     293           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
     294           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
     295             : 
     296             :         // Now redo.
     297             :         {
     298           0 :             MeasureTimeSwitch aTime(diff);
     299           0 :             aUndo.Redo();
     300             :         }
     301           0 :         PERF_ASSERT(diff, scale, 1000.0, "Redoing a pasting of a cell to A2:A100000");
     302             : 
     303             :         // Make sure it's really redone.
     304           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
     305           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
     306             :     }
     307             : 
     308           0 :     clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
     309           0 :     CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
     310           0 :     CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
     311             : 
     312             :     {
     313             :         // Measure the performance of repeat-pasting 2 adjacent cells to a
     314             :         // large cell range, undoing it, and redoing it.  The bottom one of
     315             :         // the two source cells is empty.
     316             : 
     317           0 :         ScRange aSrcRange(0,0,0,0,1,0); // A1:A2
     318             : 
     319           0 :         ScAddress aPos(0,0,0);
     320           0 :         m_pDoc->SetValue(aPos, 12);
     321           0 :         ScMarkData aMark;
     322           0 :         aMark.SetMarkArea(aSrcRange);
     323             : 
     324             :         // Copy to clipboard.
     325           0 :         ScDocument aClipDoc(SCDOCMODE_CLIP);
     326           0 :         ScClipParam aParam(aSrcRange, false);
     327           0 :         m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
     328           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
     329             : 
     330           0 :         ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
     331           0 :         pUndoDoc->InitUndo(m_pDoc, 0, 0);
     332           0 :         m_pDoc->CopyToDocument(aSrcRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
     333             : 
     334             :         // Paste it to A3:A100001, and measure its duration.
     335           0 :         ScRange aPasteRange(0,2,0,0,100000,0);
     336           0 :         aMark.SetMarkArea(aPasteRange);
     337             : 
     338             :         {
     339           0 :             MeasureTimeSwitch aTime(diff);
     340           0 :             m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
     341             :         }
     342           0 :         PERF_ASSERT(diff, scale, 1000.0, "Pasting A1:A2 to A3:A100001");
     343             : 
     344           0 :         ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
     345           0 :         pRedoDoc->InitUndo(m_pDoc, 0, 0);
     346           0 :         m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
     347             : 
     348             :         // Create an undo object for this.
     349           0 :         ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
     350           0 :         ScUndoPaste aUndo(&getDocShell(), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
     351             : 
     352             :         // Make sure it did what it's supposed to do.
     353           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
     354           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
     355           0 :         ScAddress aTmp = aPasteRange.aStart;
     356           0 :         aTmp.IncRow();
     357           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aTmp));
     358             : 
     359             :         {
     360           0 :             MeasureTimeSwitch aTime(diff);
     361           0 :             aUndo.Undo();
     362             :         }
     363           0 :         PERF_ASSERT(diff, scale, 500.0, "Undoing");
     364             : 
     365             :         // Make sure it's really undone.
     366           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE, m_pDoc->GetCellType(aPos));
     367           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
     368           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
     369             : 
     370             :         // Now redo.
     371             :         {
     372           0 :             MeasureTimeSwitch aTime(diff);
     373           0 :             aUndo.Redo();
     374             :         }
     375           0 :         PERF_ASSERT(diff, scale, 800.0, "Redoing");
     376             : 
     377             :         // Make sure it's really redone.
     378           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
     379           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
     380             :     }
     381             : 
     382           0 :     clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
     383           0 :     CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
     384           0 :     CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
     385             : 
     386             :     {
     387             :         // Measure the performance of repeat-pasting 2 adjacent cells to a
     388             :         // large cell range, undoing it, and redoing it.  The bottom one of
     389             :         // the two source cells is empty.  In this scenario, the non-empty
     390             :         // cell is a formula cell referencing a cell to the right, which
     391             :         // inserts a broadcaster to cell it references. So it has a higher
     392             :         // overhead than the previous scenario.
     393             : 
     394           0 :         ScRange aSrcRange(0,0,0,0,1,0); // A1:A2
     395             : 
     396           0 :         ScAddress aPos(0,0,0);
     397           0 :         m_pDoc->SetString(aPos, "=B1");
     398           0 :         ScMarkData aMark;
     399           0 :         aMark.SetMarkArea(aSrcRange);
     400             : 
     401             :         // Copy to clipboard.
     402           0 :         ScDocument aClipDoc(SCDOCMODE_CLIP);
     403           0 :         ScClipParam aParam(aSrcRange, false);
     404           0 :         m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
     405           0 :         CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
     406             : 
     407           0 :         ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
     408           0 :         pUndoDoc->InitUndo(m_pDoc, 0, 0);
     409           0 :         m_pDoc->CopyToDocument(aSrcRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
     410             : 
     411             :         // Paste it to A3:A50001, and measure its duration.
     412           0 :         ScRange aPasteRange(0,2,0,0,50000,0);
     413           0 :         aMark.SetMarkArea(aPasteRange);
     414             : 
     415             :         {
     416           0 :             MeasureTimeSwitch aTime(diff);
     417           0 :             m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
     418             :         }
     419           0 :         PERF_ASSERT(diff, scale, 2000.0, "Pasting");
     420             : 
     421           0 :         ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
     422           0 :         pRedoDoc->InitUndo(m_pDoc, 0, 0);
     423           0 :         m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
     424             : 
     425             :         // Create an undo object for this.
     426           0 :         ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
     427           0 :         ScUndoPaste aUndo(&getDocShell(), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
     428             : 
     429             :         // Make sure it did what it's supposed to do.
     430           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aStart));
     431           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aEnd));
     432           0 :         ScAddress aTmp = aPasteRange.aStart;
     433           0 :         aTmp.IncRow();
     434           0 :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aTmp));
     435             : 
     436             : #if 0 // TODO: Undo and redo of this scenario is currently not fast enough to be tested reliably.
     437             :         {
     438             :             MeasureTimeSwitch aTime(diff);
     439             :             aUndo.Undo();
     440             :         }
     441             :         PERF_ASSERT(diff, scale, 1.0, "Undoing");
     442             : 
     443             :         // Make sure it's really undone.
     444             :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPos));
     445             :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
     446             :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
     447             : 
     448             :         // Now redo.
     449             :         {
     450             :             MeasureTimeSwitch aTime(diff);
     451             :             aUndo.Redo();
     452             :         }
     453             :         PERF_ASSERT(diff, scale, 1.0, "Redoing");
     454             : 
     455             :         // Make sure it's really redone.
     456             :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aStart));
     457             :         CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aEnd));
     458             : #endif
     459             :     }
     460             : 
     461           0 :     m_pDoc->DeleteTab(0);
     462           0 : }
     463             : 
     464           1 : void Test::testCollator()
     465             : {
     466           1 :     CollatorWrapper* p = ScGlobal::GetCollator();
     467           1 :     sal_Int32 nRes = p->compareString("A", "B");
     468           1 :     CPPUNIT_ASSERT_MESSAGE("these strings are supposed to be different!", nRes != 0);
     469           1 : }
     470             : 
     471           1 : void Test::testSharedStringPool()
     472             : {
     473           1 :     m_pDoc->InsertTab(0, "foo");
     474             : 
     475             :     // Strings that are identical.
     476           1 :     m_pDoc->SetString(ScAddress(0,0,0), "Andy");  // A1
     477           1 :     m_pDoc->SetString(ScAddress(0,1,0), "Andy");  // A2
     478           1 :     m_pDoc->SetString(ScAddress(0,2,0), "Bruce"); // A3
     479           1 :     m_pDoc->SetString(ScAddress(0,3,0), "andy");  // A4
     480           1 :     m_pDoc->SetString(ScAddress(0,4,0), "BRUCE"); // A5
     481             : 
     482             :     {
     483             :         // These two shared string objects must go out of scope before the purge test.
     484           1 :         svl::SharedString aSS1 = m_pDoc->GetSharedString(ScAddress(0,0,0));
     485           2 :         svl::SharedString aSS2 = m_pDoc->GetSharedString(ScAddress(0,1,0));
     486           1 :         CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS1.isValid());
     487           1 :         CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS2.isValid());
     488           1 :         CPPUNIT_ASSERT_EQUAL(aSS1.getData(), aSS2.getData());
     489             : 
     490           1 :         aSS2 = m_pDoc->GetSharedString(ScAddress(0,2,0));
     491           1 :         CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
     492             : 
     493           1 :         aSS2 = m_pDoc->GetSharedString(ScAddress(0,3,0));
     494           1 :         CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
     495             : 
     496           1 :         aSS2 = m_pDoc->GetSharedString(ScAddress(0,4,0));
     497           1 :         CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
     498             : 
     499             :         // A3 and A5 should differ but should be equal case-insensitively.
     500           1 :         aSS1 = m_pDoc->GetSharedString(ScAddress(0,2,0));
     501           1 :         aSS2 = m_pDoc->GetSharedString(ScAddress(0,4,0));
     502           1 :         CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
     503           1 :         CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", aSS1.getDataIgnoreCase() == aSS2.getDataIgnoreCase());
     504             : 
     505             :         // A2 and A4 should be equal when ignoring cases.
     506           1 :         aSS1 = m_pDoc->GetSharedString(ScAddress(0,1,0));
     507           1 :         aSS2 = m_pDoc->GetSharedString(ScAddress(0,3,0));
     508           2 :         CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", aSS1.getDataIgnoreCase() == aSS2.getDataIgnoreCase());
     509             :     }
     510             : 
     511             :     // Check the string counts after purging. Purging shouldn't remove any strings in this case.
     512           1 :     svl::SharedStringPool& rPool = m_pDoc->GetSharedStringPool();
     513           1 :     rPool.purge();
     514           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
     515           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
     516             : 
     517             :     // Clear A1 and purge again.
     518           1 :     clearRange(m_pDoc, ScAddress(0,0,0));
     519           1 :     rPool.purge();
     520           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
     521           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
     522             : 
     523             :     // Clear A2 and purge again.
     524           1 :     clearRange(m_pDoc, ScAddress(0,1,0));
     525           1 :     rPool.purge();
     526           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), rPool.getCount());
     527           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
     528             : 
     529             :     // Clear A3 and purge again.
     530           1 :     clearRange(m_pDoc, ScAddress(0,2,0));
     531           1 :     rPool.purge();
     532           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCount());
     533           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
     534             : 
     535             :     // Clear A4 and purge again.
     536           1 :     clearRange(m_pDoc, ScAddress(0,3,0));
     537           1 :     rPool.purge();
     538           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCount());
     539           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCountIgnoreCase());
     540             : 
     541             :     // Clear A5 and the pool should be completely empty.
     542           1 :     clearRange(m_pDoc, ScAddress(0,4,0));
     543           1 :     rPool.purge();
     544           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCount());
     545           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCountIgnoreCase());
     546             : 
     547             :     // Now, compare string and edit text cells.
     548           1 :     m_pDoc->SetString(ScAddress(0,0,0), "Andy and Bruce"); // A1
     549           1 :     ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
     550           1 :     rEE.SetText("Andy and Bruce");
     551             : 
     552           1 :     ESelection aSel;
     553           1 :     aSel.nStartPara = aSel.nEndPara = 0;
     554             : 
     555             :     {
     556             :         // Set 'Andy' bold.
     557           1 :         SfxItemSet aItemSet = rEE.GetEmptyItemSet();
     558           1 :         aSel.nStartPos = 0;
     559           1 :         aSel.nEndPos = 4;
     560           2 :         SvxWeightItem aWeight(WEIGHT_BOLD, EE_CHAR_WEIGHT);
     561           1 :         aItemSet.Put(aWeight);
     562           2 :         rEE.QuickSetAttribs(aItemSet, aSel);
     563             :     }
     564             : 
     565             :     {
     566             :         // Set 'Bruce' italic.
     567           1 :         SfxItemSet aItemSet = rEE.GetEmptyItemSet();
     568           2 :         SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);
     569           1 :         aItemSet.Put(aItalic);
     570           1 :         aSel.nStartPos = 9;
     571           1 :         aSel.nEndPos = 14;
     572           2 :         rEE.QuickSetAttribs(aItemSet, aSel);
     573             :     }
     574             : 
     575           1 :     m_pDoc->SetEditText(ScAddress(1,0,0), rEE.CreateTextObject()); // B1
     576             : 
     577             :     // These two should be equal.
     578           1 :     svl::SharedString aSS1 = m_pDoc->GetSharedString(ScAddress(0,0,0));
     579           2 :     svl::SharedString aSS2 = m_pDoc->GetSharedString(ScAddress(1,0,0));
     580           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1.isValid());
     581           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2.isValid());
     582           1 :     CPPUNIT_ASSERT_EQUAL(aSS1.getData(), aSS2.getData());
     583             : 
     584           1 :     rEE.SetText("ANDY and BRUCE");
     585           1 :     m_pDoc->SetEditText(ScAddress(2,0,0), rEE.CreateTextObject()); // C1
     586           1 :     aSS2 = m_pDoc->GetSharedString(ScAddress(2,0,0));
     587           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2.isValid());
     588           1 :     CPPUNIT_ASSERT_MESSAGE("These two should be different when cases are considered.", aSS1.getData() != aSS2.getData());
     589             : 
     590             :     // But they should be considered equal when cases are ignored.
     591           1 :     aSS1 = m_pDoc->GetSharedString(ScAddress(0,0,0));
     592           1 :     aSS2 = m_pDoc->GetSharedString(ScAddress(2,0,0));
     593           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1.isValid());
     594           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2.isValid());
     595           1 :     CPPUNIT_ASSERT_EQUAL(aSS1.getDataIgnoreCase(), aSS2.getDataIgnoreCase());
     596             : 
     597           2 :     m_pDoc->DeleteTab(0);
     598           1 : }
     599             : 
     600           1 : void Test::testSharedStringPoolUndoDoc()
     601             : {
     602           1 :     m_pDoc->InsertTab(0, "Test");
     603             : 
     604           1 :     m_pDoc->SetString(ScAddress(0,0,0), "Header");
     605           1 :     m_pDoc->SetString(ScAddress(0,1,0), "A1");
     606           1 :     m_pDoc->SetString(ScAddress(0,2,0), "A2");
     607           1 :     m_pDoc->SetString(ScAddress(0,3,0), "A3");
     608             : 
     609           1 :     ScDocument aUndoDoc(SCDOCMODE_UNDO);
     610           1 :     aUndoDoc.InitUndo(m_pDoc, 0, 0);
     611             : 
     612             :     // Copy A1:A4 to the undo document.
     613           6 :     for (SCROW i = 0; i <= 4; ++i)
     614             :     {
     615           5 :         ScAddress aPos(0,i,0);
     616           5 :         aUndoDoc.SetString(aPos, m_pDoc->GetString(aPos));
     617             :     }
     618             : 
     619             :     // String values in A1:A4 should have identical hash.
     620           6 :     for (SCROW i = 0; i <= 4; ++i)
     621             :     {
     622           5 :         ScAddress aPos(0,i,0);
     623           5 :         svl::SharedString aSS1 = m_pDoc->GetSharedString(aPos);
     624          10 :         svl::SharedString aSS2 = aUndoDoc.GetSharedString(aPos);
     625           5 :         CPPUNIT_ASSERT_MESSAGE("String hash values are not equal.", aSS1.getDataIgnoreCase() == aSS2.getDataIgnoreCase());
     626           5 :     }
     627             : 
     628           1 :     m_pDoc->DeleteTab(0);
     629           1 : }
     630             : 
     631           1 : void Test::testRangeList()
     632             : {
     633           1 :     m_pDoc->InsertTab(0, "foo");
     634             : 
     635           1 :     ScRangeList aRL;
     636           1 :     aRL.Append(ScRange(1,1,0,3,10,0));
     637           1 :     CPPUNIT_ASSERT_MESSAGE("List should have one range.", aRL.size() == 1);
     638           1 :     const ScRange* p = aRL[0];
     639           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get the range object.", p);
     640           1 :     CPPUNIT_ASSERT_MESSAGE("Wrong range.", p->aStart == ScAddress(1,1,0) && p->aEnd == ScAddress(3,10,0));
     641             : 
     642             :     // TODO: Add more tests here.
     643             : 
     644           1 :     m_pDoc->DeleteTab(0);
     645           1 : }
     646             : 
     647           1 : void Test::testMarkData()
     648             : {
     649           1 :     ScMarkData aMarkData;
     650             : 
     651             :     // Empty mark. Nothing is selected.
     652           2 :     std::vector<sc::ColRowSpan> aSpans = aMarkData.GetMarkedRowSpans();
     653           1 :     CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans.empty());
     654           1 :     aSpans = aMarkData.GetMarkedColSpans();
     655           1 :     CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans.empty());
     656             : 
     657             :     // Select B3:F7.
     658           1 :     aMarkData.SetMarkArea(ScRange(1,2,0,5,6,0));
     659           1 :     aSpans = aMarkData.GetMarkedRowSpans();
     660           1 :     CPPUNIT_ASSERT_MESSAGE("There should be one selected row span.", aSpans.size() == 1);
     661           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(2), aSpans[0].mnStart);
     662           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(6), aSpans[0].mnEnd);
     663             : 
     664           1 :     aSpans = aMarkData.GetMarkedColSpans();
     665           1 :     CPPUNIT_ASSERT_MESSAGE("There should be one selected column span.", aSpans.size() == 1);
     666           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(1), aSpans[0].mnStart);
     667           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(5), aSpans[0].mnEnd);
     668             : 
     669             :     // Select A11:B13.
     670           1 :     aMarkData.SetMultiMarkArea(ScRange(0,10,0,1,12,0));
     671           1 :     aSpans = aMarkData.GetMarkedRowSpans();
     672           1 :     CPPUNIT_ASSERT_MESSAGE("There should be 2 selected row spans.", aSpans.size() == 2);
     673           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(2), aSpans[0].mnStart);
     674           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(6), aSpans[0].mnEnd);
     675           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(10), aSpans[1].mnStart);
     676           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(12), aSpans[1].mnEnd);
     677             : 
     678           1 :     aSpans = aMarkData.GetMarkedColSpans();
     679           1 :     CPPUNIT_ASSERT_MESSAGE("There should be one selected column span.", aSpans.size() == 1);
     680           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(0), aSpans[0].mnStart);
     681           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(5), aSpans[0].mnEnd);
     682             : 
     683             :     // Select C8:C10.
     684           1 :     aMarkData.SetMultiMarkArea(ScRange(2,7,0,2,9,0));
     685           1 :     aSpans = aMarkData.GetMarkedRowSpans();
     686           1 :     CPPUNIT_ASSERT_MESSAGE("There should be one selected row span.", aSpans.size() == 1);
     687           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(2), aSpans[0].mnStart);
     688           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(12), aSpans[0].mnEnd);
     689             : 
     690           1 :     aSpans = aMarkData.GetMarkedColSpans();
     691           1 :     CPPUNIT_ASSERT_MESSAGE("There should be one selected column span.", aSpans.size() == 1);
     692           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(0), aSpans[0].mnStart);
     693           2 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(5), aSpans[0].mnEnd);
     694           1 : }
     695             : 
     696           1 : void Test::testInput()
     697             : {
     698             : 
     699           2 :     CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
     700           1 :                             m_pDoc->InsertTab (0, "foo"));
     701           1 :     OUString test;
     702             : 
     703           1 :     m_pDoc->SetString(0, 0, 0, "'10.5");
     704           1 :     test = m_pDoc->GetString(0, 0, 0);
     705           1 :     bool bTest = test == "10.5";
     706           1 :     CPPUNIT_ASSERT_MESSAGE("String number should have the first apostrophe stripped.", bTest);
     707           1 :     m_pDoc->SetString(0, 0, 0, "'apple'");
     708           1 :     test = m_pDoc->GetString(0, 0, 0);
     709           1 :     bTest = test == "'apple'";
     710           1 :     CPPUNIT_ASSERT_MESSAGE("Text content should have retained the first apostrophe.", bTest);
     711             : 
     712             :     // Customized string handling policy.
     713           1 :     ScSetStringParam aParam;
     714           1 :     aParam.setTextInput();
     715           1 :     m_pDoc->SetString(0, 0, 0, "000123", &aParam);
     716           1 :     test = m_pDoc->GetString(0, 0, 0);
     717           1 :     CPPUNIT_ASSERT_MESSAGE("Text content should have been treated as string, not number.", test == "000123");
     718             : 
     719           1 :     m_pDoc->DeleteTab(0);
     720           1 : }
     721             : 
     722           1 : void Test::testDocStatistics()
     723             : {
     724           1 :     SCTAB nStartTabs = m_pDoc->GetTableCount();
     725           1 :     m_pDoc->InsertTab(0, "Sheet1");
     726           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to increment sheet count.", m_pDoc->GetTableCount() == nStartTabs+1);
     727           1 :     m_pDoc->InsertTab(1, "Sheet2");
     728           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to increment sheet count.", m_pDoc->GetTableCount() == nStartTabs+2);
     729             : 
     730           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), m_pDoc->GetCellCount());
     731           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 2.0);
     732           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), m_pDoc->GetCellCount());
     733           1 :     m_pDoc->SetValue(ScAddress(2,2,0), 2.5);
     734           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), m_pDoc->GetCellCount());
     735           1 :     m_pDoc->SetString(ScAddress(1,1,1), "Test");
     736           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(3), m_pDoc->GetCellCount());
     737             : 
     738           1 :     m_pDoc->DeleteTab(1);
     739           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to decrement sheet count.", m_pDoc->GetTableCount() == nStartTabs+1);
     740           1 :     m_pDoc->DeleteTab(0); // This may fail in case there is only one sheet in the document.
     741           1 : }
     742             : 
     743           1 : void Test::testDataEntries()
     744             : {
     745           1 :     m_pDoc->InsertTab(0, "Test");
     746             : 
     747           1 :     m_pDoc->SetString(ScAddress(0,5,0), "Andy");
     748           1 :     m_pDoc->SetString(ScAddress(0,6,0), "Bruce");
     749           1 :     m_pDoc->SetString(ScAddress(0,7,0), "Charlie");
     750           1 :     m_pDoc->SetString(ScAddress(0,10,0), "Andy");
     751             : 
     752           1 :     std::vector<ScTypedStrData> aEntries;
     753           1 :     m_pDoc->GetDataEntries(0, 0, 0, true, aEntries); // Try at the very top.
     754             : 
     755             :     // Entries are supposed to be sorted in ascending order, and are all unique.
     756           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries.size());
     757           1 :     std::vector<ScTypedStrData>::const_iterator it = aEntries.begin();
     758           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it->GetString());
     759           1 :     ++it;
     760           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it->GetString());
     761           1 :     ++it;
     762           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it->GetString());
     763           1 :     ++it;
     764           1 :     CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", it == aEntries.end());
     765             : 
     766           1 :     aEntries.clear();
     767           1 :     m_pDoc->GetDataEntries(0, MAXROW, 0, true, aEntries); // Try at the very bottom.
     768           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries.size());
     769             : 
     770             :     // Make sure we get the same set of suggestions.
     771           1 :     it = aEntries.begin();
     772           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it->GetString());
     773           1 :     ++it;
     774           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it->GetString());
     775           1 :     ++it;
     776           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it->GetString());
     777           1 :     ++it;
     778           1 :     CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", it == aEntries.end());
     779             : 
     780           1 :     m_pDoc->DeleteTab(0);
     781           1 : }
     782             : 
     783           1 : void Test::testSelectionFunction()
     784             : {
     785           1 :     m_pDoc->InsertTab(0, "Test");
     786             : 
     787             :     // Insert values into B2:B4.
     788           1 :     m_pDoc->SetString(ScAddress(1,1,0), "=1"); // formula
     789           1 :     m_pDoc->SetValue(ScAddress(1,2,0), 2.0);
     790           1 :     m_pDoc->SetValue(ScAddress(1,3,0), 3.0);
     791             : 
     792             :     // Insert strings into B5:B8.
     793           1 :     m_pDoc->SetString(ScAddress(1,4,0), "A");
     794           1 :     m_pDoc->SetString(ScAddress(1,5,0), "B");
     795           1 :     m_pDoc->SetString(ScAddress(1,6,0), "=\"C\""); // formula
     796           1 :     m_pDoc->SetString(ScAddress(1,7,0), "D");
     797             : 
     798             :     // Insert values into D2:D4.
     799           1 :     m_pDoc->SetValue(ScAddress(3,1,0), 4.0);
     800           1 :     m_pDoc->SetValue(ScAddress(3,2,0), 5.0);
     801           1 :     m_pDoc->SetValue(ScAddress(3,3,0), 6.0);
     802             : 
     803             :     // Insert edit text into D5.
     804           1 :     ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
     805           1 :     rEE.SetText("Rich Text");
     806           1 :     m_pDoc->SetEditText(ScAddress(3,4,0), rEE.CreateTextObject());
     807             : 
     808             :     // Insert Another string into D6.
     809           1 :     m_pDoc->SetString(ScAddress(3,5,0), "E");
     810             : 
     811             :     // Select B2:B8 & D2:D8 disjoint region.
     812           1 :     ScRangeList aRanges;
     813           1 :     aRanges.Append(ScRange(1,1,0,1,7,0)); // B2:B8
     814           1 :     aRanges.Append(ScRange(3,1,0,3,7,0)); // D2:D8
     815           2 :     ScMarkData aMark;
     816           1 :     aMark.MarkFromRangeList(aRanges, true);
     817             : 
     818             :     struct Check
     819             :     {
     820             :         ScSubTotalFunc meFunc;
     821             :         double mfExpected;
     822             :     };
     823             : 
     824             :     {
     825             :         Check aChecks[] =
     826             :         {
     827             :             { SUBTOTAL_FUNC_AVE,              3.5 },
     828             :             { SUBTOTAL_FUNC_CNT2,            12.0 },
     829             :             { SUBTOTAL_FUNC_CNT,              6.0 },
     830             :             { SUBTOTAL_FUNC_MAX,              6.0 },
     831             :             { SUBTOTAL_FUNC_MIN,              1.0 },
     832             :             { SUBTOTAL_FUNC_SUM,             21.0 },
     833             :             { SUBTOTAL_FUNC_SELECTION_COUNT, 14.0 }
     834           1 :         };
     835             : 
     836           8 :         for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
     837             :         {
     838           7 :             double fRes = 0.0;
     839           7 :             bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, ScAddress(), aMark, fRes);
     840           7 :             CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
     841           7 :             CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
     842             :         }
     843             :     }
     844             : 
     845             :     // Hide rows 4 and 6 and check the results again.
     846             : 
     847           1 :     m_pDoc->SetRowHidden(3, 3, 0, true);
     848           1 :     m_pDoc->SetRowHidden(5, 5, 0, true);
     849           1 :     CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc->RowHidden(3, 0));
     850           1 :     CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc->RowHidden(5, 0));
     851             : 
     852             :     {
     853             :         Check aChecks[] =
     854             :         {
     855             :             { SUBTOTAL_FUNC_AVE,              3.0 },
     856             :             { SUBTOTAL_FUNC_CNT2,             8.0 },
     857             :             { SUBTOTAL_FUNC_CNT,              4.0 },
     858             :             { SUBTOTAL_FUNC_MAX,              5.0 },
     859             :             { SUBTOTAL_FUNC_MIN,              1.0 },
     860             :             { SUBTOTAL_FUNC_SUM,             12.0 },
     861             :             { SUBTOTAL_FUNC_SELECTION_COUNT, 10.0 }
     862           1 :         };
     863             : 
     864           8 :         for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
     865             :         {
     866           7 :             double fRes = 0.0;
     867           7 :             bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, ScAddress(), aMark, fRes);
     868           7 :             CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
     869           7 :             CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
     870             :         }
     871             :     }
     872             : 
     873             :     // Make sure that when no selection is present, use the current cursor position.
     874           2 :     ScMarkData aEmpty;
     875             : 
     876             :     {
     877             :         // D3 (numeric cell containing 5.)
     878           1 :         ScAddress aPos(3, 2, 0);
     879             : 
     880             :         Check aChecks[] =
     881             :         {
     882             :             { SUBTOTAL_FUNC_AVE,             5.0 },
     883             :             { SUBTOTAL_FUNC_CNT2,            1.0 },
     884             :             { SUBTOTAL_FUNC_CNT,             1.0 },
     885             :             { SUBTOTAL_FUNC_MAX,             5.0 },
     886             :             { SUBTOTAL_FUNC_MIN,             5.0 },
     887             :             { SUBTOTAL_FUNC_SUM,             5.0 },
     888             :             { SUBTOTAL_FUNC_SELECTION_COUNT, 1.0 }
     889           1 :         };
     890             : 
     891           8 :         for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
     892             :         {
     893           7 :             double fRes = 0.0;
     894           7 :             bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, aPos, aEmpty, fRes);
     895           7 :             CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
     896           7 :             CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
     897             :         }
     898             :     }
     899             : 
     900             :     {
     901             :         // B7 (string formula cell containing ="C".)
     902           1 :         ScAddress aPos(1, 6, 0);
     903             : 
     904             :         Check aChecks[] =
     905             :         {
     906             :             { SUBTOTAL_FUNC_CNT2,            1.0 },
     907             :             { SUBTOTAL_FUNC_SELECTION_COUNT, 1.0 }
     908           1 :         };
     909             : 
     910           3 :         for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
     911             :         {
     912           2 :             double fRes = 0.0;
     913           2 :             bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, aPos, aEmpty, fRes);
     914           2 :             CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
     915           2 :             CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
     916             :         }
     917             :     }
     918             : 
     919           2 :     m_pDoc->DeleteTab(0);
     920           1 : }
     921             : 
     922           1 : void Test::testCopyToDocument()
     923             : {
     924           1 :     CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "src"));
     925             : 
     926           1 :     m_pDoc->SetString(0, 0, 0, "Header");
     927           1 :     m_pDoc->SetString(0, 1, 0, "1");
     928           1 :     m_pDoc->SetString(0, 2, 0, "2");
     929           1 :     m_pDoc->SetString(0, 3, 0, "3");
     930           1 :     m_pDoc->SetString(0, 4, 0, "=4/2");
     931           1 :     m_pDoc->CalcAll();
     932             : 
     933             :     //note on A1
     934           1 :     ScAddress aAdrA1 (0, 0, 0); // numerical cell content
     935           1 :     ScPostIt* pNote = m_pDoc->GetOrCreateNote(aAdrA1);
     936           1 :     pNote->SetText(aAdrA1, "Hello world in A1");
     937             : 
     938             :     // Copy statically to another document.
     939             : 
     940           1 :     ScDocument aDestDoc(SCDOCMODE_DOCUMENT);
     941           1 :     aDestDoc.InsertTab(0, "src");
     942           1 :     m_pDoc->CopyStaticToDocument(ScRange(0,1,0,0,3,0), 0, &aDestDoc); // Copy A2:A4
     943           1 :     m_pDoc->CopyStaticToDocument(ScAddress(0,0,0), 0, &aDestDoc); // Copy A1
     944           1 :     m_pDoc->CopyStaticToDocument(ScRange(0,4,0,0,7,0), 0, &aDestDoc); // Copy A5:A8
     945             : 
     946           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,0,0), aDestDoc.GetString(0,0,0));
     947           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,1,0), aDestDoc.GetString(0,1,0));
     948           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,2,0), aDestDoc.GetString(0,2,0));
     949           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,3,0), aDestDoc.GetString(0,3,0));
     950           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,4,0), aDestDoc.GetString(0,4,0));
     951             : 
     952             :     // verify note
     953           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note in A1 destDocument", aDestDoc.HasNote(ScAddress(0, 0, 0)));
     954           2 :     CPPUNIT_ASSERT_MESSAGE("The notes content should be the same on both documents",
     955           1 :             aDestDoc.GetNote(ScAddress(0, 0, 0))->GetText() ==  m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText());
     956             : 
     957           1 :     m_pDoc->DeleteTab(0);
     958           1 : }
     959             : 
     960             : namespace {
     961             : 
     962             : struct HoriIterCheck
     963             : {
     964             :     SCCOL nCol;
     965             :     SCROW nRow;
     966             :     const char* pVal;
     967             : };
     968             : 
     969             : template<size_t _Size>
     970           6 : bool checkHorizontalIterator(ScDocument* pDoc, const char* pData[][_Size], size_t nDataCount, const HoriIterCheck* pChecks, size_t nCheckCount)
     971             : {
     972           6 :     ScAddress aPos(0,0,0);
     973           6 :     Test::insertRangeData(pDoc, aPos, pData, nDataCount);
     974           6 :     ScHorizontalCellIterator aIter(pDoc, 0, 0, 0, 1, nDataCount-1);
     975             : 
     976             :     SCCOL nCol;
     977             :     SCROW nRow;
     978           6 :     size_t i = 0;
     979          31 :     for (ScRefCellValue* pCell = aIter.GetNext(nCol, nRow); pCell; pCell = aIter.GetNext(nCol, nRow), ++i)
     980             :     {
     981          25 :         if (i >= nCheckCount)
     982             :         {
     983           0 :             cerr << "hit invalid check " << i << " of " << nCheckCount << endl;
     984           0 :             CPPUNIT_FAIL("Iterator claims there is more data than there should be.");
     985           0 :             return false;
     986             :         }
     987             : 
     988          25 :         if (pChecks[i].nCol != nCol)
     989             :         {
     990           0 :             cerr << "Column mismatch " << pChecks[i].nCol << " vs. " << nCol << endl;
     991           0 :             return false;
     992             :         }
     993             : 
     994          25 :         if (pChecks[i].nRow != nRow)
     995             :         {
     996           0 :             cerr << "Row mismatch " << pChecks[i].nRow << " vs. " << nRow << endl;
     997           0 :             return false;
     998             :         }
     999             : 
    1000          25 :         if (OUString::createFromAscii(pChecks[i].pVal) != pCell->getString(pDoc))
    1001             :         {
    1002           0 :             cerr << "String mismatch " << pChecks[i].pVal << " vs. " <<
    1003             :                 OUStringToOString(pCell->getString(pDoc), RTL_TEXTENCODING_UTF8).getStr() << endl;
    1004           0 :             return false;
    1005             :         }
    1006             :     }
    1007             : 
    1008           6 :     return true;
    1009             : }
    1010             : 
    1011             : }
    1012             : 
    1013           1 : void Test::testHorizontalIterator()
    1014             : {
    1015           1 :     m_pDoc->InsertTab(0, "test");
    1016             : 
    1017             :     {
    1018             :         // Raw data - mixed types
    1019             :         const char* aData[][2] = {
    1020             :             { "A", "B" },
    1021             :             { "C", "1" },
    1022             :             { "D", "2" },
    1023             :             { "E", "3" }
    1024           1 :         };
    1025             : 
    1026             :         HoriIterCheck aChecks[] = {
    1027             :             { 0, 0, "A" },
    1028             :             { 1, 0, "B" },
    1029             :             { 0, 1, "C" },
    1030             :             { 1, 1, "1" },
    1031             :             { 0, 2, "D" },
    1032             :             { 1, 2, "2" },
    1033             :             { 0, 3, "E" },
    1034             :             { 1, 3, "3" },
    1035           1 :         };
    1036             : 
    1037             :         bool bRes = checkHorizontalIterator(
    1038           1 :             m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
    1039             : 
    1040           1 :         if (!bRes)
    1041           0 :             CPPUNIT_FAIL("Failed on test mixed.");
    1042             :     }
    1043             : 
    1044             :     {
    1045             :         // Raw data - 'hole' data
    1046             :         const char* aData[][2] = {
    1047             :             { "A", "B" },
    1048             :             { "C",  0  },
    1049             :             { "D", "E" },
    1050           1 :         };
    1051             : 
    1052             :         HoriIterCheck aChecks[] = {
    1053             :             { 0, 0, "A" },
    1054             :             { 1, 0, "B" },
    1055             :             { 0, 1, "C" },
    1056             :             { 0, 2, "D" },
    1057             :             { 1, 2, "E" },
    1058           1 :         };
    1059             : 
    1060             :         bool bRes = checkHorizontalIterator(
    1061           1 :             m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
    1062             : 
    1063           1 :         if (!bRes)
    1064           0 :             CPPUNIT_FAIL("Failed on test hole.");
    1065             :     }
    1066             : 
    1067             :     {
    1068             :         // Very holy data
    1069             :         const char* aData[][2] = {
    1070             :             {  0,  "A" },
    1071             :             {  0,   0  },
    1072             :             {  0,  "1" },
    1073             :             { "B",  0  },
    1074             :             { "C", "2" },
    1075             :             { "D", "3" },
    1076             :             { "E",  0  },
    1077             :             {  0,  "G" },
    1078             :             {  0,   0  },
    1079           1 :         };
    1080             : 
    1081             :         HoriIterCheck aChecks[] = {
    1082             :             { 1, 0, "A" },
    1083             :             { 1, 2, "1" },
    1084             :             { 0, 3, "B" },
    1085             :             { 0, 4, "C" },
    1086             :             { 1, 4, "2" },
    1087             :             { 0, 5, "D" },
    1088             :             { 1, 5, "3" },
    1089             :             { 0, 6, "E" },
    1090             :             { 1, 7, "G" },
    1091           1 :         };
    1092             : 
    1093             :         bool bRes = checkHorizontalIterator(
    1094           1 :             m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
    1095             : 
    1096           1 :         if (!bRes)
    1097           0 :             CPPUNIT_FAIL("Failed on test holy.");
    1098             :     }
    1099             : 
    1100             :     {
    1101             :         // Degenerate case
    1102             :         const char* aData[][2] = {
    1103             :             {  0,   0 },
    1104             :             {  0,   0 },
    1105             :             {  0,   0 },
    1106           1 :         };
    1107             : 
    1108             :         bool bRes = checkHorizontalIterator(
    1109           1 :             m_pDoc, aData, SAL_N_ELEMENTS(aData), NULL, 0);
    1110             : 
    1111           1 :         if (!bRes)
    1112           0 :             CPPUNIT_FAIL("Failed on test degenerate.");
    1113             :     }
    1114             : 
    1115             :     {
    1116             :         // Data at end
    1117             :         const char* aData[][2] = {
    1118             :             {  0,   0 },
    1119             :             {  0,   0 },
    1120             :             {  0,  "A" },
    1121           1 :         };
    1122             : 
    1123             :         HoriIterCheck aChecks[] = {
    1124             :             { 1, 2, "A" },
    1125           1 :         };
    1126             : 
    1127             :         bool bRes = checkHorizontalIterator(
    1128           1 :             m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
    1129             : 
    1130           1 :         if (!bRes)
    1131           0 :             CPPUNIT_FAIL("Failed on test at end.");
    1132             :     }
    1133             : 
    1134             :     {
    1135             :         // Data in middle
    1136             :         const char* aData[][2] = {
    1137             :             {  0,   0  },
    1138             :             {  0,   0  },
    1139             :             {  0,  "A" },
    1140             :             {  0,  "1" },
    1141             :             {  0,   0  },
    1142           1 :         };
    1143             : 
    1144             :         HoriIterCheck aChecks[] = {
    1145             :             { 1, 2, "A" },
    1146             :             { 1, 3, "1" },
    1147           1 :         };
    1148             : 
    1149             :         bool bRes = checkHorizontalIterator(
    1150           1 :             m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
    1151             : 
    1152           1 :         if (!bRes)
    1153           0 :             CPPUNIT_FAIL("Failed on test in middle.");
    1154             :     }
    1155             : 
    1156           1 :     m_pDoc->DeleteTab(0);
    1157           1 : }
    1158             : 
    1159           1 : void Test::testValueIterator()
    1160             : {
    1161           1 :     m_pDoc->InsertTab(0, "Test");
    1162             : 
    1163             :     // Turn on "precision as shown" option.
    1164           1 :     ScDocOptions aOpt = m_pDoc->GetDocOptions();
    1165           1 :     aOpt.SetCalcAsShown(true);
    1166           1 :     m_pDoc->SetDocOptions(aOpt);
    1167             : 
    1168             :     // Purely horizontal data layout with numeric data.
    1169           4 :     for (SCCOL i = 1; i <= 3; ++i)
    1170           3 :         m_pDoc->SetValue(ScAddress(i,2,0), i);
    1171             : 
    1172             :     double fVal;
    1173             :     sal_uInt16 nErr;
    1174             : 
    1175             :     {
    1176           1 :         const double aChecks[] = { 1.0, 2.0, 3.0 };
    1177           1 :         size_t nCheckLen = SAL_N_ELEMENTS(aChecks);
    1178             : 
    1179           1 :         ScValueIterator aIter(m_pDoc, ScRange(1,2,0,3,2,0));
    1180           1 :         bool bHas = false;
    1181             : 
    1182           1 :         size_t nCheckPos = 0;
    1183           4 :         for (bHas = aIter.GetFirst(fVal, nErr); bHas; bHas = aIter.GetNext(fVal, nErr), ++nCheckPos)
    1184             :         {
    1185           3 :             CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos < nCheckLen);
    1186           3 :             CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos], fVal);
    1187           3 :             CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(0), nErr);
    1188             :         }
    1189             :     }
    1190             : 
    1191             : 
    1192           1 :     m_pDoc->DeleteTab(0);
    1193           1 : }
    1194             : 
    1195           1 : void Test::testFormulaDepTracking()
    1196             : {
    1197           1 :     CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "foo"));
    1198             : 
    1199           1 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation.
    1200             : 
    1201             :     // B2 listens on D2.
    1202           1 :     m_pDoc->SetString(1, 1, 0, "=D2");
    1203           1 :     double val = -999.0; // dummy initial value
    1204           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1205           1 :     CPPUNIT_ASSERT_MESSAGE("Referencing an empty cell should yield zero.", val == 0.0);
    1206             : 
    1207             :     // Changing the value of D2 should trigger recalculation of B2.
    1208           1 :     m_pDoc->SetValue(3, 1, 0, 1.1);
    1209           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1210           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on value change.", val == 1.1);
    1211             : 
    1212             :     // And again.
    1213           1 :     m_pDoc->SetValue(3, 1, 0, 2.2);
    1214           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1215           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on value change.", val == 2.2);
    1216             : 
    1217           1 :     clearRange(m_pDoc, ScRange(0, 0, 0, 10, 10, 0));
    1218             : 
    1219             :     // Now, let's test the range dependency tracking.
    1220             : 
    1221             :     // B2 listens on D2:E6.
    1222           1 :     m_pDoc->SetString(1, 1, 0, "=SUM(D2:E6)");
    1223           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1224           1 :     CPPUNIT_ASSERT_MESSAGE("Summing an empty range should yield zero.", val == 0.0);
    1225             : 
    1226             :     // Set value to E3. This should trigger recalc on B2.
    1227           1 :     m_pDoc->SetValue(4, 2, 0, 2.4);
    1228           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1229           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", val == 2.4);
    1230             : 
    1231             :     // Set value to D5 to trigger recalc again.  Note that this causes an
    1232             :     // addition of 1.2 + 2.4 which is subject to binary floating point
    1233             :     // rounding error.  We need to use approxEqual to assess its value.
    1234             : 
    1235           1 :     m_pDoc->SetValue(3, 4, 0, 1.2);
    1236           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1237           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 3.6));
    1238             : 
    1239             :     // Change the value of D2 (boundary case).
    1240           1 :     m_pDoc->SetValue(3, 1, 0, 1.0);
    1241           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1242           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 4.6));
    1243             : 
    1244             :     // Change the value of E6 (another boundary case).
    1245           1 :     m_pDoc->SetValue(4, 5, 0, 2.0);
    1246           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1247           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 6.6));
    1248             : 
    1249             :     // Change the value of D6 (another boundary case).
    1250           1 :     m_pDoc->SetValue(3, 5, 0, 3.0);
    1251           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1252           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 9.6));
    1253             : 
    1254             :     // Change the value of E2 (another boundary case).
    1255           1 :     m_pDoc->SetValue(4, 1, 0, 0.4);
    1256           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1257           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 10.0));
    1258             : 
    1259             :     // Change the existing non-empty value cell (E2).
    1260           1 :     m_pDoc->SetValue(4, 1, 0, 2.4);
    1261           1 :     m_pDoc->GetValue(1, 1, 0, val);
    1262           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to recalculate on single value change.", rtl::math::approxEqual(val, 12.0));
    1263             : 
    1264           1 :     clearRange(m_pDoc, ScRange(0, 0, 0, 10, 10, 0));
    1265             : 
    1266             :     // Now, column-based dependency tracking.  We now switch to the R1C1
    1267             :     // syntax which is easier to use for repeated relative references.
    1268             : 
    1269           2 :     FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
    1270             : 
    1271           1 :     val = 0.0;
    1272          10 :     for (SCROW nRow = 1; nRow <= 9; ++nRow)
    1273             :     {
    1274             :         // Static value in column 1.
    1275           9 :         m_pDoc->SetValue(0, nRow, 0, ++val);
    1276             : 
    1277             :         // Formula in column 2 that references cell to the left.
    1278           9 :         m_pDoc->SetString(1, nRow, 0, "=RC[-1]");
    1279             : 
    1280             :         // Formula in column 3 that references cell to the left.
    1281           9 :         m_pDoc->SetString(2, nRow, 0, "=RC[-1]*2");
    1282             :     }
    1283             : 
    1284             :     // Check formula values.
    1285           1 :     val = 0.0;
    1286          10 :     for (SCROW nRow = 1; nRow <= 9; ++nRow)
    1287             :     {
    1288           9 :         ++val;
    1289           9 :         CPPUNIT_ASSERT_MESSAGE("Unexpected formula value.", m_pDoc->GetValue(1, nRow, 0) == val);
    1290           9 :         CPPUNIT_ASSERT_MESSAGE("Unexpected formula value.", m_pDoc->GetValue(2, nRow, 0) == val*2.0);
    1291             :     }
    1292             : 
    1293             :     // Intentionally insert a formula in column 1. This will break column 1's
    1294             :     // uniformity of consisting only of static value cells.
    1295           1 :     m_pDoc->SetString(0, 4, 0, "=R2C3");
    1296           1 :     CPPUNIT_ASSERT_MESSAGE("Unexpected formula value.", m_pDoc->GetValue(0, 4, 0) == 2.0);
    1297           1 :     CPPUNIT_ASSERT_MESSAGE("Unexpected formula value.", m_pDoc->GetValue(1, 4, 0) == 2.0);
    1298           1 :     CPPUNIT_ASSERT_MESSAGE("Unexpected formula value.", m_pDoc->GetValue(2, 4, 0) == 4.0);
    1299             : 
    1300           2 :     m_pDoc->DeleteTab(0);
    1301           1 : }
    1302             : 
    1303           1 : void Test::testFormulaDepTracking2()
    1304             : {
    1305           1 :     CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "foo"));
    1306             : 
    1307           1 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation.
    1308             : 
    1309           1 :     double val = 2.0;
    1310           1 :     m_pDoc->SetValue(0, 0, 0, val);
    1311           1 :     val = 4.0;
    1312           1 :     m_pDoc->SetValue(1, 0, 0, val);
    1313           1 :     val = 5.0;
    1314           1 :     m_pDoc->SetValue(0, 1, 0, val);
    1315           1 :     m_pDoc->SetString(2, 0, 0, "=A1/B1");
    1316           1 :     m_pDoc->SetString(1, 1, 0, "=B1*C1");
    1317             : 
    1318           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(1, 1, 0)); // B2 should equal 2.
    1319             : 
    1320           1 :     clearRange(m_pDoc, ScAddress(2, 0, 0)); // Delete C1.
    1321             : 
    1322           1 :     CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(1, 1, 0)); // B2 should now equal 0.
    1323             : 
    1324           1 :     m_pDoc->DeleteTab(0);
    1325           1 : }
    1326             : 
    1327           1 : void Test::testFormulaMatrixResultUpdate()
    1328             : {
    1329           1 :     m_pDoc->InsertTab(0, "Test");
    1330             : 
    1331           1 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation.
    1332             : 
    1333             :     // Set a numeric value to A1.
    1334           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 11.0);
    1335             : 
    1336           2 :     ScMarkData aMark;
    1337           1 :     aMark.SelectOneTable(0);
    1338           1 :     m_pDoc->InsertMatrixFormula(1, 0, 1, 0, aMark, "=A1", NULL);
    1339           1 :     CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1340           1 :     ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
    1341           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get formula cell.", pFC);
    1342           1 :     pFC->SetChanged(false); // Clear this flag to simulate displaying of formula cell value on screen.
    1343             : 
    1344           1 :     m_pDoc->SetString(ScAddress(0,0,0), "ABC");
    1345           1 :     CPPUNIT_ASSERT_EQUAL(OUString("ABC"), m_pDoc->GetString(ScAddress(1,0,0)));
    1346           1 :     pFC->SetChanged(false);
    1347             : 
    1348             :     // Put a new value into A1. The formula should update.
    1349           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 13.0);
    1350           1 :     CPPUNIT_ASSERT_EQUAL(13.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    1351             : 
    1352           2 :     m_pDoc->DeleteTab(0);
    1353           1 : }
    1354             : 
    1355             : namespace {
    1356             : 
    1357           7 : bool broadcasterShifted(const ScDocument& rDoc, const ScAddress& rFrom, const ScAddress& rTo)
    1358             : {
    1359           7 :     const SvtBroadcaster* pBC = rDoc.GetBroadcaster(rFrom);
    1360           7 :     if (pBC)
    1361             :     {
    1362           0 :         cerr << "Broadcaster shouldn't be here." << endl;
    1363           0 :         return false;
    1364             :     }
    1365             : 
    1366           7 :     pBC = rDoc.GetBroadcaster(rTo);
    1367           7 :     if (!pBC)
    1368             :     {
    1369           0 :         cerr << "Broadcaster should be here." << endl;
    1370           0 :         return false;
    1371             :     }
    1372           7 :     return true;
    1373             : }
    1374             : 
    1375          11 : ScToken* getSingleRefToken(ScDocument& rDoc, const ScAddress& rPos)
    1376             : {
    1377          11 :     ScFormulaCell* pFC = rDoc.GetFormulaCell(rPos);
    1378          11 :     if (!pFC)
    1379             :     {
    1380           0 :         cerr << "Formula cell expected, but not found." << endl;
    1381           0 :         return NULL;
    1382             :     }
    1383             : 
    1384          11 :     ScTokenArray* pTokens = pFC->GetCode();
    1385          11 :     if (!pTokens)
    1386             :     {
    1387           0 :         cerr << "Token array is not present." << endl;
    1388           0 :         return NULL;
    1389             :     }
    1390             : 
    1391          11 :     ScToken* pToken = static_cast<ScToken*>(pTokens->First());
    1392          11 :     if (!pToken || pToken->GetType() != formula::svSingleRef)
    1393             :     {
    1394           0 :         cerr << "Not a single reference token." << endl;
    1395           0 :         return NULL;
    1396             :     }
    1397             : 
    1398          11 :     return pToken;
    1399             : }
    1400             : 
    1401           9 : bool checkRelativeRefToken(ScDocument& rDoc, const ScAddress& rPos, SCsCOL nRelCol, SCsROW nRelRow)
    1402             : {
    1403           9 :     ScToken* pToken = getSingleRefToken(rDoc, rPos);
    1404           9 :     if (!pToken)
    1405           0 :         return false;
    1406             : 
    1407           9 :     ScSingleRefData& rRef = pToken->GetSingleRef();
    1408           9 :     if (!rRef.IsColRel() || rRef.Col() != nRelCol)
    1409             :     {
    1410           0 :         cerr << "Unexpected relative column address." << endl;
    1411           0 :         return false;
    1412             :     }
    1413             : 
    1414           9 :     if (!rRef.IsRowRel() || rRef.Row() != nRelRow)
    1415             :     {
    1416           0 :         cerr << "Unexpected relative row address." << endl;
    1417           0 :         return false;
    1418             :     }
    1419             : 
    1420           9 :     return true;
    1421             : }
    1422             : 
    1423           2 : bool checkDeletedRefToken(ScDocument& rDoc, const ScAddress& rPos)
    1424             : {
    1425           2 :     ScToken* pToken = getSingleRefToken(rDoc, rPos);
    1426           2 :     if (!pToken)
    1427           0 :         return false;
    1428             : 
    1429           2 :     ScSingleRefData& rRef = pToken->GetSingleRef();
    1430           2 :     if (!rRef.IsDeleted())
    1431             :     {
    1432           0 :         cerr << "Deleted reference is expected, but it's still a valid reference." << endl;
    1433           0 :         return false;
    1434             :     }
    1435             : 
    1436           2 :     return true;
    1437             : }
    1438             : 
    1439             : }
    1440             : 
    1441           1 : void Test::testCellBroadcaster()
    1442             : {
    1443           1 :     CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "foo"));
    1444             : 
    1445           1 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation.
    1446           1 :     m_pDoc->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
    1447           1 :     double val = m_pDoc->GetValue(ScAddress(1,0,0)); // A1 is empty, so the result should be 0.
    1448           1 :     CPPUNIT_ASSERT_EQUAL(0.0, val);
    1449             : 
    1450           1 :     const SvtBroadcaster* pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
    1451           1 :     CPPUNIT_ASSERT_MESSAGE("Cell A1 should have a broadcaster.", pBC);
    1452             : 
    1453             :     // Change the value of A1 and make sure that B1 follows.
    1454           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 1.23);
    1455           1 :     val = m_pDoc->GetValue(ScAddress(1,0,0));
    1456           1 :     CPPUNIT_ASSERT_EQUAL(1.23, val);
    1457             : 
    1458             :     // Move column A down 5 cells. Make sure B1 now references A6, not A1.
    1459           1 :     m_pDoc->InsertRow(0, 0, 0, 0, 0, 5);
    1460           2 :     CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
    1461           1 :                            checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 5));
    1462             : 
    1463             :     // Make sure the broadcaster has also moved.
    1464           2 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
    1465           1 :                            broadcasterShifted(*m_pDoc, ScAddress(0,0,0), ScAddress(0,5,0)));
    1466             : 
    1467             :     // Set new value to A6 and make sure B1 gets updated.
    1468           1 :     m_pDoc->SetValue(ScAddress(0,5,0), 45.6);
    1469           1 :     val = m_pDoc->GetValue(ScAddress(1,0,0));
    1470           1 :     CPPUNIT_ASSERT_EQUAL(45.6, val);
    1471             : 
    1472             :     // Move column A up 3 cells, and make sure B1 now references A3, not A6.
    1473           1 :     m_pDoc->DeleteRow(0, 0, 0, 0, 0, 3);
    1474           2 :     CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
    1475           1 :                            checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 2));
    1476             : 
    1477             :     // The broadcaster should also have been relocated from A6 to A3.
    1478           2 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
    1479           1 :                            broadcasterShifted(*m_pDoc, ScAddress(0,5,0), ScAddress(0,2,0)));
    1480             : 
    1481             :     // Insert cells over A1:A10 and shift cells to right.
    1482           1 :     m_pDoc->InsertCol(ScRange(0, 0, 0, 0, 10, 0));
    1483           2 :     CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
    1484           1 :                            checkRelativeRefToken(*m_pDoc, ScAddress(2,0,0), -1, 2));
    1485           2 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
    1486           1 :                            broadcasterShifted(*m_pDoc, ScAddress(0,2,0), ScAddress(1,2,0)));
    1487             : 
    1488             :     // Delete formula in C2, which should remove the broadcaster in B3.
    1489           1 :     pBC = m_pDoc->GetBroadcaster(ScAddress(1,2,0));
    1490           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should still exist.", pBC);
    1491           1 :     clearRange(m_pDoc, ScAddress(2,0,0));
    1492           1 :     CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(ScAddress(2,0,0))); // C2 should be empty.
    1493           1 :     pBC = m_pDoc->GetBroadcaster(ScAddress(1,2,0));
    1494           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should have been removed.", !pBC);
    1495             : 
    1496             :     // Clear everything and start over.
    1497           1 :     clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
    1498             : 
    1499           1 :     m_pDoc->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
    1500           1 :     pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
    1501           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", pBC);
    1502             : 
    1503             :     // While column A is still empty, move column A down 2 cells. This should
    1504             :     // move the broadcaster from A1 to A3.
    1505           1 :     m_pDoc->InsertRow(0, 0, 0, 0, 0, 2);
    1506           2 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
    1507           1 :                            broadcasterShifted(*m_pDoc, ScAddress(0,0,0), ScAddress(0,2,0)));
    1508             : 
    1509             :     // Move it back while column A is still empty.
    1510           1 :     m_pDoc->DeleteRow(0, 0, 0, 0, 0, 2);
    1511           2 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
    1512           1 :                            broadcasterShifted(*m_pDoc, ScAddress(0,2,0), ScAddress(0,0,0)));
    1513             : 
    1514             :     // Clear everything again
    1515           1 :     clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
    1516             : 
    1517             :     // B1:B3 depends on A1:A3
    1518           1 :     m_pDoc->SetString(ScAddress(1,0,0), "=A1");
    1519           1 :     m_pDoc->SetString(ScAddress(1,1,0), "=A2");
    1520           1 :     m_pDoc->SetString(ScAddress(1,2,0), "=A3");
    1521           2 :     CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
    1522           1 :                            checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 0));
    1523           2 :     CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
    1524           1 :                            checkRelativeRefToken(*m_pDoc, ScAddress(1,1,0), -1, 0));
    1525           2 :     CPPUNIT_ASSERT_MESSAGE("Relative reference check in B3 failed.",
    1526           1 :                            checkRelativeRefToken(*m_pDoc, ScAddress(1,2,0), -1, 0));
    1527           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc->GetBroadcaster(ScAddress(0,0,0)));
    1528           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A2.", m_pDoc->GetBroadcaster(ScAddress(0,1,0)));
    1529           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A3.", m_pDoc->GetBroadcaster(ScAddress(0,2,0)));
    1530             : 
    1531             :     // Insert Rows at row 2, down 5 rows.
    1532           1 :     m_pDoc->InsertRow(0, 0, 0, 0, 1, 5);
    1533           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc->GetBroadcaster(ScAddress(0,0,0)));
    1534           2 :     CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
    1535           1 :                            checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 0));
    1536             : 
    1537             :     // Broadcasters in A2 and A3 should shift down by 5 rows.
    1538           2 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
    1539           1 :                            broadcasterShifted(*m_pDoc, ScAddress(0,1,0), ScAddress(0,6,0)));
    1540           2 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
    1541           1 :                            broadcasterShifted(*m_pDoc, ScAddress(0,2,0), ScAddress(0,7,0)));
    1542             : 
    1543             :     // B2 and B3 should reference shifted cells.
    1544           2 :     CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
    1545           1 :                            checkRelativeRefToken(*m_pDoc, ScAddress(1,1,0), -1, 5));
    1546           2 :     CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
    1547           1 :                            checkRelativeRefToken(*m_pDoc, ScAddress(1,2,0), -1, 5));
    1548             : 
    1549             :     // Delete cells with broadcasters.
    1550           1 :     m_pDoc->DeleteRow(0, 0, 0, 0, 4, 6);
    1551           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A7.", !m_pDoc->GetBroadcaster(ScAddress(0,6,0)));
    1552           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A8.", !m_pDoc->GetBroadcaster(ScAddress(0,7,0)));
    1553             : 
    1554             :     // References in B2 and B3 should be invalid.
    1555           2 :     CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B2 failed.",
    1556           1 :                            checkDeletedRefToken(*m_pDoc, ScAddress(1,1,0)));
    1557           2 :     CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B3 failed.",
    1558           1 :                            checkDeletedRefToken(*m_pDoc, ScAddress(1,2,0)));
    1559             : 
    1560             :     // Clear everything again
    1561           1 :     clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
    1562             : 
    1563             :     {
    1564             :         // Switch to R1C1 to make it easier to input relative references in multiple cells.
    1565           1 :         FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
    1566             : 
    1567             :         // Have B1:B20 reference A1:A20.
    1568           1 :         val = 0.0;
    1569          21 :         for (SCROW i = 0; i < 20; ++i)
    1570             :         {
    1571          20 :             m_pDoc->SetValue(ScAddress(0,i,0), val++);
    1572          20 :             m_pDoc->SetString(ScAddress(1,i,0), "=RC[-1]");
    1573           1 :         }
    1574             :     }
    1575             : 
    1576             :     // Ensure that the formula cells show correct values, and the referenced
    1577             :     // cells have broadcasters.
    1578           1 :     val = 0.0;
    1579          21 :     for (SCROW i = 0; i < 20; ++i, ++val)
    1580             :     {
    1581          20 :         CPPUNIT_ASSERT_EQUAL(val, m_pDoc->GetValue(ScAddress(1,i,0)));
    1582          20 :         pBC = m_pDoc->GetBroadcaster(ScAddress(0,i,0));
    1583          20 :         CPPUNIT_ASSERT_MESSAGE("Broadcast should exist here.", pBC);
    1584             :     }
    1585             : 
    1586             :     // Delete formula cells in B2:B19.
    1587           1 :     clearRange(m_pDoc, ScRange(1,1,0,1,18,0));
    1588             :     // Ensure that A2:A19 no longer have broadcasters, but A1 and A20 still do.
    1589           1 :     CPPUNIT_ASSERT_MESSAGE("A1 should still have broadcaster.", m_pDoc->GetBroadcaster(ScAddress(0,0,0)));
    1590           1 :     CPPUNIT_ASSERT_MESSAGE("A20 should still have broadcaster.", m_pDoc->GetBroadcaster(ScAddress(0,19,0)));
    1591          19 :     for (SCROW i = 1; i <= 18; ++i)
    1592             :     {
    1593          18 :         pBC = m_pDoc->GetBroadcaster(ScAddress(0,i,0));
    1594          18 :         CPPUNIT_ASSERT_MESSAGE("Broadcaster should have been deleted.", !pBC);
    1595             :     }
    1596             : 
    1597             :     // Clear everything again
    1598           1 :     clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
    1599             : 
    1600           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 2.0);
    1601           1 :     m_pDoc->SetString(ScAddress(1,0,0), "=A1");
    1602           1 :     m_pDoc->SetString(ScAddress(2,0,0), "=B1");
    1603           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(0,0,0));
    1604           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(1,0,0));
    1605           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(2,0,0));
    1606             : 
    1607           1 :     pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
    1608           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
    1609           1 :     pBC = m_pDoc->GetBroadcaster(ScAddress(1,0,0));
    1610           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
    1611             : 
    1612             :     // Change the value of A1 and make sure everyone follows suit.
    1613           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 3.5);
    1614           1 :     CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc->GetValue(0,0,0));
    1615           1 :     CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc->GetValue(1,0,0));
    1616           1 :     CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc->GetValue(2,0,0));
    1617             : 
    1618             :     // Insert a column at column B.
    1619           1 :     m_pDoc->InsertCol(ScRange(1,0,0,1,MAXROW,0));
    1620           1 :     pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
    1621           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
    1622           1 :     pBC = m_pDoc->GetBroadcaster(ScAddress(2,0,0));
    1623           1 :     CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
    1624             : 
    1625             :     // Change the value of A1 again.
    1626           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 5.5);
    1627           1 :     CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc->GetValue(0,0,0));
    1628           1 :     CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc->GetValue(2,0,0));
    1629           1 :     CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc->GetValue(3,0,0));
    1630             : 
    1631           1 :     m_pDoc->DeleteTab(0);
    1632           1 : }
    1633             : 
    1634           1 : void Test::testFuncParam()
    1635             : {
    1636             : 
    1637           2 :     CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
    1638           1 :                             m_pDoc->InsertTab (0, "foo"));
    1639             : 
    1640             :     // First, the normal case, with no missing parameters.
    1641           1 :     m_pDoc->SetString(0, 0, 0, "=AVERAGE(1;2;3)");
    1642           1 :     m_pDoc->CalcFormulaTree(false, false);
    1643             :     double val;
    1644           1 :     m_pDoc->GetValue(0, 0, 0, val);
    1645           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 2);
    1646             : 
    1647             :     // Now function with missing parameters.  Missing values should be treated
    1648             :     // as zeros.
    1649           1 :     m_pDoc->SetString(0, 0, 0, "=AVERAGE(1;;;)");
    1650           1 :     m_pDoc->CalcFormulaTree(false, false);
    1651           1 :     m_pDoc->GetValue(0, 0, 0, val);
    1652           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 0.25);
    1653             : 
    1654             :     // Conversion of string to numeric argument.
    1655           1 :     m_pDoc->SetString(0, 0, 0, "=\"\"+3");    // empty string
    1656           1 :     m_pDoc->SetString(0, 1, 0, "=\" \"+3");   // only blank
    1657           1 :     m_pDoc->SetString(0, 2, 0, "=\" 4 \"+3"); // number in blanks
    1658           1 :     m_pDoc->SetString(0, 3, 0, "=\" x \"+3"); // non-numeric
    1659           1 :     m_pDoc->SetString(0, 4, 0, "=\"4.4\"+3"); // locale dependent
    1660             : 
    1661           1 :     OUString aVal;
    1662           2 :     ScCalcConfig aConfig;
    1663             : 
    1664             :     // With "Convert also locale dependent" and "Empty string as zero"=True option.
    1665           1 :     aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT;
    1666           1 :     aConfig.mbEmptyStringAsZero = true;
    1667           1 :     m_pDoc->SetCalcConfig(aConfig);
    1668           1 :     m_pDoc->CalcAll();
    1669           1 :     m_pDoc->GetValue(0, 0, 0, val);
    1670           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
    1671           1 :     m_pDoc->GetValue(0, 1, 0, val);
    1672           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
    1673           1 :     m_pDoc->GetValue(0, 2, 0, val);
    1674           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
    1675           1 :     aVal = m_pDoc->GetString( 0, 3, 0);
    1676           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1677           1 :     m_pDoc->GetValue(0, 4, 0, val);
    1678           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7.4);
    1679             : 
    1680             :     // With "Convert also locale dependent" and "Empty string as zero"=False option.
    1681           1 :     aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_LOCALE_DEPENDENT;
    1682           1 :     aConfig.mbEmptyStringAsZero = false;
    1683           1 :     m_pDoc->SetCalcConfig(aConfig);
    1684           1 :     m_pDoc->CalcAll();
    1685           1 :     aVal = m_pDoc->GetString( 0, 0, 0);
    1686           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1687           1 :     aVal = m_pDoc->GetString( 0, 1, 0);
    1688           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1689           1 :     m_pDoc->GetValue(0, 2, 0, val);
    1690           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
    1691           1 :     aVal = m_pDoc->GetString( 0, 3, 0);
    1692           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1693           1 :     m_pDoc->GetValue(0, 4, 0, val);
    1694           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7.4);
    1695             : 
    1696             :     // With "Convert only unambiguous" and "Empty string as zero"=True option.
    1697           1 :     aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS;
    1698           1 :     aConfig.mbEmptyStringAsZero = true;
    1699           1 :     m_pDoc->SetCalcConfig(aConfig);
    1700           1 :     m_pDoc->CalcAll();
    1701           1 :     m_pDoc->GetValue(0, 0, 0, val);
    1702           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
    1703           1 :     m_pDoc->GetValue(0, 1, 0, val);
    1704           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
    1705           1 :     m_pDoc->GetValue(0, 2, 0, val);
    1706           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
    1707           1 :     aVal = m_pDoc->GetString( 0, 3, 0);
    1708           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1709           1 :     aVal = m_pDoc->GetString( 0, 4, 0);
    1710           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1711             : 
    1712             :     // With "Convert only unambiguous" and "Empty string as zero"=False option.
    1713           1 :     aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_UNAMBIGUOUS;
    1714           1 :     aConfig.mbEmptyStringAsZero = false;
    1715           1 :     m_pDoc->SetCalcConfig(aConfig);
    1716           1 :     m_pDoc->CalcAll();
    1717           1 :     aVal = m_pDoc->GetString( 0, 0, 0);
    1718           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1719           1 :     aVal = m_pDoc->GetString( 0, 1, 0);
    1720           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1721           1 :     m_pDoc->GetValue(0, 2, 0, val);
    1722           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
    1723           1 :     aVal = m_pDoc->GetString( 0, 3, 0);
    1724           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1725           1 :     aVal = m_pDoc->GetString( 0, 4, 0);
    1726           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1727             : 
    1728             :     // With "Treat as zero" ("Empty string as zero" is ignored).
    1729           1 :     aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_AS_ZERO;
    1730           1 :     aConfig.mbEmptyStringAsZero = true;
    1731           1 :     m_pDoc->SetCalcConfig(aConfig);
    1732           1 :     m_pDoc->CalcAll();
    1733           1 :     m_pDoc->GetValue(0, 0, 0, val);
    1734           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
    1735           1 :     m_pDoc->GetValue(0, 1, 0, val);
    1736           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
    1737           1 :     m_pDoc->GetValue(0, 2, 0, val);
    1738           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
    1739           1 :     m_pDoc->GetValue(0, 3, 0, val);
    1740           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
    1741           1 :     m_pDoc->GetValue(0, 4, 0, val);
    1742           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
    1743             : 
    1744             :     // With "Generate #VALUE! error" ("Empty string as zero" is ignored).
    1745           1 :     aConfig.meStringConversion = ScCalcConfig::STRING_CONVERSION_AS_ERROR;
    1746           1 :     aConfig.mbEmptyStringAsZero = false;
    1747           1 :     m_pDoc->SetCalcConfig(aConfig);
    1748           1 :     m_pDoc->CalcAll();
    1749           1 :     aVal = m_pDoc->GetString( 0, 0, 0);
    1750           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1751           1 :     aVal = m_pDoc->GetString( 0, 1, 0);
    1752           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1753           1 :     aVal = m_pDoc->GetString( 0, 2, 0);
    1754           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1755           1 :     aVal = m_pDoc->GetString( 0, 3, 0);
    1756           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1757           1 :     aVal = m_pDoc->GetString( 0, 4, 0);
    1758           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
    1759             : 
    1760           2 :     m_pDoc->DeleteTab(0);
    1761           1 : }
    1762             : 
    1763           1 : void Test::testNamedRange()
    1764             : {
    1765             :     RangeNameDef aNames[] = {
    1766             :         { "Divisor",  "$Sheet1.$A$1:$A$1048576", 1 },
    1767             :         { "MyRange1", "$Sheet1.$A$1:$A$100",     2 },
    1768             :         { "MyRange2", "$Sheet1.$B$1:$B$100",     3 },
    1769             :         { "MyRange3", "$Sheet1.$C$1:$C$100",     4 }
    1770           1 :     };
    1771             : 
    1772           1 :     CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "Sheet1"));
    1773             : 
    1774           1 :     m_pDoc->SetValue (0, 0, 0, 101);
    1775             : 
    1776           1 :     ScRangeName* pNames = new ScRangeName;
    1777           1 :     bool bSuccess = insertRangeNames(m_pDoc, pNames, aNames, aNames + SAL_N_ELEMENTS(aNames));
    1778           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess);
    1779           1 :     m_pDoc->SetRangeName(pNames);
    1780             : 
    1781           1 :     ScRangeName* pNewRanges = m_pDoc->GetRangeName();
    1782           1 :     CPPUNIT_ASSERT(pNewRanges);
    1783             : 
    1784             :     // Make sure the index lookup does the right thing.
    1785           5 :     for (size_t i = 0; i < SAL_N_ELEMENTS(aNames); ++i)
    1786             :     {
    1787           4 :         const ScRangeData* p = pNewRanges->findByIndex(aNames[i].mnIndex);
    1788           4 :         CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed.", p);
    1789           4 :         OUString aName = p->GetName();
    1790           4 :         CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved.", aName.equalsAscii(aNames[i].mpName));
    1791           4 :     }
    1792             : 
    1793             :     // Test usage in formula expression.
    1794           1 :     m_pDoc->SetString (1, 0, 0, "=A1/Divisor");
    1795           1 :     m_pDoc->CalcAll();
    1796             : 
    1797             :     double result;
    1798           1 :     m_pDoc->GetValue (1, 0, 0, result);
    1799           1 :     CPPUNIT_ASSERT_MESSAGE ("calculation failed", result == 1.0);
    1800             : 
    1801             :     // Test copy-ability of range names.
    1802           1 :     ScRangeName* pCopiedRanges = new ScRangeName(*pNewRanges);
    1803           1 :     m_pDoc->SetRangeName(pCopiedRanges);
    1804             :     // Make sure the index lookup still works.
    1805           5 :     for (size_t i = 0; i < SAL_N_ELEMENTS(aNames); ++i)
    1806             :     {
    1807           4 :         const ScRangeData* p = pCopiedRanges->findByIndex(aNames[i].mnIndex);
    1808           4 :         CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed with the copied instance.", p);
    1809           4 :         OUString aName = p->GetName();
    1810           4 :         CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved with the copied instance.", aName.equalsAscii(aNames[i].mpName));
    1811           4 :     }
    1812             : 
    1813           1 :     m_pDoc->SetRangeName(NULL); // Delete the names.
    1814           1 :     m_pDoc->DeleteTab(0);
    1815           1 : }
    1816             : 
    1817           1 : void Test::testInsertNameList()
    1818             : {
    1819           1 :     m_pDoc->InsertTab(0, "Test");
    1820             : 
    1821             :     RangeNameDef aNames[] = {
    1822             :         { "MyRange1", "$Test.$A$1:$A$100", 1 },
    1823             :         { "MyRange2", "$Test.$B$1:$B$100", 2 },
    1824             :         { "MyRange3", "$Test.$C$1:$C$100", 3 }
    1825           1 :     };
    1826             : 
    1827           1 :     ScRangeName* pNames = new ScRangeName;
    1828           1 :     bool bSuccess = insertRangeNames(m_pDoc, pNames, aNames, aNames + SAL_N_ELEMENTS(aNames));
    1829           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess);
    1830           1 :     m_pDoc->SetRangeName(pNames);
    1831             : 
    1832           1 :     ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
    1833           1 :     ScAddress aPos(1,1,0);
    1834           1 :     rDocFunc.InsertNameList(aPos, true);
    1835             : 
    1836           4 :     for (size_t i = 0; i < SAL_N_ELEMENTS(aNames); ++i, aPos.IncRow())
    1837             :     {
    1838           3 :         OUString aName = m_pDoc->GetString(aPos);
    1839           3 :         CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(aNames[i].mpName), aName);
    1840           3 :         ScAddress aExprPos = aPos;
    1841           3 :         aExprPos.IncCol();
    1842           6 :         OUString aExpr = m_pDoc->GetString(aExprPos);
    1843           6 :         OUString aExpected = "=";
    1844           3 :         aExpected += OUString::createFromAscii(aNames[i].mpExpr);
    1845           3 :         CPPUNIT_ASSERT_EQUAL(aExpected, aExpr);
    1846           3 :     }
    1847             : 
    1848           1 :     m_pDoc->DeleteTab(0);
    1849           1 : }
    1850             : 
    1851           1 : void Test::testCSV()
    1852             : {
    1853           1 :     const int English = 0, European = 1;
    1854             :     struct {
    1855             :         const char *pStr; int eSep; bool bResult; double nValue;
    1856             :     } aTests[] = {
    1857             :         { "foo",       English,  false, 0.0 },
    1858             :         { "1.0",       English,  true,  1.0 },
    1859             :         { "1,0",       English,  false, 0.0 },
    1860             :         { "1.0",       European, false, 0.0 },
    1861             :         { "1.000",     European, true,  1000.0 },
    1862             :         { "1,000",     European, true,  1.0 },
    1863             :         { "1.000",     English,  true,  1.0 },
    1864             :         { "1,000",     English,  true,  1000.0 },
    1865             :         { " 1.0",      English,  true,  1.0 },
    1866             :         { " 1.0  ",    English,  true,  1.0 },
    1867             :         { "1.0 ",      European, false, 0.0 },
    1868             :         { "1.000",     European, true,  1000.0 },
    1869             :         { "1137.999",  English,  true,  1137.999 },
    1870             :         { "1.000.00",  European, false, 0.0 }
    1871           1 :     };
    1872          15 :     for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(aTests); i++) {
    1873          14 :         OUString aStr(aTests[i].pStr, strlen (aTests[i].pStr), RTL_TEXTENCODING_UTF8);
    1874          14 :         double nValue = 0.0;
    1875             :         bool bResult = ScStringUtil::parseSimpleNumber
    1876          14 :                 (aStr, aTests[i].eSep == English ? '.' : ',',
    1877          14 :                  aTests[i].eSep == English ? ',' : '.',
    1878          28 :                  nValue);
    1879          14 :         CPPUNIT_ASSERT_MESSAGE ("CSV numeric detection failure", bResult == aTests[i].bResult);
    1880          14 :         CPPUNIT_ASSERT_MESSAGE ("CSV numeric value failure", nValue == aTests[i].nValue);
    1881          14 :     }
    1882           1 : }
    1883             : 
    1884             : template<typename Evaluator>
    1885           4 : void checkMatrixElements(const ScMatrix& rMat)
    1886             : {
    1887             :     SCSIZE nC, nR;
    1888           4 :     rMat.GetDimensions(nC, nR);
    1889             :     Evaluator aEval;
    1890          32 :     for (SCSIZE i = 0; i < nC; ++i)
    1891             :     {
    1892         508 :         for (SCSIZE j = 0; j < nR; ++j)
    1893             :         {
    1894         480 :             aEval(i, j, rMat.Get(i, j));
    1895             :         }
    1896             :     }
    1897           4 : }
    1898             : 
    1899             : struct AllZeroMatrix
    1900             : {
    1901          40 :     void operator() (SCSIZE /*nCol*/, SCSIZE /*nRow*/, const ScMatrixValue& rVal) const
    1902             :     {
    1903          40 :         CPPUNIT_ASSERT_MESSAGE("element is not of numeric type", rVal.nType == SC_MATVAL_VALUE);
    1904          40 :         CPPUNIT_ASSERT_MESSAGE("element value must be zero", rVal.fVal == 0.0);
    1905          40 :     }
    1906             : };
    1907             : 
    1908             : struct PartiallyFilledZeroMatrix
    1909             : {
    1910          40 :     void operator() (SCSIZE nCol, SCSIZE nRow, const ScMatrixValue& rVal) const
    1911             :     {
    1912          40 :         CPPUNIT_ASSERT_MESSAGE("element is not of numeric type", rVal.nType == SC_MATVAL_VALUE);
    1913          40 :         if (1 <= nCol && nCol <= 2 && 2 <= nRow && nRow <= 8)
    1914             :         {
    1915          14 :             CPPUNIT_ASSERT_MESSAGE("element value must be 3.0", rVal.fVal == 3.0);
    1916             :         }
    1917             :         else
    1918             :         {
    1919          26 :             CPPUNIT_ASSERT_MESSAGE("element value must be zero", rVal.fVal == 0.0);
    1920             :         }
    1921          40 :     }
    1922             : };
    1923             : 
    1924             : struct AllEmptyMatrix
    1925             : {
    1926         200 :     void operator() (SCSIZE /*nCol*/, SCSIZE /*nRow*/, const ScMatrixValue& rVal) const
    1927             :     {
    1928         200 :         CPPUNIT_ASSERT_MESSAGE("element is not of empty type", rVal.nType == SC_MATVAL_EMPTY);
    1929         200 :         CPPUNIT_ASSERT_MESSAGE("value of \"empty\" element is expected to be zero", rVal.fVal == 0.0);
    1930         200 :     }
    1931             : };
    1932             : 
    1933             : struct PartiallyFilledEmptyMatrix
    1934             : {
    1935         200 :     void operator() (SCSIZE nCol, SCSIZE nRow, const ScMatrixValue& rVal) const
    1936             :     {
    1937         200 :         if (nCol == 1 && nRow == 1)
    1938             :         {
    1939           1 :             CPPUNIT_ASSERT_MESSAGE("element is not of boolean type", rVal.nType == SC_MATVAL_BOOLEAN);
    1940           1 :             CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.fVal == 1.0);
    1941             :         }
    1942         199 :         else if (nCol == 4 && nRow == 5)
    1943             :         {
    1944           1 :             CPPUNIT_ASSERT_MESSAGE("element is not of value type", rVal.nType == SC_MATVAL_VALUE);
    1945           1 :             CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.fVal == -12.5);
    1946             :         }
    1947         198 :         else if (nCol == 8 && nRow == 2)
    1948             :         {
    1949           1 :             CPPUNIT_ASSERT_MESSAGE("element is not of value type", rVal.nType == SC_MATVAL_STRING);
    1950           1 :             CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.aStr.getString() == "Test");
    1951             :         }
    1952         197 :         else if (nCol == 8 && nRow == 11)
    1953             :         {
    1954           1 :             CPPUNIT_ASSERT_MESSAGE("element is not of empty path type", rVal.nType == SC_MATVAL_EMPTYPATH);
    1955           1 :             CPPUNIT_ASSERT_MESSAGE("value of \"empty\" element is expected to be zero", rVal.fVal == 0.0);
    1956             :         }
    1957             :         else
    1958             :         {
    1959         196 :             CPPUNIT_ASSERT_MESSAGE("element is not of empty type", rVal.nType == SC_MATVAL_EMPTY);
    1960         196 :             CPPUNIT_ASSERT_MESSAGE("value of \"empty\" element is expected to be zero", rVal.fVal == 0.0);
    1961             :         }
    1962         200 :     }
    1963             : };
    1964             : 
    1965           1 : void Test::testMatrix()
    1966             : {
    1967           1 :     svl::SharedStringPool& rPool = m_pDoc->GetSharedStringPool();
    1968           2 :     ScMatrixRef pMat, pMat2;
    1969             : 
    1970             :     // First, test the zero matrix type.
    1971           1 :     pMat = new ScMatrix(0, 0, 0.0);
    1972             :     SCSIZE nC, nR;
    1973           1 :     pMat->GetDimensions(nC, nR);
    1974           1 :     CPPUNIT_ASSERT_MESSAGE("matrix is not empty", nC == 0 && nR == 0);
    1975           1 :     pMat->Resize(4, 10, 0.0);
    1976           1 :     pMat->GetDimensions(nC, nR);
    1977           1 :     CPPUNIT_ASSERT_MESSAGE("matrix size is not as expected", nC == 4 && nR == 10);
    1978           2 :     CPPUNIT_ASSERT_MESSAGE("both 'and' and 'or' should evaluate to false",
    1979           1 :                            !pMat->And() && !pMat->Or());
    1980             : 
    1981             :     // Resizing into a larger matrix should fill the void space with zeros.
    1982           1 :     checkMatrixElements<AllZeroMatrix>(*pMat);
    1983             : 
    1984           1 :     pMat->FillDouble(3.0, 1, 2, 2, 8);
    1985           1 :     checkMatrixElements<PartiallyFilledZeroMatrix>(*pMat);
    1986           1 :     CPPUNIT_ASSERT_MESSAGE("matrix is expected to be numeric", pMat->IsNumeric());
    1987           2 :     CPPUNIT_ASSERT_MESSAGE("partially non-zero matrix should evaluate false on 'and' and true on 'or",
    1988           1 :                            !pMat->And() && pMat->Or());
    1989           1 :     pMat->FillDouble(5.0, 0, 0, nC-1, nR-1);
    1990           2 :     CPPUNIT_ASSERT_MESSAGE("fully non-zero matrix should evaluate true both on 'and' and 'or",
    1991           1 :                            pMat->And() && pMat->Or());
    1992             : 
    1993             :     // Test the AND and OR evaluations.
    1994           1 :     pMat = new ScMatrix(2, 2, 0.0);
    1995             : 
    1996             :     // Only some of the elements are non-zero.
    1997           1 :     pMat->PutBoolean(true, 0, 0);
    1998           1 :     pMat->PutDouble(1.0, 1, 1);
    1999           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat->Or());
    2000           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect AND result", !pMat->And());
    2001             : 
    2002             :     // All of the elements are non-zero.
    2003           1 :     pMat->PutBoolean(true, 0, 1);
    2004           1 :     pMat->PutDouble(2.3, 1, 0);
    2005           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat->Or());
    2006           1 :     CPPUNIT_ASSERT_MESSAGE("incorrect AND result", pMat->And());
    2007             : 
    2008             :     // Now test the emtpy matrix type.
    2009           1 :     pMat = new ScMatrix(10, 20);
    2010           1 :     pMat->GetDimensions(nC, nR);
    2011           1 :     CPPUNIT_ASSERT_MESSAGE("matrix size is not as expected", nC == 10 && nR == 20);
    2012           1 :     checkMatrixElements<AllEmptyMatrix>(*pMat);
    2013             : 
    2014           1 :     pMat->PutBoolean(true, 1, 1);
    2015           1 :     pMat->PutDouble(-12.5, 4, 5);
    2016           1 :     pMat->PutString(rPool.intern("Test"), 8, 2);
    2017           1 :     pMat->PutEmptyPath(8, 11);
    2018           1 :     checkMatrixElements<PartiallyFilledEmptyMatrix>(*pMat);
    2019             : 
    2020             :     // Test resizing.
    2021           1 :     pMat = new ScMatrix(0, 0);
    2022           1 :     pMat->Resize(2, 2, 1.5);
    2023           1 :     pMat->PutEmpty(1, 1);
    2024             : 
    2025           1 :     CPPUNIT_ASSERT_EQUAL(1.5, pMat->GetDouble(0, 0));
    2026           1 :     CPPUNIT_ASSERT_EQUAL(1.5, pMat->GetDouble(0, 1));
    2027           1 :     CPPUNIT_ASSERT_EQUAL(1.5, pMat->GetDouble(1, 0));
    2028           1 :     CPPUNIT_ASSERT_MESSAGE("PutEmpty() call failed.", pMat->IsEmpty(1, 1));
    2029             : 
    2030             :     // Max and min values.
    2031           1 :     pMat = new ScMatrix(2, 2, 0.0);
    2032           1 :     pMat->PutDouble(-10, 0, 0);
    2033           1 :     pMat->PutDouble(-12, 0, 1);
    2034           1 :     pMat->PutDouble(-8, 1, 0);
    2035           1 :     pMat->PutDouble(-25, 1, 1);
    2036           1 :     CPPUNIT_ASSERT_EQUAL(-25.0, pMat->GetMinValue(false));
    2037           1 :     CPPUNIT_ASSERT_EQUAL(-8.0, pMat->GetMaxValue(false));
    2038           1 :     pMat->PutString(rPool.intern("Test"), 0, 0);
    2039           1 :     CPPUNIT_ASSERT_EQUAL(0.0, pMat->GetMaxValue(true)); // text as zero.
    2040           1 :     CPPUNIT_ASSERT_EQUAL(-8.0, pMat->GetMaxValue(false)); // ignore text.
    2041           1 :     pMat->PutBoolean(true, 0, 0);
    2042           1 :     CPPUNIT_ASSERT_EQUAL(1.0, pMat->GetMaxValue(false));
    2043           1 :     pMat = new ScMatrix(2, 2, 10.0);
    2044           1 :     pMat->PutBoolean(false, 0, 0);
    2045           1 :     pMat->PutDouble(12.5, 1, 1);
    2046           1 :     CPPUNIT_ASSERT_EQUAL(0.0, pMat->GetMinValue(false));
    2047           1 :     CPPUNIT_ASSERT_EQUAL(12.5, pMat->GetMaxValue(false));
    2048             : 
    2049             :     // Convert matrix into a linear double array. String elements become NaN
    2050             :     // and empty elements become 0.
    2051           1 :     pMat = new ScMatrix(3, 3);
    2052           1 :     pMat->PutDouble(2.5, 0, 0);
    2053           1 :     pMat->PutDouble(1.2, 0, 1);
    2054           1 :     pMat->PutString(rPool.intern("A"), 1, 1);
    2055           1 :     pMat->PutDouble(2.3, 2, 1);
    2056           1 :     pMat->PutDouble(-20, 2, 2);
    2057             : 
    2058             :     double fNaN;
    2059           1 :     rtl::math::setNan(&fNaN);
    2060             : 
    2061           2 :     std::vector<double> aDoubles;
    2062           1 :     pMat->GetDoubleArray(aDoubles);
    2063             : 
    2064             :     {
    2065           1 :         const double pChecks[] = { 2.5, 1.2, 0, 0, fNaN, 0, 0, 2.3, -20 };
    2066           1 :         CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks), aDoubles.size());
    2067          10 :         for (size_t i = 0, n = aDoubles.size(); i < n; ++i)
    2068             :         {
    2069           9 :             if (rtl::math::isNan(pChecks[i]))
    2070           1 :                 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", rtl::math::isNan(aDoubles[i]));
    2071             :             else
    2072           8 :                 CPPUNIT_ASSERT_EQUAL(pChecks[i], aDoubles[i]);
    2073             :         }
    2074             :     }
    2075             : 
    2076           1 :     pMat2 = new ScMatrix(3, 3, 10.0);
    2077           1 :     pMat2->PutString(rPool.intern("B"), 1, 0);
    2078           1 :     pMat2->MergeDoubleArray(aDoubles, ScMatrix::Mul);
    2079             : 
    2080             :     {
    2081           1 :         const double pChecks[] = { 25, 12, 0, fNaN, fNaN, 0, 0, 23, -200 };
    2082           1 :         CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks), aDoubles.size());
    2083          10 :         for (size_t i = 0, n = aDoubles.size(); i < n; ++i)
    2084             :         {
    2085           9 :             if (rtl::math::isNan(pChecks[i]))
    2086           2 :                 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", rtl::math::isNan(aDoubles[i]));
    2087             :             else
    2088           7 :                 CPPUNIT_ASSERT_EQUAL(pChecks[i], aDoubles[i]);
    2089             :         }
    2090           1 :     }
    2091           1 : }
    2092             : 
    2093           1 : void Test::testEnterMixedMatrix()
    2094             : {
    2095           1 :     m_pDoc->InsertTab(0, "foo");
    2096             : 
    2097             :     // Insert the source values in A1:B2.
    2098           1 :     m_pDoc->SetString(0, 0, 0, "A");
    2099           1 :     m_pDoc->SetString(1, 0, 0, "B");
    2100           1 :     double val = 1.0;
    2101           1 :     m_pDoc->SetValue(0, 1, 0, val);
    2102           1 :     val = 2.0;
    2103           1 :     m_pDoc->SetValue(1, 1, 0, val);
    2104             : 
    2105             :     // Create a matrix range in A4:B5 referencing A1:B2.
    2106           1 :     ScMarkData aMark;
    2107           1 :     aMark.SelectOneTable(0);
    2108           1 :     m_pDoc->InsertMatrixFormula(0, 3, 1, 4, aMark, "=A1:B2", NULL);
    2109             : 
    2110           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,0,0), m_pDoc->GetString(0,3,0));
    2111           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(1,0,0), m_pDoc->GetString(1,3,0));
    2112           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(0,1,0), m_pDoc->GetValue(0,4,0));
    2113           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(1,1,0), m_pDoc->GetValue(1,4,0));
    2114             : 
    2115           1 :     m_pDoc->DeleteTab(0);
    2116           1 : }
    2117             : 
    2118           1 : void Test::testCellCopy()
    2119             : {
    2120           1 :     m_pDoc->InsertTab(0, "TestTab");
    2121           1 :     ScAddress aSrc(0,0,0);
    2122           1 :     ScAddress aDest(0,1,0);
    2123           1 :     OUString aStr("please copy me");
    2124           1 :     m_pDoc->SetString(aSrc, "please copy me");
    2125           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aSrc), aStr);
    2126             :     // copy to self - why not ?
    2127           1 :     m_pDoc->CopyCellToDocument(aSrc,aDest,*m_pDoc);
    2128           1 :     CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aDest), aStr);
    2129           1 : }
    2130             : 
    2131           1 : void Test::testSheetCopy()
    2132             : {
    2133           1 :     m_pDoc->InsertTab(0, "TestTab");
    2134           1 :     CPPUNIT_ASSERT_MESSAGE("document should have one sheet to begin with.", m_pDoc->GetTableCount() == 1);
    2135             : 
    2136             :     // Insert text in A1.
    2137           1 :     m_pDoc->SetString(ScAddress(0,0,0), "copy me");
    2138             : 
    2139             :     // Insert edit cells in B1:B3.
    2140           1 :     ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
    2141           1 :     rEE.SetText("Edit 1");
    2142           1 :     m_pDoc->SetEditText(ScAddress(1,0,0), rEE.CreateTextObject());
    2143           1 :     rEE.SetText("Edit 2");
    2144           1 :     m_pDoc->SetEditText(ScAddress(1,1,0), rEE.CreateTextObject());
    2145           1 :     rEE.SetText("Edit 3");
    2146           1 :     m_pDoc->SetEditText(ScAddress(1,2,0), rEE.CreateTextObject());
    2147             : 
    2148             :     SCROW nRow1, nRow2;
    2149           1 :     bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    2150           1 :     CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
    2151             : 
    2152             :     // insert a note
    2153           1 :     ScAddress aAdrA1 (0,2,0); // empty cell content.
    2154           1 :     ScPostIt *pNoteA1 = m_pDoc->GetOrCreateNote(aAdrA1);
    2155           1 :     pNoteA1->SetText(aAdrA1, "Hello world in A3");
    2156             : 
    2157             :     // Copy and test the result.
    2158           1 :     m_pDoc->CopyTab(0, 1);
    2159           1 :     CPPUNIT_ASSERT_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount() == 2);
    2160           1 :     bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
    2161           1 :     CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
    2162           1 :     CPPUNIT_ASSERT_MESSAGE("There should be note on A3 in new sheet", m_pDoc->HasNote(ScAddress(0,2,1)));
    2163           1 :     CPPUNIT_ASSERT_EQUAL(OUString("copy me"), m_pDoc->GetString(ScAddress(0,0,1)));
    2164             : 
    2165             :     // Check the copied edit cells.
    2166           1 :     const EditTextObject* pEditObj = m_pDoc->GetEditText(ScAddress(1,0,1));
    2167           1 :     CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B1.", pEditObj);
    2168           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Edit 1"), pEditObj->GetText(0));
    2169           1 :     pEditObj = m_pDoc->GetEditText(ScAddress(1,1,1));
    2170           1 :     CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B2.", pEditObj);
    2171           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Edit 2"), pEditObj->GetText(0));
    2172           1 :     pEditObj = m_pDoc->GetEditText(ScAddress(1,2,1));
    2173           1 :     CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B3.", pEditObj);
    2174           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Edit 3"), pEditObj->GetText(0));
    2175             : 
    2176           1 :     m_pDoc->DeleteTab(1);
    2177             : 
    2178           1 :     m_pDoc->SetRowHidden(5, 10, 0, true);
    2179           1 :     bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    2180           1 :     CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
    2181           1 :     bHidden = m_pDoc->RowHidden(5, 0, &nRow1, &nRow2);
    2182           1 :     CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
    2183           1 :     bHidden = m_pDoc->RowHidden(11, 0, &nRow1, &nRow2);
    2184           1 :     CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
    2185             : 
    2186             :     // Copy the sheet once again.
    2187           1 :     m_pDoc->CopyTab(0, 1);
    2188           1 :     CPPUNIT_ASSERT_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount() == 2);
    2189           1 :     bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
    2190           1 :     CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
    2191           1 :     bHidden = m_pDoc->RowHidden(5, 1, &nRow1, &nRow2);
    2192           1 :     CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
    2193           1 :     bHidden = m_pDoc->RowHidden(11, 1, &nRow1, &nRow2);
    2194           1 :     CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
    2195           1 :     m_pDoc->DeleteTab(1);
    2196           1 :     m_pDoc->DeleteTab(0);
    2197           1 : }
    2198             : 
    2199           1 : void Test::testSheetMove()
    2200             : {
    2201           1 :     m_pDoc->InsertTab(0, "TestTab1");
    2202           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.", m_pDoc->GetTableCount(), static_cast<SCTAB>(1));
    2203             :     SCROW nRow1, nRow2;
    2204           1 :     bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    2205           1 :     CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
    2206             : 
    2207             :     //test if inserting before another sheet works
    2208           1 :     m_pDoc->InsertTab(0, "TestTab2");
    2209           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have two sheets", m_pDoc->GetTableCount(), static_cast<SCTAB>(2));
    2210           1 :     bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    2211           1 :     CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
    2212             : 
    2213             :     // Move and test the result.
    2214           1 :     m_pDoc->MoveTab(0, 1);
    2215           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount(), static_cast<SCTAB>(2));
    2216           1 :     bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
    2217           1 :     CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
    2218           1 :     OUString aName;
    2219           1 :     m_pDoc->GetName(0, aName);
    2220           1 :     CPPUNIT_ASSERT_MESSAGE( "sheets should have changed places", aName == "TestTab1" );
    2221             : 
    2222           1 :     m_pDoc->SetRowHidden(5, 10, 0, true);
    2223           1 :     bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    2224           1 :     CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
    2225           1 :     bHidden = m_pDoc->RowHidden(5, 0, &nRow1, &nRow2);
    2226           1 :     CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
    2227           1 :     bHidden = m_pDoc->RowHidden(11, 0, &nRow1, &nRow2);
    2228           1 :     CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
    2229             : 
    2230             :     // Move the sheet once again.
    2231           1 :     m_pDoc->MoveTab(1, 0);
    2232           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount(), static_cast<SCTAB>(2));
    2233           1 :     bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
    2234           1 :     CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
    2235           1 :     bHidden = m_pDoc->RowHidden(5, 1, &nRow1, &nRow2);
    2236           1 :     CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
    2237           1 :     bHidden = m_pDoc->RowHidden(11, 1, &nRow1, &nRow2);
    2238           1 :     CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
    2239           1 :     m_pDoc->GetName(0, aName);
    2240           1 :     CPPUNIT_ASSERT_MESSAGE( "sheets should have changed places", aName == "TestTab2" );
    2241           1 :     m_pDoc->DeleteTab(1);
    2242           1 :     m_pDoc->DeleteTab(0);
    2243           1 : }
    2244             : 
    2245           1 : void Test::testDataArea()
    2246             : {
    2247           1 :     m_pDoc->InsertTab(0, "Data");
    2248             : 
    2249             :     // Totally empty sheet should be rightfully considered empty in all accounts.
    2250           1 :     CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc->IsPrintEmpty(0, 0, 0, 100, 100));
    2251           1 :     CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100));
    2252             : 
    2253             :     // Now, set borders in some cells....
    2254           1 :     ::editeng::SvxBorderLine aLine(NULL, 50, table::BorderLineStyle::SOLID);
    2255           1 :     SvxBoxItem aBorderItem(ATTR_BORDER);
    2256           1 :     aBorderItem.SetLine(&aLine, BOX_LINE_LEFT);
    2257           1 :     aBorderItem.SetLine(&aLine, BOX_LINE_RIGHT);
    2258         101 :     for (SCROW i = 0; i < 100; ++i)
    2259             :         // Set borders from row 1 to 100.
    2260         100 :         m_pDoc->ApplyAttr(0, i, 0, aBorderItem);
    2261             : 
    2262             :     // Now the sheet is considered non-empty for printing purposes, but still
    2263             :     // be empty in all the other cases.
    2264           2 :     CPPUNIT_ASSERT_MESSAGE("Empty sheet with borders should be printable.",
    2265           1 :                            !m_pDoc->IsPrintEmpty(0, 0, 0, 100, 100));
    2266           2 :     CPPUNIT_ASSERT_MESSAGE("But it should still be considered empty in all the other cases.",
    2267           1 :                            m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100));
    2268             : 
    2269             :     // Adding a real cell content should turn the block non-empty.
    2270           1 :     m_pDoc->SetString(0, 0, 0, "Some text");
    2271           2 :     CPPUNIT_ASSERT_MESSAGE("Now the block should not be empty with a real cell content.",
    2272           1 :                            !m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100));
    2273             : 
    2274             :     // TODO: Add more tests for normal data area calculation.
    2275             : 
    2276           1 :     m_pDoc->DeleteTab(0);
    2277           1 : }
    2278             : 
    2279           1 : void Test::testStreamValid()
    2280             : {
    2281           1 :     m_pDoc->InsertTab(0, "Sheet1");
    2282           1 :     m_pDoc->InsertTab(1, "Sheet2");
    2283           1 :     m_pDoc->InsertTab(2, "Sheet3");
    2284           1 :     m_pDoc->InsertTab(3, "Sheet4");
    2285           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have 4 sheet instances.", m_pDoc->GetTableCount(), static_cast<SCTAB>(4));
    2286             : 
    2287           1 :     OUString a1("A1");
    2288           2 :     OUString a2("A2");
    2289           2 :     OUString test;
    2290             : 
    2291             :     // Put values into Sheet1.
    2292           1 :     m_pDoc->SetString(0, 0, 0, a1);
    2293           1 :     m_pDoc->SetString(0, 1, 0, a2);
    2294           1 :     test = m_pDoc->GetString(0, 0, 0);
    2295           1 :     CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet1.A1", test.equals(a1));
    2296           1 :     test = m_pDoc->GetString(0, 1, 0);
    2297           1 :     CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet1.A2", test.equals(a2));
    2298             : 
    2299             :     // Put formulas into Sheet2 to Sheet4 to reference values from Sheet1.
    2300           1 :     m_pDoc->SetString(0, 0, 1, "=Sheet1.A1");
    2301           1 :     m_pDoc->SetString(0, 1, 1, "=Sheet1.A2");
    2302           1 :     m_pDoc->SetString(0, 0, 2, "=Sheet1.A1");
    2303           1 :     m_pDoc->SetString(0, 0, 3, "=Sheet1.A2");
    2304             : 
    2305           1 :     test = m_pDoc->GetString(0, 0, 1);
    2306           1 :     CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet2.A1", test.equals(a1));
    2307           1 :     test = m_pDoc->GetString(0, 1, 1);
    2308           1 :     CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet2.A2", test.equals(a2));
    2309           1 :     test = m_pDoc->GetString(0, 0, 2);
    2310           1 :     CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet3.A1", test.equals(a1));
    2311           1 :     test = m_pDoc->GetString(0, 0, 3);
    2312           1 :     CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet3.A1", test.equals(a2));
    2313             : 
    2314             :     // Set all sheet streams valid after all the initial cell values are in
    2315             :     // place. In reality we need to have real XML streams stored in order to
    2316             :     // claim they are valid, but we are just testing the flag values here.
    2317           1 :     m_pDoc->SetStreamValid(0, true);
    2318           1 :     m_pDoc->SetStreamValid(1, true);
    2319           1 :     m_pDoc->SetStreamValid(2, true);
    2320           1 :     m_pDoc->SetStreamValid(3, true);
    2321           1 :     CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(0));
    2322           1 :     CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(1));
    2323           1 :     CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(2));
    2324           1 :     CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(3));
    2325             : 
    2326             :     // Now, insert a new row at row 2 position on Sheet1.  This will move cell
    2327             :     // A2 downward but cell A1 remains unmoved.
    2328           1 :     m_pDoc->InsertRow(0, 0, MAXCOL, 0, 1, 2);
    2329           1 :     test = m_pDoc->GetString(0, 0, 0);
    2330           1 :     CPPUNIT_ASSERT_MESSAGE("Cell A1 should not have moved.", test.equals(a1));
    2331           1 :     test = m_pDoc->GetString(0, 3, 0);
    2332           1 :     CPPUNIT_ASSERT_MESSAGE("the old cell A2 should now be at A4.", test.equals(a2));
    2333           2 :     ScRefCellValue aCell;
    2334           1 :     aCell.assign(*m_pDoc, ScAddress(0,1,0));
    2335           1 :     CPPUNIT_ASSERT_MESSAGE("Cell A2 should be empty.", aCell.isEmpty());
    2336           1 :     aCell.assign(*m_pDoc, ScAddress(0,2,0));
    2337           1 :     CPPUNIT_ASSERT_MESSAGE("Cell A3 should be empty.", aCell.isEmpty());
    2338             : 
    2339             :     // After the move, Sheet1, Sheet2, and Sheet4 should have their stream
    2340             :     // invalidated, whereas Sheet3's stream should still be valid.
    2341           1 :     CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc->IsStreamValid(0));
    2342           1 :     CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc->IsStreamValid(1));
    2343           1 :     CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc->IsStreamValid(3));
    2344           1 :     CPPUNIT_ASSERT_MESSAGE("Stream should still be valid.", m_pDoc->IsStreamValid(2));
    2345             : 
    2346           1 :     m_pDoc->DeleteTab(3);
    2347           1 :     m_pDoc->DeleteTab(2);
    2348           1 :     m_pDoc->DeleteTab(1);
    2349           2 :     m_pDoc->DeleteTab(0);
    2350           1 : }
    2351             : 
    2352           1 : void Test::testFunctionLists()
    2353             : {
    2354             :     const char* aDataBase[] = {
    2355             :         "DAVERAGE",
    2356             :         "DCOUNT",
    2357             :         "DCOUNTA",
    2358             :         "DGET",
    2359             :         "DMAX",
    2360             :         "DMIN",
    2361             :         "DPRODUCT",
    2362             :         "DSTDEV",
    2363             :         "DSTDEVP",
    2364             :         "DSUM",
    2365             :         "DVAR",
    2366             :         "DVARP",
    2367             :         0
    2368           1 :     };
    2369             : 
    2370             :     const char* aDateTime[] = {
    2371             :         "DATE",
    2372             :         "DATEDIF",
    2373             :         "DATEVALUE",
    2374             :         "DAY",
    2375             :         "DAYS",
    2376             :         "DAYS360",
    2377             :         "EASTERSUNDAY",
    2378             :         "HOUR",
    2379             :         "MINUTE",
    2380             :         "MONTH",
    2381             :         "NETWORKDAYS.INTL",
    2382             :         "NOW",
    2383             :         "SECOND",
    2384             :         "TIME",
    2385             :         "TIMEVALUE",
    2386             :         "TODAY",
    2387             :         "WEEKDAY",
    2388             :         "WEEKNUM",
    2389             :         "WORKDAY.INTL",
    2390             :         "YEAR",
    2391             :         0
    2392           1 :     };
    2393             : 
    2394             :     const char* aFinancial[] = {
    2395             :         "CUMIPMT",
    2396             :         "CUMPRINC",
    2397             :         "DB",
    2398             :         "DDB",
    2399             :         "DURATION",
    2400             :         "EFFECTIVE",
    2401             :         "FV",
    2402             :         "IPMT",
    2403             :         "IRR",
    2404             :         "ISPMT",
    2405             :         "MIRR",
    2406             :         "NOMINAL",
    2407             :         "NPER",
    2408             :         "NPV",
    2409             :         "PMT",
    2410             :         "PPMT",
    2411             :         "PV",
    2412             :         "RATE",
    2413             :         "RRI",
    2414             :         "SLN",
    2415             :         "SYD",
    2416             :         "VDB",
    2417             :         0
    2418           1 :     };
    2419             : 
    2420             :     const char* aInformation[] = {
    2421             :         "CELL",
    2422             :         "CURRENT",
    2423             :         "FORMULA",
    2424             :         "INFO",
    2425             :         "ISBLANK",
    2426             :         "ISERR",
    2427             :         "ISERROR",
    2428             :         "ISFORMULA",
    2429             :         "ISLOGICAL",
    2430             :         "ISNA",
    2431             :         "ISNONTEXT",
    2432             :         "ISNUMBER",
    2433             :         "ISREF",
    2434             :         "ISTEXT",
    2435             :         "N",
    2436             :         "NA",
    2437             :         "TYPE",
    2438             :         0
    2439           1 :     };
    2440             : 
    2441             :     const char* aLogical[] = {
    2442             :         "AND",
    2443             :         "FALSE",
    2444             :         "IF",
    2445             :         "IFERROR",
    2446             :         "IFNA",
    2447             :         "NOT",
    2448             :         "OR",
    2449             :         "TRUE",
    2450             :         "XOR",
    2451             :         0
    2452           1 :     };
    2453             : 
    2454             :     const char* aMathematical[] = {
    2455             :         "ABS",
    2456             :         "ACOS",
    2457             :         "ACOSH",
    2458             :         "ACOT",
    2459             :         "ACOTH",
    2460             :         "ASIN",
    2461             :         "ASINH",
    2462             :         "ATAN",
    2463             :         "ATAN2",
    2464             :         "ATANH",
    2465             :         "BITAND",
    2466             :         "BITLSHIFT",
    2467             :         "BITOR",
    2468             :         "BITRSHIFT",
    2469             :         "BITXOR",
    2470             :         "CEILING",
    2471             :         "CEILING.PRECISE",
    2472             :         "COMBIN",
    2473             :         "COMBINA",
    2474             :         "CONVERT",
    2475             :         "COS",
    2476             :         "COSH",
    2477             :         "COT",
    2478             :         "COTH",
    2479             :         "CSC",
    2480             :         "CSCH",
    2481             :         "DEGREES",
    2482             :         "EUROCONVERT",
    2483             :         "EVEN",
    2484             :         "EXP",
    2485             :         "FACT",
    2486             :         "FLOOR",
    2487             :         "FLOOR.PRECISE",
    2488             :         "GCD",
    2489             :         "INT",
    2490             :         "ISEVEN",
    2491             :         "ISO.CEILING",
    2492             :         "ISODD",
    2493             :         "LCM",
    2494             :         "LN",
    2495             :         "LOG",
    2496             :         "LOG10",
    2497             :         "MOD",
    2498             :         "ODD",
    2499             :         "PI",
    2500             :         "POWER",
    2501             :         "PRODUCT",
    2502             :         "RADIANS",
    2503             :         "RAND",
    2504             :         "ROUND",
    2505             :         "ROUNDDOWN",
    2506             :         "ROUNDUP",
    2507             :         "SEC",
    2508             :         "SECH",
    2509             :         "SIGN",
    2510             :         "SIN",
    2511             :         "SINH",
    2512             :         "SQRT",
    2513             :         "SUBTOTAL",
    2514             :         "SUM",
    2515             :         "SUMIF",
    2516             :         "SUMIFS",
    2517             :         "SUMSQ",
    2518             :         "TAN",
    2519             :         "TANH",
    2520             :         "TRUNC",
    2521             :         0
    2522           1 :     };
    2523             : 
    2524             :     const char* aArray[] = {
    2525             :         "FREQUENCY",
    2526             :         "GROWTH",
    2527             :         "LINEST",
    2528             :         "LOGEST",
    2529             :         "MDETERM",
    2530             :         "MINVERSE",
    2531             :         "MMULT",
    2532             :         "MUNIT",
    2533             :         "SUMPRODUCT",
    2534             :         "SUMX2MY2",
    2535             :         "SUMX2PY2",
    2536             :         "SUMXMY2",
    2537             :         "TRANSPOSE",
    2538             :         "TREND",
    2539             :         0
    2540           1 :     };
    2541             : 
    2542             :     const char* aStatistical[] = {
    2543             :         "AVEDEV",
    2544             :         "AVERAGE",
    2545             :         "AVERAGEA",
    2546             :         "AVERAGEIF",
    2547             :         "AVERAGEIFS",
    2548             :         "B",
    2549             :         "BETA.DIST",
    2550             :         "BETA.INV",
    2551             :         "BETADIST",
    2552             :         "BETAINV",
    2553             :         "BINOM.DIST",
    2554             :         "BINOM.INV",
    2555             :         "BINOMDIST",
    2556             :         "CHIDIST",
    2557             :         "CHIINV",
    2558             :         "CHISQ.DIST",
    2559             :         "CHISQ.DIST.RT",
    2560             :         "CHISQ.INV",
    2561             :         "CHISQ.INV.RT",
    2562             :         "CHISQ.TEST",
    2563             :         "CHISQDIST",
    2564             :         "CHISQINV",
    2565             :         "CHITEST",
    2566             :         "CONFIDENCE",
    2567             :         "CONFIDENCE.NORM",
    2568             :         "CONFIDENCE.T",
    2569             :         "CORREL",
    2570             :         "COUNT",
    2571             :         "COUNTA",
    2572             :         "COUNTBLANK",
    2573             :         "COUNTIF",
    2574             :         "COUNTIFS",
    2575             :         "COVAR",
    2576             :         "COVARIANCE.P",
    2577             :         "COVARIANCE.S",
    2578             :         "CRITBINOM",
    2579             :         "DEVSQ",
    2580             :         "EXPON.DIST",
    2581             :         "EXPONDIST",
    2582             :         "F.DIST",
    2583             :         "F.DIST.RT",
    2584             :         "F.INV",
    2585             :         "F.INV.RT",
    2586             :         "F.TEST",
    2587             :         "FDIST",
    2588             :         "FINV",
    2589             :         "FISHER",
    2590             :         "FISHERINV",
    2591             :         "FORECAST",
    2592             :         "FTEST",
    2593             :         "GAMMA",
    2594             :         "GAMMA.DIST",
    2595             :         "GAMMA.INV",
    2596             :         "GAMMADIST",
    2597             :         "GAMMAINV",
    2598             :         "GAMMALN",
    2599             :         "GAMMALN.PRECISE",
    2600             :         "GAUSS",
    2601             :         "GEOMEAN",
    2602             :         "HARMEAN",
    2603             :         "HYPGEOM.DIST",
    2604             :         "HYPGEOMDIST",
    2605             :         "INTERCEPT",
    2606             :         "KURT",
    2607             :         "LARGE",
    2608             :         "LOGINV",
    2609             :         "LOGNORM.DIST",
    2610             :         "LOGNORM.INV",
    2611             :         "LOGNORMDIST",
    2612             :         "MAX",
    2613             :         "MAXA",
    2614             :         "MEDIAN",
    2615             :         "MIN",
    2616             :         "MINA",
    2617             :         "MODE",
    2618             :         "MODE.MULT",
    2619             :         "MODE.SNGL",
    2620             :         "NEGBINOM.DIST",
    2621             :         "NEGBINOMDIST",
    2622             :         "NORM.DIST",
    2623             :         "NORM.INV",
    2624             :         "NORM.S.DIST",
    2625             :         "NORM.S.INV",
    2626             :         "NORMDIST",
    2627             :         "NORMINV",
    2628             :         "NORMSDIST",
    2629             :         "NORMSINV",
    2630             :         "PEARSON",
    2631             :         "PERCENTILE",
    2632             :         "PERCENTILE.EXC",
    2633             :         "PERCENTILE.INC",
    2634             :         "PERCENTRANK",
    2635             :         "PERCENTRANK.EXC",
    2636             :         "PERCENTRANK.INC",
    2637             :         "PERMUT",
    2638             :         "PERMUTATIONA",
    2639             :         "PHI",
    2640             :         "POISSON",
    2641             :         "POISSON.DIST",
    2642             :         "PROB",
    2643             :         "QUARTILE",
    2644             :         "QUARTILE.EXC",
    2645             :         "QUARTILE.INC",
    2646             :         "RANK",
    2647             :         "RANK.AVG",
    2648             :         "RANK.EQ",
    2649             :         "RSQ",
    2650             :         "SKEW",
    2651             :         "SKEWP",
    2652             :         "SLOPE",
    2653             :         "SMALL",
    2654             :         "STANDARDIZE",
    2655             :         "STDEV",
    2656             :         "STDEV.P",
    2657             :         "STDEV.S",
    2658             :         "STDEVA",
    2659             :         "STDEVP",
    2660             :         "STDEVPA",
    2661             :         "STEYX",
    2662             :         "T.DIST",
    2663             :         "T.DIST.2T",
    2664             :         "T.DIST.RT",
    2665             :         "T.INV",
    2666             :         "T.INV.2T",
    2667             :         "T.TEST",
    2668             :         "TDIST",
    2669             :         "TINV",
    2670             :         "TRIMMEAN",
    2671             :         "TTEST",
    2672             :         "VAR",
    2673             :         "VAR.P",
    2674             :         "VAR.S",
    2675             :         "VARA",
    2676             :         "VARP",
    2677             :         "VARPA",
    2678             :         "WEIBULL",
    2679             :         "WEIBULL.DIST",
    2680             :         "Z.TEST",
    2681             :         "ZTEST",
    2682             :         0
    2683           1 :     };
    2684             : 
    2685             :     const char* aSpreadsheet[] = {
    2686             :         "ADDRESS",
    2687             :         "AREAS",
    2688             :         "CHOOSE",
    2689             :         "COLUMN",
    2690             :         "COLUMNS",
    2691             :         "DDE",
    2692             :         "ERRORTYPE",
    2693             :         "GETPIVOTDATA",
    2694             :         "HLOOKUP",
    2695             :         "HYPERLINK",
    2696             :         "INDEX",
    2697             :         "INDIRECT",
    2698             :         "LOOKUP",
    2699             :         "MATCH",
    2700             :         "OFFSET",
    2701             :         "ROW",
    2702             :         "ROWS",
    2703             :         "SHEET",
    2704             :         "SHEETS",
    2705             :         "STYLE",
    2706             :         "VLOOKUP",
    2707             :         0
    2708           1 :     };
    2709             : 
    2710             :     const char* aText[] = {
    2711             :         "ARABIC",
    2712             :         "ASC",
    2713             :         "BAHTTEXT",
    2714             :         "BASE",
    2715             :         "CHAR",
    2716             :         "CLEAN",
    2717             :         "CODE",
    2718             :         "CONCATENATE",
    2719             :         "DECIMAL",
    2720             :         "DOLLAR",
    2721             :         "EXACT",
    2722             :         "FILTERXML",
    2723             :         "FIND",
    2724             :         "FIXED",
    2725             :         "JIS",
    2726             :         "LEFT",
    2727             :         "LEFTB",
    2728             :         "LEN",
    2729             :         "LENB",
    2730             :         "LOWER",
    2731             :         "MID",
    2732             :         "MIDB",
    2733             :         "NUMBERVALUE",
    2734             :         "PROPER",
    2735             :         "REPLACE",
    2736             :         "REPT",
    2737             :         "RIGHT",
    2738             :         "RIGHTB",
    2739             :         "ROMAN",
    2740             :         "SEARCH",
    2741             :         "SUBSTITUTE",
    2742             :         "T",
    2743             :         "TEXT",
    2744             :         "TRIM",
    2745             :         "UNICHAR",
    2746             :         "UNICODE",
    2747             :         "UPPER",
    2748             :         "VALUE",
    2749             :         "WEBSERVICE",
    2750             :         0
    2751           1 :     };
    2752             : 
    2753             :     struct {
    2754             :         const char* Category; const char** Functions;
    2755             :     } aTests[] = {
    2756             :         { "Database",     aDataBase },
    2757             :         { "Date&Time",    aDateTime },
    2758             :         { "Financial",    aFinancial },
    2759             :         { "Information",  aInformation },
    2760             :         { "Logical",      aLogical },
    2761             :         { "Mathematical", aMathematical },
    2762             :         { "Array",        aArray },
    2763             :         { "Statistical",  aStatistical },
    2764             :         { "Spreadsheet",  aSpreadsheet },
    2765             :         { "Text",         aText },
    2766             :         { "Add-in",       0 },
    2767             :         { 0, 0 }
    2768           1 :     };
    2769             : 
    2770           1 :     ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr();
    2771           1 :     sal_uInt32 n = pFuncMgr->getCount();
    2772          12 :     for (sal_uInt32 i = 0; i < n; ++i)
    2773             :     {
    2774          11 :         const formula::IFunctionCategory* pCat = pFuncMgr->getCategory(i);
    2775          11 :         CPPUNIT_ASSERT_MESSAGE("Unexpected category name", pCat->getName().equalsAscii(aTests[i].Category));
    2776          11 :         sal_uInt32 nFuncCount = pCat->getCount();
    2777         370 :         for (sal_uInt32 j = 0; j < nFuncCount; ++j)
    2778             :         {
    2779         359 :             const formula::IFunctionDescription* pFunc = pCat->getFunction(j);
    2780         359 :             CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected function name", OUString::createFromAscii(aTests[i].Functions[j]), pFunc->getFunctionName());
    2781             :         }
    2782             :     }
    2783           1 : }
    2784             : 
    2785           1 : void Test::testGraphicsInGroup()
    2786             : {
    2787           1 :     m_pDoc->InsertTab(0, "TestTab");
    2788           1 :     CPPUNIT_ASSERT_MESSAGE("document should have one sheet to begin with.", m_pDoc->GetTableCount() == 1);
    2789             :     SCROW nRow1, nRow2;
    2790           1 :     bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    2791           1 :     CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
    2792             : 
    2793           1 :     m_pDoc->InitDrawLayer();
    2794           1 :     ScDrawLayer *pDrawLayer = m_pDoc->GetDrawLayer();
    2795           1 :     CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer != NULL);
    2796           1 :     SdrPage* pPage = pDrawLayer->GetPage(0);
    2797           1 :     CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage != NULL);
    2798             : 
    2799             :     {
    2800             :         //Add a square
    2801           1 :         Rectangle aOrigRect(2,2,100,100);
    2802           1 :         SdrRectObj *pObj = new SdrRectObj(aOrigRect);
    2803           1 :         pPage->InsertObject(pObj);
    2804           1 :         const Rectangle &rNewRect = pObj->GetLogicRect();
    2805           1 :         CPPUNIT_ASSERT_MESSAGE("must have equal position and size", aOrigRect == rNewRect);
    2806             : 
    2807           1 :         ScDrawLayer::SetPageAnchored(*pObj);
    2808             : 
    2809             :         //Use a range of rows guaranteed to include all of the square
    2810           1 :         m_pDoc->ShowRows(0, 100, 0, false);
    2811           1 :         m_pDoc->SetDrawPageSize(0);
    2812           1 :         CPPUNIT_ASSERT_MESSAGE("Should not change when page anchored", aOrigRect == rNewRect);
    2813           1 :         m_pDoc->ShowRows(0, 100, 0, true);
    2814           1 :         m_pDoc->SetDrawPageSize(0);
    2815           1 :         CPPUNIT_ASSERT_MESSAGE("Should not change when page anchored", aOrigRect == rNewRect);
    2816             : 
    2817           1 :         ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
    2818           1 :         CPPUNIT_ASSERT_MESSAGE("That shouldn't change size or positioning", aOrigRect == rNewRect);
    2819             : 
    2820           1 :         m_pDoc->ShowRows(0, 100, 0, false);
    2821           1 :         m_pDoc->SetDrawPageSize(0);
    2822           2 :         CPPUNIT_ASSERT_MESSAGE("Left and Right should be unchanged",
    2823           1 :             aOrigRect.Left() == rNewRect.Left() && aOrigRect.Right() == rNewRect.Right());
    2824           2 :         CPPUNIT_ASSERT_MESSAGE("Height should be minimum allowed height",
    2825           1 :             (rNewRect.Bottom() - rNewRect.Top()) <= 1);
    2826           1 :         m_pDoc->ShowRows(0, 100, 0, true);
    2827           1 :         m_pDoc->SetDrawPageSize(0);
    2828           1 :         CPPUNIT_ASSERT_MESSAGE("Should not change when page anchored", aOrigRect == rNewRect);
    2829             :     }
    2830             : 
    2831             :     {
    2832             :         // Add a circle.
    2833           1 :         Rectangle aOrigRect = Rectangle(10,10,210,210); // 200 x 200
    2834           1 :         SdrCircObj* pObj = new SdrCircObj(OBJ_CIRC, aOrigRect);
    2835           1 :         pPage->InsertObject(pObj);
    2836           1 :         const Rectangle& rNewRect = pObj->GetLogicRect();
    2837           2 :         CPPUNIT_ASSERT_MESSAGE("Position and size of the circle shouldn't change when inserted into the page.",
    2838           1 :                                aOrigRect == rNewRect);
    2839             : 
    2840           1 :         ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
    2841           2 :         CPPUNIT_ASSERT_MESSAGE("Size changed when cell anchored. Not good.",
    2842           1 :                                aOrigRect == rNewRect);
    2843             : 
    2844             :         // Insert 2 rows at the top.  This should push the circle object down.
    2845           1 :         m_pDoc->InsertRow(0, 0, MAXCOL, 0, 0, 2);
    2846           1 :         m_pDoc->SetDrawPageSize(0);
    2847             : 
    2848             :         // Make sure the size of the circle is still identical.
    2849           2 :         CPPUNIT_ASSERT_MESSAGE("Size of the circle has changed, but shouldn't!",
    2850           1 :                                aOrigRect.GetSize() == rNewRect.GetSize());
    2851             : 
    2852             :         // Delete 2 rows at the top.  This should bring the circle object to its original position.
    2853           1 :         m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 0, 2);
    2854           1 :         m_pDoc->SetDrawPageSize(0);
    2855           1 :         CPPUNIT_ASSERT_MESSAGE("Failed to move back to its original position.", aOrigRect == rNewRect);
    2856             :     }
    2857             : 
    2858             :     {
    2859             :         // Add a line.
    2860           1 :         basegfx::B2DPolygon aTempPoly;
    2861           1 :         Point aStartPos(10,300), aEndPos(110,200); // bottom-left to top-right.
    2862           1 :         Rectangle aOrigRect(10,200,110,300); // 100 x 100
    2863           1 :         aTempPoly.append(basegfx::B2DPoint(aStartPos.X(), aStartPos.Y()));
    2864           1 :         aTempPoly.append(basegfx::B2DPoint(aEndPos.X(), aEndPos.Y()));
    2865           1 :         SdrPathObj* pObj = new SdrPathObj(OBJ_LINE, basegfx::B2DPolyPolygon(aTempPoly));
    2866           1 :         pObj->NbcSetLogicRect(aOrigRect);
    2867           1 :         pPage->InsertObject(pObj);
    2868           1 :         const Rectangle& rNewRect = pObj->GetLogicRect();
    2869           1 :         CPPUNIT_ASSERT_MESSAGE("Size differ.", aOrigRect == rNewRect);
    2870             : 
    2871           1 :         ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
    2872           2 :         CPPUNIT_ASSERT_MESSAGE("Size changed when cell-anchored. Not good.",
    2873           1 :                                aOrigRect == rNewRect);
    2874             : 
    2875             :         // Insert 2 rows at the top and delete them immediately.
    2876           1 :         m_pDoc->InsertRow(0, 0, MAXCOL, 0, 0, 2);
    2877           1 :         m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 0, 2);
    2878           1 :         m_pDoc->SetDrawPageSize(0);
    2879           2 :         CPPUNIT_ASSERT_MESSAGE("Size of a line object changed after row insertion and removal.",
    2880           1 :                                aOrigRect == rNewRect);
    2881             : 
    2882           1 :         sal_Int32 n = pObj->GetPointCount();
    2883           1 :         CPPUNIT_ASSERT_MESSAGE("There should be exactly 2 points in a line object.", n == 2);
    2884           2 :         CPPUNIT_ASSERT_MESSAGE("Line shape has changed.",
    2885           2 :                                aStartPos == pObj->GetPoint(0) && aEndPos == pObj->GetPoint(1));
    2886             :     }
    2887             : 
    2888           1 :     m_pDoc->DeleteTab(0);
    2889           1 : }
    2890             : 
    2891           1 : void Test::testGraphicsOnSheetMove()
    2892             : {
    2893           1 :     m_pDoc->InsertTab(0, "Tab1");
    2894           1 :     m_pDoc->InsertTab(1, "Tab2");
    2895           1 :     CPPUNIT_ASSERT_MESSAGE("There should be only 2 sheets to begin with", m_pDoc->GetTableCount() == 2);
    2896             : 
    2897           1 :     m_pDoc->InitDrawLayer();
    2898           1 :     ScDrawLayer* pDrawLayer = m_pDoc->GetDrawLayer();
    2899           1 :     CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer);
    2900           1 :     SdrPage* pPage = pDrawLayer->GetPage(0);
    2901           1 :     CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage);
    2902             : 
    2903             :     // Insert an object.
    2904           1 :     Rectangle aObjRect(2,2,100,100);
    2905           1 :     SdrObject* pObj = new SdrRectObj(aObjRect);
    2906           1 :     pPage->InsertObject(pObj);
    2907           1 :     ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
    2908             : 
    2909           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one object on the 1st sheet.", pPage->GetObjCount(), static_cast<sal_uIntPtr>(1));
    2910             : 
    2911           1 :     const ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj);
    2912           1 :     CPPUNIT_ASSERT_MESSAGE("Object meta-data doesn't exist.", pData);
    2913           1 :     CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 0 && pData->maEnd.Tab() == 0);
    2914             : 
    2915           1 :     pPage = pDrawLayer->GetPage(1);
    2916           1 :     CPPUNIT_ASSERT_MESSAGE("No page instance for the 2nd sheet.", pPage);
    2917           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet shouldn't have any object.", pPage->GetObjCount(), static_cast<sal_uIntPtr>(0));
    2918             : 
    2919             :     // Insert a new sheet at left-end, and make sure the object has moved to
    2920             :     // the 2nd page.
    2921           1 :     m_pDoc->InsertTab(0, "NewTab");
    2922           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 3 sheets.", m_pDoc->GetTableCount(), static_cast<SCTAB>(3));
    2923           1 :     pPage = pDrawLayer->GetPage(0);
    2924           1 :     CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage && pPage->GetObjCount() == 0);
    2925           1 :     pPage = pDrawLayer->GetPage(1);
    2926           1 :     CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage && pPage->GetObjCount() == 1);
    2927           1 :     pPage = pDrawLayer->GetPage(2);
    2928           1 :     CPPUNIT_ASSERT_MESSAGE("3rd sheet should have no object.", pPage && pPage->GetObjCount() == 0);
    2929             : 
    2930           1 :     CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 1 && pData->maEnd.Tab() == 1);
    2931             : 
    2932             :     // Now, delete the sheet that just got inserted. The object should be back
    2933             :     // on the 1st sheet.
    2934           1 :     m_pDoc->DeleteTab(0);
    2935           1 :     pPage = pDrawLayer->GetPage(0);
    2936           1 :     CPPUNIT_ASSERT_MESSAGE("1st sheet should have one object.", pPage && pPage->GetObjCount() == 1);
    2937           2 :     CPPUNIT_ASSERT_MESSAGE("Size and position of the object shouldn't change.",
    2938           1 :                            pObj->GetLogicRect() == aObjRect);
    2939             : 
    2940           1 :     CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 0 && pData->maEnd.Tab() == 0);
    2941             : 
    2942             :     // Move the 1st sheet to the last position.
    2943           1 :     m_pDoc->MoveTab(0, 1);
    2944           1 :     pPage = pDrawLayer->GetPage(0);
    2945           1 :     CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage && pPage->GetObjCount() == 0);
    2946           1 :     pPage = pDrawLayer->GetPage(1);
    2947           1 :     CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage && pPage->GetObjCount() == 1);
    2948           1 :     CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 1 && pData->maEnd.Tab() == 1);
    2949             : 
    2950             :     // Copy the 2nd sheet, which has one drawing object to the last position.
    2951           1 :     m_pDoc->CopyTab(1, 2);
    2952           1 :     pPage = pDrawLayer->GetPage(2);
    2953           1 :     CPPUNIT_ASSERT_MESSAGE("Copied sheet should have one object.", pPage && pPage->GetObjCount() == 1);
    2954           1 :     pObj = pPage->GetObj(0);
    2955           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj);
    2956           1 :     pData = ScDrawLayer::GetObjData(pObj);
    2957           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData);
    2958           1 :     CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 2 && pData->maEnd.Tab() == 2);
    2959             : 
    2960           1 :     m_pDoc->DeleteTab(2);
    2961           1 :     m_pDoc->DeleteTab(1);
    2962           1 :     m_pDoc->DeleteTab(0);
    2963           1 : }
    2964             : 
    2965           1 : void Test::testToggleRefFlag()
    2966             : {
    2967             :     // In this test, there is no need to insert formula string into a cell in
    2968             :     // the document, as ScRefFinder does not depend on the content of the
    2969             :     // document except for the sheet names.
    2970             : 
    2971           1 :     m_pDoc->InsertTab(0, "Test");
    2972             : 
    2973             :     {
    2974             :         // Calc A1: basic 2D reference
    2975             : 
    2976           1 :         OUString aFormula("=B100");
    2977           1 :         ScAddress aPos(1, 5, 0);
    2978           2 :         ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_OOO);
    2979             : 
    2980             :         // Original
    2981           1 :         CPPUNIT_ASSERT_MESSAGE("Does not equal the original text.", aFormula.equals(aFinder.GetText()));
    2982             : 
    2983             :         // column relative / row relative -> column absolute / row absolute
    2984           1 :         aFinder.ToggleRel(0, aFormula.getLength());
    2985           1 :         aFormula = aFinder.GetText();
    2986           1 :         CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=$B$100" );
    2987             : 
    2988             :         // column absolute / row absolute -> column relative / row absolute
    2989           1 :         aFinder.ToggleRel(0, aFormula.getLength());
    2990           1 :         aFormula = aFinder.GetText();
    2991           1 :         CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=B$100" );
    2992             : 
    2993             :         // column relative / row absolute -> column absolute / row relative
    2994           1 :         aFinder.ToggleRel(0, aFormula.getLength());
    2995           1 :         aFormula = aFinder.GetText();
    2996           1 :         CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=$B100" );
    2997             : 
    2998             :         // column absolute / row relative -> column relative / row relative
    2999           1 :         aFinder.ToggleRel(0, aFormula.getLength());
    3000           1 :         aFormula = aFinder.GetText();
    3001           2 :         CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=B100" );
    3002             :     }
    3003             : 
    3004             :     {
    3005             :         // Excel R1C1: basic 2D reference
    3006             : 
    3007           1 :         OUString aFormula("=R2C1");
    3008           1 :         ScAddress aPos(3, 5, 0);
    3009           2 :         ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_XL_R1C1);
    3010             : 
    3011             :         // Original
    3012           1 :         CPPUNIT_ASSERT_MESSAGE("Does not equal the original text.", aFormula.equals(aFinder.GetText()));
    3013             : 
    3014             :         // column absolute / row absolute -> column relative / row absolute
    3015           1 :         aFinder.ToggleRel(0, aFormula.getLength());
    3016           1 :         aFormula = aFinder.GetText();
    3017           1 :         CPPUNIT_ASSERT_EQUAL(OUString("=R2C[-3]"), aFormula);
    3018             : 
    3019             :         // column relative / row absolute - > column absolute / row relative
    3020           1 :         aFinder.ToggleRel(0, aFormula.getLength());
    3021           1 :         aFormula = aFinder.GetText();
    3022           1 :         CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C1"), aFormula);
    3023             : 
    3024             :         // column absolute / row relative -> column relative / row relative
    3025           1 :         aFinder.ToggleRel(0, aFormula.getLength());
    3026           1 :         aFormula = aFinder.GetText();
    3027           1 :         CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C[-3]"), aFormula);
    3028             : 
    3029             :         // column relative / row relative -> column absolute / row absolute
    3030           1 :         aFinder.ToggleRel(0, aFormula.getLength());
    3031           1 :         aFormula = aFinder.GetText();
    3032           2 :         CPPUNIT_ASSERT_EQUAL(OUString("=R2C1"), aFormula);
    3033             :     }
    3034             : 
    3035             :     {
    3036             :         // Excel R1C1: Selection at the end of the formula string and does not
    3037             :         // overlap the formula string at all (inspired by fdo#39135).
    3038           1 :         OUString aFormula("=R1C1");
    3039           1 :         ScAddress aPos(1, 1, 0);
    3040           2 :         ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_XL_R1C1);
    3041             : 
    3042             :         // Original
    3043           1 :         CPPUNIT_ASSERT_EQUAL(aFormula, aFinder.GetText());
    3044             : 
    3045             :         // Make the column relative.
    3046           1 :         sal_Int32 n = aFormula.getLength();
    3047           1 :         aFinder.ToggleRel(n, n);
    3048           1 :         aFormula = aFinder.GetText();
    3049           1 :         CPPUNIT_ASSERT_EQUAL(OUString("=R1C[-1]"), aFormula);
    3050             : 
    3051             :         // Make the row relative.
    3052           1 :         n = aFormula.getLength();
    3053           1 :         aFinder.ToggleRel(n, n);
    3054           1 :         aFormula = aFinder.GetText();
    3055           1 :         CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C1"), aFormula);
    3056             : 
    3057             :         // Make both relative.
    3058           1 :         n = aFormula.getLength();
    3059           1 :         aFinder.ToggleRel(n, n);
    3060           1 :         aFormula = aFinder.GetText();
    3061           1 :         CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C[-1]"), aFormula);
    3062             : 
    3063             :         // Back to the original.
    3064           1 :         n = aFormula.getLength();
    3065           1 :         aFinder.ToggleRel(n, n);
    3066           1 :         aFormula = aFinder.GetText();
    3067           2 :         CPPUNIT_ASSERT_EQUAL(OUString("=R1C1"), aFormula);
    3068             :     }
    3069             : 
    3070             :     {
    3071             :         // Calc A1:
    3072           1 :         OUString aFormula("=A1+4");
    3073           1 :         ScAddress aPos(1, 1, 0);
    3074           2 :         ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_OOO);
    3075             : 
    3076             :         // Original
    3077           1 :         CPPUNIT_ASSERT_EQUAL(aFormula, aFinder.GetText());
    3078             : 
    3079             :         // Set the cursor over the 'A1' part and toggle.
    3080           1 :         aFinder.ToggleRel(2, 2);
    3081           1 :         aFormula = aFinder.GetText();
    3082           1 :         CPPUNIT_ASSERT_EQUAL(OUString("=$A$1+4"), aFormula);
    3083             : 
    3084           1 :         aFinder.ToggleRel(2, 2);
    3085           1 :         aFormula = aFinder.GetText();
    3086           1 :         CPPUNIT_ASSERT_EQUAL(OUString("=A$1+4"), aFormula);
    3087             : 
    3088           1 :         aFinder.ToggleRel(2, 2);
    3089           1 :         aFormula = aFinder.GetText();
    3090           1 :         CPPUNIT_ASSERT_EQUAL(OUString("=$A1+4"), aFormula);
    3091             : 
    3092           1 :         aFinder.ToggleRel(2, 2);
    3093           1 :         aFormula = aFinder.GetText();
    3094           2 :         CPPUNIT_ASSERT_EQUAL(OUString("=A1+4"), aFormula);
    3095             :     }
    3096             : 
    3097             :     // TODO: Add more test cases esp. for 3D references, Excel A1 syntax, and
    3098             :     // partial selection within formula string.
    3099             : 
    3100           1 :     m_pDoc->DeleteTab(0);
    3101           1 : }
    3102             : 
    3103           1 : void Test::testAutofilter()
    3104             : {
    3105           1 :     OUString aDBName("NONAME");
    3106             : 
    3107           1 :     m_pDoc->InsertTab( 0, "Test" );
    3108             : 
    3109             :     // cell contents (0 = empty cell)
    3110             :     const char* aData[][3] = {
    3111             :         { "C1", "C2", "C3" },
    3112             :         {  "0",  "1",  "A" },
    3113             :         {  "1",  "2",    0 },
    3114             :         {  "1",  "2",  "B" },
    3115             :         {  "0",  "2",  "B" }
    3116           1 :     };
    3117             : 
    3118           1 :     SCCOL nCols = SAL_N_ELEMENTS(aData[0]);
    3119           1 :     SCROW nRows = SAL_N_ELEMENTS(aData);
    3120             : 
    3121             :     // Populate cells.
    3122           6 :     for (SCROW i = 0; i < nRows; ++i)
    3123          20 :         for (SCCOL j = 0; j < nCols; ++j)
    3124          15 :             if (aData[i][j])
    3125          14 :                 m_pDoc->SetString(j, i, 0, OUString::createFromAscii(aData[i][j]));
    3126             : 
    3127           1 :     ScDBData* pDBData = new ScDBData(aDBName, 0, 0, 0, nCols-1, nRows-1);
    3128           1 :     m_pDoc->SetAnonymousDBData(0,pDBData);
    3129             : 
    3130           1 :     pDBData->SetAutoFilter(true);
    3131           1 :     ScRange aRange;
    3132           1 :     pDBData->GetArea(aRange);
    3133           1 :     m_pDoc->ApplyFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
    3134           1 :                            aRange.aEnd.Col(), aRange.aStart.Row(),
    3135           3 :                            aRange.aStart.Tab(), SC_MF_AUTO);
    3136             : 
    3137             :     //create the query param
    3138           2 :     ScQueryParam aParam;
    3139           1 :     pDBData->GetQueryParam(aParam);
    3140           1 :     ScQueryEntry& rEntry = aParam.GetEntry(0);
    3141           1 :     rEntry.bDoQuery = true;
    3142           1 :     rEntry.nField = 0;
    3143           1 :     rEntry.eOp = SC_EQUAL;
    3144           1 :     rEntry.GetQueryItem().mfVal = 0;
    3145             :     // add queryParam to database range.
    3146           1 :     pDBData->SetQueryParam(aParam);
    3147             : 
    3148             :     // perform the query.
    3149           1 :     m_pDoc->Query(0, aParam, true);
    3150             : 
    3151             :     //control output
    3152             :     SCROW nRow1, nRow2;
    3153           1 :     bool bHidden = m_pDoc->RowHidden(2, 0, &nRow1, &nRow2);
    3154           1 :     CPPUNIT_ASSERT_MESSAGE("rows 2 & 3 should be hidden", bHidden && nRow1 == 2 && nRow2 == 3);
    3155             : 
    3156             :     // Remove filtering.
    3157           1 :     rEntry.Clear();
    3158           1 :     m_pDoc->Query(0, aParam, true);
    3159           1 :     bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    3160           1 :     CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
    3161             : 
    3162             :     // Filter for non-empty cells by column C.
    3163           1 :     rEntry.bDoQuery = true;
    3164           1 :     rEntry.nField = 2;
    3165           1 :     rEntry.SetQueryByNonEmpty();
    3166           1 :     m_pDoc->Query(0, aParam, true);
    3167             : 
    3168             :     // only row 3 should be hidden.  The rest should be visible.
    3169           1 :     bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    3170           1 :     CPPUNIT_ASSERT_MESSAGE("rows 1 & 2 should be visible.", !bHidden && nRow1 == 0 && nRow2 == 1);
    3171           1 :     bHidden = m_pDoc->RowHidden(2, 0, &nRow1, &nRow2);
    3172           1 :     CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden.", bHidden && nRow1 == 2 && nRow2 == 2);
    3173           1 :     bHidden = m_pDoc->RowHidden(3, 0, &nRow1, &nRow2);
    3174           1 :     CPPUNIT_ASSERT_MESSAGE("row 4 and down should be visible.", !bHidden && nRow1 == 3 && nRow2 == MAXROW);
    3175             : 
    3176             :     // Now, filter for empty cells by column C.
    3177           1 :     rEntry.SetQueryByEmpty();
    3178           1 :     m_pDoc->Query(0, aParam, true);
    3179             : 
    3180             :     // Now, only row 1 and 3, and 6 and down should be visible.
    3181           1 :     bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    3182           1 :     CPPUNIT_ASSERT_MESSAGE("row 1 should be visible.", !bHidden && nRow1 == 0 && nRow2 == 0);
    3183           1 :     bHidden = m_pDoc->RowHidden(1, 0, &nRow1, &nRow2);
    3184           1 :     CPPUNIT_ASSERT_MESSAGE("row 2 should be hidden.", bHidden && nRow1 == 1 && nRow2 == 1);
    3185           1 :     bHidden = m_pDoc->RowHidden(2, 0, &nRow1, &nRow2);
    3186           1 :     CPPUNIT_ASSERT_MESSAGE("row 3 should be visible.", !bHidden && nRow1 == 2 && nRow2 == 2);
    3187           1 :     bHidden = m_pDoc->RowHidden(3, 0, &nRow1, &nRow2);
    3188           1 :     CPPUNIT_ASSERT_MESSAGE("rows 4 & 5 should be hidden.", bHidden && nRow1 == 3 && nRow2 == 4);
    3189           1 :     bHidden = m_pDoc->RowHidden(5, 0, &nRow1, &nRow2);
    3190           1 :     CPPUNIT_ASSERT_MESSAGE("rows 6 and down should be all visible.", !bHidden && nRow1 == 5 && nRow2 == MAXROW);
    3191             : 
    3192           2 :     m_pDoc->DeleteTab(0);
    3193           1 : }
    3194             : 
    3195           1 : void Test::testCopyPaste()
    3196             : {
    3197           1 :     m_pDoc->InsertTab(0, "Sheet1");
    3198           1 :     m_pDoc->InsertTab(1, "Sheet2");
    3199             :     //test copy&paste + ScUndoPaste
    3200             :     //copy local and global range names in formulas
    3201             :     //string cells and value cells
    3202           1 :     m_pDoc->SetValue(0, 0, 0, 1);
    3203           1 :     m_pDoc->SetValue(3, 0, 0, 0);
    3204           1 :     m_pDoc->SetValue(3, 1, 0, 1);
    3205           1 :     m_pDoc->SetValue(3, 2, 0, 2);
    3206           1 :     m_pDoc->SetValue(3, 3, 0, 3);
    3207           1 :     m_pDoc->SetString(2, 0, 0, "test");
    3208           1 :     ScAddress aAdr (0, 0, 0);
    3209             : 
    3210             :     //create some range names, local and global
    3211           1 :     ScRangeData* pLocal1 = new ScRangeData(m_pDoc, OUString("local1"), aAdr);
    3212           1 :     ScRangeData* pLocal2 = new ScRangeData(m_pDoc, OUString("local2"), aAdr);
    3213           1 :     ScRangeData* pGlobal = new ScRangeData(m_pDoc, OUString("global"), aAdr);
    3214           1 :     ScRangeName* pGlobalRangeName = new ScRangeName();
    3215           1 :     pGlobalRangeName->insert(pGlobal);
    3216           1 :     ScRangeName* pLocalRangeName1 = new ScRangeName();
    3217           1 :     pLocalRangeName1->insert(pLocal1);
    3218           1 :     pLocalRangeName1->insert(pLocal2);
    3219           1 :     m_pDoc->SetRangeName(pGlobalRangeName);
    3220           1 :     m_pDoc->SetRangeName(0, pLocalRangeName1);
    3221             : 
    3222             :     // Add formula to B1.
    3223           1 :     OUString aFormulaString("=local1+global+SUM($C$1:$D$4)");
    3224           1 :     m_pDoc->SetString(1, 0, 0, aFormulaString);
    3225             : 
    3226           1 :     double fValue = m_pDoc->GetValue(ScAddress(1,0,0));
    3227           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 8", fValue, 8);
    3228             : 
    3229             :     // add notes to A1:C1
    3230           1 :     ScAddress aAdrA1 (0, 0, 0); // empty cell content
    3231           2 :     OUString aHelloA1("Hello world in A1");
    3232           1 :     ScPostIt* pNoteA1 = m_pDoc->GetOrCreateNote(aAdrA1);
    3233           1 :     pNoteA1->SetText(aAdrA1, aHelloA1);
    3234           1 :     ScAddress aAdrB1 (1, 0, 0); // formula cell content
    3235           2 :     OUString aHelloB1("Hello world in B1");
    3236           1 :     ScPostIt* pNoteB1 = m_pDoc->GetOrCreateNote(aAdrB1);
    3237           1 :     pNoteB1->SetText(aAdrB1, aHelloB1);
    3238           1 :     ScAddress aAdrC1 (2, 0, 0); // string cell content
    3239           2 :     OUString aHelloC1("Hello world in C1");
    3240           1 :     ScPostIt* pNoteC1 = m_pDoc->GetOrCreateNote(aAdrC1);
    3241           1 :     pNoteC1->SetText(aAdrC1, aHelloC1);
    3242             : 
    3243             :     //copy Sheet1.A1:C1 to Sheet2.A2:C2
    3244           1 :     ScRange aRange(0,0,0,2,0,0);
    3245           2 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    3246           1 :     copyToClip(m_pDoc, aRange, &aClipDoc);
    3247             : 
    3248           1 :     aRange = ScRange(0,1,1,2,1,1);//target: Sheet2.A2:C2
    3249           1 :     ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
    3250           1 :     pUndoDoc->InitUndo(m_pDoc, 1, 1, true, true);
    3251           2 :     boost::scoped_ptr<ScUndoPaste> pUndo(createUndoPaste(getDocShell(), aRange, pUndoDoc));
    3252           2 :     ScMarkData aMark;
    3253           1 :     aMark.SetMarkArea(aRange);
    3254           1 :     m_pDoc->CopyFromClip(aRange, aMark, IDF_ALL, NULL, &aClipDoc);
    3255             : 
    3256             :     //check values after copying
    3257           2 :     OUString aString;
    3258           1 :     fValue = m_pDoc->GetValue(ScAddress(1,1,1));
    3259           1 :     m_pDoc->GetFormula(1,1,1, aString);
    3260           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("copied formula should return 2", fValue, 2);
    3261           1 :     CPPUNIT_ASSERT_MESSAGE("formula string was not copied correctly", aString == aFormulaString);
    3262           1 :     fValue = m_pDoc->GetValue(ScAddress(0,1,1));
    3263           1 :     CPPUNIT_ASSERT_MESSAGE("copied value should be 1", fValue == 1);
    3264             : 
    3265             :     //check local range name after copying
    3266           1 :     pLocal1 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL1"));
    3267           1 :     CPPUNIT_ASSERT_MESSAGE("local range name 1 should be copied", pLocal1);
    3268           1 :     ScRange aRangeLocal1;
    3269           1 :     bool bIsValidRef = pLocal1->IsValidReference(aRangeLocal1);
    3270           1 :     CPPUNIT_ASSERT_MESSAGE("local range name 1 should be valid", bIsValidRef);
    3271           1 :     CPPUNIT_ASSERT_MESSAGE("local range 1 should still point to Sheet1.A1",aRangeLocal1 == ScRange(0,0,0,0,0,0));
    3272           1 :     pLocal2 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL2"));
    3273           1 :     CPPUNIT_ASSERT_MESSAGE("local2 should not be copied", pLocal2 == NULL);
    3274             : 
    3275             :     // check notes after copying
    3276           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.A2", m_pDoc->HasNote(ScAddress(0, 1, 1)));
    3277           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.B2", m_pDoc->HasNote(ScAddress(1, 1, 1)));
    3278           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.C2", m_pDoc->HasNote(ScAddress(2, 1, 1)));
    3279           2 :     CPPUNIT_ASSERT_MESSAGE("Note content on Sheet1.A1 not copied to Sheet2.A2, empty cell content",
    3280           1 :             m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(0, 1, 1))->GetText());
    3281           2 :     CPPUNIT_ASSERT_MESSAGE("Note content on Sheet1.B1 not copied to Sheet2.B2, formula cell content",
    3282           1 :             m_pDoc->GetNote(ScAddress(1, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(1, 1, 1))->GetText());
    3283           2 :     CPPUNIT_ASSERT_MESSAGE("Note content on Sheet1.C1 not copied to Sheet2.C2, string cell content",
    3284           1 :             m_pDoc->GetNote(ScAddress(2, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(2, 1, 1))->GetText());
    3285             : 
    3286             :     //check undo and redo
    3287           1 :     pUndo->Undo();
    3288           1 :     fValue = m_pDoc->GetValue(ScAddress(1,1,1));
    3289           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after undo formula should return nothing", fValue, 0);
    3290           1 :     aString = m_pDoc->GetString(2, 1, 1);
    3291           1 :     CPPUNIT_ASSERT_MESSAGE("after undo, string should be removed", aString == "");
    3292           1 :     CPPUNIT_ASSERT_MESSAGE("after undo, note on A2 should be removed", !m_pDoc->HasNote(ScAddress(0, 1, 1)));
    3293           1 :     CPPUNIT_ASSERT_MESSAGE("after undo, note on B2 should be removed", !m_pDoc->HasNote(ScAddress(1, 1, 1)));
    3294           1 :     CPPUNIT_ASSERT_MESSAGE("after undo, note on C2 should be removed", !m_pDoc->HasNote(ScAddress(2, 1, 1)));
    3295             : 
    3296           1 :     pUndo->Redo();
    3297           1 :     fValue = m_pDoc->GetValue(ScAddress(1,1,1));
    3298           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 2 after redo", fValue, 2);
    3299           1 :     aString = m_pDoc->GetString(2, 1, 1);
    3300           1 :     CPPUNIT_ASSERT_MESSAGE("Cell Sheet2.C2 should contain: test", aString == "test");
    3301           1 :     m_pDoc->GetFormula(1,1,1, aString);
    3302           1 :     CPPUNIT_ASSERT_MESSAGE("Formula should be correct again", aString == aFormulaString);
    3303             : 
    3304           1 :     CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.A2", m_pDoc->HasNote(ScAddress(0, 1, 1)));
    3305           1 :     CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.B2", m_pDoc->HasNote(ScAddress(1, 1, 1)));
    3306           1 :     CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.C2", m_pDoc->HasNote(ScAddress(2, 1, 1)));
    3307           2 :     CPPUNIT_ASSERT_MESSAGE("After Redo, note again on Sheet2.A2, empty cell content",
    3308           1 :             m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(0, 1, 1))->GetText());
    3309           2 :     CPPUNIT_ASSERT_MESSAGE("After Redo, note again on Sheet2.B2, formula cell content",
    3310           1 :             m_pDoc->GetNote(ScAddress(1, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(1, 1, 1))->GetText());
    3311           2 :     CPPUNIT_ASSERT_MESSAGE("After Redo, note again on Sheet2.C2, string cell content",
    3312           1 :             m_pDoc->GetNote(ScAddress(2, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(2, 1, 1))->GetText());
    3313             : 
    3314             : 
    3315           1 :     m_pDoc->DeleteTab(1);
    3316           2 :     m_pDoc->DeleteTab(0);
    3317           1 : }
    3318             : 
    3319           1 : void Test::testCopyPasteAsLink()
    3320             : {
    3321           1 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // Turn on auto calc.
    3322             : 
    3323           1 :     m_pDoc->InsertTab(0, "Sheet1");
    3324           1 :     m_pDoc->InsertTab(1, "Sheet2");
    3325             : 
    3326           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 1); // A1
    3327           1 :     m_pDoc->SetValue(ScAddress(0,1,0), 2); // A2
    3328           1 :     m_pDoc->SetValue(ScAddress(0,2,0), 3); // A3
    3329             : 
    3330           1 :     ScRange aRange(0,0,0,0,2,0); // Copy A1:A3 to clip.
    3331           2 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    3332           1 :     copyToClip(m_pDoc, aRange, &aClipDoc);
    3333             : 
    3334           1 :     aRange = ScRange(1,1,1,1,3,1); // Paste to B2:B4 on Sheet2.
    3335           2 :     ScMarkData aMark;
    3336           1 :     aMark.SetMarkArea(aRange);
    3337             :     // Paste range as link.
    3338           1 :     m_pDoc->CopyFromClip(aRange, aMark, IDF_CONTENTS, NULL, &aClipDoc, true, true);
    3339             : 
    3340             :     // Check pasted content to make sure they reference the correct cells.
    3341           1 :     ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,1));
    3342           1 :     CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
    3343           1 :     CPPUNIT_ASSERT_EQUAL(1.0, pFC->GetValue());
    3344             : 
    3345           1 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,1));
    3346           1 :     CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
    3347           1 :     CPPUNIT_ASSERT_EQUAL(2.0, pFC->GetValue());
    3348             : 
    3349           1 :     pFC = m_pDoc->GetFormulaCell(ScAddress(1,3,1));
    3350           1 :     CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
    3351           1 :     CPPUNIT_ASSERT_EQUAL(3.0, pFC->GetValue());
    3352             : 
    3353           1 :     m_pDoc->DeleteTab(1);
    3354           2 :     m_pDoc->DeleteTab(0);
    3355           1 : }
    3356             : 
    3357           1 : void Test::testCopyPasteTranspose()
    3358             : {
    3359           1 :     m_pDoc->InsertTab(0, "Sheet1");
    3360           1 :     m_pDoc->InsertTab(1, "Sheet2");
    3361             : 
    3362           1 :     m_pDoc->SetValue(0, 0, 0, 1);
    3363           1 :     m_pDoc->SetString(1, 0, 0, "=A1+1");
    3364           1 :     m_pDoc->SetString(2, 0, 0, "test");
    3365             : 
    3366             :     // add notes to A1:C1
    3367           1 :     ScAddress aAdrA1 (0, 0, 0); // numerical cell content
    3368           1 :     OUString aHelloA1("Hello world in A1");
    3369           1 :     ScPostIt* pNoteA1 = m_pDoc->GetOrCreateNote(aAdrA1);
    3370           1 :     pNoteA1->SetText(aAdrA1, aHelloA1);
    3371           1 :     ScAddress aAdrB1 (1, 0, 0); // formula cell content
    3372           2 :     OUString aHelloB1("Hello world in B1");
    3373           1 :     ScPostIt* pNoteB1 = m_pDoc->GetOrCreateNote(aAdrB1);
    3374           1 :     pNoteB1->SetText(aAdrB1, aHelloB1);
    3375           1 :     ScAddress aAdrC1 (2, 0, 0); // string cell content
    3376           2 :     OUString aHelloC1("Hello world in C1");
    3377           1 :     ScPostIt* pNoteC1 = m_pDoc->GetOrCreateNote(aAdrC1);
    3378           1 :     pNoteC1->SetText(aAdrC1, aHelloC1);
    3379             : 
    3380             :     // transpose clipboard, paste and check on Sheet2
    3381           1 :     m_pDoc->InsertTab(1, "Sheet2");
    3382             : 
    3383           1 :     ScRange aSrcRange = ScRange(0,0,0,2,0,0);
    3384           2 :     ScDocument aNewClipDoc(SCDOCMODE_CLIP);
    3385           1 :     copyToClip(m_pDoc, aSrcRange, &aNewClipDoc);
    3386             : 
    3387           2 :     ::std::auto_ptr<ScDocument> pTransClip;
    3388           1 :     pTransClip.reset(new ScDocument(SCDOCMODE_CLIP));
    3389           1 :     aNewClipDoc.TransposeClip(pTransClip.get(), IDF_ALL, false);
    3390           1 :     ScDocument* pTransposedClip = pTransClip.release();
    3391             : 
    3392           1 :     ScRange aDestRange = ScRange(3,1,1,3,3,1);//target: Sheet2.D2:D4
    3393           2 :     ScMarkData aMark;
    3394           1 :     aMark.SetMarkArea(aDestRange);
    3395           1 :     m_pDoc->CopyFromClip(aDestRange, aMark, IDF_ALL, NULL, pTransposedClip);
    3396             : 
    3397             :     //check cell content after transposed copy/paste
    3398           2 :     OUString aString = m_pDoc->GetString(3, 3, 1);
    3399           1 :     CPPUNIT_ASSERT_MESSAGE("Cell Sheet2.D4 should contain: test", aString == "test");
    3400           1 :     double fValue = m_pDoc->GetValue(ScAddress(3,1,1));
    3401           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("transposed copied cell should return 1", fValue, 1);
    3402           1 :     fValue = m_pDoc->GetValue(ScAddress(3,2,1));
    3403           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("transposed copied formula should return 2", fValue, 2);
    3404           1 :     m_pDoc->GetFormula(3, 2, 1, aString);
    3405           1 :     CPPUNIT_ASSERT_MESSAGE("transposed formula should point on Sheet2.D2", aString == "=D2+1");
    3406             : 
    3407             :     // check notes after transposed copy/paste
    3408           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.D2", m_pDoc->HasNote(ScAddress(3, 1, 1)));
    3409           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.D3", m_pDoc->HasNote(ScAddress(3, 2, 1)));
    3410           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.D4", m_pDoc->HasNote(ScAddress(3, 3, 1)));
    3411           2 :     CPPUNIT_ASSERT_MESSAGE("Content of cell note on Sheet2.D2",
    3412           1 :             m_pDoc->GetNote(ScAddress(3, 1, 1))->GetText() ==  m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText());
    3413           2 :     CPPUNIT_ASSERT_MESSAGE("Content of cell note on Sheet2.D3",
    3414           1 :             m_pDoc->GetNote(ScAddress(3, 2, 1))->GetText() ==  m_pDoc->GetNote(ScAddress(1, 0, 0))->GetText());
    3415           2 :     CPPUNIT_ASSERT_MESSAGE("Content of cell note on Sheet2.D4",
    3416           1 :             m_pDoc->GetNote(ScAddress(3, 3, 1))->GetText() ==  m_pDoc->GetNote(ScAddress(2, 0, 0))->GetText());
    3417             : 
    3418           1 :     m_pDoc->DeleteTab(1);
    3419           2 :     m_pDoc->DeleteTab(0);
    3420             : 
    3421           1 : }
    3422             : 
    3423           1 : void Test::testCopyPasteMultiRange()
    3424             : {
    3425           1 :     m_pDoc->InsertTab(0, "Test");
    3426             : 
    3427             :     // Fill A2:B6 with numbers.
    3428           6 :     for (SCROW nRow = 1; nRow <= 5; ++nRow)
    3429             :     {
    3430          15 :         for (SCCOL nCol = 0; nCol <= 1; ++nCol)
    3431             :         {
    3432          10 :             ScAddress aPos(nCol,nRow,0);
    3433          10 :             m_pDoc->SetValue(aPos, nRow+nCol);
    3434             :         }
    3435             :     }
    3436             : 
    3437             :     // Fill D9:E11 with numbers.
    3438           4 :     for (SCROW nRow = 8; nRow <= 10; ++nRow)
    3439             :     {
    3440           9 :         for (SCCOL nCol = 3; nCol <= 4; ++nCol)
    3441             :         {
    3442           6 :             ScAddress aPos(nCol,nRow,0);
    3443           6 :             m_pDoc->SetValue(aPos, 10.0);
    3444             :         }
    3445             :     }
    3446             : 
    3447           1 :     ScMarkData aMark;
    3448           1 :     aMark.SelectOneTable(0);
    3449             : 
    3450             :     // Copy A2:B2, A4:B4, and A6:B6 to clipboard.
    3451           2 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    3452           2 :     ScClipParam aClipParam;
    3453           1 :     aClipParam.maRanges.Append(ScRange(0,1,0,1,1,0)); // A2:B2
    3454           1 :     aClipParam.maRanges.Append(ScRange(0,3,0,1,3,0)); // A4:B4
    3455           1 :     aClipParam.maRanges.Append(ScRange(0,5,0,1,5,0)); // A6:B6
    3456           1 :     aClipParam.meDirection = ScClipParam::Row;
    3457           1 :     m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
    3458             : 
    3459             :     // Paste to D9:E11, and make sure it won't crash (rhbz#1080196).
    3460           1 :     m_pDoc->CopyMultiRangeFromClip(ScAddress(3,8,0), aMark, IDF_CONTENTS, &aClipDoc);
    3461           1 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(3,8,0)));
    3462           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(4,8,0)));
    3463           1 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,9,0)));
    3464           1 :     CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(4,9,0)));
    3465           1 :     CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(3,10,0)));
    3466           1 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(4,10,0)));
    3467             : 
    3468           2 :     m_pDoc->DeleteTab(0);
    3469           1 : }
    3470             : 
    3471           1 : void Test::testCopyPasteSkipEmpty()
    3472             : {
    3473             :     struct Check
    3474             :     {
    3475             :         const char* mpStr;
    3476             :         Color maColor;
    3477             :         bool mbHasNote;
    3478             :     };
    3479             : 
    3480             :     struct TestRange
    3481             :     {
    3482             :         ScDocument* mpDoc;
    3483             : 
    3484           1 :         TestRange( ScDocument* pDoc ) : mpDoc(pDoc) {}
    3485             : 
    3486           4 :         bool checkRange( const ScAddress& rPos, const Check* p, const Check* pEnd )
    3487             :         {
    3488           4 :             ScAddress aPos(rPos);
    3489           4 :             OUString aPosStr = aPos.Format(SCA_VALID);
    3490          24 :             for (; p != pEnd; ++p, aPos.IncRow())
    3491             :             {
    3492          20 :                 if (!mpDoc->GetString(aPos).equalsAscii(p->mpStr))
    3493             :                 {
    3494           0 :                     cerr << aPosStr << ": incorrect string value: expected='" << p->mpStr << "' actual='" << mpDoc->GetString(aPos) << endl;
    3495           0 :                     return false;
    3496             :                 }
    3497             : 
    3498             :                 const SvxBrushItem* pBrush =
    3499          20 :                     dynamic_cast<const SvxBrushItem*>(mpDoc->GetAttr(aPos, ATTR_BACKGROUND));
    3500             : 
    3501          20 :                 if (!pBrush)
    3502             :                 {
    3503           0 :                     cerr << aPosStr << ": failed to get brush item from the cell." << endl;
    3504           0 :                     return false;
    3505             :                 }
    3506             : 
    3507          20 :                 if (pBrush->GetColor() != p->maColor)
    3508             :                 {
    3509           0 :                     Color aExpected = p->maColor;
    3510           0 :                     Color aActual = pBrush->GetColor();
    3511           0 :                     cerr << aPosStr << ": incorrect cell background color: expected=("
    3512           0 :                         << static_cast<int>(aExpected.GetRed()) << ","
    3513           0 :                         << static_cast<int>(aExpected.GetGreen()) << ","
    3514           0 :                         << static_cast<int>(aExpected.GetBlue()) << "), actual=("
    3515           0 :                         << static_cast<int>(aActual.GetRed()) << ","
    3516           0 :                         << static_cast<int>(aActual.GetGreen()) << ","
    3517           0 :                         << static_cast<int>(aActual.GetBlue()) << ")" << endl;
    3518             : 
    3519           0 :                     return false;
    3520             :                 }
    3521             : 
    3522          20 :                 bool bHasNote = mpDoc->HasNote(aPos);
    3523          20 :                 if (bHasNote != p->mbHasNote)
    3524             :                 {
    3525           0 :                     cerr << aPosStr << ": ";
    3526           0 :                     if (p->mbHasNote)
    3527           0 :                         cerr << "this cell should have a cell note, but doesn't." << endl;
    3528             :                     else
    3529           0 :                         cerr << "this cell should NOT have a cell note, but one is found." << endl;
    3530             : 
    3531           0 :                     return false;
    3532             :                 }
    3533             :             }
    3534             : 
    3535           4 :             return true;
    3536             :         }
    3537             : 
    3538           1 :     } aTest(m_pDoc);
    3539             : 
    3540           1 :     m_pDoc->InsertTab(0, "Test");
    3541           1 :     m_pDoc->InitDrawLayer(&getDocShell()); // for cell note objects.
    3542             : 
    3543           1 :     ScRange aSrcRange(0,0,0,0,4,0);
    3544           1 :     ScRange aDestRange(1,0,0,1,4,0);
    3545             : 
    3546           1 :     ScMarkData aMark;
    3547           1 :     aMark.SetMarkArea(aDestRange);
    3548             : 
    3549             :     // Put some texts in B1:B5.
    3550           1 :     m_pDoc->SetString(ScAddress(1,0,0), "A");
    3551           1 :     m_pDoc->SetString(ScAddress(1,1,0), "B");
    3552           1 :     m_pDoc->SetString(ScAddress(1,2,0), "C");
    3553           1 :     m_pDoc->SetString(ScAddress(1,3,0), "D");
    3554           1 :     m_pDoc->SetString(ScAddress(1,4,0), "E");
    3555             : 
    3556             :     // Set the background color of B1:B5 to blue.
    3557           2 :     ScPatternAttr aCellBackColor(m_pDoc->GetPool());
    3558           1 :     aCellBackColor.GetItemSet().Put(SvxBrushItem(COL_BLUE, ATTR_BACKGROUND));
    3559           1 :     m_pDoc->ApplyPatternAreaTab(1, 0, 1, 4, 0, aCellBackColor);
    3560             : 
    3561             :     // Insert notes to B1:B5.
    3562           1 :     m_pDoc->GetOrCreateNote(ScAddress(1,0,0));
    3563           1 :     m_pDoc->GetOrCreateNote(ScAddress(1,1,0));
    3564           1 :     m_pDoc->GetOrCreateNote(ScAddress(1,2,0));
    3565           1 :     m_pDoc->GetOrCreateNote(ScAddress(1,3,0));
    3566           1 :     m_pDoc->GetOrCreateNote(ScAddress(1,4,0));
    3567             : 
    3568             :     // Prepare a clipboard content interleaved with empty cells.
    3569           2 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    3570           1 :     aClipDoc.ResetClip(m_pDoc, &aMark);
    3571           2 :     ScClipParam aParam(aSrcRange, false);
    3572           1 :     aClipDoc.SetClipParam(aParam);
    3573           1 :     aClipDoc.SetString(ScAddress(0,0,0), "Clip1");
    3574           1 :     aClipDoc.SetString(ScAddress(0,2,0), "Clip2");
    3575           1 :     aClipDoc.SetString(ScAddress(0,4,0), "Clip3");
    3576             : 
    3577             :     // Set the background color of A1:A5 to yellow.
    3578           1 :     aCellBackColor.GetItemSet().Put(SvxBrushItem(COL_YELLOW, ATTR_BACKGROUND));
    3579           1 :     aClipDoc.ApplyPatternAreaTab(0, 0, 0, 4, 0, aCellBackColor);
    3580             : 
    3581           1 :     CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aClipDoc.GetCellType(ScAddress(0,0,0)));
    3582           1 :     CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE,   aClipDoc.GetCellType(ScAddress(0,1,0)));
    3583           1 :     CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aClipDoc.GetCellType(ScAddress(0,2,0)));
    3584           1 :     CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE,   aClipDoc.GetCellType(ScAddress(0,3,0)));
    3585           1 :     CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aClipDoc.GetCellType(ScAddress(0,4,0)));
    3586             : 
    3587             :     // Check the initial condition.
    3588             :     {
    3589             :         Check aChecks[] = {
    3590             :             { "A", COL_BLUE, true },
    3591             :             { "B", COL_BLUE, true },
    3592             :             { "C", COL_BLUE, true },
    3593             :             { "D", COL_BLUE, true },
    3594             :             { "E", COL_BLUE, true },
    3595           1 :         };
    3596             : 
    3597           1 :         bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
    3598           1 :         CPPUNIT_ASSERT_MESSAGE("Initial check failed.", bRes);
    3599             :     }
    3600             : 
    3601             :     // Create undo document.
    3602           1 :     ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
    3603           1 :     pUndoDoc->InitUndo(m_pDoc, 0, 0);
    3604           1 :     m_pDoc->CopyToDocument(aDestRange, IDF_ALL, false, pUndoDoc, &aMark);
    3605             : 
    3606             :     // Paste clipboard content onto A1:A5 but skip empty cells.
    3607           1 :     bool bSkipEmpty = true;
    3608           1 :     m_pDoc->CopyFromClip(aDestRange, aMark, IDF_ALL, pUndoDoc, &aClipDoc, true, false, false, bSkipEmpty);
    3609             : 
    3610             :     // Create redo document.
    3611           1 :     ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
    3612           1 :     pRedoDoc->InitUndo(m_pDoc, 0, 0);
    3613           1 :     m_pDoc->CopyToDocument(aDestRange, IDF_ALL, false, pRedoDoc, &aMark);
    3614             : 
    3615             :     // Create an undo object for this.
    3616           1 :     ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
    3617           2 :     ScUndoPaste aUndo(&getDocShell(), aDestRange, aMark, pUndoDoc, pRedoDoc, IDF_ALL, pRefUndoData);
    3618             : 
    3619             :     // Check the content after the paste.
    3620             :     {
    3621             :         Check aChecks[] = {
    3622             :             { "Clip1", COL_YELLOW, false },
    3623             :             { "B",     COL_BLUE,   true },
    3624             :             { "Clip2", COL_YELLOW, false },
    3625             :             { "D",     COL_BLUE,   true },
    3626             :             { "Clip3", COL_YELLOW, false },
    3627           1 :         };
    3628             : 
    3629           1 :         bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
    3630           1 :         CPPUNIT_ASSERT_MESSAGE("Check after paste failed.", bRes);
    3631             :     }
    3632             : 
    3633             :     // Undo, and check the content.
    3634           1 :     aUndo.Undo();
    3635             :     {
    3636             :         Check aChecks[] = {
    3637             :             { "A", COL_BLUE, true },
    3638             :             { "B", COL_BLUE, true },
    3639             :             { "C", COL_BLUE, true },
    3640             :             { "D", COL_BLUE, true },
    3641             :             { "E", COL_BLUE, true },
    3642           1 :         };
    3643             : 
    3644           1 :         bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
    3645           1 :         CPPUNIT_ASSERT_MESSAGE("Check after undo failed.", bRes);
    3646             :     }
    3647             : 
    3648             :     // Redo, and check the content again.
    3649           1 :     aUndo.Redo();
    3650             :     {
    3651             :         Check aChecks[] = {
    3652             :             { "Clip1", COL_YELLOW, false },
    3653             :             { "B",     COL_BLUE,   true },
    3654             :             { "Clip2", COL_YELLOW, false },
    3655             :             { "D",     COL_BLUE,   true },
    3656             :             { "Clip3", COL_YELLOW, false },
    3657           1 :         };
    3658             : 
    3659           1 :         bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
    3660           1 :         CPPUNIT_ASSERT_MESSAGE("Check after redo failed.", bRes);
    3661             :     }
    3662             : 
    3663           2 :     m_pDoc->DeleteTab(0);
    3664           1 : }
    3665             : 
    3666           0 : void Test::testCopyPasteSkipEmptyConditionalFormatting()
    3667             : {
    3668           0 :     m_pDoc->InsertTab(0, "Test");
    3669             : 
    3670           0 :     ScRange aDestRange(0,0,0,1,2,0);
    3671           0 :     ScRange aSrcRange(3,3,0,5,4,0);
    3672             : 
    3673           0 :     ScMarkData aMark;
    3674           0 :     aMark.SetMarkArea(aDestRange);
    3675             : 
    3676           0 :     m_pDoc->SetValue(0,0,0,1);
    3677           0 :     m_pDoc->SetValue(1,0,0,1);
    3678           0 :     m_pDoc->SetValue(0,1,0,1);
    3679           0 :     m_pDoc->SetValue(0,2,0,1);
    3680           0 :     m_pDoc->SetValue(1,2,0,1);
    3681             : 
    3682             :     //create conditional formatting for A1:B3
    3683           0 :     ScConditionalFormatList* pCondFormatList = new ScConditionalFormatList();
    3684           0 :     m_pDoc->SetCondFormList(pCondFormatList, 0);
    3685             : 
    3686           0 :     ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
    3687           0 :     pFormat->AddRange(aDestRange);
    3688           0 :     sal_uLong nCondFormatKey = m_pDoc->AddCondFormat(pFormat, 0);
    3689             : 
    3690             :     // Prepare a clipboard content interleaved with empty cells.
    3691           0 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    3692           0 :     aClipDoc.ResetClip(m_pDoc, &aMark);
    3693           0 :     ScClipParam aParam(aSrcRange, false);
    3694           0 :     aClipDoc.SetClipParam(aParam);
    3695           0 :     aClipDoc.SetValue(3,3,0,2);
    3696           0 :     aClipDoc.SetValue(4,3,0,2);
    3697           0 :     aClipDoc.SetValue(4,4,0,2);
    3698           0 :     aClipDoc.SetValue(3,5,0,2);
    3699           0 :     aClipDoc.SetValue(4,5,0,2);
    3700             : 
    3701           0 :     ScConditionalFormat* pClipFormat = new ScConditionalFormat(2, &aClipDoc);
    3702           0 :     pClipFormat->AddRange(aSrcRange);
    3703           0 :     aClipDoc.AddCondFormat(pClipFormat, 0);
    3704             : 
    3705             :     // Create undo document.
    3706           0 :     ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
    3707           0 :     pUndoDoc->InitUndo(m_pDoc, 0, 0);
    3708           0 :     m_pDoc->CopyToDocument(aDestRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
    3709             : 
    3710             :     // Paste clipboard content onto A1:A5 but skip empty cells.
    3711           0 :     bool bSkipEmpty = true;
    3712           0 :     m_pDoc->CopyFromClip(aDestRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc, true, false, false, bSkipEmpty);
    3713             : 
    3714           0 :     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
    3715           0 :     CPPUNIT_ASSERT_EQUAL(size_t(2), pList->size());
    3716           0 :     CPPUNIT_ASSERT(m_pDoc->GetCondFormat(1,1,0));
    3717             :     // empty cell in copy area does not overwrite conditional formatting
    3718           0 :     CPPUNIT_ASSERT_EQUAL(sal_uInt32(nCondFormatKey), m_pDoc->GetCondFormat(1,1,0)->GetKey());
    3719           0 :     for(SCCOL nCol = 0; nCol <= 1; ++nCol)
    3720             :     {
    3721           0 :         for(SCROW nRow = 0; nRow <= 2; ++nRow)
    3722             :         {
    3723           0 :             if(nRow == 1 && nCol == 1)
    3724           0 :                 continue;
    3725             : 
    3726           0 :             CPPUNIT_ASSERT(m_pDoc->GetCondFormat(nCol, nRow, 0));
    3727           0 :             CPPUNIT_ASSERT(nCondFormatKey != m_pDoc->GetCondFormat(nCol, nRow, 0)->GetKey());
    3728             :         }
    3729             :     }
    3730           0 :     m_pDoc->DeleteTab(0);
    3731           0 : }
    3732             : 
    3733           1 : void Test::testUndoCut()
    3734             : {
    3735           1 :     m_pDoc->InsertTab(0, "Test");
    3736             : 
    3737           1 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
    3738             : 
    3739             :     // Insert values into A1:A3.
    3740           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
    3741           1 :     m_pDoc->SetValue(ScAddress(0,1,0), 10.0);
    3742           1 :     m_pDoc->SetValue(ScAddress(0,2,0), 100.0);
    3743             : 
    3744             :     // SUM in A4.
    3745           1 :     m_pDoc->SetString(ScAddress(0,3,0), "=SUM(A1:A3)");
    3746           1 :     CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc->GetValue(0,3,0));
    3747             : 
    3748             :     // Select A1:A3.
    3749           2 :     ScMarkData aMark;
    3750           1 :     ScRange aRange(0,0,0,0,2,0);
    3751           1 :     aMark.SetMarkArea(aRange);
    3752           1 :     aMark.MarkToMulti();
    3753             : 
    3754             :     // Set up an undo object for cutting A1:A3.
    3755           1 :     ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
    3756           1 :     pUndoDoc->InitUndo(m_pDoc, 0 ,0);
    3757           1 :     m_pDoc->CopyToDocument(aRange, IDF_ALL, false, pUndoDoc);
    3758           1 :     CPPUNIT_ASSERT_EQUAL(  1.0, pUndoDoc->GetValue(ScAddress(0,0,0)));
    3759           1 :     CPPUNIT_ASSERT_EQUAL( 10.0, pUndoDoc->GetValue(ScAddress(0,1,0)));
    3760           1 :     CPPUNIT_ASSERT_EQUAL(100.0, pUndoDoc->GetValue(ScAddress(0,2,0)));
    3761           2 :     ScUndoCut aUndo(&getDocShell(), aRange, aRange.aEnd, aMark, pUndoDoc);
    3762             : 
    3763             :     // "Cut" the selection.
    3764           1 :     m_pDoc->DeleteSelection(IDF_ALL, aMark);
    3765           1 :     CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(0,3,0)); // The SUM should be zero after the "cut".
    3766             : 
    3767             :     // Undo it, and check the result.
    3768           1 :     aUndo.Undo();
    3769           1 :     CPPUNIT_ASSERT_EQUAL(  1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    3770           1 :     CPPUNIT_ASSERT_EQUAL( 10.0, m_pDoc->GetValue(ScAddress(0,1,0)));
    3771           1 :     CPPUNIT_ASSERT_EQUAL(100.0, m_pDoc->GetValue(ScAddress(0,2,0)));
    3772           1 :     CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc->GetValue(0,3,0)); // The SUM value should be back to the original.
    3773             : 
    3774             :     // Redo it and check.
    3775           1 :     aUndo.Redo();
    3776           1 :     CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(0,3,0));
    3777             : 
    3778             :     // Undo again.
    3779           1 :     aUndo.Undo();
    3780           1 :     CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc->GetValue(0,3,0));
    3781             : 
    3782           2 :     m_pDoc->DeleteTab(0);
    3783           1 : }
    3784             : 
    3785           1 : void Test::testMoveBlock()
    3786             : {
    3787           1 :     m_pDoc->InsertTab(0, "SheetNotes");
    3788             : 
    3789           1 :     m_pDoc->SetValue(0, 0, 0, 1);
    3790           1 :     m_pDoc->SetString(1, 0, 0, "=A1+1");
    3791           1 :     m_pDoc->SetString(2, 0, 0, "test");
    3792             : 
    3793             :     // add notes to A1:C1
    3794           1 :     ScAddress aAddrA1 (0, 0, 0);
    3795           1 :     OUString aHelloA1("Hello world in A1");
    3796           1 :     ScPostIt* pNoteA1 = m_pDoc->GetOrCreateNote(aAddrA1);
    3797           1 :     pNoteA1->SetText(aAddrA1, aHelloA1);
    3798           1 :     ScAddress aAddrB1 (1, 0, 0);
    3799           2 :     OUString aHelloB1("Hello world in B1");
    3800           1 :     ScPostIt* pNoteB1 = m_pDoc->GetOrCreateNote(aAddrB1);
    3801           1 :     pNoteB1->SetText(aAddrB1, aHelloB1);
    3802           1 :     ScAddress aAddrC1 (2, 0, 0);
    3803           2 :     OUString aHelloC1("Hello world in C1");
    3804           1 :     ScPostIt* pNoteC1 = m_pDoc->GetOrCreateNote(aAddrC1);
    3805           1 :     pNoteC1->SetText(aAddrC1, aHelloC1);
    3806           1 :     ScAddress aAddrD1 (3, 0, 0);
    3807             : 
    3808             :     // previous tests on cell note content are ok. this one fails !!! :(
    3809             :     //CPPUNIT_ASSERT_MESSAGE("Note content in B1 before move block", m_pDoc->GetNote(aAddrB1)->GetText() == aHelloB1);
    3810             : 
    3811             :     // move notes to B1:D1
    3812           1 :     bool bCut = true;
    3813           1 :     ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
    3814           1 :     bool bMoveDone = rDocFunc.MoveBlock(ScRange(0, 0 ,0 ,2 ,0 ,0), ScAddress(1, 0, 0), bCut, false, false, false);
    3815             : 
    3816           1 :     CPPUNIT_ASSERT_MESSAGE("Cells not moved", bMoveDone);
    3817             : 
    3818             :     //check cell content
    3819           2 :     OUString aString = m_pDoc->GetString(3, 0, 0);
    3820           1 :     CPPUNIT_ASSERT_MESSAGE("Cell D1 should contain: test", aString == "test");
    3821           1 :     m_pDoc->GetFormula(2, 0, 0, aString);
    3822           1 :     CPPUNIT_ASSERT_MESSAGE("Cell C1 should contain an updated formula", aString == "=B1+1");
    3823           1 :     double fValue = m_pDoc->GetValue(aAddrB1);
    3824           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("Cell B1 should contain 1", fValue, 1);
    3825             : 
    3826             :     // cell notes has been moved 1 cell right (event when overlapping)
    3827           1 :     CPPUNIT_ASSERT_MESSAGE("There should be NO note on A1", !m_pDoc->HasNote(aAddrA1));
    3828           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note on B1", m_pDoc->HasNote(aAddrB1));
    3829           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note on C1", m_pDoc->HasNote(aAddrC1));
    3830           1 :     CPPUNIT_ASSERT_MESSAGE("There should be a note on D1", m_pDoc->HasNote(aAddrD1));
    3831             : /* still failing, wrong content ???
    3832             :     OUString sNoteText;
    3833             :     sNoteText =  m_pDoc->GetNote(aAddrB1)->GetText();
    3834             :     CPPUNIT_ASSERT_MESSAGE("Note content in B1", sNoteText == aHelloA1);
    3835             :     sNoteText =  m_pDoc->GetNote(aAddrC1)->GetText();
    3836             :     CPPUNIT_ASSERT_MESSAGE("Note content in C1", sNoteText == aHelloB1);
    3837             :     sNoteText =  m_pDoc->GetNote(aAddrD1)->GetText();
    3838             :     CPPUNIT_ASSERT_MESSAGE("Note content in D1", sNoteText == aHelloC1);
    3839             : */
    3840             : 
    3841           2 :     m_pDoc->DeleteTab(0);
    3842           1 : }
    3843             : 
    3844           1 : void Test::testCopyPasteRelativeFormula()
    3845             : {
    3846           1 :     m_pDoc->InsertTab(0, "Formula");
    3847             : 
    3848           1 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
    3849             : 
    3850             :     // Insert values to A2 and A4.
    3851           1 :     m_pDoc->SetValue(ScAddress(0,1,0), 1);
    3852           1 :     m_pDoc->SetValue(ScAddress(0,3,0), 2);
    3853             : 
    3854             :     // Insert formula to B4.
    3855           1 :     m_pDoc->SetString(ScAddress(1,3,0), "=A4");
    3856           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,3,0)));
    3857             : 
    3858             :     // Select and copy B3:B4 to the clipboard.
    3859           1 :     ScRange aRange(1,2,0,1,3,0);
    3860           2 :     ScClipParam aClipParam(aRange, false);
    3861           2 :     ScMarkData aMark;
    3862           1 :     aMark.SetMarkArea(aRange);
    3863           2 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    3864           1 :     m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
    3865             : 
    3866             :     // Paste it to B1:B2.
    3867           1 :     sal_uInt16 nFlags = IDF_ALL;
    3868           1 :     ScRange aDestRange(1,0,0,1,1,0);
    3869           1 :     aMark.SetMarkArea(aDestRange);
    3870           1 :     m_pDoc->CopyFromClip(aDestRange, aMark, nFlags, NULL, &aClipDoc);
    3871             : 
    3872             :     // B2 references A2, so the value should be 1.
    3873           1 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
    3874             : 
    3875             :     // Clear content and start over.
    3876           1 :     clearSheet(m_pDoc, 0);
    3877           1 :     clearSheet(&aClipDoc, 0);
    3878             : 
    3879             :     // Insert a single formula cell in A1.
    3880           1 :     m_pDoc->SetString(ScAddress(0,0,0), "=ROW()");
    3881           1 :     const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(0,0,0));
    3882           1 :     CPPUNIT_ASSERT(pFC);
    3883           1 :     CPPUNIT_ASSERT(!pFC->IsShared()); // single formula cell is never shared.
    3884             : 
    3885             :     // Copy A1 to clipboard.
    3886           1 :     aClipParam = ScClipParam(ScAddress(0,0,0), false);
    3887           1 :     m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
    3888             : 
    3889           1 :     pFC = aClipDoc.GetFormulaCell(ScAddress(0,0,0));
    3890           1 :     CPPUNIT_ASSERT(pFC);
    3891           1 :     CPPUNIT_ASSERT(!pFC->IsShared());
    3892             : 
    3893             :     // Paste to A3.
    3894           1 :     aDestRange = ScRange(0,2,0,0,2,0);
    3895           1 :     aMark.SetMarkArea(aDestRange);
    3896           1 :     m_pDoc->CopyFromClip(aDestRange, aMark, nFlags, NULL, &aClipDoc);
    3897             : 
    3898           1 :     pFC = m_pDoc->GetFormulaCell(ScAddress(0,2,0));
    3899           1 :     CPPUNIT_ASSERT(pFC);
    3900           1 :     CPPUNIT_ASSERT(!pFC->IsShared());
    3901             : 
    3902             :     // Delete A3 and make sure it doesn't crash (see fdo#76132).
    3903           1 :     clearRange(m_pDoc, ScAddress(0,2,0));
    3904           1 :     CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(0,2,0)) == CELLTYPE_NONE);
    3905             : 
    3906           2 :     m_pDoc->DeleteTab(0);
    3907           1 : }
    3908             : 
    3909           1 : void Test::testMergedCells()
    3910             : {
    3911             :     //test merge and unmerge
    3912             :     //TODO: an undo/redo test for this would be a good idea
    3913           1 :     m_pDoc->InsertTab(0, "Sheet1");
    3914           1 :     m_pDoc->DoMerge(0, 1, 1, 3, 3, false);
    3915           1 :     SCCOL nEndCol = 1;
    3916           1 :     SCROW nEndRow = 1;
    3917           1 :     m_pDoc->ExtendMerge( 1, 1, nEndCol, nEndRow, 0, false);
    3918           1 :     CPPUNIT_ASSERT_MESSAGE("did not merge cells", nEndCol == 3 && nEndRow == 3);
    3919           1 :     ScRange aRange(0,2,0,MAXCOL,2,0);
    3920           1 :     ScMarkData aMark;
    3921           1 :     aMark.SetMarkArea(aRange);
    3922           1 :     getDocShell().GetDocFunc().InsertCells(aRange, &aMark, INS_INSROWS, true, true);
    3923           1 :     m_pDoc->ExtendMerge(1, 1, nEndCol, nEndRow, 0, false);
    3924           1 :     CPPUNIT_ASSERT_MESSAGE("did not increase merge area", nEndCol == 3 && nEndRow == 4);
    3925           1 :     m_pDoc->DeleteTab(0);
    3926           1 : }
    3927             : 
    3928             : 
    3929           1 : void Test::testRenameTable()
    3930             : {
    3931             :     //test set rename table
    3932             :     //TODO: set name1 and name2 and do an undo to check if name 1 is set now
    3933             :     //TODO: also check if new name for table is same as another table
    3934             : 
    3935           1 :     m_pDoc->InsertTab(0, "Sheet1");
    3936           1 :     m_pDoc->InsertTab(1, "Sheet2");
    3937             : 
    3938             :     //test case 1 , rename table2 to sheet 1, it should return error
    3939           1 :     OUString nameToSet = "Sheet1";
    3940           1 :     ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
    3941           1 :     CPPUNIT_ASSERT_MESSAGE("name same as another table is being set", !rDocFunc.RenameTable(1,nameToSet,false,true) );
    3942             : 
    3943             :     //test case 2 , simple rename to check name
    3944           1 :     nameToSet = "test1";
    3945           1 :     getDocShell().GetDocFunc().RenameTable(0,nameToSet,false,true);
    3946           2 :     OUString nameJustSet;
    3947           1 :     m_pDoc->GetName(0,nameJustSet);
    3948           1 :     CPPUNIT_ASSERT_MESSAGE("table not renamed", nameToSet == nameJustSet);
    3949             : 
    3950             :     //test case 3 , rename again
    3951           2 :     OUString anOldName;
    3952           1 :     m_pDoc->GetName(0,anOldName);
    3953             : 
    3954           1 :     nameToSet = "test2";
    3955           1 :     rDocFunc.RenameTable(0,nameToSet,false,true);
    3956           1 :     m_pDoc->GetName(0,nameJustSet);
    3957           1 :     CPPUNIT_ASSERT_MESSAGE("table not renamed", nameToSet == nameJustSet);
    3958             : 
    3959             :     //test case 4 , check if  undo works
    3960           1 :     SfxUndoAction* pUndo = new ScUndoRenameTab(&getDocShell(),0,anOldName,nameToSet);
    3961           1 :     pUndo->Undo();
    3962           1 :     m_pDoc->GetName(0,nameJustSet);
    3963           1 :     CPPUNIT_ASSERT_MESSAGE("the correct name is not set after undo", nameJustSet == anOldName);
    3964             : 
    3965           1 :     pUndo->Redo();
    3966           1 :     m_pDoc->GetName(0,nameJustSet);
    3967           1 :     CPPUNIT_ASSERT_MESSAGE("the correct color is not set after redo", nameJustSet == nameToSet);
    3968             : 
    3969           1 :     m_pDoc->DeleteTab(0);
    3970           2 :     m_pDoc->DeleteTab(1);
    3971           1 : }
    3972             : 
    3973           1 : void Test::testSetBackgroundColor()
    3974             : {
    3975             :     //test set background color
    3976             :     //TODO: set color1 and set color2 and do an undo to check if color1 is set now.
    3977             : 
    3978           1 :     m_pDoc->InsertTab(0, "Sheet1");
    3979           1 :     Color aColor;
    3980             : 
    3981             :      //test yellow
    3982           1 :     aColor=Color(COL_YELLOW);
    3983           1 :     getDocShell().GetDocFunc().SetTabBgColor(0,aColor,false, true);
    3984           2 :     CPPUNIT_ASSERT_MESSAGE("the correct color is not set",
    3985           1 :                            m_pDoc->GetTabBgColor(0) == aColor);
    3986             : 
    3987             : 
    3988           1 :     Color aOldTabBgColor=m_pDoc->GetTabBgColor(0);
    3989           1 :     aColor.SetColor(COL_BLUE);//set BLUE
    3990           1 :     getDocShell().GetDocFunc().SetTabBgColor(0,aColor,false, true);
    3991           2 :     CPPUNIT_ASSERT_MESSAGE("the correct color is not set the second time",
    3992           1 :                            m_pDoc->GetTabBgColor(0) == aColor);
    3993             : 
    3994             :     //now check for undo
    3995           1 :     SfxUndoAction* pUndo = new ScUndoTabColor(&getDocShell(), 0, aOldTabBgColor, aColor);
    3996           1 :     pUndo->Undo();
    3997           1 :     CPPUNIT_ASSERT_MESSAGE("the correct color is not set after undo", m_pDoc->GetTabBgColor(0)== aOldTabBgColor);
    3998           1 :     pUndo->Redo();
    3999           1 :     CPPUNIT_ASSERT_MESSAGE("the correct color is not set after undo", m_pDoc->GetTabBgColor(0)== aColor);
    4000           1 :     m_pDoc->DeleteTab(0);
    4001           1 : }
    4002             : 
    4003           1 : void Test::testUpdateReference()
    4004             : {
    4005             :     //test that formulas are correctly updated during sheet delete
    4006             :     //TODO: add tests for relative references, updating of named ranges, ...
    4007           1 :     m_pDoc->InsertTab(0, "Sheet1");
    4008           1 :     m_pDoc->InsertTab(1, "Sheet2");
    4009           1 :     m_pDoc->InsertTab(2, "Sheet3");
    4010           1 :     m_pDoc->InsertTab(3, "Sheet4");
    4011             : 
    4012           1 :     m_pDoc->SetValue(0,0,2, 1);
    4013           1 :     m_pDoc->SetValue(1,0,2, 2);
    4014           1 :     m_pDoc->SetValue(1,1,3, 4);
    4015           1 :     m_pDoc->SetString(2,0,2, "=A1+B1");
    4016           1 :     m_pDoc->SetString(2,1,2, "=Sheet4.B2+A1");
    4017             : 
    4018             :     double aValue;
    4019           1 :     m_pDoc->GetValue(2,0,2, aValue);
    4020           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", aValue, 3);
    4021           1 :     m_pDoc->GetValue(2,1,2, aValue);
    4022           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", aValue, 5);
    4023             : 
    4024             :     //test deleting both sheets: one is not directly before the sheet, the other one is
    4025           1 :     m_pDoc->DeleteTab(0);
    4026           1 :     m_pDoc->GetValue(2,0,1, aValue);
    4027           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", aValue, 3);
    4028           1 :     m_pDoc->GetValue(2,1,1, aValue);
    4029           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", aValue, 5);
    4030             : 
    4031           1 :     m_pDoc->DeleteTab(0);
    4032           1 :     m_pDoc->GetValue(2,0,0, aValue);
    4033           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", aValue, 3);
    4034           1 :     m_pDoc->GetValue(2,1,0, aValue);
    4035           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", aValue, 5);
    4036             : 
    4037             :     //test adding two sheets
    4038           1 :     m_pDoc->InsertTab(0, "Sheet2");
    4039           1 :     m_pDoc->GetValue(2,0,1, aValue);
    4040           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", aValue, 3);
    4041           1 :     m_pDoc->GetValue(2,1,1, aValue);
    4042           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", aValue, 5);
    4043             : 
    4044           1 :     m_pDoc->InsertTab(0, "Sheet1");
    4045           1 :     m_pDoc->GetValue(2,0,2, aValue);
    4046           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", aValue, 3);
    4047           1 :     m_pDoc->GetValue(2,1,2, aValue);
    4048           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", aValue, 5);
    4049             : 
    4050             :     //test new DeleteTabs/InsertTabs methods
    4051           1 :     m_pDoc->DeleteTabs(0, 2);
    4052           1 :     m_pDoc->GetValue(2, 0, 0, aValue);
    4053           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", aValue, 3);
    4054           1 :     m_pDoc->GetValue(2, 1, 0, aValue);
    4055           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", aValue, 5);
    4056             : 
    4057           1 :     std::vector<OUString> aSheets;
    4058           1 :     aSheets.push_back("Sheet1");
    4059           1 :     aSheets.push_back("Sheet2");
    4060           1 :     m_pDoc->InsertTabs(0, aSheets, false, true);
    4061           1 :     m_pDoc->GetValue(2, 0, 2, aValue);
    4062           2 :     OUString aFormula;
    4063           1 :     m_pDoc->GetFormula(2,0,2, aFormula);
    4064             : 
    4065           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", aValue, 3);
    4066           1 :     m_pDoc->GetValue(2, 1, 2, aValue);
    4067           1 :     ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", aValue, 5);
    4068             : 
    4069           1 :     m_pDoc->DeleteTab(3);
    4070           1 :     m_pDoc->DeleteTab(2);
    4071           1 :     m_pDoc->DeleteTab(1);
    4072           2 :     m_pDoc->DeleteTab(0);
    4073           1 : }
    4074             : 
    4075           1 : void Test::testSearchCells()
    4076             : {
    4077           1 :     m_pDoc->InsertTab(0, "Test");
    4078             : 
    4079           1 :     m_pDoc->SetString(ScAddress(0,0,0), "A");
    4080           1 :     m_pDoc->SetString(ScAddress(0,1,0), "B");
    4081           1 :     m_pDoc->SetString(ScAddress(0,2,0), "A");
    4082             :     // Leave A4 blank.
    4083           1 :     m_pDoc->SetString(ScAddress(0,4,0), "A");
    4084           1 :     m_pDoc->SetString(ScAddress(0,5,0), "B");
    4085           1 :     m_pDoc->SetString(ScAddress(0,6,0), "C");
    4086             : 
    4087           1 :     SvxSearchItem aItem(SID_SEARCH_ITEM);
    4088           1 :     aItem.SetSearchString(OUString("A"));
    4089           1 :     aItem.SetCommand(SVX_SEARCHCMD_FIND_ALL);
    4090           2 :     ScMarkData aMarkData;
    4091           1 :     aMarkData.SelectOneTable(0);
    4092           1 :     SCCOL nCol = 0;
    4093           1 :     SCROW nRow = 0;
    4094           1 :     SCTAB nTab = 0;
    4095           2 :     ScRangeList aMatchedRanges;
    4096           2 :     OUString aUndoStr;
    4097           1 :     bool bSuccess = m_pDoc->SearchAndReplace(aItem, nCol, nRow, nTab, aMarkData, aMatchedRanges, aUndoStr);
    4098             : 
    4099           1 :     CPPUNIT_ASSERT_MESSAGE("Search And Replace should succeed", bSuccess);
    4100           1 :     CPPUNIT_ASSERT_MESSAGE("There should be exactly 3 matching cells.", aMatchedRanges.size() == 3);
    4101           1 :     ScAddress aHit(0,0,0);
    4102           1 :     CPPUNIT_ASSERT_MESSAGE("A1 should be inside the matched range.", aMatchedRanges.In(aHit));
    4103           1 :     aHit.SetRow(2);
    4104           1 :     CPPUNIT_ASSERT_MESSAGE("A3 should be inside the matched range.", aMatchedRanges.In(aHit));
    4105           1 :     aHit.SetRow(4);
    4106           1 :     CPPUNIT_ASSERT_MESSAGE("A5 should be inside the matched range.", aMatchedRanges.In(aHit));
    4107             : 
    4108           2 :     m_pDoc->DeleteTab(0);
    4109           1 : }
    4110             : 
    4111           1 : void Test::testFormulaPosition()
    4112             : {
    4113           1 :     m_pDoc->InsertTab(0, "Test");
    4114             : 
    4115           1 :     ScAddress aPos(0,0,0); // A1
    4116           1 :     m_pDoc->SetString(aPos, "=ROW()");
    4117           1 :     aPos.IncRow(); // A2
    4118           1 :     m_pDoc->SetString(aPos, "=ROW()");
    4119           1 :     aPos.SetRow(3); // A4;
    4120           1 :     m_pDoc->SetString(aPos, "=ROW()");
    4121             : 
    4122             :     {
    4123           1 :         SCROW aRows[] = { 0, 1, 3 };
    4124           1 :         bool bRes = checkFormulaPositions(*m_pDoc, aPos.Tab(), aPos.Col(), aRows, SAL_N_ELEMENTS(aRows));
    4125           1 :         CPPUNIT_ASSERT(bRes);
    4126             :     }
    4127             : 
    4128           1 :     m_pDoc->InsertRow(0,0,0,0,1,5); // Insert 5 rows at A2.
    4129             :     {
    4130           1 :         SCROW aRows[] = { 0, 6, 8 };
    4131           1 :         bool bRes = checkFormulaPositions(*m_pDoc, aPos.Tab(), aPos.Col(), aRows, SAL_N_ELEMENTS(aRows));
    4132           1 :         CPPUNIT_ASSERT(bRes);
    4133             :     }
    4134             : 
    4135           1 :     m_pDoc->DeleteTab(0);
    4136           1 : }
    4137             : 
    4138             : namespace {
    4139             : 
    4140           4 : bool hasRange(const std::vector<ScTokenRef>& rRefTokens, const ScRange& rRange, const ScAddress& rPos)
    4141             : {
    4142           4 :     std::vector<ScTokenRef>::const_iterator it = rRefTokens.begin(), itEnd = rRefTokens.end();
    4143           5 :     for (; it != itEnd; ++it)
    4144             :     {
    4145           5 :         const ScTokenRef& p = *it;
    4146           5 :         if (!ScRefTokenHelper::isRef(p) || ScRefTokenHelper::isExternalRef(p))
    4147           0 :             continue;
    4148             : 
    4149           5 :         switch (p->GetType())
    4150             :         {
    4151             :             case formula::svSingleRef:
    4152             :             {
    4153           2 :                 ScSingleRefData aData = p->GetSingleRef();
    4154           2 :                 if (rRange.aStart != rRange.aEnd)
    4155           0 :                     break;
    4156             : 
    4157           2 :                 ScAddress aThis = aData.toAbs(rPos);
    4158           2 :                 if (aThis == rRange.aStart)
    4159           2 :                     return true;
    4160             :             }
    4161           0 :             break;
    4162             :             case formula::svDoubleRef:
    4163             :             {
    4164           3 :                 ScComplexRefData aData = p->GetDoubleRef();
    4165           3 :                 ScRange aThis = aData.toAbs(rPos);
    4166           3 :                 if (aThis == rRange)
    4167           2 :                     return true;
    4168             :             }
    4169           1 :             break;
    4170             :             default:
    4171             :                 ;
    4172             :         }
    4173             :     }
    4174           0 :     return false;
    4175             : }
    4176             : 
    4177             : }
    4178             : 
    4179           1 : void Test::testJumpToPrecedentsDependents()
    4180             : {
    4181             :     // Precedent is another cell that the cell references, while dependent is
    4182             :     // another cell that references it.
    4183           1 :     m_pDoc->InsertTab(0, "Test");
    4184             : 
    4185           1 :     m_pDoc->SetString(2, 0, 0, "=A1+A2+B3"); // C1
    4186           1 :     m_pDoc->SetString(2, 1, 0, "=A1");       // C2
    4187           1 :     m_pDoc->CalcAll();
    4188             : 
    4189           1 :     std::vector<ScTokenRef> aRefTokens;
    4190           1 :     ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
    4191             : 
    4192             :     {
    4193             :         // C1's precedent should be A1:A2,B3.
    4194           1 :         ScAddress aC1(2, 0, 0);
    4195           1 :         ScRangeList aRange(aC1);
    4196           1 :         rDocFunc.DetectiveCollectAllPreds(aRange, aRefTokens);
    4197           2 :         CPPUNIT_ASSERT_MESSAGE("A1:A2 should be a precedent of C1.",
    4198           1 :                                hasRange(aRefTokens, ScRange(0, 0, 0, 0, 1, 0), aC1));
    4199           2 :         CPPUNIT_ASSERT_MESSAGE("B3 should be a precedent of C1.",
    4200           2 :                                hasRange(aRefTokens, ScRange(1, 2, 0), aC1));
    4201             :     }
    4202             : 
    4203             :     {
    4204             :         // C2's precedent should be A1 only.
    4205           1 :         ScAddress aC2(2, 1, 0);
    4206           1 :         ScRangeList aRange(aC2);
    4207           1 :         rDocFunc.DetectiveCollectAllPreds(aRange, aRefTokens);
    4208           2 :         CPPUNIT_ASSERT_EQUAL_MESSAGE("there should only be one reference token.",
    4209           1 :                                aRefTokens.size(), static_cast<size_t>(1));
    4210           2 :         CPPUNIT_ASSERT_MESSAGE("A1 should be a precedent of C1.",
    4211           2 :                                hasRange(aRefTokens, ScRange(0, 0, 0), aC2));
    4212             :     }
    4213             : 
    4214             :     {
    4215             :         // A1's dependent should be C1:C2.
    4216           1 :         ScAddress aA1(0, 0, 0);
    4217           1 :         ScRangeList aRange(aA1);
    4218           1 :         rDocFunc.DetectiveCollectAllSuccs(aRange, aRefTokens);
    4219           2 :         CPPUNIT_ASSERT_MESSAGE("C1:C2 should be the only dependent of A1.",
    4220           2 :                                aRefTokens.size() == 1 && hasRange(aRefTokens, ScRange(2, 0, 0, 2, 1, 0), aA1));
    4221             :     }
    4222             : 
    4223           1 :     m_pDoc->DeleteTab(0);
    4224           1 : }
    4225             : 
    4226           1 : void Test::testAutoFill()
    4227             : {
    4228           1 :     m_pDoc->InsertTab(0, "test");
    4229             : 
    4230           1 :     m_pDoc->SetValue(0,0,0,1);
    4231             : 
    4232           1 :     ScMarkData aMarkData;
    4233           1 :     aMarkData.SelectTable(0, true);
    4234             : 
    4235           1 :     m_pDoc->Fill( 0, 0, 0, 0, NULL, aMarkData, 5);
    4236           7 :     for (SCROW i = 0; i< 6; ++i)
    4237           6 :         ASSERT_DOUBLES_EQUAL(static_cast<double>(i+1.0), m_pDoc->GetValue(0, i, 0));
    4238             : 
    4239             :     // check that hidden rows are not affected by autofill
    4240             :     // set values for hidden rows
    4241           1 :     m_pDoc->SetValue(0,1,0,10);
    4242           1 :     m_pDoc->SetValue(0,2,0,10);
    4243             : 
    4244           1 :     m_pDoc->SetRowHidden(1, 2, 0, true);
    4245           1 :     m_pDoc->Fill( 0, 0, 0, 0, NULL, aMarkData, 8);
    4246             : 
    4247           1 :     ASSERT_DOUBLES_EQUAL(10.0, m_pDoc->GetValue(0,1,0));
    4248           1 :     ASSERT_DOUBLES_EQUAL(10.0, m_pDoc->GetValue(0,2,0));
    4249           6 :     for (SCROW i = 3; i< 8; ++i)
    4250           5 :         ASSERT_DOUBLES_EQUAL(static_cast<double>(i-1.0), m_pDoc->GetValue(0, i, 0));
    4251             : 
    4252           1 :     m_pDoc->Fill( 0, 0, 0, 8, NULL, aMarkData, 5, FILL_TO_RIGHT );
    4253           6 :     for (SCCOL i = 0; i < 5; ++i)
    4254             :     {
    4255          45 :         for(SCROW j = 0; j < 8; ++j)
    4256             :         {
    4257          40 :             if (j > 2)
    4258             :             {
    4259          25 :                 ASSERT_DOUBLES_EQUAL(static_cast<double>(j-1+i), m_pDoc->GetValue(i, j, 0));
    4260             :             }
    4261          15 :             else if (j == 0)
    4262             :             {
    4263           5 :                 ASSERT_DOUBLES_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(i, 0, 0));
    4264             :             }
    4265          10 :             else if (j == 1 || j== 2)
    4266             :             {
    4267          10 :                 if(i == 0)
    4268           2 :                     ASSERT_DOUBLES_EQUAL(10.0, m_pDoc->GetValue(0,j,0));
    4269             :                 else
    4270           8 :                     ASSERT_DOUBLES_EQUAL(0.0, m_pDoc->GetValue(i,j,0));
    4271             :             }
    4272             :         }
    4273             :     }
    4274             : 
    4275             :     // test auto fill user data lists
    4276           1 :     m_pDoc->SetString( 0, 100, 0, "January" );
    4277           1 :     m_pDoc->Fill( 0, 100, 0, 100, NULL, aMarkData, 2, FILL_TO_BOTTOM, FILL_AUTO );
    4278           2 :     OUString aTestValue = m_pDoc->GetString( 0, 101, 0 );
    4279           1 :     CPPUNIT_ASSERT_EQUAL( aTestValue, OUString("February") );
    4280           1 :     aTestValue = m_pDoc->GetString( 0, 102, 0 );
    4281           1 :     CPPUNIT_ASSERT_EQUAL( aTestValue, OUString("March") );
    4282             : 
    4283             :     // test that two same user data list entries will not result in incremental fill
    4284           1 :     m_pDoc->SetString( 0, 101, 0, "January" );
    4285           1 :     m_pDoc->Fill( 0, 100, 0, 101, NULL, aMarkData, 2, FILL_TO_BOTTOM, FILL_AUTO );
    4286           3 :     for ( SCROW i = 102; i <= 103; ++i )
    4287             :     {
    4288           2 :         aTestValue = m_pDoc->GetString( 0, i, 0 );
    4289           2 :         CPPUNIT_ASSERT_EQUAL( aTestValue, OUString("January") );
    4290             :     }
    4291             : 
    4292             :     // Clear column A for a new test.
    4293           1 :     clearRange(m_pDoc, ScRange(0,0,0,0,MAXROW,0));
    4294           1 :     m_pDoc->SetRowHidden(0, MAXROW, 0, false); // Show all rows.
    4295             : 
    4296             :     // Fill A1:A6 with 1,2,3,4,5,6.
    4297           1 :     ScDocFunc& rFunc = getDocShell().GetDocFunc();
    4298           1 :     m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
    4299           1 :     ScRange aRange(0,0,0,0,5,0);
    4300           1 :     aMarkData.SetMarkArea(aRange);
    4301           1 :     rFunc.FillSeries(aRange, &aMarkData, FILL_TO_BOTTOM, FILL_AUTO, FILL_DAY, MAXDOUBLE, 1.0, MAXDOUBLE, true, true);
    4302           1 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    4303           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
    4304           1 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,2,0)));
    4305           1 :     CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0,3,0)));
    4306           1 :     CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0,4,0)));
    4307           1 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,5,0)));
    4308             : 
    4309             :     // Undo should clear the area except for the top cell.
    4310           1 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
    4311           1 :     CPPUNIT_ASSERT(pUndoMgr);
    4312           1 :     pUndoMgr->Undo();
    4313             : 
    4314           1 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    4315           6 :     for (SCROW i = 1; i <= 5; ++i)
    4316           5 :         CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(0,i,0)) == CELLTYPE_NONE);
    4317             : 
    4318             :     // Redo should put the serial values back in.
    4319           1 :     pUndoMgr->Redo();
    4320           1 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    4321           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
    4322           1 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,2,0)));
    4323           1 :     CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0,3,0)));
    4324           1 :     CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0,4,0)));
    4325           1 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,5,0)));
    4326             : 
    4327           2 :     m_pDoc->DeleteTab(0);
    4328           1 : }
    4329             : 
    4330           1 : void Test::testCopyPasteFormulas()
    4331             : {
    4332           1 :     m_pDoc->InsertTab(0, "Sheet1");
    4333           1 :     m_pDoc->InsertTab(1, "Sheet2");
    4334             : 
    4335           1 :     m_pDoc->SetString(0,0,0, "=COLUMN($A$1)");
    4336           1 :     m_pDoc->SetString(0,1,0, "=$A$1+B2" );
    4337           1 :     m_pDoc->SetString(0,2,0, "=$Sheet2.A1");
    4338           1 :     m_pDoc->SetString(0,3,0, "=$Sheet2.$A$1");
    4339           1 :     m_pDoc->SetString(0,4,0, "=$Sheet2.A$1");
    4340             : 
    4341             :     // to prevent ScEditableTester in ScDocFunc::MoveBlock
    4342           1 :     ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(0,0,0), 1.0);
    4343           1 :     ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(0,1,0), 1.0);
    4344           1 :     ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
    4345           1 :     bool bMoveDone = rDocFunc.MoveBlock(ScRange(0,0,0,0,4,0), ScAddress( 10, 10, 0), false, false, false, true);
    4346             : 
    4347             :     // check that moving was succesful, mainly for editable tester
    4348           1 :     CPPUNIT_ASSERT(bMoveDone);
    4349           1 :     ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(10,10,0), 1.0);
    4350           1 :     ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(10,11,0), 1.0);
    4351           1 :     OUString aFormula;
    4352           1 :     m_pDoc->GetFormula(10,10,0, aFormula);
    4353           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=COLUMN($A$1)"));
    4354           1 :     m_pDoc->GetFormula(10,11,0, aFormula);
    4355           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$A$1+L12"));
    4356           1 :     m_pDoc->GetFormula(10,12,0, aFormula);
    4357           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$Sheet2.K11"));
    4358           1 :     m_pDoc->GetFormula(10,13,0, aFormula);
    4359           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$Sheet2.$A$1"));
    4360           1 :     m_pDoc->GetFormula(10,14,0, aFormula);
    4361           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$Sheet2.K$1"));
    4362           1 : }
    4363             : 
    4364           1 : void Test::testCopyPasteFormulasExternalDoc()
    4365             : {
    4366           1 :     OUString aDocName("file:///source.fake");
    4367           1 :     SfxMedium* pMedium = new SfxMedium(aDocName, STREAM_STD_READWRITE);
    4368           1 :     getDocShell().DoInitNew(pMedium);
    4369           1 :     m_pDoc = getDocShell().GetDocument();
    4370             : 
    4371           2 :     ScDocShellRef xExtDocSh = new ScDocShell;
    4372           2 :     OUString aExtDocName("file:///extdata.fake");
    4373           2 :     OUString aExtSh1Name("ExtSheet1");
    4374           2 :     OUString aExtSh2Name("ExtSheet2");
    4375           1 :     SfxMedium* pMed = new SfxMedium(aExtDocName, STREAM_STD_READWRITE);
    4376           1 :     xExtDocSh->DoInitNew(pMed);
    4377           2 :     CPPUNIT_ASSERT_MESSAGE("external document instance not loaded.",
    4378           1 :                            findLoadedDocShellByName(aExtDocName) != NULL);
    4379             : 
    4380           1 :     ScDocument* pExtDoc = xExtDocSh->GetDocument();
    4381           1 :     pExtDoc->InsertTab(0, aExtSh1Name);
    4382           1 :     pExtDoc->InsertTab(1, aExtSh2Name);
    4383             : 
    4384           1 :     m_pDoc->InsertTab(0, "Sheet1");
    4385           1 :     m_pDoc->InsertTab(1, "Sheet2");
    4386             : 
    4387           1 :     m_pDoc->SetString(0,0,0, "=COLUMN($A$1)");
    4388           1 :     m_pDoc->SetString(0,1,0, "=$A$1+B2" );
    4389           1 :     m_pDoc->SetString(0,2,0, "=$Sheet2.A1");
    4390           1 :     m_pDoc->SetString(0,3,0, "=$Sheet2.$A$1");
    4391           1 :     m_pDoc->SetString(0,4,0, "=$Sheet2.A$1");
    4392           1 :     m_pDoc->SetString(0,5,0, "=$Sheet1.$A$1");
    4393             : 
    4394           1 :     ScRange aRange(0,0,0,0,5,0);
    4395           2 :     ScClipParam aClipParam(aRange, false);
    4396           2 :     ScMarkData aMark;
    4397           1 :     aMark.SetMarkArea(aRange);
    4398           1 :     ScDocument* pClipDoc = new ScDocument(SCDOCMODE_CLIP);
    4399           1 :     m_pDoc->CopyToClip(aClipParam, pClipDoc, &aMark);
    4400             : 
    4401           1 :     sal_uInt16 nFlags = IDF_ALL;
    4402           1 :     aRange = ScRange(1,1,1,1,6,1);
    4403           2 :     ScMarkData aMarkData2;
    4404           1 :     aMarkData2.SetMarkArea(aRange);
    4405           1 :     pExtDoc->CopyFromClip(aRange, aMarkData2, nFlags, NULL, pClipDoc);
    4406             : 
    4407           2 :     OUString aFormula;
    4408           1 :     pExtDoc->GetFormula(1,1,1, aFormula);
    4409             :     //adjust absolute refs pointing to the copy area
    4410           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=COLUMN($B$2)"));
    4411           1 :     pExtDoc->GetFormula(1,2,1, aFormula);
    4412             :     //adjust absolute refs and keep relative refs
    4413           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$B$2+C3"));
    4414           1 :     pExtDoc->GetFormula(1,3,1, aFormula);
    4415             :     // make absolute sheet refs external refs
    4416           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("='file:///source.fake'#$Sheet2.B2"));
    4417           1 :     pExtDoc->GetFormula(1,4,1, aFormula);
    4418           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("='file:///source.fake'#$Sheet2.$A$1"));
    4419           1 :     pExtDoc->GetFormula(1,5,1, aFormula);
    4420           1 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("='file:///source.fake'#$Sheet2.B$1"));
    4421           1 :     pExtDoc->GetFormula(1,6,1, aFormula);
    4422           2 :     CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$ExtSheet2.$B$2"));
    4423           1 : }
    4424             : 
    4425           1 : void Test::testFindAreaPosVertical()
    4426             : {
    4427             :     const char* aData[][3] = {
    4428             :         {   0, "1", "1" },
    4429             :         { "1",   0, "1" },
    4430             :         { "1", "1", "1" },
    4431             :         {   0, "1", "1" },
    4432             :         { "1", "1", "1" },
    4433             :         { "1",   0, "1" },
    4434             :         { "1", "1", "1" },
    4435           1 :     };
    4436             : 
    4437           1 :     m_pDoc->InsertTab(0, "Test1");
    4438           1 :     clearRange( m_pDoc, ScRange(0, 0, 0, 1, SAL_N_ELEMENTS(aData), 0));
    4439           1 :     ScAddress aPos(0,0,0);
    4440           1 :     ScRange aDataRange = insertRangeData( m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    4441           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    4442             : 
    4443           1 :     m_pDoc->SetRowHidden(4,4,0,true);
    4444           1 :     bool bHidden = m_pDoc->RowHidden(4,0);
    4445           1 :     CPPUNIT_ASSERT(bHidden);
    4446             : 
    4447           1 :     SCCOL nCol = 0;
    4448           1 :     SCROW nRow = 0;
    4449           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
    4450             : 
    4451           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), nRow);
    4452           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
    4453             : 
    4454           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
    4455             : 
    4456           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), nRow);
    4457           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
    4458             : 
    4459           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
    4460             : 
    4461           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), nRow);
    4462           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
    4463             : 
    4464           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
    4465             : 
    4466           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), nRow);
    4467           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
    4468             : 
    4469           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
    4470             : 
    4471           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(MAXROW), nRow);
    4472           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
    4473             : 
    4474           1 :     nCol = 1;
    4475           1 :     nRow = 2;
    4476             : 
    4477           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
    4478             : 
    4479           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), nRow);
    4480           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(1), nCol);
    4481             : 
    4482           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
    4483             : 
    4484           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), nRow);
    4485           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(1), nCol);
    4486             : 
    4487           1 :     nCol = 2;
    4488           1 :     nRow = 6;
    4489           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_UP);
    4490           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
    4491           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(2), nCol);
    4492             : 
    4493             : 
    4494           1 :     m_pDoc->DeleteTab(0);
    4495           1 : }
    4496             : 
    4497           1 : void Test::testFindAreaPosColRight()
    4498             : {
    4499             :     const char* aData[][7] = {
    4500             :         { "", "1", "1", "", "1", "1", "1" },
    4501           1 :         { "", "", "1", "1", "1", "", "1" }, };
    4502             : 
    4503           1 :     m_pDoc->InsertTab(0, "test1");
    4504           1 :     clearRange( m_pDoc, ScRange(0, 0, 0, 7, SAL_N_ELEMENTS(aData), 0));
    4505           1 :     ScAddress aPos(0,0,0);
    4506           1 :     ScRange aDataRange = insertRangeData( m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    4507           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    4508             : 
    4509           1 :     m_pDoc->SetColHidden(4,4,0,true);
    4510           1 :     bool bHidden = m_pDoc->ColHidden(4,0);
    4511           1 :     CPPUNIT_ASSERT(bHidden);
    4512             : 
    4513           1 :     SCCOL nCol = 0;
    4514           1 :     SCROW nRow = 0;
    4515           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
    4516             : 
    4517           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
    4518           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(1), nCol);
    4519             : 
    4520           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
    4521             : 
    4522           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
    4523           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(2), nCol);
    4524             : 
    4525           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
    4526             : 
    4527           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
    4528           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(5), nCol);
    4529             : 
    4530           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
    4531             : 
    4532           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
    4533           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(6), nCol);
    4534             : 
    4535           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
    4536             : 
    4537           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
    4538           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(MAXCOL), nCol);
    4539             : 
    4540           1 :     nCol = 2;
    4541           1 :     nRow = 1;
    4542             : 
    4543           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
    4544             : 
    4545           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), nRow);
    4546           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(3), nCol);
    4547             : 
    4548           1 :     m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
    4549             : 
    4550           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), nRow);
    4551           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(6), nCol);
    4552             : 
    4553           1 :     m_pDoc->DeleteTab(0);
    4554           1 : }
    4555             : 
    4556             : // regression test fo fdo#53814, sorting doens't work as expected
    4557             : // if cells in the sort are referenced by formulas
    4558           1 : void Test::testSortWithFormulaRefs()
    4559             : {
    4560           1 :     ScDocument* pDoc = getDocShell().GetDocument();
    4561           1 :     pDoc->InsertTab(0, "List1");
    4562           1 :     pDoc->InsertTab(1, "List2");
    4563             : 
    4564             :     const char* aFormulaData[6] = {
    4565             :         "=IF($List1.A2<>\"\",$List1.A2,\"\")",
    4566             :         "=IF($List1.A3<>\"\",$List1.A3,\"\")",
    4567             :         "=IF($List1.A4<>\"\",$List1.A4,\"\")",
    4568             :         "=IF($List1.A5<>\"\",$List1.A5,\"\")",
    4569             :         "=IF($List1.A6<>\"\",$List1.A6,\"\")",
    4570             :         "=IF($List1.A7<>\"\",$List1.A7,\"\")",
    4571           1 :     };
    4572             : 
    4573             :     const char* aTextData[4] = {
    4574             :         "bob",
    4575             :         "tim",
    4576             :         "brian",
    4577             :         "larry",
    4578           1 :     };
    4579             : 
    4580             :     const char* aResults[ 6 ] = {
    4581             :         "bob",
    4582             :         "brian",
    4583             :         "larry",
    4584             :         "tim",
    4585             :         "",
    4586             :         "",
    4587           1 :     };
    4588             :     // insert data to sort
    4589           1 :     SCROW nStart = 1, nEnd = 4;
    4590           5 :     for ( SCROW i = nStart; i <= nEnd; ++i )
    4591           4 :         pDoc->SetString( 0, i, 0, OUString::createFromAscii(aTextData[i-1]) );
    4592             :     // insert forumulas
    4593           1 :     nStart = 0;
    4594           1 :     nEnd = SAL_N_ELEMENTS(aFormulaData);
    4595           7 :     for ( SCROW i = nStart; i < nEnd; ++i )
    4596           6 :         pDoc->SetString( 0, i, 1, OUString::createFromAscii(aFormulaData[i]) );
    4597             : 
    4598           1 :     ScSortParam aSortData;
    4599           1 :     aSortData.nCol1 = 0;
    4600           1 :     aSortData.nCol2 = 0;
    4601           1 :     aSortData.nRow1 = 1;
    4602           1 :     aSortData.nRow2 = 7;
    4603           1 :     aSortData.maKeyState[0].bDoSort = true;
    4604           1 :     aSortData.maKeyState[0].nField = 0;
    4605             : 
    4606           1 :     pDoc->Sort(0, aSortData, false, NULL);
    4607             : 
    4608           1 :     nEnd = SAL_N_ELEMENTS( aResults );
    4609           7 :     for ( SCROW i = nStart; i < nEnd; ++i )
    4610             :     {
    4611           6 :         OUString sResult = pDoc->GetString( 0, i + 1, 0);
    4612           6 :         CPPUNIT_ASSERT_EQUAL( OUString::createFromAscii( aResults[ i ] ), sResult );
    4613           6 :     }
    4614           1 :     pDoc->DeleteTab(0);
    4615           1 :     pDoc->DeleteTab(1);
    4616           1 : }
    4617             : 
    4618           1 : void Test::testSortWithStrings()
    4619             : {
    4620           1 :     m_pDoc->InsertTab(0, "Test");
    4621             : 
    4622           1 :     ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
    4623           1 :     rEE.SetText("Val1");
    4624           1 :     m_pDoc->SetString(ScAddress(1,1,0), "Header");
    4625           1 :     m_pDoc->SetString(ScAddress(1,2,0), "Val2");
    4626           1 :     m_pDoc->SetEditText(ScAddress(1,3,0), rEE.CreateTextObject());
    4627             : 
    4628           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
    4629           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,2,0)));
    4630           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,3,0)));
    4631             : 
    4632           1 :     ScSortParam aParam;
    4633           1 :     aParam.nCol1 = 1;
    4634           1 :     aParam.nCol2 = 1;
    4635           1 :     aParam.nRow1 = 1;
    4636           1 :     aParam.nRow2 = 3;
    4637           1 :     aParam.bHasHeader = true;
    4638           1 :     aParam.maKeyState[0].bDoSort = true;
    4639           1 :     aParam.maKeyState[0].bAscending = true;
    4640           1 :     aParam.maKeyState[0].nField = 1;
    4641             : 
    4642           1 :     m_pDoc->Sort(0, aParam, false, NULL);
    4643             : 
    4644           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
    4645           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,2,0)));
    4646           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,3,0)));
    4647             : 
    4648           1 :     aParam.maKeyState[0].bAscending = false;
    4649             : 
    4650           1 :     m_pDoc->Sort(0, aParam, false, NULL);
    4651             : 
    4652           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
    4653           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,2,0)));
    4654           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,3,0)));
    4655             : 
    4656           1 :     m_pDoc->DeleteTab(0);
    4657           1 : }
    4658             : 
    4659           1 : void Test::testSort()
    4660             : {
    4661           1 :     m_pDoc->InsertTab(0, "test1");
    4662             : 
    4663           1 :     ScRange aDataRange;
    4664           1 :     ScAddress aPos(0,0,0);
    4665             :     {
    4666             :         const char* aData[][2] = {
    4667             :             { "2", "4" },
    4668             :             { "4", "1" },
    4669             :             { "1", "2" },
    4670             :             { "1", "23" },
    4671           1 :         };
    4672             : 
    4673           1 :         clearRange(m_pDoc, ScRange(0, 0, 0, 1, SAL_N_ELEMENTS(aData), 0));
    4674           1 :         aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    4675           1 :         CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    4676             :     }
    4677             : 
    4678             :     // Insert note in cell B2.
    4679           1 :     ScAddress rAddr(1, 1, 0);
    4680           1 :     ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
    4681           1 :     pNote->SetText(rAddr, "Hello");
    4682           1 :     pNote->SetAuthor("Jim Bob");
    4683             : 
    4684           1 :     ScSortParam aSortData;
    4685           1 :     aSortData.nCol1 = 1;
    4686           1 :     aSortData.nCol2 = 1;
    4687           1 :     aSortData.nRow1 = 0;
    4688           1 :     aSortData.nRow2 = 2;
    4689           1 :     aSortData.maKeyState[0].bDoSort = true;
    4690           1 :     aSortData.maKeyState[0].nField = 1;
    4691           1 :     aSortData.maKeyState[0].bAscending = true;
    4692             : 
    4693           1 :     m_pDoc->Sort(0, aSortData, false, NULL);
    4694             : 
    4695           1 :     double nVal = m_pDoc->GetValue(1,0,0);
    4696           1 :     ASSERT_DOUBLES_EQUAL(nVal, 1.0);
    4697             : 
    4698             :     // check that note is also moved after sorting
    4699           1 :     pNote = m_pDoc->GetNote(1, 0, 0);
    4700           1 :     CPPUNIT_ASSERT(pNote);
    4701             : 
    4702           1 :     clearRange(m_pDoc, ScRange(0, 0, 0, 1, 9, 0)); // Clear A1:B10.
    4703             :     {
    4704             :         // 0 = empty cell
    4705             :         const char* aData[][1] = {
    4706             :             { "Title" },
    4707             :             { 0 },
    4708             :             { 0 },
    4709             :             { "12" },
    4710             :             { "b" },
    4711             :             { "1" },
    4712             :             { "9" },
    4713             :             { "123" }
    4714           1 :         };
    4715             : 
    4716           1 :         aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    4717           1 :         CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    4718             :     }
    4719             : 
    4720           1 :     aSortData.nCol1 = aDataRange.aStart.Col();
    4721           1 :     aSortData.nCol2 = aDataRange.aEnd.Col();
    4722           1 :     aSortData.nRow1 = aDataRange.aStart.Row();
    4723           1 :     aSortData.nRow2 = aDataRange.aEnd.Row();
    4724           1 :     aSortData.bHasHeader = true;
    4725           1 :     aSortData.maKeyState[0].nField = 0;
    4726           1 :     m_pDoc->Sort(0, aSortData, false, NULL);
    4727             : 
    4728             :     // Title should stay at the top, numbers should be sorted numerically,
    4729             :     // numbers always come before strings, and empty cells always occur at the
    4730             :     // end.
    4731           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Title"), m_pDoc->GetString(aPos));
    4732           1 :     aPos.IncRow();
    4733           1 :     CPPUNIT_ASSERT_EQUAL(OUString("1"), m_pDoc->GetString(aPos));
    4734           1 :     aPos.IncRow();
    4735           1 :     CPPUNIT_ASSERT_EQUAL(OUString("9"), m_pDoc->GetString(aPos));
    4736           1 :     aPos.IncRow();
    4737           1 :     CPPUNIT_ASSERT_EQUAL(OUString("12"), m_pDoc->GetString(aPos));
    4738           1 :     aPos.IncRow();
    4739           1 :     CPPUNIT_ASSERT_EQUAL(OUString("123"), m_pDoc->GetString(aPos));
    4740           1 :     aPos.IncRow();
    4741           1 :     CPPUNIT_ASSERT_EQUAL(OUString("b"), m_pDoc->GetString(aPos));
    4742           1 :     aPos.IncRow();
    4743           1 :     CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPos));
    4744             : 
    4745           1 :     m_pDoc->DeleteTab(0);
    4746           1 : }
    4747             : 
    4748           1 : void Test::testSortInFormulaGroup()
    4749             : {
    4750             :     static struct {
    4751             :         SCCOL nCol;
    4752             :         SCROW nRow;
    4753             :         const char *pData;
    4754             :     } aEntries[] = {
    4755             :         { 0, 0, "3" },   { 1, 0, "=A1" },
    4756             :         { 0, 1, "1" },   { 1, 1, "=A2" },
    4757             :         { 0, 2, "20" },  { 1, 2, "=A3" },
    4758             :         { 0, 3, "10" },  { 1, 3, "=A4+1" }, // swap across groups
    4759             :         { 0, 4, "2"  },  { 1, 4, "=A5+1" },
    4760             :         { 0, 5, "101" }, { 1, 5, "=A6" }, // swap inside contiguious group
    4761             :         { 0, 6, "100" }, { 1, 6, "=A7" },
    4762             :         { 0, 7, "102" }, { 1, 7, "=A8" },
    4763             :         { 0, 8, "104" }, { 1, 8, "=A9" },
    4764             :         { 0, 9, "103" }, { 1, 9, "=A10" },
    4765             :     };
    4766             : 
    4767           1 :     m_pDoc->InsertTab(0, "sorttest");
    4768             : 
    4769          21 :     for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
    4770             :         m_pDoc->SetString( aEntries[i].nCol, aEntries[i].nRow, 0,
    4771          20 :                            OUString::createFromAscii( aEntries[i].pData) );
    4772             : 
    4773           1 :     ScSortParam aSortData;
    4774           1 :     aSortData.nCol1 = 0;
    4775           1 :     aSortData.nCol2 = 1;
    4776           1 :     aSortData.nRow1 = 0;
    4777           1 :     aSortData.nRow2 = 9;
    4778           1 :     aSortData.maKeyState[0].bDoSort = true;
    4779           1 :     aSortData.maKeyState[0].nField = 0;
    4780           1 :     aSortData.maKeyState[0].bAscending = true;
    4781             : 
    4782           1 :     m_pDoc->Sort(0, aSortData, false, NULL);
    4783             : 
    4784             :     static struct {
    4785             :         SCCOL nCol;
    4786             :         SCROW nRow;
    4787             :         double fValue;
    4788             :     } aResults[] = {
    4789             :         { 0, 0, 1.0 },   { 1, 0, 1.0 },
    4790             :         { 0, 1, 2.0 },   { 1, 1, 3.0 },
    4791             :         { 0, 2, 3.0 },   { 1, 2, 3.0 },
    4792             :         { 0, 3, 10.0 },  { 1, 3, 11.0 },
    4793             :         { 0, 4, 20.0 },  { 1, 4, 20.0 },
    4794             :         { 0, 5, 100.0 }, { 1, 5, 100.0 },
    4795             :         { 0, 6, 101.0 }, { 1, 6, 101.0 },
    4796             :         { 0, 7, 102.0 }, { 1, 7, 102.0 },
    4797             :         { 0, 8, 103.0 }, { 1, 8, 103.0 },
    4798             :         { 0, 9, 104.0 }, { 1, 9, 104.0 },
    4799             :     };
    4800             : 
    4801          21 :     for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
    4802             :     {
    4803          20 :         double val = m_pDoc->GetValue( aEntries[i].nCol, aEntries[i].nRow, 0 );
    4804             : //        fprintf(stderr, "value at %d %d is %g = %g\n",
    4805             : //                (int)aResults[i].nRow, (int)aResults[i].nCol,
    4806             : //                val, aResults[i].fValue);
    4807          40 :         CPPUNIT_ASSERT_MESSAGE("Mis-matching value after sort.",
    4808          20 :                                rtl::math::approxEqual(val, aResults[i].fValue));
    4809             :     }
    4810             : 
    4811           1 :     m_pDoc->DeleteTab( 0 );
    4812           1 : }
    4813             : 
    4814           1 : void Test::testShiftCells()
    4815             : {
    4816           1 :     m_pDoc->InsertTab(0, "foo");
    4817             : 
    4818           1 :     OUString aTestVal("Some Text");
    4819             : 
    4820             :     // Text into cell E5.
    4821           1 :     m_pDoc->SetString(4, 3, 0, aTestVal);
    4822             : 
    4823             :     // put a Note in cell E5
    4824           1 :     ScAddress rAddr(4, 3, 0);
    4825           1 :     ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
    4826           1 :     pNote->SetText(rAddr, "Hello");
    4827             : 
    4828           1 :     CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(4, 3, 0));
    4829             : 
    4830             :     // Insert cell at D5. This should shift the string cell to right.
    4831           1 :     m_pDoc->InsertCol(3, 0, 3, 0, 3, 1);
    4832           2 :     OUString aStr = m_pDoc->GetString(5, 3, 0);
    4833           1 :     CPPUNIT_ASSERT_MESSAGE("We should have a string cell here.", aStr == aTestVal);
    4834           1 :     CPPUNIT_ASSERT_MESSAGE("D5 is supposed to be blank.", m_pDoc->IsBlockEmpty(0, 3, 4, 3, 4));
    4835             : 
    4836           1 :     CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc->HasNote(4, 3, 0));
    4837           1 :     CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(5, 3, 0));
    4838             : 
    4839             :     // Delete cell D5, to shift the text cell back into D5.
    4840           1 :     m_pDoc->DeleteCol(3, 0, 3, 0, 3, 1);
    4841           1 :     aStr = m_pDoc->GetString(4, 3, 0);
    4842           1 :     CPPUNIT_ASSERT_MESSAGE("We should have a string cell here.", aStr == aTestVal);
    4843           1 :     CPPUNIT_ASSERT_MESSAGE("E5 is supposed to be blank.", m_pDoc->IsBlockEmpty(0, 4, 4, 4, 4));
    4844             : 
    4845           1 :     CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc->HasNote(5, 3, 0));
    4846           1 :     CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(4, 3, 0));
    4847             : 
    4848           2 :     m_pDoc->DeleteTab(0);
    4849           1 : }
    4850             : 
    4851           1 : void Test::testNoteBasic()
    4852             : {
    4853           1 :     m_pDoc->InsertTab(0, "PostIts");
    4854             : 
    4855           1 :     ScAddress aAddr(2, 2, 0); // cell C3
    4856           1 :     ScPostIt *pNote = m_pDoc->GetOrCreateNote(aAddr);
    4857             : 
    4858           1 :     pNote->SetText(aAddr, "Hello world");
    4859           1 :     pNote->SetAuthor("Jim Bob");
    4860             : 
    4861           1 :     ScPostIt *pGetNote = m_pDoc->GetNote(aAddr);
    4862           1 :     CPPUNIT_ASSERT_MESSAGE("note should be itself", pGetNote == pNote);
    4863             : 
    4864             :     // Insert one row at row 1.
    4865           1 :     bool bInsertRow = m_pDoc->InsertRow(0, 0, MAXCOL, 0, 1, 1);
    4866           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert row", bInsertRow );
    4867             : 
    4868           1 :     CPPUNIT_ASSERT_MESSAGE("note hasn't moved", m_pDoc->GetNote(aAddr) == NULL);
    4869           1 :     aAddr.IncRow(); // cell C4
    4870           1 :     CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
    4871             : 
    4872             :     // Insert column at column A.
    4873           1 :     bool bInsertCol = m_pDoc->InsertCol(0, 0, MAXROW, 0, 1, 1);
    4874           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert column", bInsertCol );
    4875             : 
    4876           1 :     CPPUNIT_ASSERT_MESSAGE("note hasn't moved", m_pDoc->GetNote(aAddr) == NULL);
    4877           1 :     aAddr.IncCol(); // cell D4
    4878           1 :     CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
    4879             : 
    4880             :     // Insert a new sheet to shift the current sheet to the right.
    4881           1 :     m_pDoc->InsertTab(0, "Table2");
    4882           1 :     CPPUNIT_ASSERT_MESSAGE("note hasn't moved", m_pDoc->GetNote(aAddr) == NULL);
    4883           1 :     aAddr.IncTab(); // Move to the next sheet.
    4884           1 :     CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
    4885             : 
    4886           1 :     m_pDoc->DeleteTab(0);
    4887           1 :     aAddr.IncTab(-1);
    4888           1 :     CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
    4889             : 
    4890             :     // Insert cell at C4.  This should NOT shift the note position.
    4891           1 :     bInsertRow = m_pDoc->InsertRow(2, 0, 2, 0, 3, 1);
    4892           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to insert cell at C4.", bInsertRow);
    4893           1 :     CPPUNIT_ASSERT_MESSAGE("Note shouldn't have moved but it has.", m_pDoc->GetNote(aAddr) == pNote);
    4894             : 
    4895             :     // Delete cell at C4.  Again, this should NOT shift the note position.
    4896           1 :     m_pDoc->DeleteRow(2, 0, 2, 0, 3, 1);
    4897           1 :     CPPUNIT_ASSERT_MESSAGE("Note shouldn't have moved but it has.", m_pDoc->GetNote(aAddr) == pNote);
    4898             : 
    4899             :     // Now, with the note at D4, delete cell D3. This should shift the note one cell up.
    4900           1 :     m_pDoc->DeleteRow(3, 0, 3, 0, 2, 1);
    4901           1 :     aAddr.IncRow(-1); // cell D3
    4902           1 :     CPPUNIT_ASSERT_MESSAGE("Note at D4 should have shifted up to D3.", m_pDoc->GetNote(aAddr) == pNote);
    4903             : 
    4904             :     // Delete column C. This should shift the note one cell left.
    4905           1 :     m_pDoc->DeleteCol(0, 0, MAXROW, 0, 2, 1);
    4906           1 :     aAddr.IncCol(-1); // cell C3
    4907           1 :     CPPUNIT_ASSERT_MESSAGE("Note at D3 should have shifted left to C3.", m_pDoc->GetNote(aAddr) == pNote);
    4908             : 
    4909             :     // Insert a text where the note is.
    4910           1 :     m_pDoc->SetString(aAddr, "Note is here.");
    4911             : 
    4912             :     // Delete row 1. This should shift the note from C3 to C2.
    4913           1 :     m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 0, 1);
    4914           1 :     aAddr.IncRow(-1); // C2
    4915           1 :     CPPUNIT_ASSERT_MESSAGE("Note at C3 should have shifted up to C2.", m_pDoc->GetNote(aAddr) == pNote);
    4916             : 
    4917           1 :     m_pDoc->DeleteTab(0);
    4918           1 : }
    4919             : 
    4920           1 : void Test::testNoteDeleteRow()
    4921             : {
    4922           1 :     m_pDoc->InsertTab(0, "Sheet1");
    4923             : 
    4924             :     // We need a drawing layer in order to create caption objects.
    4925           1 :     m_pDoc->InitDrawLayer(&getDocShell());
    4926             : 
    4927           1 :     OUString aHello("Hello");
    4928           2 :     OUString aJimBob("Jim Bob");
    4929           1 :     ScAddress aPos(1, 1, 0);
    4930           1 :     ScPostIt* pNote = m_pDoc->GetOrCreateNote(aPos);
    4931           1 :     pNote->SetText(aPos, aHello);
    4932           1 :     pNote->SetAuthor(aJimBob);
    4933             : 
    4934           1 :     CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(1, 1, 0));
    4935             : 
    4936             :     // test with IsBlockEmpty
    4937           1 :     bool bIgnoreNotes = true;
    4938           1 :     CPPUNIT_ASSERT_MESSAGE("The Block should be detected as empty (no Notes)", m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100, bIgnoreNotes));
    4939           1 :     bIgnoreNotes = false;
    4940           1 :     CPPUNIT_ASSERT_MESSAGE("The Block should NOT be detected as empty", !m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100, bIgnoreNotes));
    4941             : 
    4942           1 :     m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 1, 1);
    4943             : 
    4944           1 :     CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc->HasNote(1, 1, 0));
    4945             : 
    4946             :     // Set values and notes into B3:B4.
    4947           1 :     aPos = ScAddress(1,2,0); // B3
    4948           1 :     m_pDoc->SetString(aPos, "First");
    4949           1 :     ScNoteUtil::CreateNoteFromString(*m_pDoc, aPos, "First Note", false, false);
    4950             : 
    4951           1 :     aPos = ScAddress(1,3,0); // B4
    4952           1 :     m_pDoc->SetString(aPos, "Second");
    4953           1 :     ScNoteUtil::CreateNoteFromString(*m_pDoc, aPos, "Second Note", false, false);
    4954             : 
    4955             :     // Delete row 2.
    4956           1 :     ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
    4957           2 :     ScMarkData aMark;
    4958           1 :     aMark.SelectOneTable(0);
    4959           1 :     rDocFunc.DeleteCells(ScRange(0,1,0,MAXCOL,1,0), &aMark, DEL_CELLSUP, true, true);
    4960             : 
    4961             :     // Check to make sure the notes have shifted upward.
    4962           1 :     pNote = m_pDoc->GetNote(ScAddress(1,1,0));
    4963           1 :     CPPUNIT_ASSERT_MESSAGE("B2 should have a note.", pNote);
    4964           1 :     CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote->GetText());
    4965           1 :     pNote = m_pDoc->GetNote(ScAddress(1,2,0));
    4966           1 :     CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
    4967           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
    4968           1 :     pNote = m_pDoc->GetNote(ScAddress(1,3,0));
    4969           1 :     CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote);
    4970             : 
    4971             :     // Undo.
    4972             : 
    4973           1 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
    4974           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr);
    4975           1 :     m_pDoc->CreateAllNoteCaptions(); // to make sure that all notes have their corresponding caption objects...
    4976             : 
    4977           1 :     pUndoMgr->Undo();
    4978           1 :     pNote = m_pDoc->GetNote(ScAddress(1,1,0));
    4979           1 :     CPPUNIT_ASSERT_MESSAGE("B2 should NOT have a note.", !pNote);
    4980           1 :     pNote = m_pDoc->GetNote(ScAddress(1,2,0));
    4981           1 :     CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
    4982           1 :     CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote->GetText());
    4983           1 :     pNote = m_pDoc->GetNote(ScAddress(1,3,0));
    4984           1 :     CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote);
    4985           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
    4986             : 
    4987             :     // Delete row 3.
    4988           1 :     rDocFunc.DeleteCells(ScRange(0,2,0,MAXCOL,2,0), &aMark, DEL_CELLSUP, true, true);
    4989             : 
    4990           1 :     pNote = m_pDoc->GetNote(ScAddress(1,2,0));
    4991           1 :     CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
    4992           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
    4993           1 :     pNote = m_pDoc->GetNote(ScAddress(1,3,0));
    4994           1 :     CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote);
    4995             : 
    4996             :     // Undo and check the result.
    4997           1 :     pUndoMgr->Undo();
    4998           1 :     pNote = m_pDoc->GetNote(ScAddress(1,2,0));
    4999           1 :     CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
    5000           1 :     CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote->GetText());
    5001           1 :     pNote = m_pDoc->GetNote(ScAddress(1,3,0));
    5002           1 :     CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote);
    5003           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
    5004             : 
    5005           2 :     m_pDoc->DeleteTab(0);
    5006           1 : }
    5007             : 
    5008           1 : void Test::testNoteDeleteCol()
    5009             : {
    5010           1 :     ScDocument* pDoc = getDocShell().GetDocument();
    5011           1 :     pDoc->InsertTab(0, "Sheet1");
    5012             : 
    5013           1 :     ScAddress rAddr(1, 1, 0);
    5014           1 :     ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
    5015           1 :     pNote->SetText(rAddr, "Hello");
    5016           1 :     pNote->SetAuthor("Jim Bob");
    5017             : 
    5018           1 :     CPPUNIT_ASSERT_MESSAGE("there should be a note", pDoc->HasNote(1, 1, 0));
    5019             : 
    5020           1 :     pDoc->DeleteCol(0, 0, MAXROW, 0, 1, 1);
    5021             : 
    5022           1 :     CPPUNIT_ASSERT_MESSAGE("there should be no more note", !pDoc->HasNote(1, 1, 0));
    5023             : 
    5024           1 :     pDoc->DeleteTab(0);
    5025           1 : }
    5026             : 
    5027           1 : void Test::testNoteLifeCycle()
    5028             : {
    5029           1 :     m_pDoc->InsertTab(0, "Test");
    5030             : 
    5031             :     // We need a drawing layer in order to create caption objects.
    5032           1 :     m_pDoc->InitDrawLayer(&getDocShell());
    5033             : 
    5034           1 :     ScAddress aPos(1,1,0);
    5035           1 :     ScPostIt* pNote = m_pDoc->GetOrCreateNote(aPos);
    5036           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to insert a new cell comment.", pNote);
    5037             : 
    5038           1 :     pNote->SetText(aPos, "New note");
    5039           1 :     ScPostIt* pNote2 = m_pDoc->ReleaseNote(aPos);
    5040           1 :     CPPUNIT_ASSERT_MESSAGE("This note instance is expected to be identical to the original.", pNote == pNote2);
    5041           1 :     CPPUNIT_ASSERT_MESSAGE("The note shouldn't be here after it's been released.", !m_pDoc->HasNote(aPos));
    5042             : 
    5043             :     // Modify the internal state of the note instance to make sure it's really
    5044             :     // been released.
    5045           1 :     pNote->SetText(aPos, "New content");
    5046             : 
    5047             :     // Re-insert the note back to the same place.
    5048           1 :     m_pDoc->SetNote(aPos, pNote);
    5049           1 :     const SdrCaptionObj* pCaption = pNote->GetOrCreateCaption(aPos);
    5050           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to create a caption object.", pCaption);
    5051           2 :     CPPUNIT_ASSERT_MESSAGE("This caption should belong to the drawing layer of the document.",
    5052           1 :                            pCaption->GetModel() == m_pDoc->GetDrawLayer());
    5053             : 
    5054             :     // Copy B2 with note to a clipboard.
    5055             : 
    5056           1 :     ScClipParam aClipParam(aPos, false);
    5057           2 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    5058           2 :     ScMarkData aMarkData;
    5059           1 :     aMarkData.SelectOneTable(0);
    5060           1 :     m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMarkData, false, false, true, true, false);
    5061             : 
    5062           1 :     ScPostIt* pClipNote = aClipDoc.GetNote(aPos);
    5063           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to copy note to the clipboard.", pClipNote);
    5064           2 :     CPPUNIT_ASSERT_MESSAGE("Note on the clipboard should share the same caption object from the original.",
    5065           1 :                            pClipNote->GetCaption() == pCaption);
    5066             : 
    5067           2 :     m_pDoc->DeleteTab(0);
    5068           1 : }
    5069             : 
    5070           1 : void Test::testAreasWithNotes()
    5071             : {
    5072           1 :     ScDocument* pDoc = getDocShell().GetDocument();
    5073           1 :     pDoc->InsertTab(0, "Sheet1");
    5074             : 
    5075           1 :     ScAddress rAddr(1, 5, 0);
    5076           1 :     ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
    5077           1 :     pNote->SetText(rAddr, "Hello");
    5078           1 :     pNote->SetAuthor("Jim Bob");
    5079           1 :     ScAddress rAddrMin(2, 2, 0);
    5080           1 :     ScPostIt* pNoteMin = m_pDoc->GetOrCreateNote(rAddrMin);
    5081           1 :     pNoteMin->SetText(rAddrMin, "Hello");
    5082             : 
    5083             :     SCCOL col;
    5084             :     SCROW row;
    5085           1 :     bool dataFound = false;
    5086             : 
    5087             :     // only cell notes (empty content)
    5088             : 
    5089           1 :     dataFound = pDoc->GetDataStart(0,col,row);
    5090             : 
    5091           1 :     CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound);
    5092           1 :     CPPUNIT_ASSERT_MESSAGE("DataStart wrong col for notes", col == 1);
    5093           1 :     CPPUNIT_ASSERT_MESSAGE("DataStart wrong row for notes", row == 2);
    5094             : 
    5095           1 :     dataFound = pDoc->GetCellArea(0,col,row);
    5096             : 
    5097           1 :     CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound);
    5098           1 :     CPPUNIT_ASSERT_MESSAGE("CellArea wrong col for notes", col == 2);
    5099           1 :     CPPUNIT_ASSERT_MESSAGE("CellArea wrong row for notes", row == 5);
    5100             : 
    5101           1 :     bool bNotes = true;
    5102           1 :     dataFound = pDoc->GetPrintArea(0,col,row, bNotes);
    5103             : 
    5104           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound);
    5105           1 :     CPPUNIT_ASSERT_MESSAGE("PrintArea wrong col for notes", col == 2);
    5106           1 :     CPPUNIT_ASSERT_MESSAGE("PrintArea wrong row for notes", row == 5);
    5107             : 
    5108           1 :     bNotes = false;
    5109           1 :     dataFound = pDoc->GetPrintArea(0,col,row, bNotes);
    5110           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintArea should be found", !dataFound);
    5111             : 
    5112           1 :     bNotes = true;
    5113           1 :     dataFound = pDoc->GetPrintAreaVer(0,0,1,row, bNotes); // cols 0 & 1
    5114           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
    5115           1 :     CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row for notes", row == 5);
    5116             : 
    5117           1 :     dataFound = pDoc->GetPrintAreaVer(0,2,3,row, bNotes); // cols 2 & 3
    5118           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
    5119           1 :     CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row for notes", row == 2);
    5120             : 
    5121           1 :     bNotes = false;
    5122           1 :     dataFound = pDoc->GetPrintAreaVer(0,0,1,row, bNotes); // col 0 & 1
    5123           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer should be found", !dataFound);
    5124             : 
    5125             :     // now add cells with value, check that notes are taken into accompt in good cases
    5126             : 
    5127           1 :     m_pDoc->SetString(0, 3, 0, "Some Text");
    5128           1 :     m_pDoc->SetString(3, 3, 0, "Some Text");
    5129             : 
    5130           1 :     dataFound = pDoc->GetDataStart(0,col,row);
    5131             : 
    5132           1 :     CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound);
    5133           1 :     CPPUNIT_ASSERT_MESSAGE("DataStart wrong col", col == 0);
    5134           1 :     CPPUNIT_ASSERT_MESSAGE("DataStart wrong row", row == 2);
    5135             : 
    5136           1 :     dataFound = pDoc->GetCellArea(0,col,row);
    5137             : 
    5138           1 :     CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound);
    5139           1 :     CPPUNIT_ASSERT_MESSAGE("CellArea wrong col", col == 3);
    5140           1 :     CPPUNIT_ASSERT_MESSAGE("CellArea wrong row", row == 5);
    5141             : 
    5142           1 :     bNotes = true;
    5143           1 :     dataFound = pDoc->GetPrintArea(0,col,row, bNotes);
    5144             : 
    5145           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound);
    5146           1 :     CPPUNIT_ASSERT_MESSAGE("PrintArea wrong col", col == 3);
    5147           1 :     CPPUNIT_ASSERT_MESSAGE("PrintArea wrong row", row == 5);
    5148             : 
    5149           1 :     bNotes = false;
    5150           1 :     dataFound = pDoc->GetPrintArea(0,col,row, bNotes);
    5151           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound);
    5152           1 :     CPPUNIT_ASSERT_MESSAGE("PrintArea wrong col", col == 3);
    5153           1 :     CPPUNIT_ASSERT_MESSAGE("PrintArea wrong row", row == 3);
    5154             : 
    5155           1 :     bNotes = true;
    5156           1 :     dataFound = pDoc->GetPrintAreaVer(0,0,1,row, bNotes); // cols 0 & 1
    5157           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
    5158           1 :     CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row", row == 5);
    5159             : 
    5160           1 :     dataFound = pDoc->GetPrintAreaVer(0,2,3,row, bNotes); // cols 2 & 3
    5161           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
    5162           1 :     CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row", row == 3);
    5163             : 
    5164           1 :     bNotes = false;
    5165           1 :     dataFound = pDoc->GetPrintAreaVer(0,0,1,row, bNotes); // cols 0 & 1
    5166           1 :     CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
    5167           1 :     CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row", row == 3);
    5168             : 
    5169           1 :     pDoc->DeleteTab(0);
    5170           1 : }
    5171             : 
    5172           1 : void Test::testAnchoredRotatedShape()
    5173             : {
    5174           1 :     m_pDoc->InsertTab(0, "TestTab");
    5175             :     SCROW nRow1, nRow2;
    5176           1 :     bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
    5177           1 :     CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
    5178             : 
    5179           1 :     m_pDoc->InitDrawLayer();
    5180           1 :     ScDrawLayer *pDrawLayer = m_pDoc->GetDrawLayer();
    5181           1 :     CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer != NULL);
    5182           1 :     SdrPage* pPage = pDrawLayer->GetPage(0);
    5183           1 :     CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage != NULL);
    5184           1 :     m_pDoc->SetRowHeightRange( 0, MAXROW, 0, sc::HMMToTwips( 1000 ) );
    5185           1 :     const long TOLERANCE = 30; //30 hmm
    5186        1024 :     for ( SCCOL nCol = 0; nCol < MAXCOL; ++nCol )
    5187        1023 :         m_pDoc->SetColWidth( nCol, 0, sc::HMMToTwips( 1000 ) );
    5188             :     {
    5189             :         //Add a rect
    5190           1 :         Rectangle aRect( 4000, 5000, 10000, 7000 );
    5191             : 
    5192           1 :         Rectangle aRotRect( 6000, 3000, 8000, 9000 );
    5193           1 :         SdrRectObj *pObj = new SdrRectObj(aRect);
    5194           1 :         pPage->InsertObject(pObj);
    5195           1 :         Point aRef1(pObj->GetSnapRect().Center());
    5196           1 :         int nAngle = 9000; //90 deg.
    5197           1 :         double nSin=sin(nAngle*nPi180);
    5198           1 :         double nCos=cos(nAngle*nPi180);
    5199           1 :         pObj->Rotate(aRef1,nAngle,nSin,nCos);
    5200             : 
    5201           1 :         ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
    5202             : 
    5203           1 :         Rectangle aSnap = pObj->GetSnapRect();
    5204           1 :         CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetHeight(), aSnap.GetHeight(), TOLERANCE ) );
    5205           1 :         CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetWidth(), aSnap.GetWidth(), TOLERANCE ) );
    5206           1 :         CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.Left(), aSnap.Left(), TOLERANCE ) );
    5207           1 :         CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.Top(), aSnap.Top(), TOLERANCE ) );
    5208             : 
    5209           1 :         ScDrawObjData aAnchor;
    5210           1 :         ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
    5211           1 :         CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData);
    5212             : 
    5213           1 :         aAnchor.maStart = pData->maStart;
    5214           1 :         aAnchor.maEnd = pData->maEnd;
    5215             : 
    5216           1 :         m_pDoc->SetDrawPageSize(0);
    5217             : 
    5218             :         // increase row 5 by 2000 hmm
    5219           1 :         m_pDoc->SetRowHeight( 5, 0, sc::HMMToTwips( 3000 ) );
    5220             :         // increase col 6 by 1000 hmm
    5221           1 :         m_pDoc->SetColWidth( 6, 0, sc::HMMToTwips( 2000 ) );
    5222             : 
    5223           1 :         aRotRect.setWidth( aRotRect.GetWidth() + 1000 );
    5224           1 :         aRotRect.setHeight( aRotRect.GetHeight() + 2000 );
    5225             : 
    5226           1 :         m_pDoc->SetDrawPageSize(0);
    5227             : 
    5228           1 :         aSnap = pObj->GetSnapRect();
    5229             : 
    5230             :         // ensure that width and height have been adjusted accordingly
    5231           1 :         CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetHeight(), aSnap.GetHeight(), TOLERANCE ) );
    5232           1 :         CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetWidth(), aSnap.GetWidth(), TOLERANCE ) );
    5233             : 
    5234             :         // ensure that anchor start and end addresses haven't changed
    5235           1 :         CPPUNIT_ASSERT_EQUAL( aAnchor.maStart.Row(), pData->maStart.Row() ); // start row 0
    5236           1 :         CPPUNIT_ASSERT_EQUAL( aAnchor.maStart.Col(), pData->maStart.Col() ); // start column 5
    5237           1 :         CPPUNIT_ASSERT_EQUAL( aAnchor.maEnd.Row(), pData->maEnd.Row() ); // end row 3
    5238           1 :         CPPUNIT_ASSERT_EQUAL( aAnchor.maEnd.Col(), pData->maEnd.Col() ); // end col 7
    5239             :     }
    5240           1 :     m_pDoc->DeleteTab(0);
    5241           1 : }
    5242             : 
    5243           1 : void Test::testCellTextWidth()
    5244             : {
    5245           1 :     m_pDoc->InsertTab(0, "Test");
    5246             : 
    5247           1 :     ScAddress aTopCell(0, 0, 0);
    5248             : 
    5249             :     // Sheet is empty.
    5250           1 :     boost::scoped_ptr<ScColumnTextWidthIterator> pIter(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
    5251           1 :     CPPUNIT_ASSERT_MESSAGE("Column should have no text widths stored.", !pIter->hasCell());
    5252             : 
    5253             :     // Sheet only has one cell.
    5254           1 :     m_pDoc->SetString(0, 0, 0, "Only one cell");
    5255           1 :     pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
    5256           1 :     CPPUNIT_ASSERT_MESSAGE("Column should have a cell.", pIter->hasCell());
    5257           1 :     SCROW nTestRow = 0;
    5258           1 :     CPPUNIT_ASSERT_EQUAL(nTestRow, pIter->getPos());
    5259             : 
    5260             :     // Setting a text width here should commit it to the column.
    5261           1 :     sal_uInt16 nTestVal = 432;
    5262           1 :     pIter->setValue(nTestVal);
    5263           1 :     CPPUNIT_ASSERT_EQUAL(nTestVal, m_pDoc->GetTextWidth(aTopCell));
    5264             : 
    5265             :     // Set values to row 2 through 6.
    5266           6 :     for (SCROW i = 2; i <= 6; ++i)
    5267           5 :         m_pDoc->SetString(0, i, 0, "foo");
    5268             : 
    5269             :     // Set values to row 10 through 18.
    5270          10 :     for (SCROW i = 10; i <= 18; ++i)
    5271           9 :         m_pDoc->SetString(0, i, 0, "foo");
    5272             : 
    5273             :     {
    5274             :         // Full range.
    5275           1 :         pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
    5276           1 :         SCROW aRows[] = { 0, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
    5277           1 :         size_t n = SAL_N_ELEMENTS(aRows);
    5278          16 :         for (size_t i = 0; i < n; ++i, pIter->next())
    5279             :         {
    5280          15 :             CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
    5281          15 :             CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
    5282             :         }
    5283           1 :         CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
    5284             :     }
    5285             : 
    5286             :     {
    5287             :         // Specify start and end rows (6 - 16)
    5288           1 :         ScAddress aStart = aTopCell;
    5289           1 :         aStart.SetRow(6);
    5290           1 :         pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aStart, 16));
    5291           1 :         SCROW aRows[] = { 6, 10, 11, 12, 13, 14, 15, 16 };
    5292           1 :         size_t n = SAL_N_ELEMENTS(aRows);
    5293           9 :         for (size_t i = 0; i < n; ++i, pIter->next())
    5294             :         {
    5295           8 :             CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
    5296           8 :             CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
    5297             :         }
    5298           1 :         CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
    5299             :     }
    5300             : 
    5301             :     // Clear from row 3 to row 17. After this, we should only have cells at rows 0, 2 and 18.
    5302           1 :     clearRange(m_pDoc, ScRange(0, 3, 0, 0, 17, 0));
    5303             : 
    5304             :     {
    5305             :         // Full range again.
    5306           1 :         pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
    5307           1 :         SCROW aRows[] = { 0, 2, 18 };
    5308           1 :         size_t n = SAL_N_ELEMENTS(aRows);
    5309           4 :         for (size_t i = 0; i < n; ++i, pIter->next())
    5310             :         {
    5311           3 :             CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
    5312           3 :             CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
    5313             :         }
    5314           1 :         CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
    5315             :     }
    5316             : 
    5317             :     // Delete row 2 which shifts all cells below row 2 upward. After this, we
    5318             :     // should only have cells at rows 0 and 17.
    5319           1 :     m_pDoc->DeleteRow(0, 0, MAXCOL, MAXTAB, 2, 1);
    5320             :     {
    5321             :         // Full range again.
    5322           1 :         pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
    5323           1 :         SCROW aRows[] = { 0, 17 };
    5324           1 :         size_t n = SAL_N_ELEMENTS(aRows);
    5325           3 :         for (size_t i = 0; i < n; ++i, pIter->next())
    5326             :         {
    5327           2 :             CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
    5328           2 :             CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
    5329             :         }
    5330           1 :         CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
    5331             :     }
    5332             : 
    5333           1 :     m_pDoc->DeleteTab(0);
    5334           1 : }
    5335             : 
    5336           5 : bool checkEditTextIterator(sc::EditTextIterator& rIter, const char** pChecks)
    5337             : {
    5338           5 :     const EditTextObject* pText = rIter.first();
    5339           5 :     const char* p = *pChecks;
    5340             : 
    5341          24 :     for (int i = 0; i < 100; ++i) // cap it to 100 loops.
    5342             :     {
    5343          24 :         if (!pText)
    5344             :             // No more edit cells. The check string array should end too.
    5345           5 :             return p == NULL;
    5346             : 
    5347          19 :         if (!p)
    5348             :             // More edit cell, but no more check string. Bad.
    5349           0 :             return false;
    5350             : 
    5351          19 :         if (pText->GetParagraphCount() != 1)
    5352             :             // For this test, we don't handle multi-paragraph text.
    5353           0 :             return false;
    5354             : 
    5355          19 :         if (pText->GetText(0) != OUString::createFromAscii(p))
    5356             :             // Text differs from what's expected.
    5357           0 :             return false;
    5358             : 
    5359          19 :         pText = rIter.next();
    5360          19 :         ++pChecks;
    5361          19 :         p = *pChecks;
    5362             :     }
    5363             : 
    5364           0 :     return false;
    5365             : }
    5366             : 
    5367           1 : void Test::testEditTextIterator()
    5368             : {
    5369           1 :     m_pDoc->InsertTab(0, "Test");
    5370             : 
    5371             :     {
    5372             :         // First, try with an empty sheet.
    5373           1 :         sc::EditTextIterator aIter(*m_pDoc,0);
    5374           1 :         const char* pChecks[] = { NULL };
    5375           1 :         CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
    5376             :     }
    5377             : 
    5378           1 :     ScFieldEditEngine& rEditEngine = m_pDoc->GetEditEngine();
    5379             : 
    5380             :     {
    5381             :         // Only set one edit cell.
    5382           1 :         rEditEngine.SetText("A2");
    5383           1 :         m_pDoc->SetEditText(ScAddress(0,1,0), rEditEngine.CreateTextObject());
    5384           1 :         sc::EditTextIterator aIter(*m_pDoc,0);
    5385           1 :         const char* pChecks[] = { "A2", NULL };
    5386           1 :         CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
    5387             :     }
    5388             : 
    5389             :     {
    5390             :         // Add a series of edit cells.
    5391           1 :         rEditEngine.SetText("A5");
    5392           1 :         m_pDoc->SetEditText(ScAddress(0,4,0), rEditEngine.CreateTextObject());
    5393           1 :         rEditEngine.SetText("A6");
    5394           1 :         m_pDoc->SetEditText(ScAddress(0,5,0), rEditEngine.CreateTextObject());
    5395           1 :         rEditEngine.SetText("A7");
    5396           1 :         m_pDoc->SetEditText(ScAddress(0,6,0), rEditEngine.CreateTextObject());
    5397           1 :         sc::EditTextIterator aIter(*m_pDoc,0);
    5398           1 :         const char* pChecks[] = { "A2", "A5", "A6", "A7", NULL };
    5399           1 :         CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
    5400             :     }
    5401             : 
    5402             :     {
    5403             :         // Add more edit cells to column C. Skip column B.
    5404           1 :         rEditEngine.SetText("C1");
    5405           1 :         m_pDoc->SetEditText(ScAddress(2,0,0), rEditEngine.CreateTextObject());
    5406           1 :         rEditEngine.SetText("C3");
    5407           1 :         m_pDoc->SetEditText(ScAddress(2,2,0), rEditEngine.CreateTextObject());
    5408           1 :         rEditEngine.SetText("C4");
    5409           1 :         m_pDoc->SetEditText(ScAddress(2,3,0), rEditEngine.CreateTextObject());
    5410           1 :         sc::EditTextIterator aIter(*m_pDoc,0);
    5411           1 :         const char* pChecks[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", NULL };
    5412           1 :         CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
    5413             :     }
    5414             : 
    5415             :     {
    5416             :         // Add some numeric, string and formula cells.  This shouldn't affect the outcome.
    5417           1 :         m_pDoc->SetString(ScAddress(0,99,0), "=ROW()");
    5418           1 :         m_pDoc->SetValue(ScAddress(1,3,0), 1.2);
    5419           1 :         m_pDoc->SetString(ScAddress(2,4,0), "Simple string");
    5420           1 :         sc::EditTextIterator aIter(*m_pDoc,0);
    5421           1 :         const char* pChecks[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", NULL };
    5422           1 :         CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
    5423             :     }
    5424             : 
    5425           1 :     m_pDoc->DeleteTab(0);
    5426           1 : }
    5427             : 
    5428           1 : void Test::testCondFormatINSDEL()
    5429             : {
    5430             :     // fdo#62206
    5431           1 :     m_pDoc->InsertTab(0, "Test");
    5432           1 :     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
    5433             : 
    5434           1 :     ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
    5435           1 :     ScRangeList aRangeList(ScRange(0,0,0,0,3,0));
    5436           1 :     pFormat->AddRange(aRangeList);
    5437           1 :     ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
    5438           1 :     pFormat->AddEntry(pEntry);
    5439             : 
    5440           1 :     m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
    5441           1 :     pList->InsertNew(pFormat);
    5442             : 
    5443           1 :     m_pDoc->InsertCol(0,0,MAXROW,0,0,2);
    5444           1 :     const ScRangeList& rRange = pFormat->GetRange();
    5445           1 :     CPPUNIT_ASSERT(rRange == ScRange(2,0,0,2,3,0));
    5446             : 
    5447           2 :     OUString aExpr = pEntry->GetExpression(ScAddress(2,0,0), 0);
    5448           1 :     CPPUNIT_ASSERT_EQUAL(aExpr, OUString("D2"));
    5449             : 
    5450           2 :     m_pDoc->DeleteTab(0);
    5451           1 : }
    5452             : 
    5453           1 : void Test::testCondFormatInsertCol()
    5454             : {
    5455           1 :     m_pDoc->InsertTab(0, "Test");
    5456           1 :     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
    5457             : 
    5458           1 :     ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
    5459           1 :     ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
    5460           1 :     pFormat->AddRange(aRangeList);
    5461             : 
    5462           1 :     ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
    5463           1 :     pFormat->AddEntry(pEntry);
    5464             : 
    5465           1 :     m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
    5466           1 :     pList->InsertNew(pFormat);
    5467             : 
    5468           1 :     m_pDoc->InsertCol(0,0,MAXROW,0,4,2);
    5469           1 :     const ScRangeList& rRange = pFormat->GetRange();
    5470           1 :     CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,5,3,0)), rRange);
    5471             : 
    5472           1 :     m_pDoc->DeleteTab(0);
    5473           1 : }
    5474             : 
    5475           1 : void Test::testCondFormatInsertRow()
    5476             : {
    5477           1 :     m_pDoc->InsertTab(0, "Test");
    5478           1 :     ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
    5479             : 
    5480           1 :     ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
    5481           1 :     ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
    5482           1 :     pFormat->AddRange(aRangeList);
    5483             : 
    5484           1 :     ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
    5485           1 :     pFormat->AddEntry(pEntry);
    5486             : 
    5487           1 :     m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
    5488           1 :     pList->InsertNew(pFormat);
    5489             : 
    5490           1 :     m_pDoc->InsertRow(0,0,MAXCOL,0,4,2);
    5491           1 :     const ScRangeList& rRange = pFormat->GetRange();
    5492           1 :     CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,3,5,0)), rRange);
    5493             : 
    5494           1 :     m_pDoc->DeleteTab(0);
    5495           1 : }
    5496             : 
    5497           1 : void Test::testCondCopyPaste()
    5498             : {
    5499           1 :     m_pDoc->InsertTab(0, "Test");
    5500             : 
    5501           1 :     ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
    5502           1 :     ScRange aCondFormatRange(0,0,0,3,3,0);
    5503           1 :     ScRangeList aRangeList(aCondFormatRange);
    5504           1 :     pFormat->AddRange(aRangeList);
    5505             : 
    5506           1 :     ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
    5507           1 :     pFormat->AddEntry(pEntry);
    5508           1 :     sal_uLong nIndex = m_pDoc->AddCondFormat(pFormat, 0);
    5509             : 
    5510           2 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    5511           1 :     copyToClip(m_pDoc, aCondFormatRange, &aClipDoc);
    5512             : 
    5513           1 :     ScRange aTargetRange(4,4,0,7,7,0);
    5514           1 :     pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
    5515             : 
    5516           1 :     ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(7,7,0);
    5517           1 :     CPPUNIT_ASSERT(pPastedFormat);
    5518             : 
    5519           1 :     CPPUNIT_ASSERT_EQUAL(ScRangeList(aTargetRange), pPastedFormat->GetRange());
    5520           1 :     CPPUNIT_ASSERT( nIndex != pPastedFormat->GetKey());
    5521           1 :     const SfxPoolItem* pItem = m_pDoc->GetAttr( 7, 7, 0, ATTR_CONDITIONAL );
    5522           1 :     const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
    5523             : 
    5524           1 :     CPPUNIT_ASSERT(pCondFormatItem);
    5525           1 :     CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
    5526           1 :     CPPUNIT_ASSERT( nIndex != pCondFormatItem->GetCondFormatData().at(0) );
    5527             : 
    5528             : 
    5529           2 :     m_pDoc->DeleteTab(0);
    5530           1 : }
    5531             : 
    5532           1 : void Test::testImportStream()
    5533             : {
    5534           1 :     sc::AutoCalcSwitch aAC(*m_pDoc, true); // turn on auto calc.
    5535           2 :     sc::UndoSwitch aUndo(*m_pDoc, true); // enable undo.
    5536             : 
    5537           1 :     m_pDoc->InsertTab(0, "Test");
    5538             : 
    5539           1 :     m_pDoc->SetString(ScAddress(0,1,0), "=SUM(A1:C1)"); // A2
    5540             : 
    5541           1 :     CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0,1,0)));
    5542             : 
    5543             :     // CSV import options.
    5544           2 :     ScAsciiOptions aOpt;
    5545           1 :     aOpt.SetFieldSeps(",");
    5546             : 
    5547             :     // Import values to A1:C1.
    5548           2 :     ScImportExport aObj(m_pDoc, ScAddress(0,0,0));
    5549           1 :     aObj.SetImportBroadcast(true);
    5550           1 :     aObj.SetExtOptions(aOpt);
    5551           1 :     aObj.ImportString("1,2,3", FORMAT_STRING);
    5552             : 
    5553           1 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    5554           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    5555           1 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
    5556             : 
    5557             :     // Formula value should have been updated.
    5558           1 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,1,0)));
    5559             : 
    5560             :     // Undo, and check the result.
    5561           1 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
    5562           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get the undo manager.", pUndoMgr);
    5563           1 :     pUndoMgr->Undo();
    5564             : 
    5565           1 :     CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    5566           1 :     CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    5567           1 :     CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(2,0,0)));
    5568             : 
    5569           1 :     CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0,1,0))); // formula
    5570             : 
    5571             :     // Redo, and check the result.
    5572           1 :     pUndoMgr->Redo();
    5573             : 
    5574           1 :     CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
    5575           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,0,0)));
    5576           1 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
    5577             : 
    5578           1 :     CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,1,0))); // formula
    5579             : 
    5580           1 :     pUndoMgr->Clear();
    5581             : 
    5582           2 :     m_pDoc->DeleteTab(0);
    5583           1 : }
    5584             : 
    5585           1 : void Test::testDeleteContents()
    5586             : {
    5587           1 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
    5588           2 :     sc::UndoSwitch aUndoSwitch(*m_pDoc, true); // enable undo.
    5589             : 
    5590           1 :     m_pDoc->InsertTab(0, "Test");
    5591             : 
    5592           1 :     m_pDoc->SetValue(ScAddress(3,1,0), 1.0);
    5593           1 :     m_pDoc->SetValue(ScAddress(3,2,0), 1.0);
    5594           1 :     m_pDoc->SetValue(ScAddress(3,3,0), 1.0);
    5595           1 :     m_pDoc->SetValue(ScAddress(3,4,0), 1.0);
    5596           1 :     m_pDoc->SetValue(ScAddress(3,5,0), 1.0);
    5597           1 :     m_pDoc->SetValue(ScAddress(3,6,0), 1.0);
    5598           1 :     m_pDoc->SetValue(ScAddress(3,7,0), 1.0);
    5599           1 :     m_pDoc->SetValue(ScAddress(3,8,0), 1.0);
    5600           1 :     m_pDoc->SetString(ScAddress(3,15,0), "=SUM(D2:D15)");
    5601             : 
    5602           1 :     CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
    5603             : 
    5604             :     // Delete D2:D6.
    5605           1 :     ScRange aRange(3,1,0,3,5,0);
    5606           2 :     ScMarkData aMark;
    5607           1 :     aMark.SelectOneTable(0);
    5608           1 :     aMark.SetMarkArea(aRange);
    5609             : 
    5610           1 :     ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
    5611           1 :     pUndoDoc->InitUndo(m_pDoc, 0, 0);
    5612           1 :     m_pDoc->CopyToDocument(aRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
    5613           2 :     ScUndoDeleteContents aUndo(&getDocShell(), aMark, aRange, pUndoDoc, false, IDF_CONTENTS, true);
    5614             : 
    5615           1 :     clearRange(m_pDoc, aRange);
    5616           1 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
    5617             : 
    5618           1 :     aUndo.Undo();
    5619           1 :     CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
    5620             : 
    5621           1 :     aUndo.Redo();
    5622           1 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
    5623             : 
    5624           2 :     m_pDoc->DeleteTab(0);
    5625           1 : }
    5626             : 
    5627           1 : void Test::testTransliterateText()
    5628             : {
    5629           1 :     m_pDoc->InsertTab(0, "Test");
    5630             : 
    5631             :     // Set texts to A1:A3.
    5632           1 :     m_pDoc->SetString(ScAddress(0,0,0), "Mike");
    5633           1 :     m_pDoc->SetString(ScAddress(0,1,0), "Noah");
    5634           1 :     m_pDoc->SetString(ScAddress(0,2,0), "Oscar");
    5635             : 
    5636             :     // Change them to uppercase.
    5637           1 :     ScMarkData aMark;
    5638           1 :     aMark.SetMarkArea(ScRange(0,0,0,0,2,0));
    5639           1 :     ScDocFunc& rFunc = getDocShell().GetDocFunc();
    5640             :     rFunc.TransliterateText(
    5641           1 :         aMark, i18n::TransliterationModules_LOWERCASE_UPPERCASE, true, true);
    5642             : 
    5643           1 :     CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc->GetString(ScAddress(0,0,0)));
    5644           1 :     CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc->GetString(ScAddress(0,1,0)));
    5645           1 :     CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc->GetString(ScAddress(0,2,0)));
    5646             : 
    5647             :     // Test the undo and redo.
    5648           1 :     SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
    5649           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr);
    5650             : 
    5651           1 :     pUndoMgr->Undo();
    5652           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Mike"), m_pDoc->GetString(ScAddress(0,0,0)));
    5653           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Noah"), m_pDoc->GetString(ScAddress(0,1,0)));
    5654           1 :     CPPUNIT_ASSERT_EQUAL(OUString("Oscar"), m_pDoc->GetString(ScAddress(0,2,0)));
    5655             : 
    5656           1 :     pUndoMgr->Redo();
    5657           1 :     CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc->GetString(ScAddress(0,0,0)));
    5658           1 :     CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc->GetString(ScAddress(0,1,0)));
    5659           1 :     CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc->GetString(ScAddress(0,2,0)));
    5660             : 
    5661           1 :     m_pDoc->DeleteTab(0);
    5662           1 : }
    5663             : 
    5664           1 : void Test::testMixData()
    5665             : {
    5666           1 :     m_pDoc->InsertTab(0, "Test");
    5667             : 
    5668           1 :     m_pDoc->SetValue(1,0,0,2);
    5669           1 :     m_pDoc->SetValue(0,1,0,3);
    5670           1 :     ScDocument aClipDoc(SCDOCMODE_CLIP);
    5671           1 :     copyToClip(m_pDoc, ScRange(0,0,0,1,0,0), &aClipDoc);
    5672             : 
    5673           2 :     ScDocument aMixDoc(SCDOCMODE_CLIP);
    5674           1 :     copyToClip(m_pDoc, ScRange(0,1,0,1,1,0), &aMixDoc);
    5675             : 
    5676           1 :     pasteFromClip(m_pDoc, ScRange(0,1,0,1,1,0), &aClipDoc);
    5677           1 :     m_pDoc->MixDocument(ScRange(0,1,0,1,1,0), 1, false, &aMixDoc);
    5678             : 
    5679           1 :     CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(1,1,0));
    5680           1 :     CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(0,1,0));
    5681             : 
    5682           2 :     m_pDoc->DeleteTab(0);
    5683           1 : }
    5684             : 
    5685           5 : ScDocShell* Test::findLoadedDocShellByName(const OUString& rName)
    5686             : {
    5687           5 :     TypeId aType(TYPE(ScDocShell));
    5688           5 :     ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(&aType, false));
    5689         306 :     while (pShell)
    5690             :     {
    5691         299 :         SfxMedium* pMedium = pShell->GetMedium();
    5692         299 :         if (pMedium)
    5693             :         {
    5694         299 :             OUString aName = pMedium->GetName();
    5695         299 :             if (aName.equals(rName))
    5696           3 :                 return pShell;
    5697             :         }
    5698         296 :         pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, &aType, false));
    5699             :     }
    5700           2 :     return NULL;
    5701             : }
    5702             : 
    5703           4 : bool Test::insertRangeNames(
    5704             :     ScDocument* pDoc, ScRangeName* pNames, const RangeNameDef* p, const RangeNameDef* pEnd)
    5705             : {
    5706           4 :     ScAddress aA1(0, 0, 0);
    5707          13 :     for (; p != pEnd; ++p)
    5708             :     {
    5709             :         ScRangeData* pNew = new ScRangeData(
    5710             :             pDoc,
    5711             :             OUString::createFromAscii(p->mpName),
    5712             :             OUString::createFromAscii(p->mpExpr),
    5713           9 :             aA1, 0, formula::FormulaGrammar::GRAM_ENGLISH);
    5714           9 :         pNew->SetIndex(p->mnIndex);
    5715           9 :         bool bSuccess = pNames->insert(pNew);
    5716           9 :         if (!bSuccess)
    5717             :         {
    5718           0 :             cerr << "Insertion failed." << endl;
    5719           0 :             return false;
    5720             :         }
    5721             :     }
    5722             : 
    5723           4 :     return true;
    5724             : }
    5725             : 
    5726          39 : void Test::printRange(ScDocument* pDoc, const ScRange& rRange, const char* pCaption)
    5727             : {
    5728          39 :     SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
    5729          39 :     SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
    5730          39 :     SheetPrinter printer(nRow2 - nRow1 + 1, nCol2 - nCol1 + 1);
    5731         349 :     for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
    5732             :     {
    5733        1185 :         for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
    5734             :         {
    5735         875 :             OUString aVal = pDoc->GetString(nCol, nRow, rRange.aStart.Tab());
    5736         875 :             printer.set(nRow-nRow1, nCol-nCol1, aVal);
    5737         875 :         }
    5738             :     }
    5739          39 :     printer.print(pCaption);
    5740          39 : }
    5741             : 
    5742          83 : void Test::clearRange(ScDocument* pDoc, const ScRange& rRange)
    5743             : {
    5744          83 :     ScMarkData aMarkData;
    5745          83 :     aMarkData.SetMarkArea(rRange);
    5746             :     pDoc->DeleteArea(
    5747          83 :         rRange.aStart.Col(), rRange.aStart.Row(),
    5748         166 :         rRange.aEnd.Col(), rRange.aEnd.Row(), aMarkData, IDF_CONTENTS);
    5749          83 : }
    5750             : 
    5751           5 : void Test::clearSheet(ScDocument* pDoc, SCTAB nTab)
    5752             : {
    5753           5 :     ScRange aRange(0,0,nTab,MAXCOL,MAXROW,nTab);
    5754           5 :     clearRange(pDoc, aRange);
    5755           5 : }
    5756             : 
    5757           7 : void Test::copyToClip(ScDocument* pSrcDoc, const ScRange& rRange, ScDocument* pClipDoc)
    5758             : {
    5759           7 :     ScClipParam aClipParam(rRange, false);
    5760          14 :     ScMarkData aMark;
    5761           7 :     aMark.SetMarkArea(rRange);
    5762          14 :     pSrcDoc->CopyToClip(aClipParam, pClipDoc, &aMark);
    5763           7 : }
    5764             : 
    5765           3 : void Test::pasteFromClip(ScDocument* pDestDoc, const ScRange& rDestRange, ScDocument* pClipDoc)
    5766             : {
    5767           3 :     ScMarkData aMark;
    5768           3 :     aMark.SetMarkArea(rDestRange);
    5769           3 :     pDestDoc->CopyFromClip(rDestRange, aMark, IDF_ALL, NULL, pClipDoc);
    5770           3 : }
    5771             : 
    5772           2 : ScUndoPaste* Test::createUndoPaste(ScDocShell& rDocSh, const ScRange& rRange, ScDocument* pUndoDoc)
    5773             : {
    5774           2 :     ScDocument* pDoc = rDocSh.GetDocument();
    5775           2 :     ScMarkData aMarkData;
    5776           2 :     aMarkData.SetMarkArea(rRange);
    5777           2 :     ScRefUndoData* pRefUndoData = new ScRefUndoData(pDoc);
    5778             : 
    5779             :     return new ScUndoPaste(
    5780           2 :         &rDocSh, rRange, aMarkData, pUndoDoc, NULL, IDF_ALL, pRefUndoData, false);
    5781             : }
    5782             : 
    5783           1 : CPPUNIT_TEST_SUITE_REGISTRATION(Test);
    5784             : 
    5785           4 : CPPUNIT_PLUGIN_IMPLEMENT();
    5786             : 
    5787             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10