Bump version to 5.0-14
[LibreOffice.git] / sc / qa / unit / ucalc.cxx
blob12973820997a6656571ba6b89bf38da68cf8a15e
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 */
9 #include "ucalc.hxx"
11 #include <sal/config.h>
12 #include <test/bootstrapfixture.hxx>
14 #include <rtl/strbuf.hxx>
15 #include <osl/file.hxx>
16 #include <osl/time.h>
18 #include "scdll.hxx"
19 #include "formulacell.hxx"
20 #include "stringutil.hxx"
21 #include "scmatrix.hxx"
22 #include "drwlayer.hxx"
23 #include "scitems.hxx"
24 #include "reffind.hxx"
25 #include "markdata.hxx"
26 #include "clipparam.hxx"
27 #include "refundo.hxx"
28 #include "undoblk.hxx"
29 #include "undotab.hxx"
30 #include "queryentry.hxx"
31 #include "postit.hxx"
32 #include "attrib.hxx"
33 #include "dbdata.hxx"
34 #include "reftokenhelper.hxx"
35 #include "userdat.hxx"
37 #include "docsh.hxx"
38 #include "docfunc.hxx"
39 #include "dbdocfun.hxx"
40 #include "funcdesc.hxx"
41 #include "externalrefmgr.hxx"
43 #include "calcconfig.hxx"
44 #include "interpre.hxx"
45 #include "columniterator.hxx"
46 #include "types.hxx"
47 #include "conditio.hxx"
48 #include "colorscale.hxx"
49 #include "fillinfo.hxx"
50 #include "globstr.hrc"
51 #include "tokenarray.hxx"
52 #include "scopetools.hxx"
53 #include "dociter.hxx"
54 #include "queryparam.hxx"
55 #include "edittextiterator.hxx"
56 #include "editutil.hxx"
57 #include <asciiopt.hxx>
58 #include <impex.hxx>
59 #include <columnspanset.hxx>
60 #include <docoptio.hxx>
61 #include <patattr.hxx>
62 #include <docpool.hxx>
63 #include <globalnames.hxx>
64 #include <inputopt.hxx>
66 #include <editable.hxx>
67 #include <bcaslot.hxx>
68 #include <sharedformula.hxx>
70 #include <formula/IFunctionDescription.hxx>
72 #include <basegfx/polygon/b2dpolygon.hxx>
73 #include <editeng/boxitem.hxx>
74 #include <editeng/brushitem.hxx>
75 #include <editeng/wghtitem.hxx>
76 #include <editeng/postitem.hxx>
78 #include <svx/svdograf.hxx>
79 #include <svx/svdpage.hxx>
80 #include <svx/svdocirc.hxx>
81 #include <svx/svdopath.hxx>
82 #include <svx/svdocapt.hxx>
83 #include <svl/srchitem.hxx>
84 #include <svl/sharedstringpool.hxx>
86 #include <sfx2/docfile.hxx>
88 #include <iostream>
89 #include <sstream>
90 #include <vector>
92 #include <com/sun/star/i18n/TransliterationModules.hpp>
94 struct TestImpl
96 ScDocShellRef m_xDocShell;
99 FormulaGrammarSwitch::FormulaGrammarSwitch(ScDocument* pDoc, formula::FormulaGrammar::Grammar eGrammar) :
100 mpDoc(pDoc), meOldGrammar(pDoc->GetGrammar())
102 mpDoc->SetGrammar(eGrammar);
105 FormulaGrammarSwitch::~FormulaGrammarSwitch()
107 mpDoc->SetGrammar(meOldGrammar);
110 class MeasureTimeSwitch
112 double& mrDiff;
113 TimeValue maTimeBefore;
114 public:
115 MeasureTimeSwitch(double& rDiff) : mrDiff(rDiff)
117 mrDiff = 9999.0;
118 osl_getSystemTime(&maTimeBefore);
121 ~MeasureTimeSwitch()
123 TimeValue aTimeAfter;
124 osl_getSystemTime(&aTimeAfter);
125 mrDiff = getTimeDiff(aTimeAfter, maTimeBefore);
128 static double getTimeDiff(const TimeValue& t1, const TimeValue& t2)
130 double tv1 = t1.Seconds;
131 double tv2 = t2.Seconds;
132 tv1 += t1.Nanosec / 1000000000.0;
133 tv2 += t2.Nanosec / 1000000000.0;
135 return tv1 - tv2;
139 Test::Test() :
140 m_pImpl(new TestImpl),
141 m_pDoc(0)
145 Test::~Test()
147 delete m_pImpl;
150 ScDocShell& Test::getDocShell()
152 return *m_pImpl->m_xDocShell;
155 void Test::setUp()
157 BootstrapFixture::setUp();
159 ScDLL::Init();
160 m_pImpl->m_xDocShell = new ScDocShell(
161 SfxModelFlags::EMBEDDED_OBJECT |
162 SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS |
163 SfxModelFlags::DISABLE_DOCUMENT_RECOVERY);
165 m_pImpl->m_xDocShell->DoInitUnitTest();
166 m_pDoc = &m_pImpl->m_xDocShell->GetDocument();
169 void Test::tearDown()
171 m_pImpl->m_xDocShell->DoClose();
172 m_pImpl->m_xDocShell.Clear();
173 BootstrapFixture::tearDown();
176 #define PERF_ASSERT(df,scale,time,message) \
177 do { \
178 double dfscaled = df / scale; \
179 if ((dfscaled) >= (time)) \
181 std::ostringstream os; \
182 os << message " took " << dfscaled << " pseudo-cycles (" << df << " real-time seconds), expected: " << time << " pseudo-cycles."; \
183 CPPUNIT_FAIL(os.str().c_str()); \
185 } while (false)
187 void Test::testPerf()
189 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "foo"));
191 // First do a set of simple operations to try to work out
192 // how fast (or not) this particular machine is:
193 double scale;
195 MeasureTimeSwitch aTime(scale);
196 for (int i = 0; i < 10000000; ++i)
198 // Bang on the allocator
199 volatile ScRange *pRange = new ScRange (ScAddress (0,0,0));
200 // Calc does quite a bit of string conversion
201 volatile double it = OUString::number ((double)i/253.0).toDouble();
202 // Do we have floating point math ?
203 volatile double another = rtl::math::sin (it);
204 (void)another;
205 delete pRange;
208 printf("CPU scale factor %g\n", scale);
210 // FIXME: we should check if this already took too long
211 // and if so not run the perf. tests to have pity on some
212 // slow ARM machines - I think.
214 // to make the numbers more round and helpful,
215 // but the calculation of scale reasonably precise.
216 scale /= 100000.0;
218 double diff;
220 // Clearing an already empty sheet should finish in a fraction of a
221 // second. Flag failure if it takes more than one second. Clearing 100
222 // columns should be large enough to flag if something goes wrong.
224 MeasureTimeSwitch aTime(diff);
225 clearRange(m_pDoc, ScRange(0,0,0,99,MAXROW,0));
227 PERF_ASSERT(diff, scale, 1.0, "Clearing an empty sheet");
230 // Switch to R1C1 to make it easier to input relative references in multiple cells.
231 FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
233 // Insert formulas in B1:B100000. This shouldn't take long, but may take
234 // close to a second on a slower machine. We don't measure this yet, for
235 // now.
236 for (SCROW i = 0; i < 100000; ++i)
237 m_pDoc->SetString(ScAddress(1,i,0), "=RC[-1]");
239 // Now, Delete B2:B100000. This should complete in a fraction of a second
240 // (0.06 sec on my machine).
242 MeasureTimeSwitch aTime(diff);
243 clearRange(m_pDoc, ScRange(1,1,0,1,99999,0));
245 PERF_ASSERT(diff, scale, 2000, "Removal of a large array of formula cells");
248 clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
249 CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
250 CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
253 // Measure the performance of repeat-pasting a single cell to a large
254 // cell range, undoing it, and redoing it.
256 ScAddress aPos(0,0,0);
257 m_pDoc->SetString(aPos, "test");
258 ScMarkData aMark;
259 aMark.SelectOneTable(0);
261 // Copy cell A1 to clipboard.
262 ScDocument aClipDoc(SCDOCMODE_CLIP);
263 ScClipParam aParam(aPos, false);
264 m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
265 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
267 ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
268 pUndoDoc->InitUndo(m_pDoc, 0, 0);
269 m_pDoc->CopyToDocument(ScRange(aPos), IDF_CONTENTS, false, pUndoDoc, &aMark);
271 // Paste it to A2:A100000, and measure its duration.
272 ScRange aPasteRange(0,1,0,0,99999,0);
273 aMark.SetMarkArea(aPasteRange);
276 MeasureTimeSwitch aTime(diff);
277 m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
279 PERF_ASSERT(diff, scale, 1500.0, "Pasting a single cell to A2:A100000");
281 ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
282 pRedoDoc->InitUndo(m_pDoc, 0, 0);
283 m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
285 // Create an undo object for this.
286 ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
287 ScUndoPaste aUndo(&getDocShell(), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
289 // Make sure it did what it's supposed to do.
290 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
291 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
294 MeasureTimeSwitch aTime(diff);
295 aUndo.Undo();
297 PERF_ASSERT(diff, scale, 500.0, "Undoing a pasting of a cell to A2:A100000");
299 // Make sure it's really undone.
300 CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, m_pDoc->GetCellType(aPos));
301 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
302 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
304 // Now redo.
306 MeasureTimeSwitch aTime(diff);
307 aUndo.Redo();
309 PERF_ASSERT(diff, scale, 1000.0, "Redoing a pasting of a cell to A2:A100000");
311 // Make sure it's really redone.
312 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
313 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
316 clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
317 CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
318 CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
321 // Measure the performance of repeat-pasting 2 adjacent cells to a
322 // large cell range, undoing it, and redoing it. The bottom one of
323 // the two source cells is empty.
325 ScRange aSrcRange(0,0,0,0,1,0); // A1:A2
327 ScAddress aPos(0,0,0);
328 m_pDoc->SetValue(aPos, 12);
329 ScMarkData aMark;
330 aMark.SetMarkArea(aSrcRange);
332 // Copy to clipboard.
333 ScDocument aClipDoc(SCDOCMODE_CLIP);
334 ScClipParam aParam(aSrcRange, false);
335 m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
336 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
338 ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
339 pUndoDoc->InitUndo(m_pDoc, 0, 0);
340 m_pDoc->CopyToDocument(aSrcRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
342 // Paste it to A3:A100001, and measure its duration.
343 ScRange aPasteRange(0,2,0,0,100000,0);
344 aMark.SetMarkArea(aPasteRange);
347 MeasureTimeSwitch aTime(diff);
348 m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
350 PERF_ASSERT(diff, scale, 1000.0, "Pasting A1:A2 to A3:A100001");
352 ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
353 pRedoDoc->InitUndo(m_pDoc, 0, 0);
354 m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
356 // Create an undo object for this.
357 ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
358 ScUndoPaste aUndo(&getDocShell(), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
360 // Make sure it did what it's supposed to do.
361 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
362 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
363 ScAddress aTmp = aPasteRange.aStart;
364 aTmp.IncRow();
365 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aTmp));
368 MeasureTimeSwitch aTime(diff);
369 aUndo.Undo();
371 PERF_ASSERT(diff, scale, 500.0, "Undoing");
373 // Make sure it's really undone.
374 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE, m_pDoc->GetCellType(aPos));
375 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
376 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
378 // Now redo.
380 MeasureTimeSwitch aTime(diff);
381 aUndo.Redo();
383 PERF_ASSERT(diff, scale, 800.0, "Redoing");
385 // Make sure it's really redone.
386 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
387 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
390 clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
391 CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
392 CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
395 // Measure the performance of repeat-pasting 2 adjacent cells to a
396 // large cell range, undoing it, and redoing it. The bottom one of
397 // the two source cells is empty. In this scenario, the non-empty
398 // cell is a formula cell referencing a cell to the right, which
399 // inserts a broadcaster to cell it references. So it has a higher
400 // overhead than the previous scenario.
402 ScRange aSrcRange(0,0,0,0,1,0); // A1:A2
404 ScAddress aPos(0,0,0);
405 m_pDoc->SetString(aPos, "=B1");
406 ScMarkData aMark;
407 aMark.SetMarkArea(aSrcRange);
409 // Copy to clipboard.
410 ScDocument aClipDoc(SCDOCMODE_CLIP);
411 ScClipParam aParam(aSrcRange, false);
412 m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
413 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
415 ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
416 pUndoDoc->InitUndo(m_pDoc, 0, 0);
417 m_pDoc->CopyToDocument(aSrcRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
419 // Paste it to A3:A50001, and measure its duration.
420 ScRange aPasteRange(0,2,0,0,50000,0);
421 aMark.SetMarkArea(aPasteRange);
424 MeasureTimeSwitch aTime(diff);
425 m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
427 PERF_ASSERT(diff, scale, 2000.0, "Pasting");
429 ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
430 pRedoDoc->InitUndo(m_pDoc, 0, 0);
431 m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
433 // Create an undo object for this.
434 ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
435 ScUndoPaste aUndo(&getDocShell(), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
437 // Make sure it did what it's supposed to do.
438 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aStart));
439 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aEnd));
440 ScAddress aTmp = aPasteRange.aStart;
441 aTmp.IncRow();
442 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aTmp));
444 #if 0 // TODO: Undo and redo of this scenario is currently not fast enough to be tested reliably.
446 MeasureTimeSwitch aTime(diff);
447 aUndo.Undo();
449 PERF_ASSERT(diff, scale, 1.0, "Undoing");
451 // Make sure it's really undone.
452 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPos));
453 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
454 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
456 // Now redo.
458 MeasureTimeSwitch aTime(diff);
459 aUndo.Redo();
461 PERF_ASSERT(diff, scale, 1.0, "Redoing");
463 // Make sure it's really redone.
464 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aStart));
465 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aEnd));
466 #endif
469 m_pDoc->DeleteTab(0);
472 void Test::testCollator()
474 CollatorWrapper* p = ScGlobal::GetCollator();
475 sal_Int32 nRes = p->compareString("A", "B");
476 CPPUNIT_ASSERT_MESSAGE("these strings are supposed to be different!", nRes != 0);
479 void Test::testSharedStringPool()
481 m_pDoc->InsertTab(0, "foo");
483 // Strings that are identical.
484 m_pDoc->SetString(ScAddress(0,0,0), "Andy"); // A1
485 m_pDoc->SetString(ScAddress(0,1,0), "Andy"); // A2
486 m_pDoc->SetString(ScAddress(0,2,0), "Bruce"); // A3
487 m_pDoc->SetString(ScAddress(0,3,0), "andy"); // A4
488 m_pDoc->SetString(ScAddress(0,4,0), "BRUCE"); // A5
491 // These two shared string objects must go out of scope before the purge test.
492 svl::SharedString aSS1 = m_pDoc->GetSharedString(ScAddress(0,0,0));
493 svl::SharedString aSS2 = m_pDoc->GetSharedString(ScAddress(0,1,0));
494 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS1.isValid());
495 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS2.isValid());
496 CPPUNIT_ASSERT_EQUAL(aSS1.getData(), aSS2.getData());
498 aSS2 = m_pDoc->GetSharedString(ScAddress(0,2,0));
499 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
501 aSS2 = m_pDoc->GetSharedString(ScAddress(0,3,0));
502 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
504 aSS2 = m_pDoc->GetSharedString(ScAddress(0,4,0));
505 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
507 // A3 and A5 should differ but should be equal case-insensitively.
508 aSS1 = m_pDoc->GetSharedString(ScAddress(0,2,0));
509 aSS2 = m_pDoc->GetSharedString(ScAddress(0,4,0));
510 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
511 CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", aSS1.getDataIgnoreCase() == aSS2.getDataIgnoreCase());
513 // A2 and A4 should be equal when ignoring cases.
514 aSS1 = m_pDoc->GetSharedString(ScAddress(0,1,0));
515 aSS2 = m_pDoc->GetSharedString(ScAddress(0,3,0));
516 CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", aSS1.getDataIgnoreCase() == aSS2.getDataIgnoreCase());
519 // Check the string counts after purging. Purging shouldn't remove any strings in this case.
520 svl::SharedStringPool& rPool = m_pDoc->GetSharedStringPool();
521 rPool.purge();
522 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
523 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
525 // Clear A1 and purge again.
526 clearRange(m_pDoc, ScAddress(0,0,0));
527 rPool.purge();
528 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
529 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
531 // Clear A2 and purge again.
532 clearRange(m_pDoc, ScAddress(0,1,0));
533 rPool.purge();
534 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), rPool.getCount());
535 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
537 // Clear A3 and purge again.
538 clearRange(m_pDoc, ScAddress(0,2,0));
539 rPool.purge();
540 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCount());
541 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
543 // Clear A4 and purge again.
544 clearRange(m_pDoc, ScAddress(0,3,0));
545 rPool.purge();
546 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCount());
547 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCountIgnoreCase());
549 // Clear A5 and the pool should be completely empty.
550 clearRange(m_pDoc, ScAddress(0,4,0));
551 rPool.purge();
552 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCount());
553 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCountIgnoreCase());
555 // Now, compare string and edit text cells.
556 m_pDoc->SetString(ScAddress(0,0,0), "Andy and Bruce"); // A1
557 ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
558 rEE.SetText("Andy and Bruce");
560 ESelection aSel;
561 aSel.nStartPara = aSel.nEndPara = 0;
564 // Set 'Andy' bold.
565 SfxItemSet aItemSet = rEE.GetEmptyItemSet();
566 aSel.nStartPos = 0;
567 aSel.nEndPos = 4;
568 SvxWeightItem aWeight(WEIGHT_BOLD, EE_CHAR_WEIGHT);
569 aItemSet.Put(aWeight);
570 rEE.QuickSetAttribs(aItemSet, aSel);
574 // Set 'Bruce' italic.
575 SfxItemSet aItemSet = rEE.GetEmptyItemSet();
576 SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);
577 aItemSet.Put(aItalic);
578 aSel.nStartPos = 9;
579 aSel.nEndPos = 14;
580 rEE.QuickSetAttribs(aItemSet, aSel);
583 m_pDoc->SetEditText(ScAddress(1,0,0), rEE.CreateTextObject()); // B1
585 // These two should be equal.
586 svl::SharedString aSS1 = m_pDoc->GetSharedString(ScAddress(0,0,0));
587 svl::SharedString aSS2 = m_pDoc->GetSharedString(ScAddress(1,0,0));
588 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1.isValid());
589 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2.isValid());
590 CPPUNIT_ASSERT_EQUAL(aSS1.getData(), aSS2.getData());
592 rEE.SetText("ANDY and BRUCE");
593 m_pDoc->SetEditText(ScAddress(2,0,0), rEE.CreateTextObject()); // C1
594 aSS2 = m_pDoc->GetSharedString(ScAddress(2,0,0));
595 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2.isValid());
596 CPPUNIT_ASSERT_MESSAGE("These two should be different when cases are considered.", aSS1.getData() != aSS2.getData());
598 // But they should be considered equal when cases are ignored.
599 aSS1 = m_pDoc->GetSharedString(ScAddress(0,0,0));
600 aSS2 = m_pDoc->GetSharedString(ScAddress(2,0,0));
601 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1.isValid());
602 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2.isValid());
603 CPPUNIT_ASSERT_EQUAL(aSS1.getDataIgnoreCase(), aSS2.getDataIgnoreCase());
605 m_pDoc->DeleteTab(0);
608 void Test::testSharedStringPoolUndoDoc()
610 struct
612 bool check( ScDocument& rSrcDoc, ScDocument& rCopyDoc )
614 // Copy A1:A4 to the undo document.
615 for (SCROW i = 0; i <= 4; ++i)
617 ScAddress aPos(0,i,0);
618 rCopyDoc.SetString(aPos, rSrcDoc.GetString(aPos));
621 // String values in A1:A4 should have identical hash.
622 for (SCROW i = 0; i <= 4; ++i)
624 ScAddress aPos(0,i,0);
625 svl::SharedString aSS1 = rSrcDoc.GetSharedString(aPos);
626 svl::SharedString aSS2 = rCopyDoc.GetSharedString(aPos);
627 if (aSS1.getDataIgnoreCase() != aSS2.getDataIgnoreCase())
629 cerr << "String hash values are not equal at row " << (i+1)
630 << " for string '" << aSS1.getString() << "'" << endl;
631 return false;
635 return true;
638 } aTest;
640 m_pDoc->InsertTab(0, "Test");
642 m_pDoc->SetString(ScAddress(0,0,0), "Header");
643 m_pDoc->SetString(ScAddress(0,1,0), "A1");
644 m_pDoc->SetString(ScAddress(0,2,0), "A2");
645 m_pDoc->SetString(ScAddress(0,3,0), "A3");
647 ScDocument aUndoDoc(SCDOCMODE_UNDO);
648 aUndoDoc.InitUndo(m_pDoc, 0, 0);
650 bool bSuccess = aTest.check(*m_pDoc, aUndoDoc);
651 CPPUNIT_ASSERT_MESSAGE("Check failed with undo document.", bSuccess);
653 // Test the clip document as well.
654 ScDocument aClipDoc(SCDOCMODE_CLIP);
655 aClipDoc.ResetClip(m_pDoc, static_cast<SCTAB>(0));
657 bSuccess = aTest.check(*m_pDoc, aClipDoc);
658 CPPUNIT_ASSERT_MESSAGE("Check failed with clip document.", bSuccess);
660 m_pDoc->DeleteTab(0);
663 void Test::testRangeList()
665 m_pDoc->InsertTab(0, "foo");
667 ScRangeList aRL;
668 aRL.Append(ScRange(1,1,0,3,10,0));
669 CPPUNIT_ASSERT_MESSAGE("List should have one range.", aRL.size() == 1);
670 const ScRange* p = aRL[0];
671 CPPUNIT_ASSERT_MESSAGE("Failed to get the range object.", p);
672 CPPUNIT_ASSERT_MESSAGE("Wrong range.", p->aStart == ScAddress(1,1,0) && p->aEnd == ScAddress(3,10,0));
674 // TODO: Add more tests here.
676 m_pDoc->DeleteTab(0);
679 void Test::testMarkData()
681 ScMarkData aMarkData;
683 // Empty mark. Nothing is selected.
684 std::vector<sc::ColRowSpan> aSpans = aMarkData.GetMarkedRowSpans();
685 CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans.empty());
686 aSpans = aMarkData.GetMarkedColSpans();
687 CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans.empty());
689 // Select B3:F7.
690 aMarkData.SetMarkArea(ScRange(1,2,0,5,6,0));
691 aSpans = aMarkData.GetMarkedRowSpans();
692 CPPUNIT_ASSERT_MESSAGE("There should be one selected row span.", aSpans.size() == 1);
693 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(2), aSpans[0].mnStart);
694 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(6), aSpans[0].mnEnd);
696 aSpans = aMarkData.GetMarkedColSpans();
697 CPPUNIT_ASSERT_MESSAGE("There should be one selected column span.", aSpans.size() == 1);
698 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(1), aSpans[0].mnStart);
699 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(5), aSpans[0].mnEnd);
701 // Select A11:B13.
702 aMarkData.SetMultiMarkArea(ScRange(0,10,0,1,12,0));
703 aSpans = aMarkData.GetMarkedRowSpans();
704 CPPUNIT_ASSERT_MESSAGE("There should be 2 selected row spans.", aSpans.size() == 2);
705 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(2), aSpans[0].mnStart);
706 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(6), aSpans[0].mnEnd);
707 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(10), aSpans[1].mnStart);
708 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(12), aSpans[1].mnEnd);
710 aSpans = aMarkData.GetMarkedColSpans();
711 CPPUNIT_ASSERT_MESSAGE("There should be one selected column span.", aSpans.size() == 1);
712 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(0), aSpans[0].mnStart);
713 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(5), aSpans[0].mnEnd);
715 // Select C8:C10.
716 aMarkData.SetMultiMarkArea(ScRange(2,7,0,2,9,0));
717 aSpans = aMarkData.GetMarkedRowSpans();
718 CPPUNIT_ASSERT_MESSAGE("There should be one selected row span.", aSpans.size() == 1);
719 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(2), aSpans[0].mnStart);
720 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(12), aSpans[0].mnEnd);
722 aSpans = aMarkData.GetMarkedColSpans();
723 CPPUNIT_ASSERT_MESSAGE("There should be one selected column span.", aSpans.size() == 1);
724 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(0), aSpans[0].mnStart);
725 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(5), aSpans[0].mnEnd);
728 void Test::testInput()
731 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
732 m_pDoc->InsertTab (0, "foo"));
733 OUString test;
735 m_pDoc->SetString(0, 0, 0, "'10.5");
736 test = m_pDoc->GetString(0, 0, 0);
737 bool bTest = test == "10.5";
738 CPPUNIT_ASSERT_MESSAGE("String number should have the first apostrophe stripped.", bTest);
739 m_pDoc->SetString(0, 0, 0, "'apple'");
740 test = m_pDoc->GetString(0, 0, 0);
741 bTest = test == "'apple'";
742 CPPUNIT_ASSERT_MESSAGE("Text content should have retained the first apostrophe.", bTest);
744 // Customized string handling policy.
745 ScSetStringParam aParam;
746 aParam.setTextInput();
747 m_pDoc->SetString(0, 0, 0, "000123", &aParam);
748 test = m_pDoc->GetString(0, 0, 0);
749 CPPUNIT_ASSERT_MESSAGE("Text content should have been treated as string, not number.", test == "000123");
751 m_pDoc->DeleteTab(0);
754 void Test::testDocStatistics()
756 SCTAB nStartTabs = m_pDoc->GetTableCount();
757 m_pDoc->InsertTab(0, "Sheet1");
758 CPPUNIT_ASSERT_MESSAGE("Failed to increment sheet count.", m_pDoc->GetTableCount() == nStartTabs+1);
759 m_pDoc->InsertTab(1, "Sheet2");
760 CPPUNIT_ASSERT_MESSAGE("Failed to increment sheet count.", m_pDoc->GetTableCount() == nStartTabs+2);
762 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), m_pDoc->GetCellCount());
763 m_pDoc->SetValue(ScAddress(0,0,0), 2.0);
764 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), m_pDoc->GetCellCount());
765 m_pDoc->SetValue(ScAddress(2,2,0), 2.5);
766 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), m_pDoc->GetCellCount());
767 m_pDoc->SetString(ScAddress(1,1,1), "Test");
768 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(3), m_pDoc->GetCellCount());
770 m_pDoc->DeleteTab(1);
771 CPPUNIT_ASSERT_MESSAGE("Failed to decrement sheet count.", m_pDoc->GetTableCount() == nStartTabs+1);
772 m_pDoc->DeleteTab(0); // This may fail in case there is only one sheet in the document.
775 void Test::testDataEntries()
777 m_pDoc->InsertTab(0, "Test");
779 m_pDoc->SetString(ScAddress(0,5,0), "Andy");
780 m_pDoc->SetString(ScAddress(0,6,0), "Bruce");
781 m_pDoc->SetString(ScAddress(0,7,0), "Charlie");
782 m_pDoc->SetString(ScAddress(0,10,0), "Andy");
784 std::vector<ScTypedStrData> aEntries;
785 m_pDoc->GetDataEntries(0, 0, 0, true, aEntries); // Try at the very top.
787 // Entries are supposed to be sorted in ascending order, and are all unique.
788 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries.size());
789 std::vector<ScTypedStrData>::const_iterator it = aEntries.begin();
790 CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it->GetString());
791 ++it;
792 CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it->GetString());
793 ++it;
794 CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it->GetString());
795 ++it;
796 CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", it == aEntries.end());
798 aEntries.clear();
799 m_pDoc->GetDataEntries(0, MAXROW, 0, true, aEntries); // Try at the very bottom.
800 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries.size());
802 // Make sure we get the same set of suggestions.
803 it = aEntries.begin();
804 CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it->GetString());
805 ++it;
806 CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it->GetString());
807 ++it;
808 CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it->GetString());
809 ++it;
810 CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", it == aEntries.end());
812 m_pDoc->DeleteTab(0);
815 void Test::testSelectionFunction()
817 m_pDoc->InsertTab(0, "Test");
819 // Insert values into B2:B4.
820 m_pDoc->SetString(ScAddress(1,1,0), "=1"); // formula
821 m_pDoc->SetValue(ScAddress(1,2,0), 2.0);
822 m_pDoc->SetValue(ScAddress(1,3,0), 3.0);
824 // Insert strings into B5:B8.
825 m_pDoc->SetString(ScAddress(1,4,0), "A");
826 m_pDoc->SetString(ScAddress(1,5,0), "B");
827 m_pDoc->SetString(ScAddress(1,6,0), "=\"C\""); // formula
828 m_pDoc->SetString(ScAddress(1,7,0), "D");
830 // Insert values into D2:D4.
831 m_pDoc->SetValue(ScAddress(3,1,0), 4.0);
832 m_pDoc->SetValue(ScAddress(3,2,0), 5.0);
833 m_pDoc->SetValue(ScAddress(3,3,0), 6.0);
835 // Insert edit text into D5.
836 ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
837 rEE.SetText("Rich Text");
838 m_pDoc->SetEditText(ScAddress(3,4,0), rEE.CreateTextObject());
840 // Insert Another string into D6.
841 m_pDoc->SetString(ScAddress(3,5,0), "E");
843 // Select B2:B8 & D2:D8 disjoint region.
844 ScRangeList aRanges;
845 aRanges.Append(ScRange(1,1,0,1,7,0)); // B2:B8
846 aRanges.Append(ScRange(3,1,0,3,7,0)); // D2:D8
847 ScMarkData aMark;
848 aMark.MarkFromRangeList(aRanges, true);
850 struct Check
852 ScSubTotalFunc meFunc;
853 double mfExpected;
857 Check aChecks[] =
859 { SUBTOTAL_FUNC_AVE, 3.5 },
860 { SUBTOTAL_FUNC_CNT2, 12.0 },
861 { SUBTOTAL_FUNC_CNT, 6.0 },
862 { SUBTOTAL_FUNC_MAX, 6.0 },
863 { SUBTOTAL_FUNC_MIN, 1.0 },
864 { SUBTOTAL_FUNC_SUM, 21.0 },
865 { SUBTOTAL_FUNC_SELECTION_COUNT, 14.0 }
868 for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
870 double fRes = 0.0;
871 bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, ScAddress(), aMark, fRes);
872 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
873 CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
877 // Hide rows 4 and 6 and check the results again.
879 m_pDoc->SetRowHidden(3, 3, 0, true);
880 m_pDoc->SetRowHidden(5, 5, 0, true);
881 CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc->RowHidden(3, 0));
882 CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc->RowHidden(5, 0));
885 Check aChecks[] =
887 { SUBTOTAL_FUNC_AVE, 3.0 },
888 { SUBTOTAL_FUNC_CNT2, 8.0 },
889 { SUBTOTAL_FUNC_CNT, 4.0 },
890 { SUBTOTAL_FUNC_MAX, 5.0 },
891 { SUBTOTAL_FUNC_MIN, 1.0 },
892 { SUBTOTAL_FUNC_SUM, 12.0 },
893 { SUBTOTAL_FUNC_SELECTION_COUNT, 10.0 }
896 for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
898 double fRes = 0.0;
899 bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, ScAddress(), aMark, fRes);
900 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
901 CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
905 // Make sure that when no selection is present, use the current cursor position.
906 ScMarkData aEmpty;
909 // D3 (numeric cell containing 5.)
910 ScAddress aPos(3, 2, 0);
912 Check aChecks[] =
914 { SUBTOTAL_FUNC_AVE, 5.0 },
915 { SUBTOTAL_FUNC_CNT2, 1.0 },
916 { SUBTOTAL_FUNC_CNT, 1.0 },
917 { SUBTOTAL_FUNC_MAX, 5.0 },
918 { SUBTOTAL_FUNC_MIN, 5.0 },
919 { SUBTOTAL_FUNC_SUM, 5.0 },
920 { SUBTOTAL_FUNC_SELECTION_COUNT, 1.0 }
923 for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
925 double fRes = 0.0;
926 bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, aPos, aEmpty, fRes);
927 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
928 CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
933 // B7 (string formula cell containing ="C".)
934 ScAddress aPos(1, 6, 0);
936 Check aChecks[] =
938 { SUBTOTAL_FUNC_CNT2, 1.0 },
939 { SUBTOTAL_FUNC_SELECTION_COUNT, 1.0 }
942 for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
944 double fRes = 0.0;
945 bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, aPos, aEmpty, fRes);
946 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
947 CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
951 m_pDoc->DeleteTab(0);
954 void Test::testCopyToDocument()
956 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "src"));
958 m_pDoc->SetString(0, 0, 0, "Header");
959 m_pDoc->SetString(0, 1, 0, "1");
960 m_pDoc->SetString(0, 2, 0, "2");
961 m_pDoc->SetString(0, 3, 0, "3");
962 m_pDoc->SetString(0, 4, 0, "=4/2");
963 m_pDoc->CalcAll();
965 //note on A1
966 ScAddress aAdrA1 (0, 0, 0); // numerical cell content
967 ScPostIt* pNote = m_pDoc->GetOrCreateNote(aAdrA1);
968 pNote->SetText(aAdrA1, "Hello world in A1");
970 // Copy statically to another document.
972 ScDocument aDestDoc(SCDOCMODE_DOCUMENT);
973 aDestDoc.InsertTab(0, "src");
974 m_pDoc->CopyStaticToDocument(ScRange(0,1,0,0,3,0), 0, &aDestDoc); // Copy A2:A4
975 m_pDoc->CopyStaticToDocument(ScAddress(0,0,0), 0, &aDestDoc); // Copy A1
976 m_pDoc->CopyStaticToDocument(ScRange(0,4,0,0,7,0), 0, &aDestDoc); // Copy A5:A8
978 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,0,0), aDestDoc.GetString(0,0,0));
979 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,1,0), aDestDoc.GetString(0,1,0));
980 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,2,0), aDestDoc.GetString(0,2,0));
981 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,3,0), aDestDoc.GetString(0,3,0));
982 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,4,0), aDestDoc.GetString(0,4,0));
984 // verify note
985 CPPUNIT_ASSERT_MESSAGE("There should be a note in A1 destDocument", aDestDoc.HasNote(ScAddress(0, 0, 0)));
986 CPPUNIT_ASSERT_MESSAGE("The notes content should be the same on both documents",
987 aDestDoc.GetNote(ScAddress(0, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText());
989 m_pDoc->DeleteTab(0);
992 namespace {
994 struct HoriIterCheck
996 SCCOL nCol;
997 SCROW nRow;
998 const char* pVal;
1001 template<size_t _Size>
1002 bool checkHorizontalIterator(ScDocument* pDoc, const char* pData[][_Size], size_t nDataCount, const HoriIterCheck* pChecks, size_t nCheckCount)
1004 ScAddress aPos(0,0,0);
1005 Test::insertRangeData(pDoc, aPos, pData, nDataCount);
1006 ScHorizontalCellIterator aIter(pDoc, 0, 0, 0, 1, nDataCount-1);
1008 SCCOL nCol;
1009 SCROW nRow;
1010 size_t i = 0;
1011 for (ScRefCellValue* pCell = aIter.GetNext(nCol, nRow); pCell; pCell = aIter.GetNext(nCol, nRow), ++i)
1013 if (i >= nCheckCount)
1015 cerr << "hit invalid check " << i << " of " << nCheckCount << endl;
1016 CPPUNIT_FAIL("Iterator claims there is more data than there should be.");
1017 return false;
1020 if (pChecks[i].nCol != nCol)
1022 cerr << "Column mismatch " << pChecks[i].nCol << " vs. " << nCol << endl;
1023 return false;
1026 if (pChecks[i].nRow != nRow)
1028 cerr << "Row mismatch " << pChecks[i].nRow << " vs. " << nRow << endl;
1029 return false;
1032 if (OUString::createFromAscii(pChecks[i].pVal) != pCell->getString(pDoc))
1034 cerr << "String mismatch " << pChecks[i].pVal << " vs. " <<
1035 OUStringToOString(pCell->getString(pDoc), RTL_TEXTENCODING_UTF8).getStr() << endl;
1036 return false;
1040 return true;
1045 void Test::testHorizontalIterator()
1047 m_pDoc->InsertTab(0, "test");
1050 // Raw data - mixed types
1051 const char* aData[][2] = {
1052 { "A", "B" },
1053 { "C", "1" },
1054 { "D", "2" },
1055 { "E", "3" }
1058 HoriIterCheck aChecks[] = {
1059 { 0, 0, "A" },
1060 { 1, 0, "B" },
1061 { 0, 1, "C" },
1062 { 1, 1, "1" },
1063 { 0, 2, "D" },
1064 { 1, 2, "2" },
1065 { 0, 3, "E" },
1066 { 1, 3, "3" },
1069 bool bRes = checkHorizontalIterator(
1070 m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1072 if (!bRes)
1073 CPPUNIT_FAIL("Failed on test mixed.");
1077 // Raw data - 'hole' data
1078 const char* aData[][2] = {
1079 { "A", "B" },
1080 { "C", 0 },
1081 { "D", "E" },
1084 HoriIterCheck aChecks[] = {
1085 { 0, 0, "A" },
1086 { 1, 0, "B" },
1087 { 0, 1, "C" },
1088 { 0, 2, "D" },
1089 { 1, 2, "E" },
1092 bool bRes = checkHorizontalIterator(
1093 m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1095 if (!bRes)
1096 CPPUNIT_FAIL("Failed on test hole.");
1100 // Very holy data
1101 const char* aData[][2] = {
1102 { 0, "A" },
1103 { 0, 0 },
1104 { 0, "1" },
1105 { "B", 0 },
1106 { "C", "2" },
1107 { "D", "3" },
1108 { "E", 0 },
1109 { 0, "G" },
1110 { 0, 0 },
1113 HoriIterCheck aChecks[] = {
1114 { 1, 0, "A" },
1115 { 1, 2, "1" },
1116 { 0, 3, "B" },
1117 { 0, 4, "C" },
1118 { 1, 4, "2" },
1119 { 0, 5, "D" },
1120 { 1, 5, "3" },
1121 { 0, 6, "E" },
1122 { 1, 7, "G" },
1125 bool bRes = checkHorizontalIterator(
1126 m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1128 if (!bRes)
1129 CPPUNIT_FAIL("Failed on test holy.");
1133 // Degenerate case
1134 const char* aData[][2] = {
1135 { 0, 0 },
1136 { 0, 0 },
1137 { 0, 0 },
1140 bool bRes = checkHorizontalIterator(
1141 m_pDoc, aData, SAL_N_ELEMENTS(aData), NULL, 0);
1143 if (!bRes)
1144 CPPUNIT_FAIL("Failed on test degenerate.");
1148 // Data at end
1149 const char* aData[][2] = {
1150 { 0, 0 },
1151 { 0, 0 },
1152 { 0, "A" },
1155 HoriIterCheck aChecks[] = {
1156 { 1, 2, "A" },
1159 bool bRes = checkHorizontalIterator(
1160 m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1162 if (!bRes)
1163 CPPUNIT_FAIL("Failed on test at end.");
1167 // Data in middle
1168 const char* aData[][2] = {
1169 { 0, 0 },
1170 { 0, 0 },
1171 { 0, "A" },
1172 { 0, "1" },
1173 { 0, 0 },
1176 HoriIterCheck aChecks[] = {
1177 { 1, 2, "A" },
1178 { 1, 3, "1" },
1181 bool bRes = checkHorizontalIterator(
1182 m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1184 if (!bRes)
1185 CPPUNIT_FAIL("Failed on test in middle.");
1188 m_pDoc->DeleteTab(0);
1191 void Test::testValueIterator()
1193 m_pDoc->InsertTab(0, "Test");
1195 // Turn on "precision as shown" option.
1196 ScDocOptions aOpt = m_pDoc->GetDocOptions();
1197 aOpt.SetCalcAsShown(true);
1198 m_pDoc->SetDocOptions(aOpt);
1200 // Purely horizontal data layout with numeric data.
1201 for (SCCOL i = 1; i <= 3; ++i)
1202 m_pDoc->SetValue(ScAddress(i,2,0), i);
1204 double fVal;
1205 sal_uInt16 nErr;
1208 const double aChecks[] = { 1.0, 2.0, 3.0 };
1209 size_t nCheckLen = SAL_N_ELEMENTS(aChecks);
1211 ScValueIterator aIter(m_pDoc, ScRange(1,2,0,3,2,0));
1212 bool bHas = false;
1214 size_t nCheckPos = 0;
1215 for (bHas = aIter.GetFirst(fVal, nErr); bHas; bHas = aIter.GetNext(fVal, nErr), ++nCheckPos)
1217 CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos < nCheckLen);
1218 CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos], fVal);
1219 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(0), nErr);
1223 m_pDoc->DeleteTab(0);
1226 void Test::testHorizontalAttrIterator()
1228 m_pDoc->InsertTab(0, "Test");
1230 // Set the background color of B2:C3,D2,E3,C4:D4,B5:D5 to blue
1231 ScPatternAttr aCellBackColor(m_pDoc->GetPool());
1232 aCellBackColor.GetItemSet().Put(SvxBrushItem(COL_BLUE, ATTR_BACKGROUND));
1233 m_pDoc->ApplyPatternAreaTab(1, 1, 2, 2, 0, aCellBackColor);
1234 m_pDoc->ApplyPatternAreaTab(3, 1, 3, 1, 0, aCellBackColor);
1235 m_pDoc->ApplyPatternAreaTab(4, 2, 4, 2, 0, aCellBackColor);
1236 m_pDoc->ApplyPatternAreaTab(2, 3, 3, 3, 0, aCellBackColor);
1237 m_pDoc->ApplyPatternAreaTab(1, 4, 4, 4, 0, aCellBackColor);
1239 // some numeric data
1240 for (SCCOL i = 1; i <= 4; ++i)
1241 for (SCROW j = 1; j <= 4; ++j)
1242 m_pDoc->SetValue(ScAddress(i,j,0), i*10+j);
1245 const int aChecks[][3] = { {1, 3, 1}, {1, 2, 2}, {4, 4, 2}, {2, 3, 3}, {1, 4, 4} };
1246 size_t nCheckLen = SAL_N_ELEMENTS(aChecks);
1248 ScHorizontalAttrIterator aIter(m_pDoc, 0, 0, 0, 5, 5);
1249 SCCOL nCol1, nCol2;
1250 SCROW nRow;
1251 size_t nCheckPos = 0;
1252 for (const ScPatternAttr* pAttr = aIter.GetNext(nCol1, nCol2, nRow); pAttr; pAttr = aIter.GetNext(nCol1, nCol2, nRow), ++nCheckPos)
1254 CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos < nCheckLen);
1255 CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][0], static_cast<int>(nCol1));
1256 CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][1], static_cast<int>(nCol2));
1257 CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][2], static_cast<int>(nRow));
1261 m_pDoc->DeleteTab(0);
1264 namespace {
1266 bool broadcasterShifted(const ScDocument& rDoc, const ScAddress& rFrom, const ScAddress& rTo)
1268 const SvtBroadcaster* pBC = rDoc.GetBroadcaster(rFrom);
1269 if (pBC)
1271 cerr << "Broadcaster shouldn't be here." << endl;
1272 return false;
1275 pBC = rDoc.GetBroadcaster(rTo);
1276 if (!pBC)
1278 cerr << "Broadcaster should be here." << endl;
1279 return false;
1281 return true;
1284 formula::FormulaToken* getSingleRefToken(ScDocument& rDoc, const ScAddress& rPos)
1286 ScFormulaCell* pFC = rDoc.GetFormulaCell(rPos);
1287 if (!pFC)
1289 cerr << "Formula cell expected, but not found." << endl;
1290 return NULL;
1293 ScTokenArray* pTokens = pFC->GetCode();
1294 if (!pTokens)
1296 cerr << "Token array is not present." << endl;
1297 return NULL;
1300 formula::FormulaToken* pToken = pTokens->First();
1301 if (!pToken || pToken->GetType() != formula::svSingleRef)
1303 cerr << "Not a single reference token." << endl;
1304 return NULL;
1307 return pToken;
1310 bool checkRelativeRefToken(ScDocument& rDoc, const ScAddress& rPos, SCsCOL nRelCol, SCsROW nRelRow)
1312 formula::FormulaToken* pToken = getSingleRefToken(rDoc, rPos);
1313 if (!pToken)
1314 return false;
1316 ScSingleRefData& rRef = *pToken->GetSingleRef();
1317 if (!rRef.IsColRel() || rRef.Col() != nRelCol)
1319 cerr << "Unexpected relative column address." << endl;
1320 return false;
1323 if (!rRef.IsRowRel() || rRef.Row() != nRelRow)
1325 cerr << "Unexpected relative row address." << endl;
1326 return false;
1329 return true;
1332 bool checkDeletedRefToken(ScDocument& rDoc, const ScAddress& rPos)
1334 formula::FormulaToken* pToken = getSingleRefToken(rDoc, rPos);
1335 if (!pToken)
1336 return false;
1338 ScSingleRefData& rRef = *pToken->GetSingleRef();
1339 if (!rRef.IsDeleted())
1341 cerr << "Deleted reference is expected, but it's still a valid reference." << endl;
1342 return false;
1345 return true;
1350 void Test::testCellBroadcaster()
1352 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "foo"));
1354 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation.
1355 m_pDoc->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
1356 double val = m_pDoc->GetValue(ScAddress(1,0,0)); // A1 is empty, so the result should be 0.
1357 CPPUNIT_ASSERT_EQUAL(0.0, val);
1359 const SvtBroadcaster* pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
1360 CPPUNIT_ASSERT_MESSAGE("Cell A1 should have a broadcaster.", pBC);
1362 // Change the value of A1 and make sure that B1 follows.
1363 m_pDoc->SetValue(ScAddress(0,0,0), 1.23);
1364 val = m_pDoc->GetValue(ScAddress(1,0,0));
1365 CPPUNIT_ASSERT_EQUAL(1.23, val);
1367 // Move column A down 5 cells. Make sure B1 now references A6, not A1.
1368 m_pDoc->InsertRow(0, 0, 0, 0, 0, 5);
1369 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1370 checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 5));
1372 // Make sure the broadcaster has also moved.
1373 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1374 broadcasterShifted(*m_pDoc, ScAddress(0,0,0), ScAddress(0,5,0)));
1376 // Set new value to A6 and make sure B1 gets updated.
1377 m_pDoc->SetValue(ScAddress(0,5,0), 45.6);
1378 val = m_pDoc->GetValue(ScAddress(1,0,0));
1379 CPPUNIT_ASSERT_EQUAL(45.6, val);
1381 // Move column A up 3 cells, and make sure B1 now references A3, not A6.
1382 m_pDoc->DeleteRow(0, 0, 0, 0, 0, 3);
1383 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1384 checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 2));
1386 // The broadcaster should also have been relocated from A6 to A3.
1387 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1388 broadcasterShifted(*m_pDoc, ScAddress(0,5,0), ScAddress(0,2,0)));
1390 // Insert cells over A1:A10 and shift cells to right.
1391 m_pDoc->InsertCol(ScRange(0, 0, 0, 0, 10, 0));
1392 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1393 checkRelativeRefToken(*m_pDoc, ScAddress(2,0,0), -1, 2));
1394 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1395 broadcasterShifted(*m_pDoc, ScAddress(0,2,0), ScAddress(1,2,0)));
1397 // Delete formula in C2, which should remove the broadcaster in B3.
1398 pBC = m_pDoc->GetBroadcaster(ScAddress(1,2,0));
1399 CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should still exist.", pBC);
1400 clearRange(m_pDoc, ScAddress(2,0,0));
1401 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(ScAddress(2,0,0))); // C2 should be empty.
1402 pBC = m_pDoc->GetBroadcaster(ScAddress(1,2,0));
1403 CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should have been removed.", !pBC);
1405 // Clear everything and start over.
1406 clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
1408 m_pDoc->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
1409 pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
1410 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", pBC);
1412 // While column A is still empty, move column A down 2 cells. This should
1413 // move the broadcaster from A1 to A3.
1414 m_pDoc->InsertRow(0, 0, 0, 0, 0, 2);
1415 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1416 broadcasterShifted(*m_pDoc, ScAddress(0,0,0), ScAddress(0,2,0)));
1418 // Move it back while column A is still empty.
1419 m_pDoc->DeleteRow(0, 0, 0, 0, 0, 2);
1420 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1421 broadcasterShifted(*m_pDoc, ScAddress(0,2,0), ScAddress(0,0,0)));
1423 // Clear everything again
1424 clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
1426 // B1:B3 depends on A1:A3
1427 m_pDoc->SetString(ScAddress(1,0,0), "=A1");
1428 m_pDoc->SetString(ScAddress(1,1,0), "=A2");
1429 m_pDoc->SetString(ScAddress(1,2,0), "=A3");
1430 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1431 checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 0));
1432 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1433 checkRelativeRefToken(*m_pDoc, ScAddress(1,1,0), -1, 0));
1434 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B3 failed.",
1435 checkRelativeRefToken(*m_pDoc, ScAddress(1,2,0), -1, 0));
1436 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc->GetBroadcaster(ScAddress(0,0,0)));
1437 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A2.", m_pDoc->GetBroadcaster(ScAddress(0,1,0)));
1438 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A3.", m_pDoc->GetBroadcaster(ScAddress(0,2,0)));
1440 // Insert Rows at row 2, down 5 rows.
1441 m_pDoc->InsertRow(0, 0, 0, 0, 1, 5);
1442 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc->GetBroadcaster(ScAddress(0,0,0)));
1443 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1444 checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 0));
1446 // Broadcasters in A2 and A3 should shift down by 5 rows.
1447 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1448 broadcasterShifted(*m_pDoc, ScAddress(0,1,0), ScAddress(0,6,0)));
1449 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1450 broadcasterShifted(*m_pDoc, ScAddress(0,2,0), ScAddress(0,7,0)));
1452 // B2 and B3 should reference shifted cells.
1453 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1454 checkRelativeRefToken(*m_pDoc, ScAddress(1,1,0), -1, 5));
1455 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1456 checkRelativeRefToken(*m_pDoc, ScAddress(1,2,0), -1, 5));
1458 // Delete cells with broadcasters.
1459 m_pDoc->DeleteRow(0, 0, 0, 0, 4, 6);
1460 CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A7.", !m_pDoc->GetBroadcaster(ScAddress(0,6,0)));
1461 CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A8.", !m_pDoc->GetBroadcaster(ScAddress(0,7,0)));
1463 // References in B2 and B3 should be invalid.
1464 CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B2 failed.",
1465 checkDeletedRefToken(*m_pDoc, ScAddress(1,1,0)));
1466 CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B3 failed.",
1467 checkDeletedRefToken(*m_pDoc, ScAddress(1,2,0)));
1469 // Clear everything again
1470 clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
1473 // Switch to R1C1 to make it easier to input relative references in multiple cells.
1474 FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
1476 // Have B1:B20 reference A1:A20.
1477 val = 0.0;
1478 for (SCROW i = 0; i < 20; ++i)
1480 m_pDoc->SetValue(ScAddress(0,i,0), val++);
1481 m_pDoc->SetString(ScAddress(1,i,0), "=RC[-1]");
1485 // Ensure that the formula cells show correct values, and the referenced
1486 // cells have broadcasters.
1487 val = 0.0;
1488 for (SCROW i = 0; i < 20; ++i, ++val)
1490 CPPUNIT_ASSERT_EQUAL(val, m_pDoc->GetValue(ScAddress(1,i,0)));
1491 pBC = m_pDoc->GetBroadcaster(ScAddress(0,i,0));
1492 CPPUNIT_ASSERT_MESSAGE("Broadcast should exist here.", pBC);
1495 // Delete formula cells in B2:B19.
1496 clearRange(m_pDoc, ScRange(1,1,0,1,18,0));
1497 // Ensure that A2:A19 no longer have broadcasters, but A1 and A20 still do.
1498 CPPUNIT_ASSERT_MESSAGE("A1 should still have broadcaster.", m_pDoc->GetBroadcaster(ScAddress(0,0,0)));
1499 CPPUNIT_ASSERT_MESSAGE("A20 should still have broadcaster.", m_pDoc->GetBroadcaster(ScAddress(0,19,0)));
1500 for (SCROW i = 1; i <= 18; ++i)
1502 pBC = m_pDoc->GetBroadcaster(ScAddress(0,i,0));
1503 CPPUNIT_ASSERT_MESSAGE("Broadcaster should have been deleted.", !pBC);
1506 // Clear everything again
1507 clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
1509 m_pDoc->SetValue(ScAddress(0,0,0), 2.0);
1510 m_pDoc->SetString(ScAddress(1,0,0), "=A1");
1511 m_pDoc->SetString(ScAddress(2,0,0), "=B1");
1512 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(0,0,0));
1513 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(1,0,0));
1514 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(2,0,0));
1516 pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
1517 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
1518 pBC = m_pDoc->GetBroadcaster(ScAddress(1,0,0));
1519 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
1521 // Change the value of A1 and make sure everyone follows suit.
1522 m_pDoc->SetValue(ScAddress(0,0,0), 3.5);
1523 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc->GetValue(0,0,0));
1524 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc->GetValue(1,0,0));
1525 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc->GetValue(2,0,0));
1527 // Insert a column at column B.
1528 m_pDoc->InsertCol(ScRange(1,0,0,1,MAXROW,0));
1529 pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
1530 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
1531 pBC = m_pDoc->GetBroadcaster(ScAddress(2,0,0));
1532 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
1534 // Change the value of A1 again.
1535 m_pDoc->SetValue(ScAddress(0,0,0), 5.5);
1536 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc->GetValue(0,0,0));
1537 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc->GetValue(2,0,0));
1538 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc->GetValue(3,0,0));
1540 m_pDoc->DeleteTab(0);
1543 void Test::testFuncParam()
1546 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
1547 m_pDoc->InsertTab (0, "foo"));
1549 // First, the normal case, with no missing parameters.
1550 m_pDoc->SetString(0, 0, 0, "=AVERAGE(1;2;3)");
1551 m_pDoc->CalcFormulaTree(false, false);
1552 double val;
1553 m_pDoc->GetValue(0, 0, 0, val);
1554 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 2);
1556 // Now function with missing parameters. Missing values should be treated
1557 // as zeros.
1558 m_pDoc->SetString(0, 0, 0, "=AVERAGE(1;;;)");
1559 m_pDoc->CalcFormulaTree(false, false);
1560 m_pDoc->GetValue(0, 0, 0, val);
1561 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 0.25);
1563 // Conversion of string to numeric argument.
1564 m_pDoc->SetString(0, 0, 0, "=\"\"+3"); // empty string
1565 m_pDoc->SetString(0, 1, 0, "=\" \"+3"); // only blank
1566 m_pDoc->SetString(0, 2, 0, "=\" 4 \"+3"); // number in blanks
1567 m_pDoc->SetString(0, 3, 0, "=\" x \"+3"); // non-numeric
1568 m_pDoc->SetString(0, 4, 0, "=\"4.4\"+3"); // locale dependent
1570 OUString aVal;
1571 ScCalcConfig aConfig;
1573 // With "Convert also locale dependent" and "Empty string as zero"=True option.
1574 aConfig.meStringConversion = ScCalcConfig::StringConversion::LOCALE;
1575 aConfig.mbEmptyStringAsZero = true;
1576 m_pDoc->SetCalcConfig(aConfig);
1577 m_pDoc->CalcAll();
1578 m_pDoc->GetValue(0, 0, 0, val);
1579 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1580 m_pDoc->GetValue(0, 1, 0, val);
1581 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1582 m_pDoc->GetValue(0, 2, 0, val);
1583 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
1584 aVal = m_pDoc->GetString( 0, 3, 0);
1585 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1586 m_pDoc->GetValue(0, 4, 0, val);
1587 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7.4);
1589 // With "Convert also locale dependent" and "Empty string as zero"=False option.
1590 aConfig.meStringConversion = ScCalcConfig::StringConversion::LOCALE;
1591 aConfig.mbEmptyStringAsZero = false;
1592 m_pDoc->SetCalcConfig(aConfig);
1593 m_pDoc->CalcAll();
1594 aVal = m_pDoc->GetString( 0, 0, 0);
1595 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1596 aVal = m_pDoc->GetString( 0, 1, 0);
1597 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1598 m_pDoc->GetValue(0, 2, 0, val);
1599 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
1600 aVal = m_pDoc->GetString( 0, 3, 0);
1601 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1602 m_pDoc->GetValue(0, 4, 0, val);
1603 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7.4);
1605 // With "Convert only unambiguous" and "Empty string as zero"=True option.
1606 aConfig.meStringConversion = ScCalcConfig::StringConversion::UNAMBIGUOUS;
1607 aConfig.mbEmptyStringAsZero = true;
1608 m_pDoc->SetCalcConfig(aConfig);
1609 m_pDoc->CalcAll();
1610 m_pDoc->GetValue(0, 0, 0, val);
1611 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1612 m_pDoc->GetValue(0, 1, 0, val);
1613 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1614 m_pDoc->GetValue(0, 2, 0, val);
1615 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
1616 aVal = m_pDoc->GetString( 0, 3, 0);
1617 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1618 aVal = m_pDoc->GetString( 0, 4, 0);
1619 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1621 // With "Convert only unambiguous" and "Empty string as zero"=False option.
1622 aConfig.meStringConversion = ScCalcConfig::StringConversion::UNAMBIGUOUS;
1623 aConfig.mbEmptyStringAsZero = false;
1624 m_pDoc->SetCalcConfig(aConfig);
1625 m_pDoc->CalcAll();
1626 aVal = m_pDoc->GetString( 0, 0, 0);
1627 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1628 aVal = m_pDoc->GetString( 0, 1, 0);
1629 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1630 m_pDoc->GetValue(0, 2, 0, val);
1631 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
1632 aVal = m_pDoc->GetString( 0, 3, 0);
1633 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1634 aVal = m_pDoc->GetString( 0, 4, 0);
1635 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1637 // With "Treat as zero" ("Empty string as zero" is ignored).
1638 aConfig.meStringConversion = ScCalcConfig::StringConversion::ZERO;
1639 aConfig.mbEmptyStringAsZero = true;
1640 m_pDoc->SetCalcConfig(aConfig);
1641 m_pDoc->CalcAll();
1642 m_pDoc->GetValue(0, 0, 0, val);
1643 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1644 m_pDoc->GetValue(0, 1, 0, val);
1645 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1646 m_pDoc->GetValue(0, 2, 0, val);
1647 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1648 m_pDoc->GetValue(0, 3, 0, val);
1649 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1650 m_pDoc->GetValue(0, 4, 0, val);
1651 CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1653 // With "Generate #VALUE! error" ("Empty string as zero" is ignored).
1654 aConfig.meStringConversion = ScCalcConfig::StringConversion::ILLEGAL;
1655 aConfig.mbEmptyStringAsZero = false;
1656 m_pDoc->SetCalcConfig(aConfig);
1657 m_pDoc->CalcAll();
1658 aVal = m_pDoc->GetString( 0, 0, 0);
1659 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1660 aVal = m_pDoc->GetString( 0, 1, 0);
1661 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1662 aVal = m_pDoc->GetString( 0, 2, 0);
1663 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1664 aVal = m_pDoc->GetString( 0, 3, 0);
1665 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1666 aVal = m_pDoc->GetString( 0, 4, 0);
1667 CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1669 m_pDoc->DeleteTab(0);
1672 void Test::testNamedRange()
1674 RangeNameDef aNames[] = {
1675 { "Divisor", "$Sheet1.$A$1:$A$1048576", 1 },
1676 { "MyRange1", "$Sheet1.$A$1:$A$100", 2 },
1677 { "MyRange2", "$Sheet1.$B$1:$B$100", 3 },
1678 { "MyRange3", "$Sheet1.$C$1:$C$100", 4 }
1681 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "Sheet1"));
1683 m_pDoc->SetValue (0, 0, 0, 101);
1685 ScRangeName* pNames = new ScRangeName;
1686 bool bSuccess = insertRangeNames(m_pDoc, pNames, aNames, aNames + SAL_N_ELEMENTS(aNames));
1687 CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess);
1688 m_pDoc->SetRangeName(pNames);
1690 ScRangeName* pNewRanges = m_pDoc->GetRangeName();
1691 CPPUNIT_ASSERT(pNewRanges);
1693 // Make sure the index lookup does the right thing.
1694 for (size_t i = 0; i < SAL_N_ELEMENTS(aNames); ++i)
1696 const ScRangeData* p = pNewRanges->findByIndex(aNames[i].mnIndex);
1697 CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed.", p);
1698 OUString aName = p->GetName();
1699 CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved.", aName.equalsAscii(aNames[i].mpName));
1702 // Test usage in formula expression.
1703 m_pDoc->SetString (1, 0, 0, "=A1/Divisor");
1704 m_pDoc->CalcAll();
1706 double result;
1707 m_pDoc->GetValue (1, 0, 0, result);
1708 CPPUNIT_ASSERT_MESSAGE ("calculation failed", result == 1.0);
1710 // Test copy-ability of range names.
1711 ScRangeName* pCopiedRanges = new ScRangeName(*pNewRanges);
1712 m_pDoc->SetRangeName(pCopiedRanges);
1713 // Make sure the index lookup still works.
1714 for (size_t i = 0; i < SAL_N_ELEMENTS(aNames); ++i)
1716 const ScRangeData* p = pCopiedRanges->findByIndex(aNames[i].mnIndex);
1717 CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed with the copied instance.", p);
1718 OUString aName = p->GetName();
1719 CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved with the copied instance.", aName.equalsAscii(aNames[i].mpName));
1722 m_pDoc->SetRangeName(NULL); // Delete the names.
1723 m_pDoc->DeleteTab(0);
1726 void Test::testInsertNameList()
1728 m_pDoc->InsertTab(0, "Test");
1730 RangeNameDef aNames[] = {
1731 { "MyRange1", "$Test.$A$1:$A$100", 1 },
1732 { "MyRange2", "$Test.$B$1:$B$100", 2 },
1733 { "MyRange3", "$Test.$C$1:$C$100", 3 }
1736 ScRangeName* pNames = new ScRangeName;
1737 bool bSuccess = insertRangeNames(m_pDoc, pNames, aNames, aNames + SAL_N_ELEMENTS(aNames));
1738 CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess);
1739 m_pDoc->SetRangeName(pNames);
1741 ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
1742 ScAddress aPos(1,1,0);
1743 rDocFunc.InsertNameList(aPos, true);
1745 for (size_t i = 0; i < SAL_N_ELEMENTS(aNames); ++i, aPos.IncRow())
1747 OUString aName = m_pDoc->GetString(aPos);
1748 CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(aNames[i].mpName), aName);
1749 ScAddress aExprPos = aPos;
1750 aExprPos.IncCol();
1751 OUString aExpr = m_pDoc->GetString(aExprPos);
1752 OUString aExpected = "=";
1753 aExpected += OUString::createFromAscii(aNames[i].mpExpr);
1754 CPPUNIT_ASSERT_EQUAL(aExpected, aExpr);
1757 m_pDoc->DeleteTab(0);
1760 void Test::testCSV()
1762 const int English = 0, European = 1;
1763 struct {
1764 const char *pStr; int eSep; bool bResult; double nValue;
1765 } aTests[] = {
1766 { "foo", English, false, 0.0 },
1767 { "1.0", English, true, 1.0 },
1768 { "1,0", English, false, 0.0 },
1769 { "1.0", European, false, 0.0 },
1770 { "1.000", European, true, 1000.0 },
1771 { "1,000", European, true, 1.0 },
1772 { "1.000", English, true, 1.0 },
1773 { "1,000", English, true, 1000.0 },
1774 { " 1.0", English, true, 1.0 },
1775 { " 1.0 ", English, true, 1.0 },
1776 { "1.0 ", European, false, 0.0 },
1777 { "1.000", European, true, 1000.0 },
1778 { "1137.999", English, true, 1137.999 },
1779 { "1.000.00", European, false, 0.0 }
1781 for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(aTests); i++) {
1782 OUString aStr(aTests[i].pStr, strlen (aTests[i].pStr), RTL_TEXTENCODING_UTF8);
1783 double nValue = 0.0;
1784 bool bResult = ScStringUtil::parseSimpleNumber
1785 (aStr, aTests[i].eSep == English ? '.' : ',',
1786 aTests[i].eSep == English ? ',' : '.',
1787 nValue);
1788 CPPUNIT_ASSERT_MESSAGE ("CSV numeric detection failure", bResult == aTests[i].bResult);
1789 CPPUNIT_ASSERT_MESSAGE ("CSV numeric value failure", nValue == aTests[i].nValue);
1793 template<typename Evaluator>
1794 void checkMatrixElements(const ScMatrix& rMat)
1796 SCSIZE nC, nR;
1797 rMat.GetDimensions(nC, nR);
1798 Evaluator aEval;
1799 for (SCSIZE i = 0; i < nC; ++i)
1801 for (SCSIZE j = 0; j < nR; ++j)
1803 aEval(i, j, rMat.Get(i, j));
1808 struct AllZeroMatrix
1810 void operator() (SCSIZE /*nCol*/, SCSIZE /*nRow*/, const ScMatrixValue& rVal) const
1812 CPPUNIT_ASSERT_MESSAGE("element is not of numeric type", rVal.nType == SC_MATVAL_VALUE);
1813 CPPUNIT_ASSERT_MESSAGE("element value must be zero", rVal.fVal == 0.0);
1817 struct PartiallyFilledZeroMatrix
1819 void operator() (SCSIZE nCol, SCSIZE nRow, const ScMatrixValue& rVal) const
1821 CPPUNIT_ASSERT_MESSAGE("element is not of numeric type", rVal.nType == SC_MATVAL_VALUE);
1822 if (1 <= nCol && nCol <= 2 && 2 <= nRow && nRow <= 8)
1824 CPPUNIT_ASSERT_MESSAGE("element value must be 3.0", rVal.fVal == 3.0);
1826 else
1828 CPPUNIT_ASSERT_MESSAGE("element value must be zero", rVal.fVal == 0.0);
1833 struct AllEmptyMatrix
1835 void operator() (SCSIZE /*nCol*/, SCSIZE /*nRow*/, const ScMatrixValue& rVal) const
1837 CPPUNIT_ASSERT_MESSAGE("element is not of empty type", rVal.nType == SC_MATVAL_EMPTY);
1838 CPPUNIT_ASSERT_MESSAGE("value of \"empty\" element is expected to be zero", rVal.fVal == 0.0);
1842 struct PartiallyFilledEmptyMatrix
1844 void operator() (SCSIZE nCol, SCSIZE nRow, const ScMatrixValue& rVal) const
1846 if (nCol == 1 && nRow == 1)
1848 CPPUNIT_ASSERT_MESSAGE("element is not of boolean type", rVal.nType == SC_MATVAL_BOOLEAN);
1849 CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.fVal == 1.0);
1851 else if (nCol == 4 && nRow == 5)
1853 CPPUNIT_ASSERT_MESSAGE("element is not of value type", rVal.nType == SC_MATVAL_VALUE);
1854 CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.fVal == -12.5);
1856 else if (nCol == 8 && nRow == 2)
1858 CPPUNIT_ASSERT_MESSAGE("element is not of value type", rVal.nType == SC_MATVAL_STRING);
1859 CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.aStr.getString() == "Test");
1861 else if (nCol == 8 && nRow == 11)
1863 CPPUNIT_ASSERT_MESSAGE("element is not of empty path type", rVal.nType == SC_MATVAL_EMPTYPATH);
1864 CPPUNIT_ASSERT_MESSAGE("value of \"empty\" element is expected to be zero", rVal.fVal == 0.0);
1866 else
1868 CPPUNIT_ASSERT_MESSAGE("element is not of empty type", rVal.nType == SC_MATVAL_EMPTY);
1869 CPPUNIT_ASSERT_MESSAGE("value of \"empty\" element is expected to be zero", rVal.fVal == 0.0);
1874 void Test::testMatrix()
1876 svl::SharedStringPool& rPool = m_pDoc->GetSharedStringPool();
1877 ScMatrixRef pMat, pMat2;
1879 // First, test the zero matrix type.
1880 pMat = new ScMatrix(0, 0, 0.0);
1881 SCSIZE nC, nR;
1882 pMat->GetDimensions(nC, nR);
1883 CPPUNIT_ASSERT_MESSAGE("matrix is not empty", nC == 0 && nR == 0);
1884 pMat->Resize(4, 10, 0.0);
1885 pMat->GetDimensions(nC, nR);
1886 CPPUNIT_ASSERT_MESSAGE("matrix size is not as expected", nC == 4 && nR == 10);
1887 CPPUNIT_ASSERT_MESSAGE("both 'and' and 'or' should evaluate to false",
1888 !pMat->And() && !pMat->Or());
1890 // Resizing into a larger matrix should fill the void space with zeros.
1891 checkMatrixElements<AllZeroMatrix>(*pMat);
1893 pMat->FillDouble(3.0, 1, 2, 2, 8);
1894 checkMatrixElements<PartiallyFilledZeroMatrix>(*pMat);
1895 CPPUNIT_ASSERT_MESSAGE("matrix is expected to be numeric", pMat->IsNumeric());
1896 CPPUNIT_ASSERT_MESSAGE("partially non-zero matrix should evaluate false on 'and' and true on 'or",
1897 !pMat->And() && pMat->Or());
1898 pMat->FillDouble(5.0, 0, 0, nC-1, nR-1);
1899 CPPUNIT_ASSERT_MESSAGE("fully non-zero matrix should evaluate true both on 'and' and 'or",
1900 pMat->And() && pMat->Or());
1902 // Test the AND and OR evaluations.
1903 pMat = new ScMatrix(2, 2, 0.0);
1905 // Only some of the elements are non-zero.
1906 pMat->PutBoolean(true, 0, 0);
1907 pMat->PutDouble(1.0, 1, 1);
1908 CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat->Or());
1909 CPPUNIT_ASSERT_MESSAGE("incorrect AND result", !pMat->And());
1911 // All of the elements are non-zero.
1912 pMat->PutBoolean(true, 0, 1);
1913 pMat->PutDouble(2.3, 1, 0);
1914 CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat->Or());
1915 CPPUNIT_ASSERT_MESSAGE("incorrect AND result", pMat->And());
1917 // Now test the emtpy matrix type.
1918 pMat = new ScMatrix(10, 20);
1919 pMat->GetDimensions(nC, nR);
1920 CPPUNIT_ASSERT_MESSAGE("matrix size is not as expected", nC == 10 && nR == 20);
1921 checkMatrixElements<AllEmptyMatrix>(*pMat);
1923 pMat->PutBoolean(true, 1, 1);
1924 pMat->PutDouble(-12.5, 4, 5);
1925 pMat->PutString(rPool.intern("Test"), 8, 2);
1926 pMat->PutEmptyPath(8, 11);
1927 checkMatrixElements<PartiallyFilledEmptyMatrix>(*pMat);
1929 // Test resizing.
1930 pMat = new ScMatrix(0, 0);
1931 pMat->Resize(2, 2, 1.5);
1932 pMat->PutEmpty(1, 1);
1934 CPPUNIT_ASSERT_EQUAL(1.5, pMat->GetDouble(0, 0));
1935 CPPUNIT_ASSERT_EQUAL(1.5, pMat->GetDouble(0, 1));
1936 CPPUNIT_ASSERT_EQUAL(1.5, pMat->GetDouble(1, 0));
1937 CPPUNIT_ASSERT_MESSAGE("PutEmpty() call failed.", pMat->IsEmpty(1, 1));
1939 // Max and min values.
1940 pMat = new ScMatrix(2, 2, 0.0);
1941 pMat->PutDouble(-10, 0, 0);
1942 pMat->PutDouble(-12, 0, 1);
1943 pMat->PutDouble(-8, 1, 0);
1944 pMat->PutDouble(-25, 1, 1);
1945 CPPUNIT_ASSERT_EQUAL(-25.0, pMat->GetMinValue(false));
1946 CPPUNIT_ASSERT_EQUAL(-8.0, pMat->GetMaxValue(false));
1947 pMat->PutString(rPool.intern("Test"), 0, 0);
1948 CPPUNIT_ASSERT_EQUAL(0.0, pMat->GetMaxValue(true)); // text as zero.
1949 CPPUNIT_ASSERT_EQUAL(-8.0, pMat->GetMaxValue(false)); // ignore text.
1950 pMat->PutBoolean(true, 0, 0);
1951 CPPUNIT_ASSERT_EQUAL(1.0, pMat->GetMaxValue(false));
1952 pMat = new ScMatrix(2, 2, 10.0);
1953 pMat->PutBoolean(false, 0, 0);
1954 pMat->PutDouble(12.5, 1, 1);
1955 CPPUNIT_ASSERT_EQUAL(0.0, pMat->GetMinValue(false));
1956 CPPUNIT_ASSERT_EQUAL(12.5, pMat->GetMaxValue(false));
1958 // Convert matrix into a linear double array. String elements become NaN
1959 // and empty elements become 0.
1960 pMat = new ScMatrix(3, 3);
1961 pMat->PutDouble(2.5, 0, 0);
1962 pMat->PutDouble(1.2, 0, 1);
1963 pMat->PutString(rPool.intern("A"), 1, 1);
1964 pMat->PutDouble(2.3, 2, 1);
1965 pMat->PutDouble(-20, 2, 2);
1967 double fNaN;
1968 rtl::math::setNan(&fNaN);
1970 std::vector<double> aDoubles;
1971 pMat->GetDoubleArray(aDoubles);
1974 const double pChecks[] = { 2.5, 1.2, 0, 0, fNaN, 0, 0, 2.3, -20 };
1975 CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks), aDoubles.size());
1976 for (size_t i = 0, n = aDoubles.size(); i < n; ++i)
1978 if (rtl::math::isNan(pChecks[i]))
1979 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", rtl::math::isNan(aDoubles[i]));
1980 else
1981 CPPUNIT_ASSERT_EQUAL(pChecks[i], aDoubles[i]);
1985 pMat2 = new ScMatrix(3, 3, 10.0);
1986 pMat2->PutString(rPool.intern("B"), 1, 0);
1987 pMat2->MergeDoubleArray(aDoubles, ScMatrix::Mul);
1990 const double pChecks[] = { 25, 12, 0, fNaN, fNaN, 0, 0, 23, -200 };
1991 CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks), aDoubles.size());
1992 for (size_t i = 0, n = aDoubles.size(); i < n; ++i)
1994 if (rtl::math::isNan(pChecks[i]))
1995 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", rtl::math::isNan(aDoubles[i]));
1996 else
1997 CPPUNIT_ASSERT_EQUAL(pChecks[i], aDoubles[i]);
2002 void Test::testMatrixComparisonWithErrors()
2004 m_pDoc->InsertTab(0, "foo");
2006 // Insert the source values in A1:A2.
2007 m_pDoc->SetString(0, 0, 0, "=1/0");
2008 m_pDoc->SetValue( 0, 1, 0, 1.0);
2010 // Create a matrix formula in B3:B4 referencing A1:A2 and doing a greater
2011 // than comparison on it's values. Error value must be propagated.
2012 ScMarkData aMark;
2013 aMark.SelectOneTable(0);
2014 m_pDoc->InsertMatrixFormula(1, 2, 1, 3, aMark, "=A1:A2>0");
2016 CPPUNIT_ASSERT_EQUAL(OUString("#DIV/0!"), m_pDoc->GetString(0,0,0));
2017 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue( 0,1,0));
2018 CPPUNIT_ASSERT_EQUAL(OUString("#DIV/0!"), m_pDoc->GetString(1,2,0));
2019 CPPUNIT_ASSERT_EQUAL(OUString("TRUE"), m_pDoc->GetString(1,3,0));
2021 m_pDoc->DeleteTab(0);
2024 void Test::testEnterMixedMatrix()
2026 m_pDoc->InsertTab(0, "foo");
2028 // Insert the source values in A1:B2.
2029 m_pDoc->SetString(0, 0, 0, "A");
2030 m_pDoc->SetString(1, 0, 0, "B");
2031 double val = 1.0;
2032 m_pDoc->SetValue(0, 1, 0, val);
2033 val = 2.0;
2034 m_pDoc->SetValue(1, 1, 0, val);
2036 // Create a matrix range in A4:B5 referencing A1:B2.
2037 ScMarkData aMark;
2038 aMark.SelectOneTable(0);
2039 m_pDoc->InsertMatrixFormula(0, 3, 1, 4, aMark, "=A1:B2", NULL);
2041 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,0,0), m_pDoc->GetString(0,3,0));
2042 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(1,0,0), m_pDoc->GetString(1,3,0));
2043 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(0,1,0), m_pDoc->GetValue(0,4,0));
2044 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(1,1,0), m_pDoc->GetValue(1,4,0));
2046 m_pDoc->DeleteTab(0);
2049 void Test::testMatrixEditable()
2051 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
2053 m_pDoc->InsertTab(0, "Test");
2055 // Values in A1:B1.
2056 m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
2057 m_pDoc->SetValue(ScAddress(1,0,0), 2.0);
2059 // A2 is a normal formula.
2060 m_pDoc->SetString(ScAddress(0,1,0), "=5");
2062 // A3:A4 is a matrix.
2063 ScRange aMatRange(0,2,0,0,3,0);
2064 ScMarkData aMark;
2065 aMark.SetMarkArea(aMatRange);
2066 m_pDoc->InsertMatrixFormula(0, 2, 0, 3, aMark, "=TRANSPOSE(A1:B1)", NULL);
2068 // Check their values.
2069 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0,1,0)));
2070 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,2,0)));
2071 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
2073 // Make sure A3:A4 is a matrix.
2074 ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(0,2,0));
2075 CPPUNIT_ASSERT(pFC);
2076 CPPUNIT_ASSERT_MESSAGE("A3 should be matrix origin.", pFC->GetMatrixFlag() == MM_FORMULA);
2078 pFC = m_pDoc->GetFormulaCell(ScAddress(0,3,0));
2079 CPPUNIT_ASSERT(pFC);
2080 CPPUNIT_ASSERT_MESSAGE("A4 should be matrix reference.", pFC->GetMatrixFlag() == MM_REFERENCE);
2082 // Check to make sure A3:A4 combined is editable.
2083 ScEditableTester aTester;
2084 aTester.TestSelection(m_pDoc, aMark);
2085 CPPUNIT_ASSERT(aTester.IsEditable());
2087 m_pDoc->DeleteTab(0);
2090 void Test::testCellCopy()
2092 m_pDoc->InsertTab(0, "TestTab");
2093 ScAddress aSrc(0,0,0);
2094 ScAddress aDest(0,1,0);
2095 OUString aStr("please copy me");
2096 m_pDoc->SetString(aSrc, "please copy me");
2097 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aSrc), aStr);
2098 // copy to self - why not ?
2099 m_pDoc->CopyCellToDocument(aSrc,aDest,*m_pDoc);
2100 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aDest), aStr);
2103 void Test::testSheetCopy()
2105 m_pDoc->InsertTab(0, "TestTab");
2106 CPPUNIT_ASSERT_MESSAGE("document should have one sheet to begin with.", m_pDoc->GetTableCount() == 1);
2108 // Insert text in A1.
2109 m_pDoc->SetString(ScAddress(0,0,0), "copy me");
2111 // Insert edit cells in B1:B3.
2112 ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
2113 rEE.SetText("Edit 1");
2114 m_pDoc->SetEditText(ScAddress(1,0,0), rEE.CreateTextObject());
2115 rEE.SetText("Edit 2");
2116 m_pDoc->SetEditText(ScAddress(1,1,0), rEE.CreateTextObject());
2117 rEE.SetText("Edit 3");
2118 m_pDoc->SetEditText(ScAddress(1,2,0), rEE.CreateTextObject());
2120 SCROW nRow1, nRow2;
2121 bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2122 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2124 // insert a note
2125 ScAddress aAdrA1 (0,2,0); // empty cell content.
2126 ScPostIt *pNoteA1 = m_pDoc->GetOrCreateNote(aAdrA1);
2127 pNoteA1->SetText(aAdrA1, "Hello world in A3");
2129 // Copy and test the result.
2130 m_pDoc->CopyTab(0, 1);
2131 CPPUNIT_ASSERT_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount() == 2);
2132 bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
2133 CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2134 CPPUNIT_ASSERT_MESSAGE("There should be note on A3 in new sheet", m_pDoc->HasNote(ScAddress(0,2,1)));
2135 CPPUNIT_ASSERT_EQUAL(OUString("copy me"), m_pDoc->GetString(ScAddress(0,0,1)));
2137 // Check the copied edit cells.
2138 const EditTextObject* pEditObj = m_pDoc->GetEditText(ScAddress(1,0,1));
2139 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B1.", pEditObj);
2140 CPPUNIT_ASSERT_EQUAL(OUString("Edit 1"), pEditObj->GetText(0));
2141 pEditObj = m_pDoc->GetEditText(ScAddress(1,1,1));
2142 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B2.", pEditObj);
2143 CPPUNIT_ASSERT_EQUAL(OUString("Edit 2"), pEditObj->GetText(0));
2144 pEditObj = m_pDoc->GetEditText(ScAddress(1,2,1));
2145 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B3.", pEditObj);
2146 CPPUNIT_ASSERT_EQUAL(OUString("Edit 3"), pEditObj->GetText(0));
2148 m_pDoc->DeleteTab(1);
2150 m_pDoc->SetRowHidden(5, 10, 0, true);
2151 bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2152 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
2153 bHidden = m_pDoc->RowHidden(5, 0, &nRow1, &nRow2);
2154 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
2155 bHidden = m_pDoc->RowHidden(11, 0, &nRow1, &nRow2);
2156 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
2158 // Copy the sheet once again.
2159 m_pDoc->CopyTab(0, 1);
2160 CPPUNIT_ASSERT_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount() == 2);
2161 bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
2162 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
2163 bHidden = m_pDoc->RowHidden(5, 1, &nRow1, &nRow2);
2164 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
2165 bHidden = m_pDoc->RowHidden(11, 1, &nRow1, &nRow2);
2166 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
2167 m_pDoc->DeleteTab(1);
2168 m_pDoc->DeleteTab(0);
2171 void Test::testSheetMove()
2173 m_pDoc->InsertTab(0, "TestTab1");
2174 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.", m_pDoc->GetTableCount(), static_cast<SCTAB>(1));
2175 SCROW nRow1, nRow2;
2176 bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2177 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2179 //test if inserting before another sheet works
2180 m_pDoc->InsertTab(0, "TestTab2");
2181 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have two sheets", m_pDoc->GetTableCount(), static_cast<SCTAB>(2));
2182 bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2183 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2185 // Move and test the result.
2186 m_pDoc->MoveTab(0, 1);
2187 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount(), static_cast<SCTAB>(2));
2188 bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
2189 CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2190 OUString aName;
2191 m_pDoc->GetName(0, aName);
2192 CPPUNIT_ASSERT_MESSAGE( "sheets should have changed places", aName == "TestTab1" );
2194 m_pDoc->SetRowHidden(5, 10, 0, true);
2195 bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2196 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
2197 bHidden = m_pDoc->RowHidden(5, 0, &nRow1, &nRow2);
2198 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
2199 bHidden = m_pDoc->RowHidden(11, 0, &nRow1, &nRow2);
2200 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
2202 // Move the sheet once again.
2203 m_pDoc->MoveTab(1, 0);
2204 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount(), static_cast<SCTAB>(2));
2205 bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
2206 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
2207 bHidden = m_pDoc->RowHidden(5, 1, &nRow1, &nRow2);
2208 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
2209 bHidden = m_pDoc->RowHidden(11, 1, &nRow1, &nRow2);
2210 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
2211 m_pDoc->GetName(0, aName);
2212 CPPUNIT_ASSERT_MESSAGE( "sheets should have changed places", aName == "TestTab2" );
2213 m_pDoc->DeleteTab(1);
2214 m_pDoc->DeleteTab(0);
2217 void Test::testDataArea()
2219 m_pDoc->InsertTab(0, "Data");
2221 // Totally empty sheet should be rightfully considered empty in all accounts.
2222 CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc->IsPrintEmpty(0, 0, 0, 100, 100));
2223 CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100));
2225 // Now, set borders in some cells....
2226 ::editeng::SvxBorderLine aLine(NULL, 50, table::BorderLineStyle::SOLID);
2227 SvxBoxItem aBorderItem(ATTR_BORDER);
2228 aBorderItem.SetLine(&aLine, SvxBoxItemLine::LEFT);
2229 aBorderItem.SetLine(&aLine, SvxBoxItemLine::RIGHT);
2230 for (SCROW i = 0; i < 100; ++i)
2231 // Set borders from row 1 to 100.
2232 m_pDoc->ApplyAttr(0, i, 0, aBorderItem);
2234 // Now the sheet is considered non-empty for printing purposes, but still
2235 // be empty in all the other cases.
2236 CPPUNIT_ASSERT_MESSAGE("Empty sheet with borders should be printable.",
2237 !m_pDoc->IsPrintEmpty(0, 0, 0, 100, 100));
2238 CPPUNIT_ASSERT_MESSAGE("But it should still be considered empty in all the other cases.",
2239 m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100));
2241 // Adding a real cell content should turn the block non-empty.
2242 m_pDoc->SetString(0, 0, 0, "Some text");
2243 CPPUNIT_ASSERT_MESSAGE("Now the block should not be empty with a real cell content.",
2244 !m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100));
2246 // TODO: Add more tests for normal data area calculation.
2248 m_pDoc->DeleteTab(0);
2251 void Test::testStreamValid()
2253 m_pDoc->InsertTab(0, "Sheet1");
2254 m_pDoc->InsertTab(1, "Sheet2");
2255 m_pDoc->InsertTab(2, "Sheet3");
2256 m_pDoc->InsertTab(3, "Sheet4");
2257 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have 4 sheet instances.", m_pDoc->GetTableCount(), static_cast<SCTAB>(4));
2259 OUString a1("A1");
2260 OUString a2("A2");
2261 OUString test;
2263 // Put values into Sheet1.
2264 m_pDoc->SetString(0, 0, 0, a1);
2265 m_pDoc->SetString(0, 1, 0, a2);
2266 test = m_pDoc->GetString(0, 0, 0);
2267 CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet1.A1", test.equals(a1));
2268 test = m_pDoc->GetString(0, 1, 0);
2269 CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet1.A2", test.equals(a2));
2271 // Put formulas into Sheet2 to Sheet4 to reference values from Sheet1.
2272 m_pDoc->SetString(0, 0, 1, "=Sheet1.A1");
2273 m_pDoc->SetString(0, 1, 1, "=Sheet1.A2");
2274 m_pDoc->SetString(0, 0, 2, "=Sheet1.A1");
2275 m_pDoc->SetString(0, 0, 3, "=Sheet1.A2");
2277 test = m_pDoc->GetString(0, 0, 1);
2278 CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet2.A1", test.equals(a1));
2279 test = m_pDoc->GetString(0, 1, 1);
2280 CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet2.A2", test.equals(a2));
2281 test = m_pDoc->GetString(0, 0, 2);
2282 CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet3.A1", test.equals(a1));
2283 test = m_pDoc->GetString(0, 0, 3);
2284 CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet3.A1", test.equals(a2));
2286 // Set all sheet streams valid after all the initial cell values are in
2287 // place. In reality we need to have real XML streams stored in order to
2288 // claim they are valid, but we are just testing the flag values here.
2289 m_pDoc->SetStreamValid(0, true);
2290 m_pDoc->SetStreamValid(1, true);
2291 m_pDoc->SetStreamValid(2, true);
2292 m_pDoc->SetStreamValid(3, true);
2293 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(0));
2294 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(1));
2295 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(2));
2296 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(3));
2298 // Now, insert a new row at row 2 position on Sheet1. This will move cell
2299 // A2 downward but cell A1 remains unmoved.
2300 m_pDoc->InsertRow(0, 0, MAXCOL, 0, 1, 2);
2301 test = m_pDoc->GetString(0, 0, 0);
2302 CPPUNIT_ASSERT_MESSAGE("Cell A1 should not have moved.", test.equals(a1));
2303 test = m_pDoc->GetString(0, 3, 0);
2304 CPPUNIT_ASSERT_MESSAGE("the old cell A2 should now be at A4.", test.equals(a2));
2305 ScRefCellValue aCell;
2306 aCell.assign(*m_pDoc, ScAddress(0,1,0));
2307 CPPUNIT_ASSERT_MESSAGE("Cell A2 should be empty.", aCell.isEmpty());
2308 aCell.assign(*m_pDoc, ScAddress(0,2,0));
2309 CPPUNIT_ASSERT_MESSAGE("Cell A3 should be empty.", aCell.isEmpty());
2311 // After the move, Sheet1, Sheet2, and Sheet4 should have their stream
2312 // invalidated, whereas Sheet3's stream should still be valid.
2313 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc->IsStreamValid(0));
2314 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc->IsStreamValid(1));
2315 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc->IsStreamValid(3));
2316 CPPUNIT_ASSERT_MESSAGE("Stream should still be valid.", m_pDoc->IsStreamValid(2));
2318 m_pDoc->DeleteTab(3);
2319 m_pDoc->DeleteTab(2);
2320 m_pDoc->DeleteTab(1);
2321 m_pDoc->DeleteTab(0);
2324 void Test::testFunctionLists()
2326 const char* aDataBase[] = {
2327 "DAVERAGE",
2328 "DCOUNT",
2329 "DCOUNTA",
2330 "DGET",
2331 "DMAX",
2332 "DMIN",
2333 "DPRODUCT",
2334 "DSTDEV",
2335 "DSTDEVP",
2336 "DSUM",
2337 "DVAR",
2338 "DVARP",
2342 const char* aDateTime[] = {
2343 "DATE",
2344 "DATEDIF",
2345 "DATEVALUE",
2346 "DAY",
2347 "DAYS",
2348 "DAYS360",
2349 "DAYSINMONTH",
2350 "DAYSINYEAR",
2351 "EASTERSUNDAY",
2352 "HOUR",
2353 "ISLEAPYEAR",
2354 "MINUTE",
2355 "MONTH",
2356 "MONTHS",
2357 "NETWORKDAYS",
2358 "NETWORKDAYS.INTL",
2359 "NOW",
2360 "SECOND",
2361 "TIME",
2362 "TIMEVALUE",
2363 "TODAY",
2364 "WEEKDAY",
2365 "WEEKNUM",
2366 "WEEKS",
2367 "WEEKSINYEAR",
2368 "WORKDAY.INTL",
2369 "YEAR",
2370 "YEARS",
2374 const char* aFinancial[] = {
2375 "CUMIPMT",
2376 "CUMPRINC",
2377 "DB",
2378 "DDB",
2379 "DURATION",
2380 "EFFECTIVE",
2381 "FV",
2382 "IPMT",
2383 "IRR",
2384 "ISPMT",
2385 "MIRR",
2386 "NOMINAL",
2387 "NPER",
2388 "NPV",
2389 "OPT_BARRIER",
2390 "OPT_PROB_HIT",
2391 "OPT_PROB_INMONEY",
2392 "OPT_TOUCH",
2393 "PMT",
2394 "PPMT",
2395 "PV",
2396 "RATE",
2397 "RRI",
2398 "SLN",
2399 "SYD",
2400 "VDB",
2404 const char* aInformation[] = {
2405 "CELL",
2406 "CURRENT",
2407 "FORMULA",
2408 "INFO",
2409 "ISBLANK",
2410 "ISERR",
2411 "ISERROR",
2412 "ISEVEN",
2413 "ISFORMULA",
2414 "ISLOGICAL",
2415 "ISNA",
2416 "ISNONTEXT",
2417 "ISNUMBER",
2418 "ISODD",
2419 "ISREF",
2420 "ISTEXT",
2421 "N",
2422 "NA",
2423 "TYPE",
2427 const char* aLogical[] = {
2428 "AND",
2429 "FALSE",
2430 "IF",
2431 "IFERROR",
2432 "IFNA",
2433 "NOT",
2434 "OR",
2435 "TRUE",
2436 "XOR",
2440 const char* aMathematical[] = {
2441 "ABS",
2442 "ACOS",
2443 "ACOSH",
2444 "ACOT",
2445 "ACOTH",
2446 "AGGREGATE",
2447 "ASIN",
2448 "ASINH",
2449 "ATAN",
2450 "ATAN2",
2451 "ATANH",
2452 "BITAND",
2453 "BITLSHIFT",
2454 "BITOR",
2455 "BITRSHIFT",
2456 "BITXOR",
2457 "CEILING",
2458 "CEILING.MATH",
2459 "CEILING.PRECISE",
2460 "CEILING.XCL",
2461 "COLOR",
2462 "COMBIN",
2463 "COMBINA",
2464 "CONVERT",
2465 "COS",
2466 "COSH",
2467 "COT",
2468 "COTH",
2469 "CSC",
2470 "CSCH",
2471 "DEGREES",
2472 "EUROCONVERT",
2473 "EVEN",
2474 "EXP",
2475 "FACT",
2476 "FLOOR",
2477 "FLOOR.MATH",
2478 "FLOOR.PRECISE",
2479 "FLOOR.XCL",
2480 "GCD",
2481 "INT",
2482 "ISO.CEILING",
2483 "LCM",
2484 "LN",
2485 "LOG",
2486 "LOG10",
2487 "MOD",
2488 "ODD",
2489 "PI",
2490 "POWER",
2491 "PRODUCT",
2492 "RADIANS",
2493 "RAND",
2494 "ROUND",
2495 "ROUNDDOWN",
2496 "ROUNDUP",
2497 "SEC",
2498 "SECH",
2499 "SIGN",
2500 "SIN",
2501 "SINH",
2502 "SQRT",
2503 "SUBTOTAL",
2504 "SUM",
2505 "SUMIF",
2506 "SUMIFS",
2507 "SUMSQ",
2508 "TAN",
2509 "TANH",
2510 "TRUNC",
2514 const char* aArray[] = {
2515 "FREQUENCY",
2516 "GROWTH",
2517 "LINEST",
2518 "LOGEST",
2519 "MDETERM",
2520 "MINVERSE",
2521 "MMULT",
2522 "MUNIT",
2523 "SUMPRODUCT",
2524 "SUMX2MY2",
2525 "SUMX2PY2",
2526 "SUMXMY2",
2527 "TRANSPOSE",
2528 "TREND",
2532 const char* aStatistical[] = {
2533 "AVEDEV",
2534 "AVERAGE",
2535 "AVERAGEA",
2536 "AVERAGEIF",
2537 "AVERAGEIFS",
2538 "B",
2539 "BETA.DIST",
2540 "BETA.INV",
2541 "BETADIST",
2542 "BETAINV",
2543 "BINOM.DIST",
2544 "BINOM.INV",
2545 "BINOMDIST",
2546 "CHIDIST",
2547 "CHIINV",
2548 "CHISQ.DIST",
2549 "CHISQ.DIST.RT",
2550 "CHISQ.INV",
2551 "CHISQ.INV.RT",
2552 "CHISQ.TEST",
2553 "CHISQDIST",
2554 "CHISQINV",
2555 "CHITEST",
2556 "CONFIDENCE",
2557 "CONFIDENCE.NORM",
2558 "CONFIDENCE.T",
2559 "CORREL",
2560 "COUNT",
2561 "COUNTA",
2562 "COUNTBLANK",
2563 "COUNTIF",
2564 "COUNTIFS",
2565 "COVAR",
2566 "COVARIANCE.P",
2567 "COVARIANCE.S",
2568 "CRITBINOM",
2569 "DEVSQ",
2570 "ERF.PRECISE",
2571 "ERFC.PRECISE",
2572 "EXPON.DIST",
2573 "EXPONDIST",
2574 "F.DIST",
2575 "F.DIST.RT",
2576 "F.INV",
2577 "F.INV.RT",
2578 "F.TEST",
2579 "FDIST",
2580 "FINV",
2581 "FISHER",
2582 "FISHERINV",
2583 "FORECAST",
2584 "FTEST",
2585 "GAMMA",
2586 "GAMMA.DIST",
2587 "GAMMA.INV",
2588 "GAMMADIST",
2589 "GAMMAINV",
2590 "GAMMALN",
2591 "GAMMALN.PRECISE",
2592 "GAUSS",
2593 "GEOMEAN",
2594 "HARMEAN",
2595 "HYPGEOM.DIST",
2596 "HYPGEOMDIST",
2597 "INTERCEPT",
2598 "KURT",
2599 "LARGE",
2600 "LOGINV",
2601 "LOGNORM.DIST",
2602 "LOGNORM.INV",
2603 "LOGNORMDIST",
2604 "MAX",
2605 "MAXA",
2606 "MEDIAN",
2607 "MIN",
2608 "MINA",
2609 "MODE",
2610 "MODE.MULT",
2611 "MODE.SNGL",
2612 "NEGBINOM.DIST",
2613 "NEGBINOMDIST",
2614 "NORM.DIST",
2615 "NORM.INV",
2616 "NORM.S.DIST",
2617 "NORM.S.INV",
2618 "NORMDIST",
2619 "NORMINV",
2620 "NORMSDIST",
2621 "NORMSINV",
2622 "PEARSON",
2623 "PERCENTILE",
2624 "PERCENTILE.EXC",
2625 "PERCENTILE.INC",
2626 "PERCENTRANK",
2627 "PERCENTRANK.EXC",
2628 "PERCENTRANK.INC",
2629 "PERMUT",
2630 "PERMUTATIONA",
2631 "PHI",
2632 "POISSON",
2633 "POISSON.DIST",
2634 "PROB",
2635 "QUARTILE",
2636 "QUARTILE.EXC",
2637 "QUARTILE.INC",
2638 "RANK",
2639 "RANK.AVG",
2640 "RANK.EQ",
2641 "RSQ",
2642 "SKEW",
2643 "SKEWP",
2644 "SLOPE",
2645 "SMALL",
2646 "STANDARDIZE",
2647 "STDEV",
2648 "STDEV.P",
2649 "STDEV.S",
2650 "STDEVA",
2651 "STDEVP",
2652 "STDEVPA",
2653 "STEYX",
2654 "T.DIST",
2655 "T.DIST.2T",
2656 "T.DIST.RT",
2657 "T.INV",
2658 "T.INV.2T",
2659 "T.TEST",
2660 "TDIST",
2661 "TINV",
2662 "TRIMMEAN",
2663 "TTEST",
2664 "VAR",
2665 "VAR.P",
2666 "VAR.S",
2667 "VARA",
2668 "VARP",
2669 "VARPA",
2670 "WEIBULL",
2671 "WEIBULL.DIST",
2672 "Z.TEST",
2673 "ZTEST",
2677 const char* aSpreadsheet[] = {
2678 "ADDRESS",
2679 "AREAS",
2680 "CHOOSE",
2681 "COLUMN",
2682 "COLUMNS",
2683 "DDE",
2684 "ERROR.TYPE",
2685 "ERRORTYPE",
2686 "GETPIVOTDATA",
2687 "HLOOKUP",
2688 "HYPERLINK",
2689 "INDEX",
2690 "INDIRECT",
2691 "LOOKUP",
2692 "MATCH",
2693 "OFFSET",
2694 "ROW",
2695 "ROWS",
2696 "SHEET",
2697 "SHEETS",
2698 "STYLE",
2699 "VLOOKUP",
2703 const char* aText[] = {
2704 "ARABIC",
2705 "ASC",
2706 "BAHTTEXT",
2707 "BASE",
2708 "CHAR",
2709 "CLEAN",
2710 "CODE",
2711 "CONCATENATE",
2712 "DECIMAL",
2713 "DOLLAR",
2714 "ENCODEURL",
2715 "EXACT",
2716 "FILTERXML",
2717 "FIND",
2718 "FIXED",
2719 "JIS",
2720 "LEFT",
2721 "LEFTB",
2722 "LEN",
2723 "LENB",
2724 "LOWER",
2725 "MID",
2726 "MIDB",
2727 "NUMBERVALUE",
2728 "PROPER",
2729 "REPLACE",
2730 "REPT",
2731 "RIGHT",
2732 "RIGHTB",
2733 "ROMAN",
2734 "ROT13",
2735 "SEARCH",
2736 "SUBSTITUTE",
2737 "T",
2738 "TEXT",
2739 "TRIM",
2740 "UNICHAR",
2741 "UNICODE",
2742 "UPPER",
2743 "VALUE",
2744 "WEBSERVICE",
2748 struct {
2749 const char* Category; const char** Functions;
2750 } aTests[] = {
2751 { "Database", aDataBase },
2752 { "Date&Time", aDateTime },
2753 { "Financial", aFinancial },
2754 { "Information", aInformation },
2755 { "Logical", aLogical },
2756 { "Mathematical", aMathematical },
2757 { "Array", aArray },
2758 { "Statistical", aStatistical },
2759 { "Spreadsheet", aSpreadsheet },
2760 { "Text", aText },
2761 { "Add-in", 0 },
2762 { 0, 0 }
2765 ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr();
2766 sal_uInt32 n = pFuncMgr->getCount();
2767 for (sal_uInt32 i = 0; i < n; ++i)
2769 const formula::IFunctionCategory* pCat = pFuncMgr->getCategory(i);
2770 CPPUNIT_ASSERT_MESSAGE("Unexpected category name", pCat->getName().equalsAscii(aTests[i].Category));
2771 sal_uInt32 nFuncCount = pCat->getCount();
2772 for (sal_uInt32 j = 0; j < nFuncCount; ++j)
2774 const formula::IFunctionDescription* pFunc = pCat->getFunction(j);
2775 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected function name", OUString::createFromAscii(aTests[i].Functions[j]), pFunc->getFunctionName());
2780 void Test::testGraphicsInGroup()
2782 m_pDoc->InsertTab(0, "TestTab");
2783 CPPUNIT_ASSERT_MESSAGE("document should have one sheet to begin with.", m_pDoc->GetTableCount() == 1);
2784 SCROW nRow1, nRow2;
2785 bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2786 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2788 m_pDoc->InitDrawLayer();
2789 ScDrawLayer *pDrawLayer = m_pDoc->GetDrawLayer();
2790 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer != NULL);
2791 SdrPage* pPage = pDrawLayer->GetPage(0);
2792 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage != NULL);
2795 //Add a square
2796 Rectangle aOrigRect(2,2,100,100);
2797 SdrRectObj *pObj = new SdrRectObj(aOrigRect);
2798 pPage->InsertObject(pObj);
2799 const Rectangle &rNewRect = pObj->GetLogicRect();
2800 CPPUNIT_ASSERT_MESSAGE("must have equal position and size", aOrigRect == rNewRect);
2802 ScDrawLayer::SetPageAnchored(*pObj);
2804 //Use a range of rows guaranteed to include all of the square
2805 m_pDoc->ShowRows(0, 100, 0, false);
2806 m_pDoc->SetDrawPageSize(0);
2807 CPPUNIT_ASSERT_MESSAGE("Should not change when page anchored", aOrigRect == rNewRect);
2808 m_pDoc->ShowRows(0, 100, 0, true);
2809 m_pDoc->SetDrawPageSize(0);
2810 CPPUNIT_ASSERT_MESSAGE("Should not change when page anchored", aOrigRect == rNewRect);
2812 ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
2813 CPPUNIT_ASSERT_MESSAGE("That shouldn't change size or positioning", aOrigRect == rNewRect);
2815 m_pDoc->ShowRows(0, 100, 0, false);
2816 m_pDoc->SetDrawPageSize(0);
2817 CPPUNIT_ASSERT_MESSAGE("Left and Right should be unchanged",
2818 aOrigRect.Left() == rNewRect.Left() && aOrigRect.Right() == rNewRect.Right());
2819 CPPUNIT_ASSERT_MESSAGE("Height should be minimum allowed height",
2820 (rNewRect.Bottom() - rNewRect.Top()) <= 1);
2821 m_pDoc->ShowRows(0, 100, 0, true);
2822 m_pDoc->SetDrawPageSize(0);
2823 CPPUNIT_ASSERT_MESSAGE("Should not change when page anchored", aOrigRect == rNewRect);
2827 // Add a circle.
2828 Rectangle aOrigRect = Rectangle(10,10,210,210); // 200 x 200
2829 SdrCircObj* pObj = new SdrCircObj(OBJ_CIRC, aOrigRect);
2830 pPage->InsertObject(pObj);
2831 const Rectangle& rNewRect = pObj->GetLogicRect();
2832 CPPUNIT_ASSERT_MESSAGE("Position and size of the circle shouldn't change when inserted into the page.",
2833 aOrigRect == rNewRect);
2835 ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
2836 CPPUNIT_ASSERT_MESSAGE("Size changed when cell anchored. Not good.",
2837 aOrigRect == rNewRect);
2839 // Insert 2 rows at the top. This should push the circle object down.
2840 m_pDoc->InsertRow(0, 0, MAXCOL, 0, 0, 2);
2841 m_pDoc->SetDrawPageSize(0);
2843 // Make sure the size of the circle is still identical.
2844 CPPUNIT_ASSERT_MESSAGE("Size of the circle has changed, but shouldn't!",
2845 aOrigRect.GetSize() == rNewRect.GetSize());
2847 // Delete 2 rows at the top. This should bring the circle object to its original position.
2848 m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 0, 2);
2849 m_pDoc->SetDrawPageSize(0);
2850 CPPUNIT_ASSERT_MESSAGE("Failed to move back to its original position.", aOrigRect == rNewRect);
2854 // Add a line.
2855 basegfx::B2DPolygon aTempPoly;
2856 Point aStartPos(10,300), aEndPos(110,200); // bottom-left to top-right.
2857 Rectangle aOrigRect(10,200,110,300); // 100 x 100
2858 aTempPoly.append(basegfx::B2DPoint(aStartPos.X(), aStartPos.Y()));
2859 aTempPoly.append(basegfx::B2DPoint(aEndPos.X(), aEndPos.Y()));
2860 SdrPathObj* pObj = new SdrPathObj(OBJ_LINE, basegfx::B2DPolyPolygon(aTempPoly));
2861 pObj->NbcSetLogicRect(aOrigRect);
2862 pPage->InsertObject(pObj);
2863 const Rectangle& rNewRect = pObj->GetLogicRect();
2864 CPPUNIT_ASSERT_MESSAGE("Size differ.", aOrigRect == rNewRect);
2866 ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
2867 CPPUNIT_ASSERT_MESSAGE("Size changed when cell-anchored. Not good.",
2868 aOrigRect == rNewRect);
2870 // Insert 2 rows at the top and delete them immediately.
2871 m_pDoc->InsertRow(0, 0, MAXCOL, 0, 0, 2);
2872 m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 0, 2);
2873 m_pDoc->SetDrawPageSize(0);
2874 CPPUNIT_ASSERT_MESSAGE("Size of a line object changed after row insertion and removal.",
2875 aOrigRect == rNewRect);
2877 sal_Int32 n = pObj->GetPointCount();
2878 CPPUNIT_ASSERT_MESSAGE("There should be exactly 2 points in a line object.", n == 2);
2879 CPPUNIT_ASSERT_MESSAGE("Line shape has changed.",
2880 aStartPos == pObj->GetPoint(0) && aEndPos == pObj->GetPoint(1));
2883 m_pDoc->DeleteTab(0);
2886 void Test::testGraphicsOnSheetMove()
2888 m_pDoc->InsertTab(0, "Tab1");
2889 m_pDoc->InsertTab(1, "Tab2");
2890 CPPUNIT_ASSERT_MESSAGE("There should be only 2 sheets to begin with", m_pDoc->GetTableCount() == 2);
2892 m_pDoc->InitDrawLayer();
2893 ScDrawLayer* pDrawLayer = m_pDoc->GetDrawLayer();
2894 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer);
2895 SdrPage* pPage = pDrawLayer->GetPage(0);
2896 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage);
2898 // Insert an object.
2899 Rectangle aObjRect(2,2,100,100);
2900 SdrObject* pObj = new SdrRectObj(aObjRect);
2901 pPage->InsertObject(pObj);
2902 ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
2904 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one object on the 1st sheet.", pPage->GetObjCount(), static_cast<size_t>(1));
2906 const ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj);
2907 CPPUNIT_ASSERT_MESSAGE("Object meta-data doesn't exist.", pData);
2908 CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 0 && pData->maEnd.Tab() == 0);
2910 pPage = pDrawLayer->GetPage(1);
2911 CPPUNIT_ASSERT_MESSAGE("No page instance for the 2nd sheet.", pPage);
2912 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet shouldn't have any object.", pPage->GetObjCount(), static_cast<size_t>(0));
2914 // Insert a new sheet at left-end, and make sure the object has moved to
2915 // the 2nd page.
2916 m_pDoc->InsertTab(0, "NewTab");
2917 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 3 sheets.", m_pDoc->GetTableCount(), static_cast<SCTAB>(3));
2918 pPage = pDrawLayer->GetPage(0);
2919 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage && pPage->GetObjCount() == 0);
2920 pPage = pDrawLayer->GetPage(1);
2921 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage && pPage->GetObjCount() == 1);
2922 pPage = pDrawLayer->GetPage(2);
2923 CPPUNIT_ASSERT_MESSAGE("3rd sheet should have no object.", pPage && pPage->GetObjCount() == 0);
2925 CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 1 && pData->maEnd.Tab() == 1);
2927 // Now, delete the sheet that just got inserted. The object should be back
2928 // on the 1st sheet.
2929 m_pDoc->DeleteTab(0);
2930 pPage = pDrawLayer->GetPage(0);
2931 CPPUNIT_ASSERT_MESSAGE("1st sheet should have one object.", pPage && pPage->GetObjCount() == 1);
2932 CPPUNIT_ASSERT_MESSAGE("Size and position of the object shouldn't change.",
2933 pObj->GetLogicRect() == aObjRect);
2935 CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 0 && pData->maEnd.Tab() == 0);
2937 // Move the 1st sheet to the last position.
2938 m_pDoc->MoveTab(0, 1);
2939 pPage = pDrawLayer->GetPage(0);
2940 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage && pPage->GetObjCount() == 0);
2941 pPage = pDrawLayer->GetPage(1);
2942 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage && pPage->GetObjCount() == 1);
2943 CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 1 && pData->maEnd.Tab() == 1);
2945 // Copy the 2nd sheet, which has one drawing object to the last position.
2946 m_pDoc->CopyTab(1, 2);
2947 pPage = pDrawLayer->GetPage(2);
2948 CPPUNIT_ASSERT_MESSAGE("Copied sheet should have one object.", pPage && pPage->GetObjCount() == 1);
2949 pObj = pPage->GetObj(0);
2950 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj);
2951 pData = ScDrawLayer::GetObjData(pObj);
2952 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData);
2953 CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 2 && pData->maEnd.Tab() == 2);
2955 m_pDoc->DeleteTab(2);
2956 m_pDoc->DeleteTab(1);
2957 m_pDoc->DeleteTab(0);
2960 void Test::testToggleRefFlag()
2962 // In this test, there is no need to insert formula string into a cell in
2963 // the document, as ScRefFinder does not depend on the content of the
2964 // document except for the sheet names.
2966 m_pDoc->InsertTab(0, "Test");
2969 // Calc A1: basic 2D reference
2971 OUString aFormula("=B100");
2972 ScAddress aPos(1, 5, 0);
2973 ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_OOO);
2975 // Original
2976 CPPUNIT_ASSERT_MESSAGE("Does not equal the original text.", aFormula.equals(aFinder.GetText()));
2978 // column relative / row relative -> column absolute / row absolute
2979 aFinder.ToggleRel(0, aFormula.getLength());
2980 aFormula = aFinder.GetText();
2981 CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=$B$100" );
2983 // column absolute / row absolute -> column relative / row absolute
2984 aFinder.ToggleRel(0, aFormula.getLength());
2985 aFormula = aFinder.GetText();
2986 CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=B$100" );
2988 // column relative / row absolute -> column absolute / row relative
2989 aFinder.ToggleRel(0, aFormula.getLength());
2990 aFormula = aFinder.GetText();
2991 CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=$B100" );
2993 // column absolute / row relative -> column relative / row relative
2994 aFinder.ToggleRel(0, aFormula.getLength());
2995 aFormula = aFinder.GetText();
2996 CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=B100" );
3000 // Excel R1C1: basic 2D reference
3002 OUString aFormula("=R2C1");
3003 ScAddress aPos(3, 5, 0);
3004 ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_XL_R1C1);
3006 // Original
3007 CPPUNIT_ASSERT_MESSAGE("Does not equal the original text.", aFormula.equals(aFinder.GetText()));
3009 // column absolute / row absolute -> column relative / row absolute
3010 aFinder.ToggleRel(0, aFormula.getLength());
3011 aFormula = aFinder.GetText();
3012 CPPUNIT_ASSERT_EQUAL(OUString("=R2C[-3]"), aFormula);
3014 // column relative / row absolute - > column absolute / row relative
3015 aFinder.ToggleRel(0, aFormula.getLength());
3016 aFormula = aFinder.GetText();
3017 CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C1"), aFormula);
3019 // column absolute / row relative -> column relative / row relative
3020 aFinder.ToggleRel(0, aFormula.getLength());
3021 aFormula = aFinder.GetText();
3022 CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C[-3]"), aFormula);
3024 // column relative / row relative -> column absolute / row absolute
3025 aFinder.ToggleRel(0, aFormula.getLength());
3026 aFormula = aFinder.GetText();
3027 CPPUNIT_ASSERT_EQUAL(OUString("=R2C1"), aFormula);
3031 // Excel R1C1: Selection at the end of the formula string and does not
3032 // overlap the formula string at all (inspired by fdo#39135).
3033 OUString aFormula("=R1C1");
3034 ScAddress aPos(1, 1, 0);
3035 ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_XL_R1C1);
3037 // Original
3038 CPPUNIT_ASSERT_EQUAL(aFormula, aFinder.GetText());
3040 // Make the column relative.
3041 sal_Int32 n = aFormula.getLength();
3042 aFinder.ToggleRel(n, n);
3043 aFormula = aFinder.GetText();
3044 CPPUNIT_ASSERT_EQUAL(OUString("=R1C[-1]"), aFormula);
3046 // Make the row relative.
3047 n = aFormula.getLength();
3048 aFinder.ToggleRel(n, n);
3049 aFormula = aFinder.GetText();
3050 CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C1"), aFormula);
3052 // Make both relative.
3053 n = aFormula.getLength();
3054 aFinder.ToggleRel(n, n);
3055 aFormula = aFinder.GetText();
3056 CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C[-1]"), aFormula);
3058 // Back to the original.
3059 n = aFormula.getLength();
3060 aFinder.ToggleRel(n, n);
3061 aFormula = aFinder.GetText();
3062 CPPUNIT_ASSERT_EQUAL(OUString("=R1C1"), aFormula);
3066 // Calc A1:
3067 OUString aFormula("=A1+4");
3068 ScAddress aPos(1, 1, 0);
3069 ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_OOO);
3071 // Original
3072 CPPUNIT_ASSERT_EQUAL(aFormula, aFinder.GetText());
3074 // Set the cursor over the 'A1' part and toggle.
3075 aFinder.ToggleRel(2, 2);
3076 aFormula = aFinder.GetText();
3077 CPPUNIT_ASSERT_EQUAL(OUString("=$A$1+4"), aFormula);
3079 aFinder.ToggleRel(2, 2);
3080 aFormula = aFinder.GetText();
3081 CPPUNIT_ASSERT_EQUAL(OUString("=A$1+4"), aFormula);
3083 aFinder.ToggleRel(2, 2);
3084 aFormula = aFinder.GetText();
3085 CPPUNIT_ASSERT_EQUAL(OUString("=$A1+4"), aFormula);
3087 aFinder.ToggleRel(2, 2);
3088 aFormula = aFinder.GetText();
3089 CPPUNIT_ASSERT_EQUAL(OUString("=A1+4"), aFormula);
3092 // TODO: Add more test cases esp. for 3D references, Excel A1 syntax, and
3093 // partial selection within formula string.
3095 m_pDoc->DeleteTab(0);
3098 void Test::testAutofilter()
3100 OUString aDBName("NONAME");
3102 m_pDoc->InsertTab( 0, "Test" );
3104 // cell contents (0 = empty cell)
3105 const char* aData[][3] = {
3106 { "C1", "C2", "C3" },
3107 { "0", "1", "A" },
3108 { "1", "2", 0 },
3109 { "1", "2", "B" },
3110 { "0", "2", "B" }
3113 SCCOL nCols = SAL_N_ELEMENTS(aData[0]);
3114 SCROW nRows = SAL_N_ELEMENTS(aData);
3116 // Populate cells.
3117 for (SCROW i = 0; i < nRows; ++i)
3118 for (SCCOL j = 0; j < nCols; ++j)
3119 if (aData[i][j])
3120 m_pDoc->SetString(j, i, 0, OUString::createFromAscii(aData[i][j]));
3122 ScDBData* pDBData = new ScDBData(aDBName, 0, 0, 0, nCols-1, nRows-1);
3123 m_pDoc->SetAnonymousDBData(0,pDBData);
3125 pDBData->SetAutoFilter(true);
3126 ScRange aRange;
3127 pDBData->GetArea(aRange);
3128 m_pDoc->ApplyFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
3129 aRange.aEnd.Col(), aRange.aStart.Row(),
3130 aRange.aStart.Tab(), SC_MF_AUTO);
3132 //create the query param
3133 ScQueryParam aParam;
3134 pDBData->GetQueryParam(aParam);
3135 ScQueryEntry& rEntry = aParam.GetEntry(0);
3136 rEntry.bDoQuery = true;
3137 rEntry.nField = 0;
3138 rEntry.eOp = SC_EQUAL;
3139 rEntry.GetQueryItem().mfVal = 0;
3140 // add queryParam to database range.
3141 pDBData->SetQueryParam(aParam);
3143 // perform the query.
3144 m_pDoc->Query(0, aParam, true);
3146 //control output
3147 SCROW nRow1, nRow2;
3148 bool bHidden = m_pDoc->RowHidden(2, 0, &nRow1, &nRow2);
3149 CPPUNIT_ASSERT_MESSAGE("rows 2 & 3 should be hidden", bHidden && nRow1 == 2 && nRow2 == 3);
3151 // Remove filtering.
3152 rEntry.Clear();
3153 m_pDoc->Query(0, aParam, true);
3154 bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
3155 CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
3157 // Filter for non-empty cells by column C.
3158 rEntry.bDoQuery = true;
3159 rEntry.nField = 2;
3160 rEntry.SetQueryByNonEmpty();
3161 m_pDoc->Query(0, aParam, true);
3163 // only row 3 should be hidden. The rest should be visible.
3164 bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
3165 CPPUNIT_ASSERT_MESSAGE("rows 1 & 2 should be visible.", !bHidden && nRow1 == 0 && nRow2 == 1);
3166 bHidden = m_pDoc->RowHidden(2, 0, &nRow1, &nRow2);
3167 CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden.", bHidden && nRow1 == 2 && nRow2 == 2);
3168 bHidden = m_pDoc->RowHidden(3, 0, &nRow1, &nRow2);
3169 CPPUNIT_ASSERT_MESSAGE("row 4 and down should be visible.", !bHidden && nRow1 == 3 && nRow2 == MAXROW);
3171 // Now, filter for empty cells by column C.
3172 rEntry.SetQueryByEmpty();
3173 m_pDoc->Query(0, aParam, true);
3175 // Now, only row 1 and 3, and 6 and down should be visible.
3176 bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
3177 CPPUNIT_ASSERT_MESSAGE("row 1 should be visible.", !bHidden && nRow1 == 0 && nRow2 == 0);
3178 bHidden = m_pDoc->RowHidden(1, 0, &nRow1, &nRow2);
3179 CPPUNIT_ASSERT_MESSAGE("row 2 should be hidden.", bHidden && nRow1 == 1 && nRow2 == 1);
3180 bHidden = m_pDoc->RowHidden(2, 0, &nRow1, &nRow2);
3181 CPPUNIT_ASSERT_MESSAGE("row 3 should be visible.", !bHidden && nRow1 == 2 && nRow2 == 2);
3182 bHidden = m_pDoc->RowHidden(3, 0, &nRow1, &nRow2);
3183 CPPUNIT_ASSERT_MESSAGE("rows 4 & 5 should be hidden.", bHidden && nRow1 == 3 && nRow2 == 4);
3184 bHidden = m_pDoc->RowHidden(5, 0, &nRow1, &nRow2);
3185 CPPUNIT_ASSERT_MESSAGE("rows 6 and down should be all visible.", !bHidden && nRow1 == 5 && nRow2 == MAXROW);
3187 m_pDoc->DeleteTab(0);
3190 void Test::testCopyPaste()
3192 m_pDoc->InsertTab(0, "Sheet1");
3193 m_pDoc->InsertTab(1, "Sheet2");
3194 //test copy&paste + ScUndoPaste
3195 //copy local and global range names in formulas
3196 //string cells and value cells
3197 m_pDoc->SetValue(0, 0, 0, 1);
3198 m_pDoc->SetValue(3, 0, 0, 0);
3199 m_pDoc->SetValue(3, 1, 0, 1);
3200 m_pDoc->SetValue(3, 2, 0, 2);
3201 m_pDoc->SetValue(3, 3, 0, 3);
3202 m_pDoc->SetString(2, 0, 0, "test");
3203 ScAddress aAdr (0, 0, 0);
3205 //create some range names, local and global
3206 ScRangeData* pLocal1 = new ScRangeData(m_pDoc, OUString("local1"), aAdr);
3207 ScRangeData* pLocal2 = new ScRangeData(m_pDoc, OUString("local2"), aAdr);
3208 ScRangeData* pGlobal = new ScRangeData(m_pDoc, OUString("global"), aAdr);
3209 ScRangeName* pGlobalRangeName = new ScRangeName();
3210 pGlobalRangeName->insert(pGlobal);
3211 ScRangeName* pLocalRangeName1 = new ScRangeName();
3212 pLocalRangeName1->insert(pLocal1);
3213 pLocalRangeName1->insert(pLocal2);
3214 m_pDoc->SetRangeName(pGlobalRangeName);
3215 m_pDoc->SetRangeName(0, pLocalRangeName1);
3217 // Add formula to B1.
3218 OUString aFormulaString("=local1+global+SUM($C$1:$D$4)");
3219 m_pDoc->SetString(1, 0, 0, aFormulaString);
3221 double fValue = m_pDoc->GetValue(ScAddress(1,0,0));
3222 ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 8", fValue, 8);
3224 // add notes to A1:C1
3225 ScAddress aAdrA1 (0, 0, 0); // empty cell content
3226 OUString aHelloA1("Hello world in A1");
3227 ScPostIt* pNoteA1 = m_pDoc->GetOrCreateNote(aAdrA1);
3228 pNoteA1->SetText(aAdrA1, aHelloA1);
3229 ScAddress aAdrB1 (1, 0, 0); // formula cell content
3230 OUString aHelloB1("Hello world in B1");
3231 ScPostIt* pNoteB1 = m_pDoc->GetOrCreateNote(aAdrB1);
3232 pNoteB1->SetText(aAdrB1, aHelloB1);
3233 ScAddress aAdrC1 (2, 0, 0); // string cell content
3234 OUString aHelloC1("Hello world in C1");
3235 ScPostIt* pNoteC1 = m_pDoc->GetOrCreateNote(aAdrC1);
3236 pNoteC1->SetText(aAdrC1, aHelloC1);
3238 //copy Sheet1.A1:C1 to Sheet2.A2:C2
3239 ScRange aRange(0,0,0,2,0,0);
3240 ScDocument aClipDoc(SCDOCMODE_CLIP);
3241 copyToClip(m_pDoc, aRange, &aClipDoc);
3243 aRange = ScRange(0,1,1,2,1,1);//target: Sheet2.A2:C2
3244 ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3245 pUndoDoc->InitUndo(m_pDoc, 1, 1, true, true);
3246 boost::scoped_ptr<ScUndoPaste> pUndo(createUndoPaste(getDocShell(), aRange, pUndoDoc));
3247 ScMarkData aMark;
3248 aMark.SetMarkArea(aRange);
3249 m_pDoc->CopyFromClip(aRange, aMark, IDF_ALL, NULL, &aClipDoc);
3251 //check values after copying
3252 OUString aString;
3253 fValue = m_pDoc->GetValue(ScAddress(1,1,1));
3254 m_pDoc->GetFormula(1,1,1, aString);
3255 ASSERT_DOUBLES_EQUAL_MESSAGE("copied formula should return 2", fValue, 2);
3256 CPPUNIT_ASSERT_MESSAGE("formula string was not copied correctly", aString == aFormulaString);
3257 fValue = m_pDoc->GetValue(ScAddress(0,1,1));
3258 CPPUNIT_ASSERT_MESSAGE("copied value should be 1", fValue == 1);
3260 //check local range name after copying
3261 pLocal1 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL1"));
3262 CPPUNIT_ASSERT_MESSAGE("local range name 1 should be copied", pLocal1);
3263 ScRange aRangeLocal1;
3264 bool bIsValidRef = pLocal1->IsValidReference(aRangeLocal1);
3265 CPPUNIT_ASSERT_MESSAGE("local range name 1 should be valid", bIsValidRef);
3266 CPPUNIT_ASSERT_MESSAGE("local range 1 should still point to Sheet1.A1",aRangeLocal1 == ScRange(0,0,0,0,0,0));
3267 pLocal2 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL2"));
3268 CPPUNIT_ASSERT_MESSAGE("local2 should not be copied", pLocal2 == NULL);
3270 // check notes after copying
3271 CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.A2", m_pDoc->HasNote(ScAddress(0, 1, 1)));
3272 CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.B2", m_pDoc->HasNote(ScAddress(1, 1, 1)));
3273 CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.C2", m_pDoc->HasNote(ScAddress(2, 1, 1)));
3274 CPPUNIT_ASSERT_MESSAGE("Note content on Sheet1.A1 not copied to Sheet2.A2, empty cell content",
3275 m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(0, 1, 1))->GetText());
3276 CPPUNIT_ASSERT_MESSAGE("Note content on Sheet1.B1 not copied to Sheet2.B2, formula cell content",
3277 m_pDoc->GetNote(ScAddress(1, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(1, 1, 1))->GetText());
3278 CPPUNIT_ASSERT_MESSAGE("Note content on Sheet1.C1 not copied to Sheet2.C2, string cell content",
3279 m_pDoc->GetNote(ScAddress(2, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(2, 1, 1))->GetText());
3281 //check undo and redo
3282 pUndo->Undo();
3283 fValue = m_pDoc->GetValue(ScAddress(1,1,1));
3284 ASSERT_DOUBLES_EQUAL_MESSAGE("after undo formula should return nothing", fValue, 0);
3285 aString = m_pDoc->GetString(2, 1, 1);
3286 CPPUNIT_ASSERT_MESSAGE("after undo, string should be removed", aString.isEmpty());
3287 CPPUNIT_ASSERT_MESSAGE("after undo, note on A2 should be removed", !m_pDoc->HasNote(ScAddress(0, 1, 1)));
3288 CPPUNIT_ASSERT_MESSAGE("after undo, note on B2 should be removed", !m_pDoc->HasNote(ScAddress(1, 1, 1)));
3289 CPPUNIT_ASSERT_MESSAGE("after undo, note on C2 should be removed", !m_pDoc->HasNote(ScAddress(2, 1, 1)));
3291 pUndo->Redo();
3292 fValue = m_pDoc->GetValue(ScAddress(1,1,1));
3293 ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 2 after redo", fValue, 2);
3294 aString = m_pDoc->GetString(2, 1, 1);
3295 CPPUNIT_ASSERT_MESSAGE("Cell Sheet2.C2 should contain: test", aString == "test");
3296 m_pDoc->GetFormula(1,1,1, aString);
3297 CPPUNIT_ASSERT_MESSAGE("Formula should be correct again", aString == aFormulaString);
3299 CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.A2", m_pDoc->HasNote(ScAddress(0, 1, 1)));
3300 CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.B2", m_pDoc->HasNote(ScAddress(1, 1, 1)));
3301 CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.C2", m_pDoc->HasNote(ScAddress(2, 1, 1)));
3302 CPPUNIT_ASSERT_MESSAGE("After Redo, note again on Sheet2.A2, empty cell content",
3303 m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(0, 1, 1))->GetText());
3304 CPPUNIT_ASSERT_MESSAGE("After Redo, note again on Sheet2.B2, formula cell content",
3305 m_pDoc->GetNote(ScAddress(1, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(1, 1, 1))->GetText());
3306 CPPUNIT_ASSERT_MESSAGE("After Redo, note again on Sheet2.C2, string cell content",
3307 m_pDoc->GetNote(ScAddress(2, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(2, 1, 1))->GetText());
3309 m_pDoc->DeleteTab(1);
3310 m_pDoc->DeleteTab(0);
3313 void Test::testCopyPasteAsLink()
3315 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // Turn on auto calc.
3317 m_pDoc->InsertTab(0, "Sheet1");
3318 m_pDoc->InsertTab(1, "Sheet2");
3320 m_pDoc->SetValue(ScAddress(0,0,0), 1); // A1
3321 m_pDoc->SetValue(ScAddress(0,1,0), 2); // A2
3322 m_pDoc->SetValue(ScAddress(0,2,0), 3); // A3
3324 ScRange aRange(0,0,0,0,2,0); // Copy A1:A3 to clip.
3325 ScDocument aClipDoc(SCDOCMODE_CLIP);
3326 copyToClip(m_pDoc, aRange, &aClipDoc);
3328 aRange = ScRange(1,1,1,1,3,1); // Paste to B2:B4 on Sheet2.
3329 ScMarkData aMark;
3330 aMark.SetMarkArea(aRange);
3331 // Paste range as link.
3332 m_pDoc->CopyFromClip(aRange, aMark, IDF_CONTENTS, NULL, &aClipDoc, true, true);
3334 // Check pasted content to make sure they reference the correct cells.
3335 ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,1));
3336 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
3337 CPPUNIT_ASSERT_EQUAL(1.0, pFC->GetValue());
3339 pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,1));
3340 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
3341 CPPUNIT_ASSERT_EQUAL(2.0, pFC->GetValue());
3343 pFC = m_pDoc->GetFormulaCell(ScAddress(1,3,1));
3344 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
3345 CPPUNIT_ASSERT_EQUAL(3.0, pFC->GetValue());
3347 m_pDoc->DeleteTab(1);
3348 m_pDoc->DeleteTab(0);
3351 void Test::testCopyPasteTranspose()
3353 m_pDoc->InsertTab(0, "Sheet1");
3354 m_pDoc->InsertTab(1, "Sheet2");
3356 m_pDoc->SetValue(0, 0, 0, 1);
3357 m_pDoc->SetString(1, 0, 0, "=A1+1");
3358 m_pDoc->SetString(2, 0, 0, "test");
3360 // add notes to A1:C1
3361 ScAddress aAdrA1 (0, 0, 0); // numerical cell content
3362 OUString aHelloA1("Hello world in A1");
3363 ScPostIt* pNoteA1 = m_pDoc->GetOrCreateNote(aAdrA1);
3364 pNoteA1->SetText(aAdrA1, aHelloA1);
3365 ScAddress aAdrB1 (1, 0, 0); // formula cell content
3366 OUString aHelloB1("Hello world in B1");
3367 ScPostIt* pNoteB1 = m_pDoc->GetOrCreateNote(aAdrB1);
3368 pNoteB1->SetText(aAdrB1, aHelloB1);
3369 ScAddress aAdrC1 (2, 0, 0); // string cell content
3370 OUString aHelloC1("Hello world in C1");
3371 ScPostIt* pNoteC1 = m_pDoc->GetOrCreateNote(aAdrC1);
3372 pNoteC1->SetText(aAdrC1, aHelloC1);
3374 // transpose clipboard, paste and check on Sheet2
3375 m_pDoc->InsertTab(1, "Sheet2");
3377 ScRange aSrcRange = ScRange(0,0,0,2,0,0);
3378 ScDocument aNewClipDoc(SCDOCMODE_CLIP);
3379 copyToClip(m_pDoc, aSrcRange, &aNewClipDoc);
3381 ::std::unique_ptr<ScDocument> pTransClip;
3382 pTransClip.reset(new ScDocument(SCDOCMODE_CLIP));
3383 aNewClipDoc.TransposeClip(pTransClip.get(), IDF_ALL, false);
3384 ScDocument* pTransposedClip = pTransClip.release();
3386 ScRange aDestRange = ScRange(3,1,1,3,3,1);//target: Sheet2.D2:D4
3387 ScMarkData aMark;
3388 aMark.SetMarkArea(aDestRange);
3389 m_pDoc->CopyFromClip(aDestRange, aMark, IDF_ALL, NULL, pTransposedClip);
3391 //check cell content after transposed copy/paste
3392 OUString aString = m_pDoc->GetString(3, 3, 1);
3393 CPPUNIT_ASSERT_MESSAGE("Cell Sheet2.D4 should contain: test", aString == "test");
3394 double fValue = m_pDoc->GetValue(ScAddress(3,1,1));
3395 ASSERT_DOUBLES_EQUAL_MESSAGE("transposed copied cell should return 1", fValue, 1);
3396 fValue = m_pDoc->GetValue(ScAddress(3,2,1));
3397 ASSERT_DOUBLES_EQUAL_MESSAGE("transposed copied formula should return 2", fValue, 2);
3398 m_pDoc->GetFormula(3, 2, 1, aString);
3399 CPPUNIT_ASSERT_MESSAGE("transposed formula should point on Sheet2.D2", aString == "=D2+1");
3401 // check notes after transposed copy/paste
3402 CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.D2", m_pDoc->HasNote(ScAddress(3, 1, 1)));
3403 CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.D3", m_pDoc->HasNote(ScAddress(3, 2, 1)));
3404 CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.D4", m_pDoc->HasNote(ScAddress(3, 3, 1)));
3405 CPPUNIT_ASSERT_MESSAGE("Content of cell note on Sheet2.D2",
3406 m_pDoc->GetNote(ScAddress(3, 1, 1))->GetText() == m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText());
3407 CPPUNIT_ASSERT_MESSAGE("Content of cell note on Sheet2.D3",
3408 m_pDoc->GetNote(ScAddress(3, 2, 1))->GetText() == m_pDoc->GetNote(ScAddress(1, 0, 0))->GetText());
3409 CPPUNIT_ASSERT_MESSAGE("Content of cell note on Sheet2.D4",
3410 m_pDoc->GetNote(ScAddress(3, 3, 1))->GetText() == m_pDoc->GetNote(ScAddress(2, 0, 0))->GetText());
3412 m_pDoc->DeleteTab(1);
3413 m_pDoc->DeleteTab(0);
3417 void Test::testCopyPasteMultiRange()
3419 m_pDoc->InsertTab(0, "Test");
3421 // Fill A2:B6 with numbers.
3422 for (SCROW nRow = 1; nRow <= 5; ++nRow)
3424 for (SCCOL nCol = 0; nCol <= 1; ++nCol)
3426 ScAddress aPos(nCol,nRow,0);
3427 m_pDoc->SetValue(aPos, nRow+nCol);
3431 // Fill D9:E11 with numbers.
3432 for (SCROW nRow = 8; nRow <= 10; ++nRow)
3434 for (SCCOL nCol = 3; nCol <= 4; ++nCol)
3436 ScAddress aPos(nCol,nRow,0);
3437 m_pDoc->SetValue(aPos, 10.0);
3441 ScMarkData aMark;
3442 aMark.SelectOneTable(0);
3444 // Copy A2:B2, A4:B4, and A6:B6 to clipboard.
3445 ScDocument aClipDoc(SCDOCMODE_CLIP);
3446 ScClipParam aClipParam;
3447 aClipParam.maRanges.Append(ScRange(0,1,0,1,1,0)); // A2:B2
3448 aClipParam.maRanges.Append(ScRange(0,3,0,1,3,0)); // A4:B4
3449 aClipParam.maRanges.Append(ScRange(0,5,0,1,5,0)); // A6:B6
3450 aClipParam.meDirection = ScClipParam::Row;
3451 m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
3453 // Paste to D9:E11, and make sure it won't crash (rhbz#1080196).
3454 m_pDoc->CopyMultiRangeFromClip(ScAddress(3,8,0), aMark, IDF_CONTENTS, &aClipDoc);
3455 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(3,8,0)));
3456 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(4,8,0)));
3457 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,9,0)));
3458 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(4,9,0)));
3459 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(3,10,0)));
3460 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(4,10,0)));
3462 m_pDoc->DeleteTab(0);
3465 void Test::testCopyPasteSkipEmpty()
3467 struct Check
3469 const char* mpStr;
3470 Color maColor;
3471 bool mbHasNote;
3474 struct TestRange
3476 ScDocument* mpDoc;
3478 TestRange( ScDocument* pDoc ) : mpDoc(pDoc) {}
3480 bool checkRange( const ScAddress& rPos, const Check* p, const Check* pEnd )
3482 ScAddress aPos(rPos);
3483 OUString aPosStr = aPos.Format(SCA_VALID);
3484 for (; p != pEnd; ++p, aPos.IncRow())
3486 if (!mpDoc->GetString(aPos).equalsAscii(p->mpStr))
3488 cerr << aPosStr << ": incorrect string value: expected='" << p->mpStr << "' actual='" << mpDoc->GetString(aPos) << endl;
3489 return false;
3492 const SvxBrushItem* pBrush =
3493 dynamic_cast<const SvxBrushItem*>(mpDoc->GetAttr(aPos, ATTR_BACKGROUND));
3495 if (!pBrush)
3497 cerr << aPosStr << ": failed to get brush item from the cell." << endl;
3498 return false;
3501 if (pBrush->GetColor() != p->maColor)
3503 Color aExpected = p->maColor;
3504 Color aActual = pBrush->GetColor();
3505 cerr << aPosStr << ": incorrect cell background color: expected=("
3506 << static_cast<int>(aExpected.GetRed()) << ","
3507 << static_cast<int>(aExpected.GetGreen()) << ","
3508 << static_cast<int>(aExpected.GetBlue()) << "), actual=("
3509 << static_cast<int>(aActual.GetRed()) << ","
3510 << static_cast<int>(aActual.GetGreen()) << ","
3511 << static_cast<int>(aActual.GetBlue()) << ")" << endl;
3513 return false;
3516 bool bHasNote = mpDoc->HasNote(aPos);
3517 if (bHasNote != p->mbHasNote)
3519 cerr << aPosStr << ": ";
3520 if (p->mbHasNote)
3521 cerr << "this cell should have a cell note, but doesn't." << endl;
3522 else
3523 cerr << "this cell should NOT have a cell note, but one is found." << endl;
3525 return false;
3529 return true;
3532 } aTest(m_pDoc);
3534 m_pDoc->InsertTab(0, "Test");
3535 m_pDoc->InitDrawLayer(&getDocShell()); // for cell note objects.
3537 ScRange aSrcRange(0,0,0,0,4,0);
3538 ScRange aDestRange(1,0,0,1,4,0);
3540 ScMarkData aMark;
3541 aMark.SetMarkArea(aDestRange);
3543 // Put some texts in B1:B5.
3544 m_pDoc->SetString(ScAddress(1,0,0), "A");
3545 m_pDoc->SetString(ScAddress(1,1,0), "B");
3546 m_pDoc->SetString(ScAddress(1,2,0), "C");
3547 m_pDoc->SetString(ScAddress(1,3,0), "D");
3548 m_pDoc->SetString(ScAddress(1,4,0), "E");
3550 // Set the background color of B1:B5 to blue.
3551 ScPatternAttr aCellBackColor(m_pDoc->GetPool());
3552 aCellBackColor.GetItemSet().Put(SvxBrushItem(COL_BLUE, ATTR_BACKGROUND));
3553 m_pDoc->ApplyPatternAreaTab(1, 0, 1, 4, 0, aCellBackColor);
3555 // Insert notes to B1:B5.
3556 m_pDoc->GetOrCreateNote(ScAddress(1,0,0));
3557 m_pDoc->GetOrCreateNote(ScAddress(1,1,0));
3558 m_pDoc->GetOrCreateNote(ScAddress(1,2,0));
3559 m_pDoc->GetOrCreateNote(ScAddress(1,3,0));
3560 m_pDoc->GetOrCreateNote(ScAddress(1,4,0));
3562 // Prepare a clipboard content interleaved with empty cells.
3563 ScDocument aClipDoc(SCDOCMODE_CLIP);
3564 aClipDoc.ResetClip(m_pDoc, &aMark);
3565 ScClipParam aParam(aSrcRange, false);
3566 aClipDoc.SetClipParam(aParam);
3567 aClipDoc.SetString(ScAddress(0,0,0), "Clip1");
3568 aClipDoc.SetString(ScAddress(0,2,0), "Clip2");
3569 aClipDoc.SetString(ScAddress(0,4,0), "Clip3");
3571 // Set the background color of A1:A5 to yellow.
3572 aCellBackColor.GetItemSet().Put(SvxBrushItem(COL_YELLOW, ATTR_BACKGROUND));
3573 aClipDoc.ApplyPatternAreaTab(0, 0, 0, 4, 0, aCellBackColor);
3575 CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aClipDoc.GetCellType(ScAddress(0,0,0)));
3576 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, aClipDoc.GetCellType(ScAddress(0,1,0)));
3577 CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aClipDoc.GetCellType(ScAddress(0,2,0)));
3578 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, aClipDoc.GetCellType(ScAddress(0,3,0)));
3579 CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aClipDoc.GetCellType(ScAddress(0,4,0)));
3581 // Check the initial condition.
3583 Check aChecks[] = {
3584 { "A", COL_BLUE, true },
3585 { "B", COL_BLUE, true },
3586 { "C", COL_BLUE, true },
3587 { "D", COL_BLUE, true },
3588 { "E", COL_BLUE, true },
3591 bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
3592 CPPUNIT_ASSERT_MESSAGE("Initial check failed.", bRes);
3595 // Create undo document.
3596 ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3597 pUndoDoc->InitUndo(m_pDoc, 0, 0);
3598 m_pDoc->CopyToDocument(aDestRange, IDF_ALL, false, pUndoDoc, &aMark);
3600 // Paste clipboard content onto A1:A5 but skip empty cells.
3601 bool bSkipEmpty = true;
3602 m_pDoc->CopyFromClip(aDestRange, aMark, IDF_ALL, pUndoDoc, &aClipDoc, true, false, false, bSkipEmpty);
3604 // Create redo document.
3605 ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
3606 pRedoDoc->InitUndo(m_pDoc, 0, 0);
3607 m_pDoc->CopyToDocument(aDestRange, IDF_ALL, false, pRedoDoc, &aMark);
3609 // Create an undo object for this.
3610 ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
3611 ScUndoPaste aUndo(&getDocShell(), aDestRange, aMark, pUndoDoc, pRedoDoc, IDF_ALL, pRefUndoData);
3613 // Check the content after the paste.
3615 Check aChecks[] = {
3616 { "Clip1", COL_YELLOW, false },
3617 { "B", COL_BLUE, true },
3618 { "Clip2", COL_YELLOW, false },
3619 { "D", COL_BLUE, true },
3620 { "Clip3", COL_YELLOW, false },
3623 bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
3624 CPPUNIT_ASSERT_MESSAGE("Check after paste failed.", bRes);
3627 // Undo, and check the content.
3628 aUndo.Undo();
3630 Check aChecks[] = {
3631 { "A", COL_BLUE, true },
3632 { "B", COL_BLUE, true },
3633 { "C", COL_BLUE, true },
3634 { "D", COL_BLUE, true },
3635 { "E", COL_BLUE, true },
3638 bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
3639 CPPUNIT_ASSERT_MESSAGE("Check after undo failed.", bRes);
3642 // Redo, and check the content again.
3643 aUndo.Redo();
3645 Check aChecks[] = {
3646 { "Clip1", COL_YELLOW, false },
3647 { "B", COL_BLUE, true },
3648 { "Clip2", COL_YELLOW, false },
3649 { "D", COL_BLUE, true },
3650 { "Clip3", COL_YELLOW, false },
3653 bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
3654 CPPUNIT_ASSERT_MESSAGE("Check after redo failed.", bRes);
3657 m_pDoc->DeleteTab(0);
3660 void Test::testCopyPasteSkipEmpty2()
3662 m_pDoc->InsertTab(0, "Test");
3664 m_pDoc->SetString(ScAddress(0,0,0), "A");
3665 m_pDoc->SetString(ScAddress(2,0,0), "C");
3667 // Copy A1:C1 to clipboard.
3668 ScDocument aClipDoc(SCDOCMODE_CLIP);
3669 aClipDoc.ResetClip(m_pDoc, static_cast<SCTAB>(0));
3670 copyToClip(m_pDoc, ScRange(0,0,0,2,0,0), &aClipDoc);
3672 // Paste to A3 with the skip empty option set. This used to freeze. (fdo#77735)
3673 ScRange aDestRange(0,2,0,2,2,0);
3674 ScMarkData aMark;
3675 aMark.SetMarkArea(aDestRange);
3676 m_pDoc->CopyFromClip(aDestRange, aMark, IDF_ALL, NULL, &aClipDoc, false, false, true, true);
3678 CPPUNIT_ASSERT_EQUAL(OUString("A"), m_pDoc->GetString(ScAddress(0,2,0)));
3679 CPPUNIT_ASSERT_MESSAGE("B3 should be empty.", m_pDoc->GetCellType(ScAddress(1,2,0)) == CELLTYPE_NONE);
3680 CPPUNIT_ASSERT_EQUAL(OUString("C"), m_pDoc->GetString(ScAddress(2,2,0)));
3682 m_pDoc->DeleteTab(0);
3685 void Test::testCopyPasteSkipEmptyConditionalFormatting()
3687 m_pDoc->InsertTab(0, "Test");
3689 ScRange aDestRange(0,0,0,1,2,0);
3690 ScRange aSrcRange(3,3,0,5,4,0);
3692 ScMarkData aMark;
3693 aMark.SetMarkArea(aDestRange);
3695 m_pDoc->SetValue(0,0,0,1);
3696 m_pDoc->SetValue(1,0,0,1);
3697 m_pDoc->SetValue(0,1,0,1);
3698 m_pDoc->SetValue(0,2,0,1);
3699 m_pDoc->SetValue(1,2,0,1);
3701 //create conditional formatting for A1:B3
3702 ScConditionalFormatList* pCondFormatList = new ScConditionalFormatList();
3703 m_pDoc->SetCondFormList(pCondFormatList, 0);
3705 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
3706 pFormat->SetRange(aDestRange);
3707 sal_uLong nCondFormatKey = m_pDoc->AddCondFormat(pFormat, 0);
3709 // Prepare a clipboard content interleaved with empty cells.
3710 ScDocument aClipDoc(SCDOCMODE_CLIP);
3711 aClipDoc.ResetClip(m_pDoc, &aMark);
3712 ScClipParam aParam(aSrcRange, false);
3713 aClipDoc.SetClipParam(aParam);
3714 aClipDoc.SetValue(3,3,0,2);
3715 aClipDoc.SetValue(4,3,0,2);
3716 aClipDoc.SetValue(4,4,0,2);
3717 aClipDoc.SetValue(3,5,0,2);
3718 aClipDoc.SetValue(4,5,0,2);
3720 ScConditionalFormat* pClipFormat = new ScConditionalFormat(2, &aClipDoc);
3721 pClipFormat->SetRange(aSrcRange);
3722 aClipDoc.AddCondFormat(pClipFormat, 0);
3724 // Create undo document.
3725 ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3726 pUndoDoc->InitUndo(m_pDoc, 0, 0);
3727 m_pDoc->CopyToDocument(aDestRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
3729 // Paste clipboard content onto A1:A5 but skip empty cells.
3730 bool bSkipEmpty = true;
3731 m_pDoc->CopyFromClip(aDestRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc, true, false, false, bSkipEmpty);
3733 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
3734 CPPUNIT_ASSERT_EQUAL(size_t(2), pList->size());
3735 CPPUNIT_ASSERT(m_pDoc->GetCondFormat(1,1,0));
3736 // empty cell in copy area does not overwrite conditional formatting
3737 CPPUNIT_ASSERT_EQUAL(sal_uInt32(nCondFormatKey), m_pDoc->GetCondFormat(1,1,0)->GetKey());
3738 for(SCCOL nCol = 0; nCol <= 1; ++nCol)
3740 for(SCROW nRow = 0; nRow <= 2; ++nRow)
3742 if(nRow == 1 && nCol == 1)
3743 continue;
3745 CPPUNIT_ASSERT(m_pDoc->GetCondFormat(nCol, nRow, 0));
3746 CPPUNIT_ASSERT(nCondFormatKey != m_pDoc->GetCondFormat(nCol, nRow, 0)->GetKey());
3749 m_pDoc->DeleteTab(0);
3752 void Test::testCutPasteRefUndo()
3754 // Testing scenario: A2 references B2, and B2 gets cut and pasted onto C2,
3755 // which updates A2's formula to reference C2. Then the paste action gets
3756 // undone, which should also undo A2's formula to reference back to B2.
3758 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
3760 m_pDoc->InsertTab(0, "Test");
3762 // A2 references B2.
3763 m_pDoc->SetString(ScAddress(0,1,0), "=B2");
3765 ScMarkData aMark;
3766 aMark.SelectOneTable(0);
3768 // Set up clip document for cutting of B2.
3769 ScDocument aClipDoc(SCDOCMODE_CLIP);
3770 aClipDoc.ResetClip(m_pDoc, &aMark);
3771 ScClipParam aParam(ScAddress(1,1,0), true);
3772 aClipDoc.SetClipParam(aParam);
3773 aClipDoc.SetValue(ScAddress(1,1,0), 12.0);
3775 // Set up undo document for reference update.
3776 ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3777 pUndoDoc->InitUndo(m_pDoc, 0, 0);
3779 // Do the pasting of 12 into C2. This should update A2 to reference C2.
3780 m_pDoc->CopyFromClip(ScAddress(2,1,0), aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc, true, false);
3781 CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(0,1,0));
3783 if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "C2"))
3784 CPPUNIT_FAIL("A2 should be referencing C2.");
3786 // At this point, the ref undo document should contain a formula cell at A2 that references B2.
3787 if (!checkFormula(*pUndoDoc, ScAddress(0,1,0), "B2"))
3788 CPPUNIT_FAIL("A2 in the undo document should be referencing B2.");
3790 ScUndoPaste aUndo(&getDocShell(), ScRange(ScAddress(2,1,0)), aMark, pUndoDoc, NULL, IDF_CONTENTS, NULL, false, NULL);
3791 aUndo.Undo();
3793 // Now A2 should be referencing B2 once again.
3794 if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "B2"))
3795 CPPUNIT_FAIL("A2 should be referencing B2 after undo.");
3797 m_pDoc->DeleteTab(0);
3800 void Test::testMoveRefBetweenSheets()
3802 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
3804 m_pDoc->InsertTab(0, "Test1");
3805 m_pDoc->InsertTab(1, "Test2");
3807 m_pDoc->SetValue(ScAddress(0,0,0), 12.0);
3808 m_pDoc->SetValue(ScAddress(1,0,0), 10.0);
3809 m_pDoc->SetValue(ScAddress(2,0,0), 8.0);
3810 m_pDoc->SetString(ScAddress(0,1,0), "=A1");
3811 m_pDoc->SetString(ScAddress(0,2,0), "=SUM(A1:C1)");
3813 CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,0,0)));
3814 CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,1,0)));
3815 CPPUNIT_ASSERT_EQUAL(30.0, m_pDoc->GetValue(ScAddress(0,2,0)));
3817 // These formulas should not display the sheet name.
3818 if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "A1"))
3819 CPPUNIT_FAIL("Wrong formula!");
3820 if (!checkFormula(*m_pDoc, ScAddress(0,2,0), "SUM(A1:C1)"))
3821 CPPUNIT_FAIL("Wrong formula!");
3823 // Move Test1.A2:A3 to Test2.A2:A3.
3824 ScDocFunc& rFunc = getDocShell().GetDocFunc();
3825 bool bMoved = rFunc.MoveBlock(ScRange(0,1,0,0,2,0), ScAddress(0,1,1), true, true, false, true);
3826 CPPUNIT_ASSERT(bMoved);
3828 CPPUNIT_ASSERT_MESSAGE("This cell should be empty after the move.", m_pDoc->GetCellType(ScAddress(0,1,0)) == CELLTYPE_NONE);
3829 CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,1,1)));
3830 CPPUNIT_ASSERT_EQUAL(30.0, m_pDoc->GetValue(ScAddress(0,2,1)));
3832 // The reference in the pasted formula should display sheet name after the move.
3833 if (!checkFormula(*m_pDoc, ScAddress(0,1,1), "Test1.A1"))
3834 CPPUNIT_FAIL("Wrong formula!");
3835 if (!checkFormula(*m_pDoc, ScAddress(0,2,1), "SUM(Test1.A1:C1)"))
3836 CPPUNIT_FAIL("Wrong formula!");
3838 m_pDoc->DeleteTab(1);
3839 m_pDoc->DeleteTab(0);
3842 void Test::testUndoCut()
3844 m_pDoc->InsertTab(0, "Test");
3846 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
3848 // Insert values into A1:A3.
3849 m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
3850 m_pDoc->SetValue(ScAddress(0,1,0), 10.0);
3851 m_pDoc->SetValue(ScAddress(0,2,0), 100.0);
3853 // SUM in A4.
3854 m_pDoc->SetString(ScAddress(0,3,0), "=SUM(A1:A3)");
3855 CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc->GetValue(0,3,0));
3857 // Select A1:A3.
3858 ScMarkData aMark;
3859 ScRange aRange(0,0,0,0,2,0);
3860 aMark.SetMarkArea(aRange);
3861 aMark.MarkToMulti();
3863 // Set up an undo object for cutting A1:A3.
3864 ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3865 pUndoDoc->InitUndo(m_pDoc, 0 ,0);
3866 m_pDoc->CopyToDocument(aRange, IDF_ALL, false, pUndoDoc);
3867 CPPUNIT_ASSERT_EQUAL( 1.0, pUndoDoc->GetValue(ScAddress(0,0,0)));
3868 CPPUNIT_ASSERT_EQUAL( 10.0, pUndoDoc->GetValue(ScAddress(0,1,0)));
3869 CPPUNIT_ASSERT_EQUAL(100.0, pUndoDoc->GetValue(ScAddress(0,2,0)));
3870 ScUndoCut aUndo(&getDocShell(), aRange, aRange.aEnd, aMark, pUndoDoc);
3872 // "Cut" the selection.
3873 m_pDoc->DeleteSelection(IDF_ALL, aMark);
3874 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(0,3,0)); // The SUM should be zero after the "cut".
3876 // Undo it, and check the result.
3877 aUndo.Undo();
3878 CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
3879 CPPUNIT_ASSERT_EQUAL( 10.0, m_pDoc->GetValue(ScAddress(0,1,0)));
3880 CPPUNIT_ASSERT_EQUAL(100.0, m_pDoc->GetValue(ScAddress(0,2,0)));
3881 CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc->GetValue(0,3,0)); // The SUM value should be back to the original.
3883 // Redo it and check.
3884 aUndo.Redo();
3885 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(0,3,0));
3887 // Undo again.
3888 aUndo.Undo();
3889 CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc->GetValue(0,3,0));
3891 m_pDoc->DeleteTab(0);
3894 void Test::testMoveBlock()
3896 m_pDoc->InsertTab(0, "SheetNotes");
3898 m_pDoc->SetValue(0, 0, 0, 1);
3899 m_pDoc->SetString(1, 0, 0, "=A1+1");
3900 m_pDoc->SetString(2, 0, 0, "test");
3902 // add notes to A1:C1
3903 ScAddress aAddrA1 (0, 0, 0);
3904 OUString aHelloA1("Hello world in A1");
3905 ScPostIt* pNoteA1 = m_pDoc->GetOrCreateNote(aAddrA1);
3906 pNoteA1->SetText(aAddrA1, aHelloA1);
3907 ScAddress aAddrB1 (1, 0, 0);
3908 OUString aHelloB1("Hello world in B1");
3909 ScPostIt* pNoteB1 = m_pDoc->GetOrCreateNote(aAddrB1);
3910 pNoteB1->SetText(aAddrB1, aHelloB1);
3911 ScAddress aAddrC1 (2, 0, 0);
3912 OUString aHelloC1("Hello world in C1");
3913 ScPostIt* pNoteC1 = m_pDoc->GetOrCreateNote(aAddrC1);
3914 pNoteC1->SetText(aAddrC1, aHelloC1);
3915 ScAddress aAddrD1 (3, 0, 0);
3917 // previous tests on cell note content are ok. this one fails !!! :(
3918 //CPPUNIT_ASSERT_MESSAGE("Note content in B1 before move block", m_pDoc->GetNote(aAddrB1)->GetText() == aHelloB1);
3920 // move notes to B1:D1
3921 bool bCut = true;
3922 ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
3923 bool bMoveDone = rDocFunc.MoveBlock(ScRange(0, 0 ,0 ,2 ,0 ,0), ScAddress(1, 0, 0), bCut, false, false, false);
3925 CPPUNIT_ASSERT_MESSAGE("Cells not moved", bMoveDone);
3927 //check cell content
3928 OUString aString = m_pDoc->GetString(3, 0, 0);
3929 CPPUNIT_ASSERT_MESSAGE("Cell D1 should contain: test", aString == "test");
3930 m_pDoc->GetFormula(2, 0, 0, aString);
3931 CPPUNIT_ASSERT_MESSAGE("Cell C1 should contain an updated formula", aString == "=B1+1");
3932 double fValue = m_pDoc->GetValue(aAddrB1);
3933 ASSERT_DOUBLES_EQUAL_MESSAGE("Cell B1 should contain 1", fValue, 1);
3935 // cell notes has been moved 1 cell right (event when overlapping)
3936 CPPUNIT_ASSERT_MESSAGE("There should be NO note on A1", !m_pDoc->HasNote(aAddrA1));
3937 CPPUNIT_ASSERT_MESSAGE("There should be a note on B1", m_pDoc->HasNote(aAddrB1));
3938 CPPUNIT_ASSERT_MESSAGE("There should be a note on C1", m_pDoc->HasNote(aAddrC1));
3939 CPPUNIT_ASSERT_MESSAGE("There should be a note on D1", m_pDoc->HasNote(aAddrD1));
3940 /* still failing, wrong content ???
3941 OUString sNoteText;
3942 sNoteText = m_pDoc->GetNote(aAddrB1)->GetText();
3943 CPPUNIT_ASSERT_MESSAGE("Note content in B1", sNoteText == aHelloA1);
3944 sNoteText = m_pDoc->GetNote(aAddrC1)->GetText();
3945 CPPUNIT_ASSERT_MESSAGE("Note content in C1", sNoteText == aHelloB1);
3946 sNoteText = m_pDoc->GetNote(aAddrD1)->GetText();
3947 CPPUNIT_ASSERT_MESSAGE("Note content in D1", sNoteText == aHelloC1);
3950 m_pDoc->DeleteTab(0);
3953 void Test::testCopyPasteRelativeFormula()
3955 m_pDoc->InsertTab(0, "Formula");
3957 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
3959 // Insert values to A2 and A4.
3960 m_pDoc->SetValue(ScAddress(0,1,0), 1);
3961 m_pDoc->SetValue(ScAddress(0,3,0), 2);
3963 // Insert formula to B4.
3964 m_pDoc->SetString(ScAddress(1,3,0), "=A4");
3965 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,3,0)));
3967 // Select and copy B3:B4 to the clipboard.
3968 ScRange aRange(1,2,0,1,3,0);
3969 ScClipParam aClipParam(aRange, false);
3970 ScMarkData aMark;
3971 aMark.SetMarkArea(aRange);
3972 ScDocument aClipDoc(SCDOCMODE_CLIP);
3973 m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
3975 // Paste it to B1:B2.
3976 InsertDeleteFlags nFlags = IDF_ALL;
3977 ScRange aDestRange(1,0,0,1,1,0);
3978 aMark.SetMarkArea(aDestRange);
3979 m_pDoc->CopyFromClip(aDestRange, aMark, nFlags, NULL, &aClipDoc);
3981 // B2 references A2, so the value should be 1.
3982 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
3984 // Clear content and start over.
3985 clearSheet(m_pDoc, 0);
3986 clearSheet(&aClipDoc, 0);
3988 // Insert a single formula cell in A1.
3989 m_pDoc->SetString(ScAddress(0,0,0), "=ROW()");
3990 const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(0,0,0));
3991 CPPUNIT_ASSERT(pFC);
3992 CPPUNIT_ASSERT(!pFC->IsShared()); // single formula cell is never shared.
3994 // Copy A1 to clipboard.
3995 aClipParam = ScClipParam(ScAddress(0,0,0), false);
3996 m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
3998 pFC = aClipDoc.GetFormulaCell(ScAddress(0,0,0));
3999 CPPUNIT_ASSERT(pFC);
4000 CPPUNIT_ASSERT(!pFC->IsShared());
4002 // Paste to A3.
4003 aDestRange = ScRange(0,2,0,0,2,0);
4004 aMark.SetMarkArea(aDestRange);
4005 m_pDoc->CopyFromClip(aDestRange, aMark, nFlags, NULL, &aClipDoc);
4007 pFC = m_pDoc->GetFormulaCell(ScAddress(0,2,0));
4008 CPPUNIT_ASSERT(pFC);
4009 CPPUNIT_ASSERT(!pFC->IsShared());
4011 // Delete A3 and make sure it doesn't crash (see fdo#76132).
4012 clearRange(m_pDoc, ScAddress(0,2,0));
4013 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(0,2,0)) == CELLTYPE_NONE);
4015 m_pDoc->DeleteTab(0);
4018 void Test::testCopyPasteRepeatOneFormula()
4020 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
4022 m_pDoc->InsertTab(0, "Test");
4024 ScDocument aClipDoc(SCDOCMODE_CLIP);
4025 ScMarkData aMark;
4027 // Insert values in A1:B10.
4028 for (SCROW i = 0; i < 10; ++i)
4030 m_pDoc->SetValue(ScAddress(0,i,0), i+1.0); // column A
4031 m_pDoc->SetValue(ScAddress(1,i,0), (i+1.0)*10.0); // column B
4034 // Insert a formula in C1.
4035 ScAddress aPos(2,0,0); // C1
4036 m_pDoc->SetString(aPos, "=SUM(A1:B1)");
4037 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(aPos));
4039 // This check makes only sense if group listeners are activated.
4040 #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
4041 // At this point, there should be only one normal area listener listening
4042 // on A1:B1.
4043 ScRange aWholeSheet(0,0,0,MAXCOL,MAXROW,0);
4044 ScBroadcastAreaSlotMachine* pBASM = m_pDoc->GetBASM();
4045 CPPUNIT_ASSERT(pBASM);
4046 std::vector<sc::AreaListener> aListeners = pBASM->GetAllListeners(aWholeSheet, sc::AreaInside);
4047 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aListeners.size());
4048 const sc::AreaListener* pListener = &aListeners[0];
4049 CPPUNIT_ASSERT_EQUAL(ScRange(0,0,0,1,0,0), pListener->maArea);
4050 CPPUNIT_ASSERT_MESSAGE("This listener shouldn't be a group listener.", !pListener->mbGroupListening);
4051 #endif
4053 // Copy C1 to clipboard.
4054 ScClipParam aClipParam(aPos, false);
4055 aMark.SetMarkArea(aPos);
4056 m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
4058 // Paste it to C2:C10.
4059 InsertDeleteFlags nFlags = IDF_CONTENTS;
4060 ScRange aDestRange(2,1,0,2,9,0);
4061 aMark.SetMarkArea(aDestRange);
4062 m_pDoc->CopyFromClip(aDestRange, aMark, nFlags, NULL, &aClipDoc);
4064 // Make sure C1:C10 are grouped.
4065 const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
4066 CPPUNIT_ASSERT(pFC);
4067 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
4069 // Check the formula results.
4070 for (SCROW i = 0; i < 10; ++i)
4072 double fExpected = (i+1.0)*11.0;
4073 CPPUNIT_ASSERT_EQUAL(fExpected, m_pDoc->GetValue(ScAddress(2,i,0)));
4076 // This check makes only sense if group listeners are activated.
4077 #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
4078 // At this point, there should only be one area listener and it should be
4079 // a group listener listening on A1:B10.
4080 aListeners = pBASM->GetAllListeners(aWholeSheet, sc::AreaInside);
4081 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aListeners.size());
4082 pListener = &aListeners[0];
4083 CPPUNIT_ASSERT_EQUAL(ScRange(0,0,0,1,9,0), pListener->maArea);
4084 CPPUNIT_ASSERT_MESSAGE("This listener should be a group listener.", pListener->mbGroupListening);
4085 #endif
4087 // Insert a new row at row 1.
4088 ScRange aRowOne(0,0,0,MAXCOL,0,0);
4089 aMark.SetMarkArea(aRowOne);
4090 ScDocFunc& rFunc = getDocShell().GetDocFunc();
4091 rFunc.InsertCells(aRowOne, &aMark, INS_INSROWS, true, true, false);
4093 CPPUNIT_ASSERT_MESSAGE("C1 should be empty.", m_pDoc->GetCellType(ScAddress(2,0,0)) == CELLTYPE_NONE);
4095 // This check makes only sense if group listeners are activated.
4096 #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
4097 // Make there we only have one group area listener listening on A2:B11.
4098 aListeners = pBASM->GetAllListeners(aWholeSheet, sc::AreaInside);
4099 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aListeners.size());
4100 pListener = &aListeners[0];
4101 CPPUNIT_ASSERT_EQUAL(ScRange(0,1,0,1,10,0), pListener->maArea);
4102 CPPUNIT_ASSERT_MESSAGE("This listener should be a group listener.", pListener->mbGroupListening);
4103 #endif
4105 // Check the formula results.
4106 for (SCROW i = 0; i < 10; ++i)
4108 double fExpected = (i+1.0)*11.0;
4109 CPPUNIT_ASSERT_EQUAL(fExpected, m_pDoc->GetValue(ScAddress(2,i+1,0)));
4112 // Delete row at row 1 to shift the cells up.
4113 rFunc.DeleteCells(aRowOne, &aMark, DEL_DELROWS, true, true);
4115 // Check the formula results again.
4116 for (SCROW i = 0; i < 10; ++i)
4118 double fExpected = (i+1.0)*11.0;
4119 CPPUNIT_ASSERT_EQUAL(fExpected, m_pDoc->GetValue(ScAddress(2,i,0)));
4122 // This check makes only sense if group listeners are activated.
4123 #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
4124 // Check the group area listener again to make sure it's listening on A1:B10 once again.
4125 aListeners = pBASM->GetAllListeners(aWholeSheet, sc::AreaInside);
4126 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aListeners.size());
4127 pListener = &aListeners[0];
4128 CPPUNIT_ASSERT_EQUAL(ScRange(0,0,0,1,9,0), pListener->maArea);
4129 CPPUNIT_ASSERT_MESSAGE("This listener should be a group listener.", pListener->mbGroupListening);
4130 #endif
4132 m_pDoc->DeleteTab(0);
4135 void Test::testMergedCells()
4137 //test merge and unmerge
4138 //TODO: an undo/redo test for this would be a good idea
4139 m_pDoc->InsertTab(0, "Sheet1");
4140 m_pDoc->DoMerge(0, 1, 1, 3, 3, false);
4141 SCCOL nEndCol = 1;
4142 SCROW nEndRow = 1;
4143 m_pDoc->ExtendMerge( 1, 1, nEndCol, nEndRow, 0, false);
4144 CPPUNIT_ASSERT_MESSAGE("did not merge cells", nEndCol == 3 && nEndRow == 3);
4145 ScRange aRange(0,2,0,MAXCOL,2,0);
4146 ScMarkData aMark;
4147 aMark.SetMarkArea(aRange);
4148 getDocShell().GetDocFunc().InsertCells(aRange, &aMark, INS_INSROWS, true, true);
4149 m_pDoc->ExtendMerge(1, 1, nEndCol, nEndRow, 0, false);
4150 CPPUNIT_ASSERT_MESSAGE("did not increase merge area", nEndCol == 3 && nEndRow == 4);
4151 m_pDoc->DeleteTab(0);
4154 void Test::testRenameTable()
4156 //test set rename table
4157 //TODO: set name1 and name2 and do an undo to check if name 1 is set now
4158 //TODO: also check if new name for table is same as another table
4160 m_pDoc->InsertTab(0, "Sheet1");
4161 m_pDoc->InsertTab(1, "Sheet2");
4163 //test case 1 , rename table2 to sheet 1, it should return error
4164 OUString nameToSet = "Sheet1";
4165 ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
4166 CPPUNIT_ASSERT_MESSAGE("name same as another table is being set", !rDocFunc.RenameTable(1,nameToSet,false,true) );
4168 //test case 2 , simple rename to check name
4169 nameToSet = "test1";
4170 getDocShell().GetDocFunc().RenameTable(0,nameToSet,false,true);
4171 OUString nameJustSet;
4172 m_pDoc->GetName(0,nameJustSet);
4173 CPPUNIT_ASSERT_MESSAGE("table not renamed", nameToSet == nameJustSet);
4175 //test case 3 , rename again
4176 OUString anOldName;
4177 m_pDoc->GetName(0,anOldName);
4179 nameToSet = "test2";
4180 rDocFunc.RenameTable(0,nameToSet,false,true);
4181 m_pDoc->GetName(0,nameJustSet);
4182 CPPUNIT_ASSERT_MESSAGE("table not renamed", nameToSet == nameJustSet);
4184 //test case 4 , check if undo works
4185 SfxUndoAction* pUndo = new ScUndoRenameTab(&getDocShell(),0,anOldName,nameToSet);
4186 pUndo->Undo();
4187 m_pDoc->GetName(0,nameJustSet);
4188 CPPUNIT_ASSERT_MESSAGE("the correct name is not set after undo", nameJustSet == anOldName);
4190 pUndo->Redo();
4191 m_pDoc->GetName(0,nameJustSet);
4192 CPPUNIT_ASSERT_MESSAGE("the correct color is not set after redo", nameJustSet == nameToSet);
4194 m_pDoc->DeleteTab(0);
4195 m_pDoc->DeleteTab(1);
4198 void Test::testSetBackgroundColor()
4200 //test set background color
4201 //TODO: set color1 and set color2 and do an undo to check if color1 is set now.
4203 m_pDoc->InsertTab(0, "Sheet1");
4204 Color aColor;
4206 //test yellow
4207 aColor=Color(COL_YELLOW);
4208 getDocShell().GetDocFunc().SetTabBgColor(0,aColor,false, true);
4209 CPPUNIT_ASSERT_MESSAGE("the correct color is not set",
4210 m_pDoc->GetTabBgColor(0) == aColor);
4212 Color aOldTabBgColor=m_pDoc->GetTabBgColor(0);
4213 aColor.SetColor(COL_BLUE);//set BLUE
4214 getDocShell().GetDocFunc().SetTabBgColor(0,aColor,false, true);
4215 CPPUNIT_ASSERT_MESSAGE("the correct color is not set the second time",
4216 m_pDoc->GetTabBgColor(0) == aColor);
4218 //now check for undo
4219 SfxUndoAction* pUndo = new ScUndoTabColor(&getDocShell(), 0, aOldTabBgColor, aColor);
4220 pUndo->Undo();
4221 CPPUNIT_ASSERT_MESSAGE("the correct color is not set after undo", m_pDoc->GetTabBgColor(0)== aOldTabBgColor);
4222 pUndo->Redo();
4223 CPPUNIT_ASSERT_MESSAGE("the correct color is not set after undo", m_pDoc->GetTabBgColor(0)== aColor);
4224 m_pDoc->DeleteTab(0);
4227 void Test::testUpdateReference()
4229 //test that formulas are correctly updated during sheet delete
4230 //TODO: add tests for relative references, updating of named ranges, ...
4231 m_pDoc->InsertTab(0, "Sheet1");
4232 m_pDoc->InsertTab(1, "Sheet2");
4233 m_pDoc->InsertTab(2, "Sheet3");
4234 m_pDoc->InsertTab(3, "Sheet4");
4236 m_pDoc->SetValue(0,0,2, 1);
4237 m_pDoc->SetValue(1,0,2, 2);
4238 m_pDoc->SetValue(1,1,3, 4);
4239 m_pDoc->SetString(2,0,2, "=A1+B1");
4240 m_pDoc->SetString(2,1,2, "=Sheet4.B2+A1");
4242 double aValue;
4243 m_pDoc->GetValue(2,0,2, aValue);
4244 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", aValue, 3);
4245 m_pDoc->GetValue(2,1,2, aValue);
4246 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", aValue, 5);
4248 //test deleting both sheets: one is not directly before the sheet, the other one is
4249 m_pDoc->DeleteTab(0);
4250 m_pDoc->GetValue(2,0,1, aValue);
4251 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", aValue, 3);
4252 m_pDoc->GetValue(2,1,1, aValue);
4253 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", aValue, 5);
4255 m_pDoc->DeleteTab(0);
4256 m_pDoc->GetValue(2,0,0, aValue);
4257 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", aValue, 3);
4258 m_pDoc->GetValue(2,1,0, aValue);
4259 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", aValue, 5);
4261 //test adding two sheets
4262 m_pDoc->InsertTab(0, "Sheet2");
4263 m_pDoc->GetValue(2,0,1, aValue);
4264 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", aValue, 3);
4265 m_pDoc->GetValue(2,1,1, aValue);
4266 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", aValue, 5);
4268 m_pDoc->InsertTab(0, "Sheet1");
4269 m_pDoc->GetValue(2,0,2, aValue);
4270 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", aValue, 3);
4271 m_pDoc->GetValue(2,1,2, aValue);
4272 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", aValue, 5);
4274 //test new DeleteTabs/InsertTabs methods
4275 m_pDoc->DeleteTabs(0, 2);
4276 m_pDoc->GetValue(2, 0, 0, aValue);
4277 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", aValue, 3);
4278 m_pDoc->GetValue(2, 1, 0, aValue);
4279 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", aValue, 5);
4281 std::vector<OUString> aSheets;
4282 aSheets.push_back("Sheet1");
4283 aSheets.push_back("Sheet2");
4284 m_pDoc->InsertTabs(0, aSheets, false, true);
4285 m_pDoc->GetValue(2, 0, 2, aValue);
4286 OUString aFormula;
4287 m_pDoc->GetFormula(2,0,2, aFormula);
4289 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", aValue, 3);
4290 m_pDoc->GetValue(2, 1, 2, aValue);
4291 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", aValue, 5);
4293 m_pDoc->DeleteTab(3);
4294 m_pDoc->DeleteTab(2);
4295 m_pDoc->DeleteTab(1);
4296 m_pDoc->DeleteTab(0);
4299 void Test::testSearchCells()
4301 m_pDoc->InsertTab(0, "Test");
4303 m_pDoc->SetString(ScAddress(0,0,0), "A");
4304 m_pDoc->SetString(ScAddress(0,1,0), "B");
4305 m_pDoc->SetString(ScAddress(0,2,0), "A");
4306 // Leave A4 blank.
4307 m_pDoc->SetString(ScAddress(0,4,0), "A");
4308 m_pDoc->SetString(ScAddress(0,5,0), "B");
4309 m_pDoc->SetString(ScAddress(0,6,0), "C");
4311 SvxSearchItem aItem(SID_SEARCH_ITEM);
4312 aItem.SetSearchString(OUString("A"));
4313 aItem.SetCommand(SvxSearchCmd::FIND_ALL);
4314 ScMarkData aMarkData;
4315 aMarkData.SelectOneTable(0);
4316 SCCOL nCol = 0;
4317 SCROW nRow = 0;
4318 SCTAB nTab = 0;
4319 ScRangeList aMatchedRanges;
4320 OUString aUndoStr;
4321 bool bSuccess = m_pDoc->SearchAndReplace(aItem, nCol, nRow, nTab, aMarkData, aMatchedRanges, aUndoStr);
4323 CPPUNIT_ASSERT_MESSAGE("Search And Replace should succeed", bSuccess);
4324 CPPUNIT_ASSERT_MESSAGE("There should be exactly 3 matching cells.", aMatchedRanges.size() == 3);
4325 ScAddress aHit(0,0,0);
4326 CPPUNIT_ASSERT_MESSAGE("A1 should be inside the matched range.", aMatchedRanges.In(aHit));
4327 aHit.SetRow(2);
4328 CPPUNIT_ASSERT_MESSAGE("A3 should be inside the matched range.", aMatchedRanges.In(aHit));
4329 aHit.SetRow(4);
4330 CPPUNIT_ASSERT_MESSAGE("A5 should be inside the matched range.", aMatchedRanges.In(aHit));
4332 m_pDoc->DeleteTab(0);
4335 void Test::testFormulaPosition()
4337 m_pDoc->InsertTab(0, "Test");
4339 ScAddress aPos(0,0,0); // A1
4340 m_pDoc->SetString(aPos, "=ROW()");
4341 aPos.IncRow(); // A2
4342 m_pDoc->SetString(aPos, "=ROW()");
4343 aPos.SetRow(3); // A4;
4344 m_pDoc->SetString(aPos, "=ROW()");
4347 SCROW aRows[] = { 0, 1, 3 };
4348 bool bRes = checkFormulaPositions(*m_pDoc, aPos.Tab(), aPos.Col(), aRows, SAL_N_ELEMENTS(aRows));
4349 CPPUNIT_ASSERT(bRes);
4352 m_pDoc->InsertRow(0,0,0,0,1,5); // Insert 5 rows at A2.
4354 SCROW aRows[] = { 0, 6, 8 };
4355 bool bRes = checkFormulaPositions(*m_pDoc, aPos.Tab(), aPos.Col(), aRows, SAL_N_ELEMENTS(aRows));
4356 CPPUNIT_ASSERT(bRes);
4359 m_pDoc->DeleteTab(0);
4362 namespace {
4364 bool hasRange(const std::vector<ScTokenRef>& rRefTokens, const ScRange& rRange, const ScAddress& rPos)
4366 std::vector<ScTokenRef>::const_iterator it = rRefTokens.begin(), itEnd = rRefTokens.end();
4367 for (; it != itEnd; ++it)
4369 const ScTokenRef& p = *it;
4370 if (!ScRefTokenHelper::isRef(p) || ScRefTokenHelper::isExternalRef(p))
4371 continue;
4373 switch (p->GetType())
4375 case formula::svSingleRef:
4377 ScSingleRefData aData = *p->GetSingleRef();
4378 if (rRange.aStart != rRange.aEnd)
4379 break;
4381 ScAddress aThis = aData.toAbs(rPos);
4382 if (aThis == rRange.aStart)
4383 return true;
4385 break;
4386 case formula::svDoubleRef:
4388 ScComplexRefData aData = *p->GetDoubleRef();
4389 ScRange aThis = aData.toAbs(rPos);
4390 if (aThis == rRange)
4391 return true;
4393 break;
4394 default:
4398 return false;
4403 void Test::testJumpToPrecedentsDependents()
4405 // Precedent is another cell that the cell references, while dependent is
4406 // another cell that references it.
4407 m_pDoc->InsertTab(0, "Test");
4409 m_pDoc->SetString(2, 0, 0, "=A1+A2+B3"); // C1
4410 m_pDoc->SetString(2, 1, 0, "=A1"); // C2
4411 m_pDoc->CalcAll();
4413 std::vector<ScTokenRef> aRefTokens;
4414 ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
4417 // C1's precedent should be A1:A2,B3.
4418 ScAddress aC1(2, 0, 0);
4419 ScRangeList aRange(aC1);
4420 rDocFunc.DetectiveCollectAllPreds(aRange, aRefTokens);
4421 CPPUNIT_ASSERT_MESSAGE("A1:A2 should be a precedent of C1.",
4422 hasRange(aRefTokens, ScRange(0, 0, 0, 0, 1, 0), aC1));
4423 CPPUNIT_ASSERT_MESSAGE("B3 should be a precedent of C1.",
4424 hasRange(aRefTokens, ScRange(1, 2, 0), aC1));
4428 // C2's precedent should be A1 only.
4429 ScAddress aC2(2, 1, 0);
4430 ScRangeList aRange(aC2);
4431 rDocFunc.DetectiveCollectAllPreds(aRange, aRefTokens);
4432 CPPUNIT_ASSERT_EQUAL_MESSAGE("there should only be one reference token.",
4433 aRefTokens.size(), static_cast<size_t>(1));
4434 CPPUNIT_ASSERT_MESSAGE("A1 should be a precedent of C1.",
4435 hasRange(aRefTokens, ScRange(0, 0, 0), aC2));
4439 // A1's dependent should be C1:C2.
4440 ScAddress aA1(0, 0, 0);
4441 ScRangeList aRange(aA1);
4442 rDocFunc.DetectiveCollectAllSuccs(aRange, aRefTokens);
4443 CPPUNIT_ASSERT_MESSAGE("C1:C2 should be the only dependent of A1.",
4444 aRefTokens.size() == 1 && hasRange(aRefTokens, ScRange(2, 0, 0, 2, 1, 0), aA1));
4447 m_pDoc->DeleteTab(0);
4450 void Test::testAutoFill()
4452 m_pDoc->InsertTab(0, "test");
4454 m_pDoc->SetValue(0,0,0,1);
4456 ScMarkData aMarkData;
4457 aMarkData.SelectTable(0, true);
4459 m_pDoc->Fill( 0, 0, 0, 0, NULL, aMarkData, 5);
4460 for (SCROW i = 0; i< 6; ++i)
4461 ASSERT_DOUBLES_EQUAL(static_cast<double>(i+1.0), m_pDoc->GetValue(0, i, 0));
4463 // check that hidden rows are not affected by autofill
4464 // set values for hidden rows
4465 m_pDoc->SetValue(0,1,0,10);
4466 m_pDoc->SetValue(0,2,0,10);
4468 m_pDoc->SetRowHidden(1, 2, 0, true);
4469 m_pDoc->Fill( 0, 0, 0, 0, NULL, aMarkData, 8);
4471 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc->GetValue(0,1,0));
4472 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc->GetValue(0,2,0));
4473 for (SCROW i = 3; i< 8; ++i)
4474 ASSERT_DOUBLES_EQUAL(static_cast<double>(i-1.0), m_pDoc->GetValue(0, i, 0));
4476 m_pDoc->Fill( 0, 0, 0, 8, NULL, aMarkData, 5, FILL_TO_RIGHT );
4477 for (SCCOL i = 0; i < 5; ++i)
4479 for(SCROW j = 0; j < 8; ++j)
4481 if (j > 2)
4483 ASSERT_DOUBLES_EQUAL(static_cast<double>(j-1+i), m_pDoc->GetValue(i, j, 0));
4485 else if (j == 0)
4487 ASSERT_DOUBLES_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(i, 0, 0));
4489 else if (j == 1 || j== 2)
4491 if(i == 0)
4492 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc->GetValue(0,j,0));
4493 else
4494 ASSERT_DOUBLES_EQUAL(0.0, m_pDoc->GetValue(i,j,0));
4499 // test auto fill user data lists
4500 m_pDoc->SetString( 0, 100, 0, "January" );
4501 m_pDoc->Fill( 0, 100, 0, 100, NULL, aMarkData, 2, FILL_TO_BOTTOM, FILL_AUTO );
4502 OUString aTestValue = m_pDoc->GetString( 0, 101, 0 );
4503 CPPUNIT_ASSERT_EQUAL( aTestValue, OUString("February") );
4504 aTestValue = m_pDoc->GetString( 0, 102, 0 );
4505 CPPUNIT_ASSERT_EQUAL( aTestValue, OUString("March") );
4507 // test that two same user data list entries will not result in incremental fill
4508 m_pDoc->SetString( 0, 101, 0, "January" );
4509 m_pDoc->Fill( 0, 100, 0, 101, NULL, aMarkData, 2, FILL_TO_BOTTOM, FILL_AUTO );
4510 for ( SCROW i = 102; i <= 103; ++i )
4512 aTestValue = m_pDoc->GetString( 0, i, 0 );
4513 CPPUNIT_ASSERT_EQUAL( aTestValue, OUString("January") );
4516 // Clear column A for a new test.
4517 clearRange(m_pDoc, ScRange(0,0,0,0,MAXROW,0));
4518 m_pDoc->SetRowHidden(0, MAXROW, 0, false); // Show all rows.
4520 // Fill A1:A6 with 1,2,3,4,5,6.
4521 ScDocFunc& rFunc = getDocShell().GetDocFunc();
4522 m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
4523 ScRange aRange(0,0,0,0,5,0);
4524 aMarkData.SetMarkArea(aRange);
4525 rFunc.FillSeries(aRange, &aMarkData, FILL_TO_BOTTOM, FILL_AUTO, FILL_DAY, MAXDOUBLE, 1.0, MAXDOUBLE, true, true);
4526 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
4527 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
4528 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,2,0)));
4529 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0,3,0)));
4530 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0,4,0)));
4531 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,5,0)));
4533 // Undo should clear the area except for the top cell.
4534 SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
4535 CPPUNIT_ASSERT(pUndoMgr);
4536 pUndoMgr->Undo();
4538 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
4539 for (SCROW i = 1; i <= 5; ++i)
4540 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(0,i,0)) == CELLTYPE_NONE);
4542 // Redo should put the serial values back in.
4543 pUndoMgr->Redo();
4544 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
4545 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
4546 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,2,0)));
4547 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0,3,0)));
4548 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0,4,0)));
4549 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,5,0)));
4551 // test that filling formulas vertically up does the right thing
4552 for(SCROW nRow = 0; nRow < 10; ++nRow)
4553 m_pDoc->SetValue(100, 100 + nRow, 0, 1);
4555 m_pDoc->SetString(100, 110, 0, "=A111");
4557 m_pDoc->Fill(100, 110, 100, 110, NULL, aMarkData, 10, FILL_TO_TOP, FILL_AUTO);
4558 for(SCROW nRow = 110; nRow >= 100; --nRow)
4560 OUString aExpected = "=A" + OUString::number(nRow +1);
4561 OUString aFormula;
4562 m_pDoc->GetFormula(100, nRow, 0, aFormula);
4563 CPPUNIT_ASSERT_EQUAL(aExpected, aFormula);
4566 m_pDoc->DeleteTab(0);
4569 void Test::testAutoFillSimple()
4571 m_pDoc->InsertTab(0, "test");
4573 m_pDoc->SetValue(0, 0, 0, 1);
4574 m_pDoc->SetString(0, 1, 0, "=10");
4576 ScMarkData aMarkData;
4577 aMarkData.SelectTable(0, true);
4579 m_pDoc->Fill( 0, 0, 0, 1, NULL, aMarkData, 6, FILL_TO_BOTTOM, FILL_AUTO);
4581 for(SCROW nRow = 0; nRow < 8; ++nRow)
4583 if (nRow % 2 == 0)
4585 double nVal = m_pDoc->GetValue(0, nRow, 0);
4586 CPPUNIT_ASSERT_EQUAL((nRow+2)/2.0, nVal);
4588 else
4590 OString aMsg = OString("wrong value in row: ") + OString::number(nRow);
4591 double nVal = m_pDoc->GetValue(0, nRow, 0);
4592 CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), 10.0, nVal);
4596 m_pDoc->DeleteTab(0);
4599 void Test::testCopyPasteFormulas()
4601 m_pDoc->InsertTab(0, "Sheet1");
4602 m_pDoc->InsertTab(1, "Sheet2");
4604 m_pDoc->SetString(0,0,0, "=COLUMN($A$1)");
4605 m_pDoc->SetString(0,1,0, "=$A$1+B2" );
4606 m_pDoc->SetString(0,2,0, "=$Sheet2.A1");
4607 m_pDoc->SetString(0,3,0, "=$Sheet2.$A$1");
4608 m_pDoc->SetString(0,4,0, "=$Sheet2.A$1");
4610 // to prevent ScEditableTester in ScDocFunc::MoveBlock
4611 ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(0,0,0), 1.0);
4612 ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(0,1,0), 1.0);
4613 ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
4614 bool bMoveDone = rDocFunc.MoveBlock(ScRange(0,0,0,0,4,0), ScAddress( 10, 10, 0), false, false, false, true);
4616 // check that moving was successful, mainly for editable tester
4617 CPPUNIT_ASSERT(bMoveDone);
4618 ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(10,10,0), 1.0);
4619 ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(10,11,0), 1.0);
4620 OUString aFormula;
4621 m_pDoc->GetFormula(10,10,0, aFormula);
4622 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=COLUMN($A$1)"));
4623 m_pDoc->GetFormula(10,11,0, aFormula);
4624 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$A$1+L12"));
4625 m_pDoc->GetFormula(10,12,0, aFormula);
4626 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$Sheet2.K11"));
4627 m_pDoc->GetFormula(10,13,0, aFormula);
4628 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$Sheet2.$A$1"));
4629 m_pDoc->GetFormula(10,14,0, aFormula);
4630 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$Sheet2.K$1"));
4633 void Test::testCopyPasteFormulasExternalDoc()
4635 OUString aDocName("file:///source.fake");
4636 SfxMedium* pMedium = new SfxMedium(aDocName, STREAM_STD_READWRITE);
4637 getDocShell().DoInitNew(pMedium);
4638 m_pDoc = &getDocShell().GetDocument();
4640 ScDocShellRef xExtDocSh = new ScDocShell;
4641 OUString aExtDocName("file:///extdata.fake");
4642 OUString aExtSh1Name("ExtSheet1");
4643 OUString aExtSh2Name("ExtSheet2");
4644 SfxMedium* pMed = new SfxMedium(aExtDocName, STREAM_STD_READWRITE);
4645 xExtDocSh->DoInitNew(pMed);
4646 CPPUNIT_ASSERT_MESSAGE("external document instance not loaded.",
4647 findLoadedDocShellByName(aExtDocName) != NULL);
4649 ScDocument& rExtDoc = xExtDocSh->GetDocument();
4650 rExtDoc.InsertTab(0, aExtSh1Name);
4651 rExtDoc.InsertTab(1, aExtSh2Name);
4653 m_pDoc->InsertTab(0, "Sheet1");
4654 m_pDoc->InsertTab(1, "Sheet2");
4656 m_pDoc->SetString(0,0,0, "=COLUMN($A$1)");
4657 m_pDoc->SetString(0,1,0, "=$A$1+B2" );
4658 m_pDoc->SetString(0,2,0, "=$Sheet2.A1");
4659 m_pDoc->SetString(0,3,0, "=$Sheet2.$A$1");
4660 m_pDoc->SetString(0,4,0, "=$Sheet2.A$1");
4661 m_pDoc->SetString(0,5,0, "=$Sheet1.$A$1");
4663 ScRange aRange(0,0,0,0,5,0);
4664 ScClipParam aClipParam(aRange, false);
4665 ScMarkData aMark;
4666 aMark.SetMarkArea(aRange);
4667 ScDocument* pClipDoc = new ScDocument(SCDOCMODE_CLIP);
4668 m_pDoc->CopyToClip(aClipParam, pClipDoc, &aMark);
4670 InsertDeleteFlags nFlags = IDF_ALL;
4671 aRange = ScRange(1,1,1,1,6,1);
4672 ScMarkData aMarkData2;
4673 aMarkData2.SetMarkArea(aRange);
4674 rExtDoc.CopyFromClip(aRange, aMarkData2, nFlags, NULL, pClipDoc);
4676 OUString aFormula;
4677 rExtDoc.GetFormula(1,1,1, aFormula);
4678 //adjust absolute refs pointing to the copy area
4679 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=COLUMN($B$2)"));
4680 rExtDoc.GetFormula(1,2,1, aFormula);
4681 //adjust absolute refs and keep relative refs
4682 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$B$2+C3"));
4683 rExtDoc.GetFormula(1,3,1, aFormula);
4684 // make absolute sheet refs external refs
4685 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("='file:///source.fake'#$Sheet2.B2"));
4686 rExtDoc.GetFormula(1,4,1, aFormula);
4687 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("='file:///source.fake'#$Sheet2.$A$1"));
4688 rExtDoc.GetFormula(1,5,1, aFormula);
4689 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("='file:///source.fake'#$Sheet2.B$1"));
4690 rExtDoc.GetFormula(1,6,1, aFormula);
4691 CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$ExtSheet2.$B$2"));
4693 xExtDocSh->DoClose();
4696 void Test::testFindAreaPosVertical()
4698 const char* aData[][3] = {
4699 { 0, "1", "1" },
4700 { "1", 0, "1" },
4701 { "1", "1", "1" },
4702 { 0, "1", "1" },
4703 { "1", "1", "1" },
4704 { "1", 0, "1" },
4705 { "1", "1", "1" },
4708 m_pDoc->InsertTab(0, "Test1");
4709 clearRange( m_pDoc, ScRange(0, 0, 0, 1, SAL_N_ELEMENTS(aData), 0));
4710 ScAddress aPos(0,0,0);
4711 ScRange aDataRange = insertRangeData( m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
4712 CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
4714 m_pDoc->SetRowHidden(4,4,0,true);
4715 bool bHidden = m_pDoc->RowHidden(4,0);
4716 CPPUNIT_ASSERT(bHidden);
4718 SCCOL nCol = 0;
4719 SCROW nRow = 0;
4720 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4722 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), nRow);
4723 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4725 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4727 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), nRow);
4728 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4730 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4732 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), nRow);
4733 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4735 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4737 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), nRow);
4738 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4740 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4742 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(MAXROW), nRow);
4743 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4745 nCol = 1;
4746 nRow = 2;
4748 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4750 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), nRow);
4751 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(1), nCol);
4753 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4755 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), nRow);
4756 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(1), nCol);
4758 nCol = 2;
4759 nRow = 6;
4760 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_UP);
4761 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4762 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(2), nCol);
4764 m_pDoc->DeleteTab(0);
4767 void Test::testFindAreaPosColRight()
4769 const char* aData[][7] = {
4770 { "", "1", "1", "", "1", "1", "1" },
4771 { "", "", "1", "1", "1", "", "1" }, };
4773 m_pDoc->InsertTab(0, "test1");
4774 clearRange( m_pDoc, ScRange(0, 0, 0, 7, SAL_N_ELEMENTS(aData), 0));
4775 ScAddress aPos(0,0,0);
4776 ScRange aDataRange = insertRangeData( m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
4777 CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
4779 m_pDoc->SetColHidden(4,4,0,true);
4780 bool bHidden = m_pDoc->ColHidden(4,0);
4781 CPPUNIT_ASSERT(bHidden);
4783 SCCOL nCol = 0;
4784 SCROW nRow = 0;
4785 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4787 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4788 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(1), nCol);
4790 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4792 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4793 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(2), nCol);
4795 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4797 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4798 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(5), nCol);
4800 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4802 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4803 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(6), nCol);
4805 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4807 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4808 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(MAXCOL), nCol);
4810 nCol = 2;
4811 nRow = 1;
4813 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4815 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), nRow);
4816 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(3), nCol);
4818 m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4820 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), nRow);
4821 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(6), nCol);
4823 m_pDoc->DeleteTab(0);
4826 void Test::testShiftCells()
4828 m_pDoc->InsertTab(0, "foo");
4830 OUString aTestVal("Some Text");
4832 // Text into cell E5.
4833 m_pDoc->SetString(4, 3, 0, aTestVal);
4835 // put a Note in cell E5
4836 ScAddress rAddr(4, 3, 0);
4837 ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
4838 pNote->SetText(rAddr, "Hello");
4840 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(4, 3, 0));
4842 // Insert cell at D5. This should shift the string cell to right.
4843 m_pDoc->InsertCol(3, 0, 3, 0, 3, 1);
4844 OUString aStr = m_pDoc->GetString(5, 3, 0);
4845 CPPUNIT_ASSERT_MESSAGE("We should have a string cell here.", aStr == aTestVal);
4846 CPPUNIT_ASSERT_MESSAGE("D5 is supposed to be blank.", m_pDoc->IsBlockEmpty(0, 3, 4, 3, 4));
4848 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc->HasNote(4, 3, 0));
4849 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(5, 3, 0));
4851 // Delete cell D5, to shift the text cell back into D5.
4852 m_pDoc->DeleteCol(3, 0, 3, 0, 3, 1);
4853 aStr = m_pDoc->GetString(4, 3, 0);
4854 CPPUNIT_ASSERT_MESSAGE("We should have a string cell here.", aStr == aTestVal);
4855 CPPUNIT_ASSERT_MESSAGE("E5 is supposed to be blank.", m_pDoc->IsBlockEmpty(0, 4, 4, 4, 4));
4857 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc->HasNote(5, 3, 0));
4858 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(4, 3, 0));
4860 m_pDoc->DeleteTab(0);
4863 void Test::testNoteBasic()
4865 m_pDoc->InsertTab(0, "PostIts");
4867 CPPUNIT_ASSERT(!m_pDoc->HasNotes());
4869 // Check for note's presence in all tables before inserting any notes.
4870 for (SCTAB i = 0; i <= MAXTAB; ++i)
4872 bool bHasNotes = m_pDoc->HasTabNotes(i);
4873 CPPUNIT_ASSERT(!bHasNotes);
4876 ScAddress aAddr(2, 2, 0); // cell C3
4877 ScPostIt *pNote = m_pDoc->GetOrCreateNote(aAddr);
4879 pNote->SetText(aAddr, "Hello world");
4880 pNote->SetAuthor("Jim Bob");
4882 ScPostIt *pGetNote = m_pDoc->GetNote(aAddr);
4883 CPPUNIT_ASSERT_MESSAGE("note should be itself", pGetNote == pNote);
4885 // Insert one row at row 1.
4886 bool bInsertRow = m_pDoc->InsertRow(0, 0, MAXCOL, 0, 1, 1);
4887 CPPUNIT_ASSERT_MESSAGE("failed to insert row", bInsertRow );
4889 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", m_pDoc->GetNote(aAddr) == NULL);
4890 aAddr.IncRow(); // cell C4
4891 CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
4893 // Insert column at column A.
4894 bool bInsertCol = m_pDoc->InsertCol(0, 0, MAXROW, 0, 1, 1);
4895 CPPUNIT_ASSERT_MESSAGE("failed to insert column", bInsertCol );
4897 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", m_pDoc->GetNote(aAddr) == NULL);
4898 aAddr.IncCol(); // cell D4
4899 CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
4901 // Insert a new sheet to shift the current sheet to the right.
4902 m_pDoc->InsertTab(0, "Table2");
4903 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", m_pDoc->GetNote(aAddr) == NULL);
4904 aAddr.IncTab(); // Move to the next sheet.
4905 CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
4907 m_pDoc->DeleteTab(0);
4908 aAddr.IncTab(-1);
4909 CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
4911 // Insert cell at C4. This should NOT shift the note position.
4912 bInsertRow = m_pDoc->InsertRow(2, 0, 2, 0, 3, 1);
4913 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell at C4.", bInsertRow);
4914 CPPUNIT_ASSERT_MESSAGE("Note shouldn't have moved but it has.", m_pDoc->GetNote(aAddr) == pNote);
4916 // Delete cell at C4. Again, this should NOT shift the note position.
4917 m_pDoc->DeleteRow(2, 0, 2, 0, 3, 1);
4918 CPPUNIT_ASSERT_MESSAGE("Note shouldn't have moved but it has.", m_pDoc->GetNote(aAddr) == pNote);
4920 // Now, with the note at D4, delete cell D3. This should shift the note one cell up.
4921 m_pDoc->DeleteRow(3, 0, 3, 0, 2, 1);
4922 aAddr.IncRow(-1); // cell D3
4923 CPPUNIT_ASSERT_MESSAGE("Note at D4 should have shifted up to D3.", m_pDoc->GetNote(aAddr) == pNote);
4925 // Delete column C. This should shift the note one cell left.
4926 m_pDoc->DeleteCol(0, 0, MAXROW, 0, 2, 1);
4927 aAddr.IncCol(-1); // cell C3
4928 CPPUNIT_ASSERT_MESSAGE("Note at D3 should have shifted left to C3.", m_pDoc->GetNote(aAddr) == pNote);
4930 // Insert a text where the note is.
4931 m_pDoc->SetString(aAddr, "Note is here.");
4933 // Delete row 1. This should shift the note from C3 to C2.
4934 m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 0, 1);
4935 aAddr.IncRow(-1); // C2
4936 CPPUNIT_ASSERT_MESSAGE("Note at C3 should have shifted up to C2.", m_pDoc->GetNote(aAddr) == pNote);
4938 m_pDoc->DeleteTab(0);
4941 void Test::testNoteDeleteRow()
4943 m_pDoc->InsertTab(0, "Sheet1");
4945 // We need a drawing layer in order to create caption objects.
4946 m_pDoc->InitDrawLayer(&getDocShell());
4948 OUString aHello("Hello");
4949 OUString aJimBob("Jim Bob");
4950 ScAddress aPos(1, 1, 0);
4951 ScPostIt* pNote = m_pDoc->GetOrCreateNote(aPos);
4952 pNote->SetText(aPos, aHello);
4953 pNote->SetAuthor(aJimBob);
4955 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(1, 1, 0));
4957 // test with IsBlockEmpty
4958 bool bIgnoreNotes = true;
4959 CPPUNIT_ASSERT_MESSAGE("The Block should be detected as empty (no Notes)", m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100, bIgnoreNotes));
4960 bIgnoreNotes = false;
4961 CPPUNIT_ASSERT_MESSAGE("The Block should NOT be detected as empty", !m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100, bIgnoreNotes));
4963 m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 1, 1);
4965 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc->HasNote(1, 1, 0));
4967 // Set values and notes into B3:B4.
4968 aPos = ScAddress(1,2,0); // B3
4969 m_pDoc->SetString(aPos, "First");
4970 ScNoteUtil::CreateNoteFromString(*m_pDoc, aPos, "First Note", false, false);
4972 aPos = ScAddress(1,3,0); // B4
4973 m_pDoc->SetString(aPos, "Second");
4974 ScNoteUtil::CreateNoteFromString(*m_pDoc, aPos, "Second Note", false, false);
4976 // Delete row 2.
4977 ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
4978 ScMarkData aMark;
4979 aMark.SelectOneTable(0);
4980 rDocFunc.DeleteCells(ScRange(0,1,0,MAXCOL,1,0), &aMark, DEL_CELLSUP, true, true);
4982 // Check to make sure the notes have shifted upward.
4983 pNote = m_pDoc->GetNote(ScAddress(1,1,0));
4984 CPPUNIT_ASSERT_MESSAGE("B2 should have a note.", pNote);
4985 CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote->GetText());
4986 pNote = m_pDoc->GetNote(ScAddress(1,2,0));
4987 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
4988 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
4989 pNote = m_pDoc->GetNote(ScAddress(1,3,0));
4990 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote);
4992 // Undo.
4994 SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
4995 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr);
4996 m_pDoc->CreateAllNoteCaptions(); // to make sure that all notes have their corresponding caption objects...
4998 pUndoMgr->Undo();
4999 pNote = m_pDoc->GetNote(ScAddress(1,1,0));
5000 CPPUNIT_ASSERT_MESSAGE("B2 should NOT have a note.", !pNote);
5001 pNote = m_pDoc->GetNote(ScAddress(1,2,0));
5002 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
5003 CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote->GetText());
5004 pNote = m_pDoc->GetNote(ScAddress(1,3,0));
5005 CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote);
5006 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
5008 // Delete row 3.
5009 rDocFunc.DeleteCells(ScRange(0,2,0,MAXCOL,2,0), &aMark, DEL_CELLSUP, true, true);
5011 pNote = m_pDoc->GetNote(ScAddress(1,2,0));
5012 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
5013 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
5014 pNote = m_pDoc->GetNote(ScAddress(1,3,0));
5015 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote);
5017 // Undo and check the result.
5018 pUndoMgr->Undo();
5019 pNote = m_pDoc->GetNote(ScAddress(1,2,0));
5020 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
5021 CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote->GetText());
5022 pNote = m_pDoc->GetNote(ScAddress(1,3,0));
5023 CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote);
5024 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
5026 m_pDoc->DeleteTab(0);
5029 void Test::testNoteDeleteCol()
5031 ScDocument& rDoc = getDocShell().GetDocument();
5032 rDoc.InsertTab(0, "Sheet1");
5034 ScAddress rAddr(1, 1, 0);
5035 ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
5036 pNote->SetText(rAddr, "Hello");
5037 pNote->SetAuthor("Jim Bob");
5039 CPPUNIT_ASSERT_MESSAGE("there should be a note", rDoc.HasNote(1, 1, 0));
5041 rDoc.DeleteCol(0, 0, MAXROW, 0, 1, 1);
5043 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !rDoc.HasNote(1, 1, 0));
5045 rDoc.DeleteTab(0);
5048 void Test::testNoteLifeCycle()
5050 m_pDoc->InsertTab(0, "Test");
5052 // We need a drawing layer in order to create caption objects.
5053 m_pDoc->InitDrawLayer(&getDocShell());
5055 ScAddress aPos(1,1,0);
5056 ScPostIt* pNote = m_pDoc->GetOrCreateNote(aPos);
5057 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new cell comment.", pNote);
5059 pNote->SetText(aPos, "New note");
5060 ScPostIt* pNote2 = m_pDoc->ReleaseNote(aPos);
5061 CPPUNIT_ASSERT_MESSAGE("This note instance is expected to be identical to the original.", pNote == pNote2);
5062 CPPUNIT_ASSERT_MESSAGE("The note shouldn't be here after it's been released.", !m_pDoc->HasNote(aPos));
5064 // Modify the internal state of the note instance to make sure it's really
5065 // been released.
5066 pNote->SetText(aPos, "New content");
5068 // Re-insert the note back to the same place.
5069 m_pDoc->SetNote(aPos, pNote);
5070 const SdrCaptionObj* pCaption = pNote->GetOrCreateCaption(aPos);
5071 CPPUNIT_ASSERT_MESSAGE("Failed to create a caption object.", pCaption);
5072 CPPUNIT_ASSERT_MESSAGE("This caption should belong to the drawing layer of the document.",
5073 pCaption->GetModel() == m_pDoc->GetDrawLayer());
5075 // Copy B2 with note to a clipboard.
5077 ScClipParam aClipParam(aPos, false);
5078 ScDocument aClipDoc(SCDOCMODE_CLIP);
5079 ScMarkData aMarkData;
5080 aMarkData.SelectOneTable(0);
5081 m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMarkData, false, false, true, true, false);
5083 ScPostIt* pClipNote = aClipDoc.GetNote(aPos);
5084 CPPUNIT_ASSERT_MESSAGE("Failed to copy note to the clipboard.", pClipNote);
5085 CPPUNIT_ASSERT_MESSAGE("Note on the clipboard should share the same caption object from the original.",
5086 pClipNote->GetCaption() == pCaption);
5088 m_pDoc->DeleteTab(0);
5091 void Test::testNoteCopyPaste()
5093 m_pDoc->InsertTab(0, "Test");
5095 // We need a drawing layer in order to create caption objects.
5096 m_pDoc->InitDrawLayer(&getDocShell());
5098 // Insert in B2 a text and cell comment.
5099 ScAddress aPos(1,1,0);
5100 m_pDoc->SetString(aPos, "Text");
5101 ScPostIt* pNote = m_pDoc->GetOrCreateNote(aPos);
5102 CPPUNIT_ASSERT(pNote);
5103 pNote->SetText(aPos, "Note1");
5105 // Insert in B4 a number and cell comment.
5106 aPos.SetRow(3);
5107 m_pDoc->SetValue(aPos, 1.1);
5108 pNote = m_pDoc->GetOrCreateNote(aPos);
5109 CPPUNIT_ASSERT(pNote);
5110 pNote->SetText(aPos, "Note2");
5112 // Copy B2:B4 to clipboard.
5113 ScMarkData aMark;
5114 aMark.SelectOneTable(0);
5115 ScRange aCopyRange(1,1,0,1,3,0);
5116 ScDocument aClipDoc(SCDOCMODE_CLIP);
5117 aClipDoc.ResetClip(m_pDoc, &aMark);
5118 ScClipParam aClipParam(aCopyRange, false);
5119 m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark, false, false, false, true, false);
5121 // Make sure the notes are in the clipboard.
5122 pNote = aClipDoc.GetNote(ScAddress(1,1,0));
5123 CPPUNIT_ASSERT(pNote);
5124 CPPUNIT_ASSERT_EQUAL(OUString("Note1"), pNote->GetText());
5126 pNote = aClipDoc.GetNote(ScAddress(1,3,0));
5127 CPPUNIT_ASSERT(pNote);
5128 CPPUNIT_ASSERT_EQUAL(OUString("Note2"), pNote->GetText());
5130 // Paste to B6:B8 but only cell notes.
5131 ScRange aDestRange(1,5,0,1,7,0);
5132 m_pDoc->CopyFromClip(aDestRange, aMark, IDF_NOTE, NULL, &aClipDoc);
5134 // Make sure the notes are there.
5135 pNote = m_pDoc->GetNote(ScAddress(1,5,0));
5136 CPPUNIT_ASSERT(pNote);
5137 CPPUNIT_ASSERT_EQUAL(OUString("Note1"), pNote->GetText());
5139 pNote = m_pDoc->GetNote(ScAddress(1,7,0));
5140 CPPUNIT_ASSERT(pNote);
5141 CPPUNIT_ASSERT_EQUAL(OUString("Note2"), pNote->GetText());
5143 m_pDoc->DeleteTab(0);
5146 void Test::testAreasWithNotes()
5148 ScDocument& rDoc = getDocShell().GetDocument();
5149 rDoc.InsertTab(0, "Sheet1");
5151 ScAddress rAddr(1, 5, 0);
5152 ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
5153 pNote->SetText(rAddr, "Hello");
5154 pNote->SetAuthor("Jim Bob");
5155 ScAddress rAddrMin(2, 2, 0);
5156 ScPostIt* pNoteMin = m_pDoc->GetOrCreateNote(rAddrMin);
5157 pNoteMin->SetText(rAddrMin, "Hello");
5159 SCCOL col;
5160 SCROW row;
5161 bool dataFound = false;
5163 // only cell notes (empty content)
5165 dataFound = rDoc.GetDataStart(0,col,row);
5167 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound);
5168 CPPUNIT_ASSERT_MESSAGE("DataStart wrong col for notes", col == 1);
5169 CPPUNIT_ASSERT_MESSAGE("DataStart wrong row for notes", row == 2);
5171 dataFound = rDoc.GetCellArea(0,col,row);
5173 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound);
5174 CPPUNIT_ASSERT_MESSAGE("CellArea wrong col for notes", col == 2);
5175 CPPUNIT_ASSERT_MESSAGE("CellArea wrong row for notes", row == 5);
5177 bool bNotes = true;
5178 dataFound = rDoc.GetPrintArea(0,col,row, bNotes);
5180 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound);
5181 CPPUNIT_ASSERT_MESSAGE("PrintArea wrong col for notes", col == 2);
5182 CPPUNIT_ASSERT_MESSAGE("PrintArea wrong row for notes", row == 5);
5184 bNotes = false;
5185 dataFound = rDoc.GetPrintArea(0,col,row, bNotes);
5186 CPPUNIT_ASSERT_MESSAGE("No PrintArea should be found", !dataFound);
5188 bNotes = true;
5189 dataFound = rDoc.GetPrintAreaVer(0,0,1,row, bNotes); // cols 0 & 1
5190 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5191 CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row for notes", row == 5);
5193 dataFound = rDoc.GetPrintAreaVer(0,2,3,row, bNotes); // cols 2 & 3
5194 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5195 CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row for notes", row == 2);
5197 bNotes = false;
5198 dataFound = rDoc.GetPrintAreaVer(0,0,1,row, bNotes); // col 0 & 1
5199 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer should be found", !dataFound);
5201 // now add cells with value, check that notes are taken into accompt in good cases
5203 m_pDoc->SetString(0, 3, 0, "Some Text");
5204 m_pDoc->SetString(3, 3, 0, "Some Text");
5206 dataFound = rDoc.GetDataStart(0,col,row);
5208 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound);
5209 CPPUNIT_ASSERT_MESSAGE("DataStart wrong col", col == 0);
5210 CPPUNIT_ASSERT_MESSAGE("DataStart wrong row", row == 2);
5212 dataFound = rDoc.GetCellArea(0,col,row);
5214 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound);
5215 CPPUNIT_ASSERT_MESSAGE("CellArea wrong col", col == 3);
5216 CPPUNIT_ASSERT_MESSAGE("CellArea wrong row", row == 5);
5218 bNotes = true;
5219 dataFound = rDoc.GetPrintArea(0,col,row, bNotes);
5221 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound);
5222 CPPUNIT_ASSERT_MESSAGE("PrintArea wrong col", col == 3);
5223 CPPUNIT_ASSERT_MESSAGE("PrintArea wrong row", row == 5);
5225 bNotes = false;
5226 dataFound = rDoc.GetPrintArea(0,col,row, bNotes);
5227 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound);
5228 CPPUNIT_ASSERT_MESSAGE("PrintArea wrong col", col == 3);
5229 CPPUNIT_ASSERT_MESSAGE("PrintArea wrong row", row == 3);
5231 bNotes = true;
5232 dataFound = rDoc.GetPrintAreaVer(0,0,1,row, bNotes); // cols 0 & 1
5233 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5234 CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row", row == 5);
5236 dataFound = rDoc.GetPrintAreaVer(0,2,3,row, bNotes); // cols 2 & 3
5237 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5238 CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row", row == 3);
5240 bNotes = false;
5241 dataFound = rDoc.GetPrintAreaVer(0,0,1,row, bNotes); // cols 0 & 1
5242 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5243 CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row", row == 3);
5245 rDoc.DeleteTab(0);
5248 void Test::testAnchoredRotatedShape()
5250 m_pDoc->InsertTab(0, "TestTab");
5251 SCROW nRow1, nRow2;
5252 bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
5253 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
5255 m_pDoc->InitDrawLayer();
5256 ScDrawLayer *pDrawLayer = m_pDoc->GetDrawLayer();
5257 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer != NULL);
5258 SdrPage* pPage = pDrawLayer->GetPage(0);
5259 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage != NULL);
5260 m_pDoc->SetRowHeightRange( 0, MAXROW, 0, sc::HMMToTwips( 1000 ) );
5261 const long TOLERANCE = 30; //30 hmm
5262 for ( SCCOL nCol = 0; nCol < MAXCOL; ++nCol )
5263 m_pDoc->SetColWidth( nCol, 0, sc::HMMToTwips( 1000 ) );
5265 //Add a rect
5266 Rectangle aRect( 4000, 5000, 10000, 7000 );
5268 Rectangle aRotRect( 6000, 3000, 8000, 9000 );
5269 SdrRectObj *pObj = new SdrRectObj(aRect);
5270 pPage->InsertObject(pObj);
5271 Point aRef1(pObj->GetSnapRect().Center());
5272 int nAngle = 9000; //90 deg.
5273 double nSin=sin(nAngle*nPi180);
5274 double nCos=cos(nAngle*nPi180);
5275 pObj->Rotate(aRef1,nAngle,nSin,nCos);
5277 ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
5279 Rectangle aSnap = pObj->GetSnapRect();
5280 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetHeight(), aSnap.GetHeight(), TOLERANCE ) );
5281 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetWidth(), aSnap.GetWidth(), TOLERANCE ) );
5282 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.Left(), aSnap.Left(), TOLERANCE ) );
5283 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.Top(), aSnap.Top(), TOLERANCE ) );
5285 ScDrawObjData aAnchor;
5286 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
5287 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData);
5289 aAnchor.maStart = pData->maStart;
5290 aAnchor.maEnd = pData->maEnd;
5292 m_pDoc->SetDrawPageSize(0);
5294 // increase row 5 by 2000 hmm
5295 m_pDoc->SetRowHeight( 5, 0, sc::HMMToTwips( 3000 ) );
5296 // increase col 6 by 1000 hmm
5297 m_pDoc->SetColWidth( 6, 0, sc::HMMToTwips( 2000 ) );
5299 aRotRect.setWidth( aRotRect.GetWidth() + 1000 );
5300 aRotRect.setHeight( aRotRect.GetHeight() + 2000 );
5302 m_pDoc->SetDrawPageSize(0);
5304 aSnap = pObj->GetSnapRect();
5306 // ensure that width and height have been adjusted accordingly
5307 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetHeight(), aSnap.GetHeight(), TOLERANCE ) );
5308 CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetWidth(), aSnap.GetWidth(), TOLERANCE ) );
5310 // ensure that anchor start and end addresses haven't changed
5311 CPPUNIT_ASSERT_EQUAL( aAnchor.maStart.Row(), pData->maStart.Row() ); // start row 0
5312 CPPUNIT_ASSERT_EQUAL( aAnchor.maStart.Col(), pData->maStart.Col() ); // start column 5
5313 CPPUNIT_ASSERT_EQUAL( aAnchor.maEnd.Row(), pData->maEnd.Row() ); // end row 3
5314 CPPUNIT_ASSERT_EQUAL( aAnchor.maEnd.Col(), pData->maEnd.Col() ); // end col 7
5316 m_pDoc->DeleteTab(0);
5319 void Test::testCellTextWidth()
5321 m_pDoc->InsertTab(0, "Test");
5323 ScAddress aTopCell(0, 0, 0);
5325 // Sheet is empty.
5326 boost::scoped_ptr<ScColumnTextWidthIterator> pIter(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5327 CPPUNIT_ASSERT_MESSAGE("Column should have no text widths stored.", !pIter->hasCell());
5329 // Sheet only has one cell.
5330 m_pDoc->SetString(0, 0, 0, "Only one cell");
5331 pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5332 CPPUNIT_ASSERT_MESSAGE("Column should have a cell.", pIter->hasCell());
5333 SCROW nTestRow = 0;
5334 CPPUNIT_ASSERT_EQUAL(nTestRow, pIter->getPos());
5336 // Setting a text width here should commit it to the column.
5337 sal_uInt16 nTestVal = 432;
5338 pIter->setValue(nTestVal);
5339 CPPUNIT_ASSERT_EQUAL(nTestVal, m_pDoc->GetTextWidth(aTopCell));
5341 // Set values to row 2 through 6.
5342 for (SCROW i = 2; i <= 6; ++i)
5343 m_pDoc->SetString(0, i, 0, "foo");
5345 // Set values to row 10 through 18.
5346 for (SCROW i = 10; i <= 18; ++i)
5347 m_pDoc->SetString(0, i, 0, "foo");
5350 // Full range.
5351 pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5352 SCROW aRows[] = { 0, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
5353 size_t n = SAL_N_ELEMENTS(aRows);
5354 for (size_t i = 0; i < n; ++i, pIter->next())
5356 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
5357 CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
5359 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
5363 // Specify start and end rows (6 - 16)
5364 ScAddress aStart = aTopCell;
5365 aStart.SetRow(6);
5366 pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aStart, 16));
5367 SCROW aRows[] = { 6, 10, 11, 12, 13, 14, 15, 16 };
5368 size_t n = SAL_N_ELEMENTS(aRows);
5369 for (size_t i = 0; i < n; ++i, pIter->next())
5371 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
5372 CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
5374 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
5377 // Clear from row 3 to row 17. After this, we should only have cells at rows 0, 2 and 18.
5378 clearRange(m_pDoc, ScRange(0, 3, 0, 0, 17, 0));
5381 // Full range again.
5382 pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5383 SCROW aRows[] = { 0, 2, 18 };
5384 size_t n = SAL_N_ELEMENTS(aRows);
5385 for (size_t i = 0; i < n; ++i, pIter->next())
5387 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
5388 CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
5390 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
5393 // Delete row 2 which shifts all cells below row 2 upward. After this, we
5394 // should only have cells at rows 0 and 17.
5395 m_pDoc->DeleteRow(0, 0, MAXCOL, MAXTAB, 2, 1);
5397 // Full range again.
5398 pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5399 SCROW aRows[] = { 0, 17 };
5400 size_t n = SAL_N_ELEMENTS(aRows);
5401 for (size_t i = 0; i < n; ++i, pIter->next())
5403 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
5404 CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
5406 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
5409 m_pDoc->DeleteTab(0);
5412 bool checkEditTextIterator(sc::EditTextIterator& rIter, const char** pChecks)
5414 const EditTextObject* pText = rIter.first();
5415 const char* p = *pChecks;
5417 for (int i = 0; i < 100; ++i) // cap it to 100 loops.
5419 if (!pText)
5420 // No more edit cells. The check string array should end too.
5421 return p == NULL;
5423 if (!p)
5424 // More edit cell, but no more check string. Bad.
5425 return false;
5427 if (pText->GetParagraphCount() != 1)
5428 // For this test, we don't handle multi-paragraph text.
5429 return false;
5431 if (pText->GetText(0) != OUString::createFromAscii(p))
5432 // Text differs from what's expected.
5433 return false;
5435 pText = rIter.next();
5436 ++pChecks;
5437 p = *pChecks;
5440 return false;
5443 void Test::testEditTextIterator()
5445 m_pDoc->InsertTab(0, "Test");
5448 // First, try with an empty sheet.
5449 sc::EditTextIterator aIter(*m_pDoc,0);
5450 const char* pChecks[] = { NULL };
5451 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5454 ScFieldEditEngine& rEditEngine = m_pDoc->GetEditEngine();
5457 // Only set one edit cell.
5458 rEditEngine.SetText("A2");
5459 m_pDoc->SetEditText(ScAddress(0,1,0), rEditEngine.CreateTextObject());
5460 sc::EditTextIterator aIter(*m_pDoc,0);
5461 const char* pChecks[] = { "A2", NULL };
5462 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5466 // Add a series of edit cells.
5467 rEditEngine.SetText("A5");
5468 m_pDoc->SetEditText(ScAddress(0,4,0), rEditEngine.CreateTextObject());
5469 rEditEngine.SetText("A6");
5470 m_pDoc->SetEditText(ScAddress(0,5,0), rEditEngine.CreateTextObject());
5471 rEditEngine.SetText("A7");
5472 m_pDoc->SetEditText(ScAddress(0,6,0), rEditEngine.CreateTextObject());
5473 sc::EditTextIterator aIter(*m_pDoc,0);
5474 const char* pChecks[] = { "A2", "A5", "A6", "A7", NULL };
5475 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5479 // Add more edit cells to column C. Skip column B.
5480 rEditEngine.SetText("C1");
5481 m_pDoc->SetEditText(ScAddress(2,0,0), rEditEngine.CreateTextObject());
5482 rEditEngine.SetText("C3");
5483 m_pDoc->SetEditText(ScAddress(2,2,0), rEditEngine.CreateTextObject());
5484 rEditEngine.SetText("C4");
5485 m_pDoc->SetEditText(ScAddress(2,3,0), rEditEngine.CreateTextObject());
5486 sc::EditTextIterator aIter(*m_pDoc,0);
5487 const char* pChecks[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", NULL };
5488 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5492 // Add some numeric, string and formula cells. This shouldn't affect the outcome.
5493 m_pDoc->SetString(ScAddress(0,99,0), "=ROW()");
5494 m_pDoc->SetValue(ScAddress(1,3,0), 1.2);
5495 m_pDoc->SetString(ScAddress(2,4,0), "Simple string");
5496 sc::EditTextIterator aIter(*m_pDoc,0);
5497 const char* pChecks[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", NULL };
5498 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5501 m_pDoc->DeleteTab(0);
5504 void Test::testCondFormatINSDEL()
5506 // fdo#62206
5507 m_pDoc->InsertTab(0, "Test");
5508 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5510 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5511 ScRangeList aRangeList(ScRange(0,0,0,0,3,0));
5512 pFormat->SetRange(aRangeList);
5513 ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5514 pFormat->AddEntry(pEntry);
5516 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
5517 pList->InsertNew(pFormat);
5519 m_pDoc->InsertCol(0,0,MAXROW,0,0,2);
5520 const ScRangeList& rRange = pFormat->GetRange();
5521 CPPUNIT_ASSERT(rRange == ScRange(2,0,0,2,3,0));
5523 OUString aExpr = pEntry->GetExpression(ScAddress(2,0,0), 0);
5524 CPPUNIT_ASSERT_EQUAL(aExpr, OUString("D2"));
5526 m_pDoc->DeleteTab(0);
5529 void Test::testCondFormatInsertCol()
5531 m_pDoc->InsertTab(0, "Test");
5532 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5534 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5535 ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
5536 pFormat->SetRange(aRangeList);
5538 ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5539 pFormat->AddEntry(pEntry);
5541 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
5542 pList->InsertNew(pFormat);
5544 m_pDoc->InsertCol(0,0,MAXROW,0,4,2);
5545 const ScRangeList& rRange = pFormat->GetRange();
5546 CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,5,3,0)), rRange);
5548 m_pDoc->DeleteTab(0);
5551 void Test::testCondFormatInsertRow()
5553 m_pDoc->InsertTab(0, "Test");
5554 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5556 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5557 ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
5558 pFormat->SetRange(aRangeList);
5560 ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5561 pFormat->AddEntry(pEntry);
5563 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
5564 pList->InsertNew(pFormat);
5566 m_pDoc->InsertRow(0,0,MAXCOL,0,4,2);
5567 const ScRangeList& rRange = pFormat->GetRange();
5568 CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,3,5,0)), rRange);
5570 m_pDoc->DeleteTab(0);
5573 void Test::testCondFormatInsertDeleteSheets()
5575 m_pDoc->InsertTab(0, "Test");
5577 // Add a conditional format to B2:B4.
5578 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5579 pFormat->SetRange(ScRange(1,1,0,1,3,0));
5581 sal_uLong nKey = m_pDoc->AddCondFormat(pFormat, 0);
5583 // Add condition in which if the value equals 2, set the "Result" style.
5584 ScCondFormatEntry* pEntry = new ScCondFormatEntry(
5585 SC_COND_EQUAL, "=2", "" , m_pDoc, ScAddress(0,0,0), ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5586 pFormat->AddEntry(pEntry);
5588 // Apply the format to the range.
5589 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, nKey);
5591 // Make sure this conditional format entry is really there.
5592 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5593 CPPUNIT_ASSERT(pList);
5594 const ScConditionalFormat* pCheck = pList->GetFormat(nKey);
5595 CPPUNIT_ASSERT_MESSAGE("Wrong condntional format instance.", pCheck == pFormat);
5597 // ... and its range is B2:B4.
5598 ScRangeList aCheckRange = pCheck->GetRange();
5599 CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5600 const ScRange* pRange = aCheckRange[0];
5601 CPPUNIT_ASSERT(pRange);
5602 CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4.", *pRange == ScRange(1,1,0,1,3,0));
5604 ScDocFunc& rFunc = getDocShell().GetDocFunc();
5606 // Insert a new sheet at the left.
5607 bool bInserted = rFunc.InsertTable(0, "Inserted", true, true);
5608 CPPUNIT_ASSERT(bInserted);
5610 pList = m_pDoc->GetCondFormList(1);
5611 CPPUNIT_ASSERT(pList);
5612 pCheck = pList->GetFormat(nKey);
5613 CPPUNIT_ASSERT(pCheck);
5615 // Make sure the range also got shifted.
5616 aCheckRange = pCheck->GetRange();
5617 CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5618 pRange = aCheckRange[0];
5619 CPPUNIT_ASSERT(pRange);
5620 CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4 on the 2nd sheet after the sheet insertion.", *pRange == ScRange(1,1,1,1,3,1));
5622 // Delete the sheet to the left.
5623 bool bDeleted = rFunc.DeleteTable(0, true, true);
5624 CPPUNIT_ASSERT(bDeleted);
5626 pList = m_pDoc->GetCondFormList(0);
5627 CPPUNIT_ASSERT(pList);
5628 pCheck = pList->GetFormat(nKey);
5629 CPPUNIT_ASSERT(pCheck);
5631 // Make sure the range got shifted back.
5632 aCheckRange = pCheck->GetRange();
5633 CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5634 pRange = aCheckRange[0];
5635 CPPUNIT_ASSERT(pRange);
5636 CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4 on the 1st sheet after the sheet removal.", *pRange == ScRange(1,1,0,1,3,0));
5638 SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
5639 CPPUNIT_ASSERT(pUndoMgr);
5641 // Undo and re-check.
5642 pUndoMgr->Undo();
5644 pList = m_pDoc->GetCondFormList(1);
5645 CPPUNIT_ASSERT(pList);
5646 pCheck = pList->GetFormat(nKey);
5647 CPPUNIT_ASSERT(pCheck);
5649 aCheckRange = pCheck->GetRange();
5650 CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5651 pRange = aCheckRange[0];
5652 CPPUNIT_ASSERT(pRange);
5653 CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4 on the 2nd sheet after the undo of the sheet removal.", *pRange == ScRange(1,1,1,1,3,1));
5655 #if 0 // TODO : Undo of sheet insertion currently depends on the presence of
5656 // view shell, and crashes when executed during cppunit run.
5658 // Undo again and re-check.
5659 pUndoMgr->Undo();
5661 pList = m_pDoc->GetCondFormList(0);
5662 CPPUNIT_ASSERT(pList);
5663 pCheck = pList->GetFormat(nKey);
5664 CPPUNIT_ASSERT(pCheck);
5666 // Make sure the range got shifted back.
5667 aCheckRange = pCheck->GetRange();
5668 CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5669 pRange = aCheckRange[0];
5670 CPPUNIT_ASSERT(pRange);
5671 CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4 on the 1st sheet after the undo of sheet insertion.", *pRange == ScRange(1,1,0,1,3,0));
5672 #else
5673 m_pDoc->DeleteTab(1);
5674 #endif
5676 m_pDoc->DeleteTab(0);
5679 void Test::testCondCopyPaste()
5681 m_pDoc->InsertTab(0, "Test");
5683 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5684 ScRange aCondFormatRange(0,0,0,3,3,0);
5685 ScRangeList aRangeList(aCondFormatRange);
5686 pFormat->SetRange(aRangeList);
5688 ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5689 pFormat->AddEntry(pEntry);
5690 sal_uLong nIndex = m_pDoc->AddCondFormat(pFormat, 0);
5692 ScDocument aClipDoc(SCDOCMODE_CLIP);
5693 copyToClip(m_pDoc, aCondFormatRange, &aClipDoc);
5695 ScRange aTargetRange(4,4,0,7,7,0);
5696 pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
5698 ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(7,7,0);
5699 CPPUNIT_ASSERT(pPastedFormat);
5701 CPPUNIT_ASSERT_EQUAL(ScRangeList(aTargetRange), pPastedFormat->GetRange());
5702 CPPUNIT_ASSERT( nIndex != pPastedFormat->GetKey());
5703 const SfxPoolItem* pItem = m_pDoc->GetAttr( 7, 7, 0, ATTR_CONDITIONAL );
5704 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
5706 CPPUNIT_ASSERT(pCondFormatItem);
5707 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
5708 CPPUNIT_ASSERT( nIndex != pCondFormatItem->GetCondFormatData().at(0) );
5710 m_pDoc->DeleteTab(0);
5713 void Test::testCondCopyPasteSingleCell()
5715 m_pDoc->InsertTab(0, "Test");
5717 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5718 ScRange aCondFormatRange(0,0,0,3,3,0);
5719 ScRangeList aRangeList(aCondFormatRange);
5720 pFormat->SetRange(aRangeList);
5722 ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5723 pFormat->AddEntry(pEntry);
5724 sal_uLong nIndex = m_pDoc->AddCondFormat(pFormat, 0);
5726 ScDocument aClipDoc(SCDOCMODE_CLIP);
5727 copyToClip(m_pDoc, ScRange(0,0,0,0,0,0), &aClipDoc);
5729 ScRange aTargetRange(4,4,0,4,4,0);
5730 pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
5732 ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(4,4,0);
5733 CPPUNIT_ASSERT(pPastedFormat);
5735 CPPUNIT_ASSERT_EQUAL(ScRangeList(aTargetRange), pPastedFormat->GetRange());
5736 CPPUNIT_ASSERT( nIndex != pPastedFormat->GetKey());
5737 const SfxPoolItem* pItem = m_pDoc->GetAttr( 4, 4, 0, ATTR_CONDITIONAL );
5738 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
5740 CPPUNIT_ASSERT(pCondFormatItem);
5741 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
5742 CPPUNIT_ASSERT( nIndex != pCondFormatItem->GetCondFormatData().at(0) );
5744 m_pDoc->DeleteTab(0);
5747 void Test::testCondCopyPasteSingleCellToRange()
5749 m_pDoc->InsertTab(0, "Test");
5751 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5752 ScRange aCondFormatRange(0,0,0,3,3,0);
5753 ScRangeList aRangeList(aCondFormatRange);
5754 pFormat->SetRange(aRangeList);
5756 ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5757 pFormat->AddEntry(pEntry);
5758 sal_uLong nIndex = m_pDoc->AddCondFormat(pFormat, 0);
5760 ScDocument aClipDoc(SCDOCMODE_CLIP);
5761 copyToClip(m_pDoc, ScRange(0,0,0,0,0,0), &aClipDoc);
5763 ScRange aTargetRange(4,4,0,4,8,0);
5764 pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
5766 std::set<sal_uLong> aCondFormatIndices;
5767 for(SCROW nRow = 4; nRow <= 8; ++nRow)
5769 ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(4, nRow, 0);
5770 CPPUNIT_ASSERT(pPastedFormat);
5772 CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(4, nRow, 0)), pPastedFormat->GetRange());
5773 sal_uLong nPastedKey = pPastedFormat->GetKey();
5774 CPPUNIT_ASSERT( nIndex != nPastedKey);
5775 const SfxPoolItem* pItem = m_pDoc->GetAttr( 4, nRow, 0, ATTR_CONDITIONAL );
5776 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
5778 CPPUNIT_ASSERT(pCondFormatItem);
5779 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
5780 CPPUNIT_ASSERT( nIndex != pCondFormatItem->GetCondFormatData().at(0) );
5781 auto itr = aCondFormatIndices.find(nPastedKey);
5782 CPPUNIT_ASSERT(itr == aCondFormatIndices.end());
5783 aCondFormatIndices.insert(nPastedKey);
5786 m_pDoc->DeleteTab(0);
5789 void Test::testCondCopyPasteSheetBetweenDoc()
5791 m_pDoc->InsertTab(0, "Test");
5793 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5794 ScRange aCondFormatRange(0,0,0,3,3,0);
5795 ScRangeList aRangeList(aCondFormatRange);
5796 pFormat->SetRange(aRangeList);
5798 ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5799 pFormat->AddEntry(pEntry);
5800 m_pDoc->AddCondFormat(pFormat, 0);
5802 ScDocument aDoc;
5803 aDoc.TransferTab(m_pDoc, 0, 0, true);
5805 ScConditionalFormatList* pList = aDoc.GetCondFormList(0);
5806 CPPUNIT_ASSERT_EQUAL(size_t(1), pList->size());
5808 m_pDoc->DeleteTab(0);
5811 void Test::testCondCopyPasteSheet()
5813 m_pDoc->InsertTab(0, "Test");
5815 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5816 ScRange aCondFormatRange(0,0,0,3,3,0);
5817 ScRangeList aRangeList(aCondFormatRange);
5818 pFormat->SetRange(aRangeList);
5820 ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5821 pFormat->AddEntry(pEntry);
5822 m_pDoc->AddCondFormat(pFormat, 0);
5824 m_pDoc->CopyTab(0, SC_TAB_APPEND);
5826 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(1);
5827 CPPUNIT_ASSERT_EQUAL(size_t(1), pList->size());
5829 ScConditionalFormat& rFormat = *pList->begin();
5830 const ScRangeList& rRange = rFormat.GetRange();
5831 CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,1,3,3,1)), rRange);
5832 sal_uInt32 nKey = rFormat.GetKey();
5833 const SfxPoolItem* pItem = m_pDoc->GetAttr( 2, 2, 1, ATTR_CONDITIONAL );
5834 const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
5836 CPPUNIT_ASSERT(pCondFormatItem);
5837 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
5838 CPPUNIT_ASSERT( nKey == pCondFormatItem->GetCondFormatData().at(0) );
5840 m_pDoc->DeleteTab(1);
5841 m_pDoc->DeleteTab(0);
5844 void Test::testIconSet()
5846 m_pDoc->InsertTab(0, "Test");
5847 ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5849 ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5850 ScRangeList aRangeList(ScRange(0,0,0,0,0,0));
5851 pFormat->SetRange(aRangeList);
5853 ScIconSetFormat* pEntry = new ScIconSetFormat(m_pDoc);
5854 ScIconSetFormatData* pData = new ScIconSetFormatData;
5855 pData->maEntries.push_back(new ScColorScaleEntry(0, COL_BLUE));
5856 pData->maEntries.push_back(new ScColorScaleEntry(1, COL_GREEN));
5857 pData->maEntries.push_back(new ScColorScaleEntry(2, COL_RED));
5858 pEntry->SetIconSetData(pData);
5860 m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
5861 pList->InsertNew(pFormat);
5863 struct {
5864 double nVal; sal_Int32 nIndex;
5865 } aTests[] = {
5866 { -1.0, 0 },
5867 { 0.0, 0 },
5868 { 1.0, 1 },
5869 { 2.0, 2 },
5870 { 3.0, 2 }
5872 for(size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i)
5874 m_pDoc->SetValue(0,0,0,aTests[i].nVal);
5875 ScIconSetInfo* pInfo = pEntry->GetIconSetInfo(ScAddress(0,0,0));
5876 CPPUNIT_ASSERT_EQUAL(aTests[i].nIndex, pInfo->nIconIndex);
5877 delete pInfo;
5880 delete pEntry;
5881 m_pDoc->DeleteTab(0);
5884 namespace {
5886 struct ScDataBarLengthData
5888 double nVal;
5889 double nLength;
5892 void testDataBarLengthImpl(ScDocument* pDoc, ScDataBarLengthData* pData, const ScRange& rRange,
5893 double nMinVal, ScColorScaleEntryType eMinType,
5894 double nMaxVal, ScColorScaleEntryType eMaxType,
5895 double nZeroPos, databar::ScAxisPosition eAxisPos)
5897 ScConditionalFormat* pFormat = new ScConditionalFormat(1, pDoc);
5898 ScRangeList aRangeList(rRange);
5899 pFormat->SetRange(aRangeList);
5901 SCCOL nCol = rRange.aStart.Col();
5903 ScDataBarFormat* pDatabar = new ScDataBarFormat(pDoc);
5904 pFormat->AddEntry(pDatabar);
5906 ScDataBarFormatData* pFormatData = new ScDataBarFormatData();
5907 pFormatData->meAxisPosition = eAxisPos;
5909 pFormatData->mpLowerLimit.reset(new ScColorScaleEntry());
5910 pFormatData->mpLowerLimit->SetValue(nMinVal);
5911 pFormatData->mpLowerLimit->SetType(eMinType);
5912 pFormatData->mpUpperLimit.reset(new ScColorScaleEntry());
5913 pFormatData->mpUpperLimit->SetValue(nMaxVal);
5914 pFormatData->mpUpperLimit->SetType(eMaxType);
5915 pDatabar->SetDataBarData(pFormatData);
5917 for (size_t i = 0; pData[i].nLength != -200; ++i)
5919 pDoc->SetValue(nCol, i, 0, pData[i].nVal);
5922 for (size_t i = 0; pData[i].nLength != -200; ++i)
5924 ScDataBarInfo* pInfo = pDatabar->GetDataBarInfo(ScAddress(nCol, i, 0));
5925 CPPUNIT_ASSERT(pInfo);
5926 ASSERT_DOUBLES_EQUAL(pData[i].nLength, pInfo->mnLength);
5927 ASSERT_DOUBLES_EQUAL(nZeroPos, pInfo->mnZero);
5929 delete pFormat;
5934 void Test::testDataBarLengthAutomaticAxis()
5936 m_pDoc->InsertTab(0, "Test");
5938 ScDataBarLengthData aValues[] = {
5939 { 2, 0 },
5940 { 3, 0 },
5941 { 4, 25.0 },
5942 { 5, 50.0 },
5943 { 6, 75.0 },
5944 { 7, 100.0 },
5945 { 8, 100.0 },
5946 { 9, 100.0 },
5947 { 0, -200 }
5950 testDataBarLengthImpl(m_pDoc, aValues, ScRange(0,0,0,0,7,0),
5951 3, COLORSCALE_VALUE, 7, COLORSCALE_VALUE, 0.0, databar::AUTOMATIC);
5953 ScDataBarLengthData aValues2[] = {
5954 { -6, -100 },
5955 { -5, -100 },
5956 { -4, -100 },
5957 { -3, -75.0 },
5958 { -2, -50.0 },
5959 { -1, -25.0 },
5960 { 0, 0.0 },
5961 { 1, 12.5 },
5962 { 2, 25.0 },
5963 { 3, 37.5 },
5964 { 4, 50.0 },
5965 { 5, 62.5 },
5966 { 6, 75.0 },
5967 { 7, 87.5 },
5968 { 8, 100.0 },
5969 { 9, 100.0 },
5970 { 0, -200 }
5972 testDataBarLengthImpl(m_pDoc, aValues2, ScRange(1,0,0,1,15,0),
5973 -4, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 1.0/3.0 * 100, databar::AUTOMATIC);
5975 ScDataBarLengthData aValues3[] = {
5976 { 2, 0.0 },
5977 { 3, 25.0 },
5978 { 4, 50.0 },
5979 { 6, 100.0 },
5980 { 0, -200 }
5982 testDataBarLengthImpl(m_pDoc, aValues3, ScRange(2,0,0,2,3,0),
5983 0, COLORSCALE_MIN, 0, COLORSCALE_MAX, 0, databar::AUTOMATIC);
5985 ScDataBarLengthData aValues4[] = {
5986 { 2, 40.0 },
5987 { 3, 60.0 },
5988 { 4, 80.0 },
5989 { 5, 100.0 },
5990 { 0, -200 }
5992 testDataBarLengthImpl(m_pDoc, aValues4, ScRange(3,0,0,3,3,0),
5993 0, COLORSCALE_AUTO, 0, COLORSCALE_AUTO, 0, databar::AUTOMATIC);
5995 m_pDoc->DeleteTab(0);
5998 void Test::testDataBarLengthMiddleAxis()
6000 m_pDoc->InsertTab(0, "Test");
6002 ScDataBarLengthData aValues[] = {
6003 { 1, 25.0 },
6004 { 2, 25.0 },
6005 { 3, 37.5 },
6006 { 4, 50.0 },
6007 { 5, 62.5 },
6008 { 6, 75.0 },
6009 { 7, 87.5 },
6010 { 8, 100.0 },
6011 { 9, 100.0 },
6012 { 0, -200 }
6015 testDataBarLengthImpl(m_pDoc, aValues, ScRange(0,0,0,0,8,0),
6016 2, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 50.0, databar::MIDDLE);
6018 ScDataBarLengthData aValues2[] = {
6019 { -6, -50 },
6020 { -5, -50 },
6021 { -4, -50 },
6022 { -3, -37.5 },
6023 { -2, -25.0 },
6024 { -1, -12.5 },
6025 { 0, 0.0 },
6026 { 1, 12.5 },
6027 { 2, 25.0 },
6028 { 3, 37.5 },
6029 { 4, 50.0 },
6030 { 5, 62.5 },
6031 { 6, 75.0 },
6032 { 7, 87.5 },
6033 { 8, 100.0 },
6034 { 9, 100.0 },
6035 { 0, -200 }
6037 testDataBarLengthImpl(m_pDoc, aValues2, ScRange(1,0,0,1,15,0),
6038 -4, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 50.0, databar::MIDDLE);
6040 m_pDoc->DeleteTab(0);
6043 void Test::testImportStream()
6045 sc::AutoCalcSwitch aAC(*m_pDoc, true); // turn on auto calc.
6046 sc::UndoSwitch aUndo(*m_pDoc, true); // enable undo.
6048 m_pDoc->InsertTab(0, "Test");
6050 m_pDoc->SetString(ScAddress(0,1,0), "=SUM(A1:C1)"); // A2
6052 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0,1,0)));
6054 // CSV import options.
6055 ScAsciiOptions aOpt;
6056 aOpt.SetFieldSeps(",");
6058 // Import values to A1:C1.
6059 ScImportExport aObj(m_pDoc, ScAddress(0,0,0));
6060 aObj.SetImportBroadcast(true);
6061 aObj.SetExtOptions(aOpt);
6062 aObj.ImportString("1,2,3", SotClipboardFormatId::STRING);
6064 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
6065 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,0,0)));
6066 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
6068 // Formula value should have been updated.
6069 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,1,0)));
6071 // Undo, and check the result.
6072 SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6073 CPPUNIT_ASSERT_MESSAGE("Failed to get the undo manager.", pUndoMgr);
6074 pUndoMgr->Undo();
6076 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0,0,0)));
6077 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(1,0,0)));
6078 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(2,0,0)));
6080 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0,1,0))); // formula
6082 // Redo, and check the result.
6083 pUndoMgr->Redo();
6085 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
6086 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,0,0)));
6087 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
6089 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,1,0))); // formula
6091 pUndoMgr->Clear();
6093 m_pDoc->DeleteTab(0);
6096 void Test::testDeleteContents()
6098 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
6099 sc::UndoSwitch aUndoSwitch(*m_pDoc, true); // enable undo.
6101 m_pDoc->InsertTab(0, "Test");
6103 m_pDoc->SetValue(ScAddress(3,1,0), 1.0);
6104 m_pDoc->SetValue(ScAddress(3,2,0), 1.0);
6105 m_pDoc->SetValue(ScAddress(3,3,0), 1.0);
6106 m_pDoc->SetValue(ScAddress(3,4,0), 1.0);
6107 m_pDoc->SetValue(ScAddress(3,5,0), 1.0);
6108 m_pDoc->SetValue(ScAddress(3,6,0), 1.0);
6109 m_pDoc->SetValue(ScAddress(3,7,0), 1.0);
6110 m_pDoc->SetValue(ScAddress(3,8,0), 1.0);
6111 m_pDoc->SetString(ScAddress(3,15,0), "=SUM(D2:D15)");
6113 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
6115 // Delete D2:D6.
6116 ScRange aRange(3,1,0,3,5,0);
6117 ScMarkData aMark;
6118 aMark.SelectOneTable(0);
6119 aMark.SetMarkArea(aRange);
6121 ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
6122 pUndoDoc->InitUndo(m_pDoc, 0, 0);
6123 m_pDoc->CopyToDocument(aRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
6124 ScUndoDeleteContents aUndo(&getDocShell(), aMark, aRange, pUndoDoc, false, IDF_CONTENTS, true);
6126 clearRange(m_pDoc, aRange);
6127 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
6129 aUndo.Undo();
6130 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
6132 aUndo.Redo();
6133 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
6135 m_pDoc->DeleteTab(0);
6138 void Test::testTransliterateText()
6140 m_pDoc->InsertTab(0, "Test");
6142 // Set texts to A1:A3.
6143 m_pDoc->SetString(ScAddress(0,0,0), "Mike");
6144 m_pDoc->SetString(ScAddress(0,1,0), "Noah");
6145 m_pDoc->SetString(ScAddress(0,2,0), "Oscar");
6147 // Change them to uppercase.
6148 ScMarkData aMark;
6149 aMark.SetMarkArea(ScRange(0,0,0,0,2,0));
6150 ScDocFunc& rFunc = getDocShell().GetDocFunc();
6151 rFunc.TransliterateText(
6152 aMark, i18n::TransliterationModules_LOWERCASE_UPPERCASE, true, true);
6154 CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc->GetString(ScAddress(0,0,0)));
6155 CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc->GetString(ScAddress(0,1,0)));
6156 CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc->GetString(ScAddress(0,2,0)));
6158 // Test the undo and redo.
6159 SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6160 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr);
6162 pUndoMgr->Undo();
6163 CPPUNIT_ASSERT_EQUAL(OUString("Mike"), m_pDoc->GetString(ScAddress(0,0,0)));
6164 CPPUNIT_ASSERT_EQUAL(OUString("Noah"), m_pDoc->GetString(ScAddress(0,1,0)));
6165 CPPUNIT_ASSERT_EQUAL(OUString("Oscar"), m_pDoc->GetString(ScAddress(0,2,0)));
6167 pUndoMgr->Redo();
6168 CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc->GetString(ScAddress(0,0,0)));
6169 CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc->GetString(ScAddress(0,1,0)));
6170 CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc->GetString(ScAddress(0,2,0)));
6172 m_pDoc->DeleteTab(0);
6175 void Test::testFormulaToValue()
6177 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
6178 FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
6180 m_pDoc->InsertTab(0, "Test");
6182 const char* aData[][3] = {
6183 { "=1", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6184 { "=2", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6185 { "=3", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6186 { "=4", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6187 { "=5", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6188 { "=6", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6191 ScAddress aPos(1,2,0); // B3
6192 ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
6193 CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
6196 // Expected output table content. 0 = empty cell
6197 const char* aOutputCheck[][3] = {
6198 { "1", "2", "TRUE" },
6199 { "2", "4", "TRUE" },
6200 { "3", "6", "TRUE" },
6201 { "4", "8", "TRUE" },
6202 { "5", "10", "TRUE" },
6203 { "6", "12", "TRUE" },
6206 bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
6207 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6210 // Convert B5:C6 to static values, and check the result.
6211 ScDocFunc& rFunc = getDocShell().GetDocFunc();
6212 ScRange aConvRange(1,4,0,2,5,0); // B5:C6
6213 rFunc.ConvertFormulaToValue(aConvRange, true, false);
6216 // Expected output table content. 0 = empty cell
6217 const char* aOutputCheck[][3] = {
6218 { "1", "2", "TRUE" },
6219 { "2", "4", "TRUE" },
6220 { "3", "6", "FALSE" },
6221 { "4", "8", "FALSE" },
6222 { "5", "10", "TRUE" },
6223 { "6", "12", "TRUE" },
6226 bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "Converted");
6227 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6230 // Make sure that B3:B4 and B7:B8 are formula cells.
6231 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,2,0)) == CELLTYPE_FORMULA);
6232 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,3,0)) == CELLTYPE_FORMULA);
6233 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,6,0)) == CELLTYPE_FORMULA);
6234 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,7,0)) == CELLTYPE_FORMULA);
6236 // Make sure that B5:C6 are numeric cells.
6237 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,4,0)) == CELLTYPE_VALUE);
6238 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,5,0)) == CELLTYPE_VALUE);
6239 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(2,4,0)) == CELLTYPE_VALUE);
6240 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(2,5,0)) == CELLTYPE_VALUE);
6242 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
6243 const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(2,2,0));
6244 CPPUNIT_ASSERT(pFC);
6245 CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 2);
6246 CPPUNIT_ASSERT(pFC->GetSharedLength() == 2);
6247 pFC = m_pDoc->GetFormulaCell(ScAddress(2,6,0));
6248 CPPUNIT_ASSERT(pFC);
6249 CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 6);
6250 CPPUNIT_ASSERT(pFC->GetSharedLength() == 2);
6252 // Undo and check.
6253 SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6254 CPPUNIT_ASSERT(pUndoMgr);
6255 pUndoMgr->Undo();
6258 // Expected output table content. 0 = empty cell
6259 const char* aOutputCheck[][3] = {
6260 { "1", "2", "TRUE" },
6261 { "2", "4", "TRUE" },
6262 { "3", "6", "TRUE" },
6263 { "4", "8", "TRUE" },
6264 { "5", "10", "TRUE" },
6265 { "6", "12", "TRUE" },
6268 bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "After undo");
6269 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6272 // B3:B8 should all be (ungrouped) formula cells.
6273 for (SCROW i = 2; i <= 7; ++i)
6275 pFC = m_pDoc->GetFormulaCell(ScAddress(1,i,0));
6276 CPPUNIT_ASSERT(pFC);
6277 CPPUNIT_ASSERT(!pFC->IsShared());
6280 // C3:C8 should be shared formula cells.
6281 pFC = m_pDoc->GetFormulaCell(ScAddress(2,2,0));
6282 CPPUNIT_ASSERT(pFC);
6283 CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 2);
6284 CPPUNIT_ASSERT(pFC->GetSharedLength() == 6);
6286 // Redo and check.
6287 pUndoMgr->Redo();
6289 // Expected output table content. 0 = empty cell
6290 const char* aOutputCheck[][3] = {
6291 { "1", "2", "TRUE" },
6292 { "2", "4", "TRUE" },
6293 { "3", "6", "FALSE" },
6294 { "4", "8", "FALSE" },
6295 { "5", "10", "TRUE" },
6296 { "6", "12", "TRUE" },
6299 bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "Converted");
6300 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6303 // Make sure that B3:B4 and B7:B8 are formula cells.
6304 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,2,0)) == CELLTYPE_FORMULA);
6305 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,3,0)) == CELLTYPE_FORMULA);
6306 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,6,0)) == CELLTYPE_FORMULA);
6307 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,7,0)) == CELLTYPE_FORMULA);
6309 // Make sure that B5:C6 are numeric cells.
6310 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,4,0)) == CELLTYPE_VALUE);
6311 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,5,0)) == CELLTYPE_VALUE);
6312 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(2,4,0)) == CELLTYPE_VALUE);
6313 CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(2,5,0)) == CELLTYPE_VALUE);
6315 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
6316 pFC = m_pDoc->GetFormulaCell(ScAddress(2,2,0));
6317 CPPUNIT_ASSERT(pFC);
6318 CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 2);
6319 CPPUNIT_ASSERT(pFC->GetSharedLength() == 2);
6320 pFC = m_pDoc->GetFormulaCell(ScAddress(2,6,0));
6321 CPPUNIT_ASSERT(pFC);
6322 CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 6);
6323 CPPUNIT_ASSERT(pFC->GetSharedLength() == 2);
6325 // Undo again and make sure the recovered formulas in C5:C6 still track B5:B6.
6326 pUndoMgr->Undo();
6327 m_pDoc->SetValue(ScAddress(1,4,0), 10);
6328 m_pDoc->SetValue(ScAddress(1,5,0), 11);
6329 CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc->GetValue(ScAddress(2,4,0)));
6330 CPPUNIT_ASSERT_EQUAL(22.0, m_pDoc->GetValue(ScAddress(2,5,0)));
6332 m_pDoc->DeleteTab(0);
6335 void Test::testFormulaToValue2()
6337 sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
6338 FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
6340 m_pDoc->InsertTab(0, "Test");
6342 const char* aData[][2] = {
6343 { "=1", "=ISFORMULA(RC[-1])" },
6344 { "=2", "=ISFORMULA(RC[-1])" },
6345 { "3", "=ISFORMULA(RC[-1])" },
6346 { "=4", "=ISFORMULA(RC[-1])" },
6347 { "=5", "=ISFORMULA(RC[-1])" },
6350 // Insert data into B2:C6.
6351 ScAddress aPos(1,1,0); // B2
6352 ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
6353 CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
6356 // Expected output table content. 0 = empty cell
6357 const char* aOutputCheck[][2] = {
6358 { "1", "TRUE" },
6359 { "2", "TRUE" },
6360 { "3", "FALSE" },
6361 { "4", "TRUE" },
6362 { "5", "TRUE" },
6365 bool bSuccess = checkOutput<2>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
6366 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6369 // Convert B3:B5 to a value.
6370 ScDocFunc& rFunc = getDocShell().GetDocFunc();
6371 ScRange aConvRange(1,2,0,1,4,0); // B3:B5
6372 rFunc.ConvertFormulaToValue(aConvRange, true, false);
6375 // Expected output table content. 0 = empty cell
6376 const char* aOutputCheck[][2] = {
6377 { "1", "TRUE" },
6378 { "2", "FALSE" },
6379 { "3", "FALSE" },
6380 { "4", "FALSE" },
6381 { "5", "TRUE" },
6384 bool bSuccess = checkOutput<2>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
6385 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6388 // Undo and check.
6389 SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6390 CPPUNIT_ASSERT(pUndoMgr);
6391 pUndoMgr->Undo();
6394 // Expected output table content. 0 = empty cell
6395 const char* aOutputCheck[][2] = {
6396 { "1", "TRUE" },
6397 { "2", "TRUE" },
6398 { "3", "FALSE" },
6399 { "4", "TRUE" },
6400 { "5", "TRUE" },
6403 bool bSuccess = checkOutput<2>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
6404 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6407 m_pDoc->DeleteTab(0);
6410 void Test::testMixData()
6412 m_pDoc->InsertTab(0, "Test");
6414 m_pDoc->SetValue(ScAddress(1,0,0), 2.0); // B1
6415 m_pDoc->SetValue(ScAddress(0,1,0), 3.0); // A2
6417 // Copy A1:B1 to the clip document.
6418 ScDocument aClipDoc(SCDOCMODE_CLIP);
6419 copyToClip(m_pDoc, ScRange(0,0,0,1,0,0), &aClipDoc); // A1:B1
6421 // Copy A2:B2 to the mix document (for arithemetic paste).
6422 ScDocument aMixDoc(SCDOCMODE_CLIP);
6423 copyToClip(m_pDoc, ScRange(0,1,0,1,1,0), &aMixDoc); // A2:B2
6425 // Paste A1:B1 to A2:B2 and perform addition.
6426 pasteFromClip(m_pDoc, ScRange(0,1,0,1,1,0), &aClipDoc);
6427 m_pDoc->MixDocument(ScRange(0,1,0,1,1,0), PASTE_ADD, false, &aMixDoc);
6429 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(0,1,0)); // A2
6430 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(1,1,0)); // B2
6432 // Clear everything and start over.
6433 clearSheet(m_pDoc, 0);
6434 clearSheet(&aClipDoc, 0);
6435 clearSheet(&aMixDoc, 0);
6437 // Set values to A1, A2, and B1. B2 will remain empty.
6438 m_pDoc->SetValue(ScAddress(0,0,0), 15.0);
6439 m_pDoc->SetValue(ScAddress(0,1,0), 16.0);
6440 m_pDoc->SetValue(ScAddress(1,0,0), 12.0);
6441 CPPUNIT_ASSERT_MESSAGE("B2 should be empty.", m_pDoc->GetCellType(ScAddress(1,1,0)) == CELLTYPE_NONE);
6443 // Copy A1:A2 and paste it onto B1:B2 with subtraction operation.
6444 copyToClip(m_pDoc, ScRange(0,0,0,0,1,0), &aClipDoc);
6445 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(0,0,0)), aClipDoc.GetValue(ScAddress(0,0,0)));
6446 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(0,1,0)), aClipDoc.GetValue(ScAddress(0,1,0)));
6448 copyToClip(m_pDoc, ScRange(1,0,0,1,1,0), &aMixDoc);
6449 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(1,0,0)), aMixDoc.GetValue(ScAddress(1,0,0)));
6450 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(1,1,0)), aMixDoc.GetValue(ScAddress(1,1,0)));
6452 pasteFromClip(m_pDoc, ScRange(1,0,0,1,1,0), &aClipDoc);
6453 m_pDoc->MixDocument(ScRange(1,0,0,1,1,0), PASTE_SUB, false, &aMixDoc);
6455 CPPUNIT_ASSERT_EQUAL( -3.0, m_pDoc->GetValue(ScAddress(1,0,0))); // 12 - 15
6456 CPPUNIT_ASSERT_EQUAL(-16.0, m_pDoc->GetValue(ScAddress(1,1,0))); // 0 - 16
6458 m_pDoc->DeleteTab(0);
6461 void Test::testSetStringAndNote()
6463 m_pDoc->InsertTab(0, "Test");
6465 //note on A1
6466 ScAddress aAdrA1 (0, 0, 0);
6467 ScPostIt* pNote = m_pDoc->GetOrCreateNote(aAdrA1);
6468 pNote->SetText(aAdrA1, "Hello world in A1");
6470 m_pDoc->SetString(0, 0, 0, "");
6472 pNote = m_pDoc->GetNote(aAdrA1);
6473 CPPUNIT_ASSERT(pNote);
6475 m_pDoc->DeleteTab(0);
6478 void Test::testCopyPasteMatrixFormula()
6480 m_pDoc->InsertTab(0, "hcv");
6482 // Set Values to B1, C1, D1
6483 m_pDoc->SetValue(ScAddress(1,0,0), 2.0); // B1
6484 m_pDoc->SetValue(ScAddress(2,0,0), 5.0); // C1
6485 m_pDoc->SetValue(ScAddress(3,0,0), 3.0); // D1
6487 // Set Values to B2, C2
6488 m_pDoc->SetString(ScAddress(1,1,0), "B2"); // B2
6489 //m_pDoc->SetString(ScAddress(2,1,0), "C2"); // C2
6490 m_pDoc->SetString(ScAddress(3,1,0), "D2"); // D2
6492 // Set Vallues to D3
6493 //m_pDoc->SetValue(ScAddress(1,2,0), 9.0); // B3
6494 //m_pDoc->SetString(ScAddress(2,2,0), "C3"); // C3
6495 m_pDoc->SetValue(ScAddress(3,2,0), 11.0); // D3
6497 // Insert matrix formula to A1
6498 ScMarkData aMark;
6499 aMark.SelectOneTable(0);
6500 m_pDoc->InsertMatrixFormula(0, 0, 0, 0, aMark, "=COUNTIF(ISBLANK(B1:D1);TRUE())");
6501 m_pDoc->CalcAll();
6502 // A1 should containg 0
6503 CPPUNIT_ASSERT_EQUAL( 0.0, m_pDoc->GetValue(ScAddress(0,0,0)) ); // A1
6505 // Copy cell A1 to clipboard.
6506 ScAddress aPos(0,0,0); // A1
6507 ScDocument aClipDoc(SCDOCMODE_CLIP);
6508 ScClipParam aParam(aPos, false);
6509 m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
6510 // Formula string should be equal.
6511 CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
6513 // First try single range.
6514 // Paste matrix formula to A2
6515 pasteFromClip(m_pDoc, ScRange(0,1,0,0,1,0), &aClipDoc); // A2
6516 // A2 Cell value should contain 1.0
6517 CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
6519 // Paste matrix formula to A3
6520 pasteFromClip(m_pDoc, ScRange(0,2,0,0,2,0), &aClipDoc); // A3
6521 // A3 Cell value should contain 2.0
6522 CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,2,0)));
6524 // Paste matrix formula to A4
6525 pasteFromClip(m_pDoc, ScRange(0,3,0,0,3,0), &aClipDoc); // A4
6526 // A4 Cell value should contain 3.0
6527 CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,3,0)));
6529 // Clear cell A2:A4
6530 clearRange(m_pDoc, ScRange(0,1,0,0,3,0));
6532 // Paste matrix formula to range A2:A4
6533 pasteFromClip(m_pDoc, ScRange(0,1,0,0,3,0), &aClipDoc); // A2:A4
6535 // A2 Cell value should contain 1.0
6536 CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
6537 // A3 Cell value should contain 2.0
6538 CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,2,0)));
6539 // A4 Cell value should contain 3.0
6540 CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,3,0)));
6542 m_pDoc->DeleteTab(0);
6545 void Test::testUndoDataAnchor()
6547 m_pDoc->InsertTab(0, "Tab1");
6548 CPPUNIT_ASSERT_MESSAGE("There should be only 1 sheets to begin with", m_pDoc->GetTableCount() == 1);
6550 m_pDoc->InitDrawLayer();
6551 ScDrawLayer* pDrawLayer = m_pDoc->GetDrawLayer();
6552 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer);
6553 SdrPage* pPage = pDrawLayer->GetPage(0);
6554 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage);
6556 // Insert an object.
6557 Rectangle aObjRect(2,1000,100,1100);
6558 SdrObject* pObj = new SdrRectObj(aObjRect);
6559 pPage->InsertObject(pObj);
6560 ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
6562 // Get anchor data
6563 ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj, false);
6564 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
6566 ScAddress aOldStart = pData->maStart;
6567 ScAddress aOldEnd = pData->maEnd;
6569 // Get non rotated anchor data
6570 ScDrawObjData* pNData = ScDrawLayer::GetNonRotatedObjData( pObj );
6571 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
6573 ScAddress aNOldStart = pNData->maStart;
6574 ScAddress aNOldEnd = pNData->maEnd;
6575 CPPUNIT_ASSERT_EQUAL(aOldStart, aNOldStart);
6576 CPPUNIT_ASSERT_EQUAL(aOldEnd, aNOldEnd);
6578 //pDrawLayer->BeginCalcUndo(false);
6579 // Insert a new row at row 3.
6580 ScDocFunc& rFunc = getDocShell().GetDocFunc();
6581 ScMarkData aMark;
6582 aMark.SelectOneTable(0);
6583 rFunc.InsertCells(ScRange( 0, aOldStart.Row() - 1, 0, MAXCOL, aOldStart.Row(), 0 ), &aMark, INS_INSROWS, true, true, false);
6585 pData = ScDrawLayer::GetObjData(pObj, false);
6586 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
6588 ScAddress aNewStart = pData->maStart;
6589 ScAddress aNewEnd = pData->maEnd;
6591 // Get non rotated anchor data
6592 pNData = ScDrawLayer::GetNonRotatedObjData( pObj );
6593 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
6595 ScAddress aNNewStart = pNData->maStart;
6596 ScAddress aNNewEnd = pNData->maEnd;
6597 CPPUNIT_ASSERT_EQUAL(aNewStart, aNNewStart);
6598 CPPUNIT_ASSERT_EQUAL(aNewEnd, aNNewEnd);
6599 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewStart != aOldStart && aNewEnd != aOldEnd &&
6600 aNNewStart != aNOldStart && aNNewEnd != aNOldEnd );
6602 SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6603 CPPUNIT_ASSERT(pUndoMgr);
6604 pUndoMgr->Undo();
6606 // Check state
6607 ScAnchorType oldType = ScDrawLayer::GetAnchorType(*pObj);
6608 CPPUNIT_ASSERT_MESSAGE( "Failed to check state SCA_CELL.", oldType == SCA_CELL );
6610 // Get anchor data
6611 pData = ScDrawLayer::GetObjData(pObj, false);
6612 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
6614 // Get non rotated anchor data
6615 pNData = ScDrawLayer::GetNonRotatedObjData( pObj );
6616 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
6618 // Check if data has moved to new rows
6619 CPPUNIT_ASSERT_EQUAL(pData->maStart, aOldStart);
6620 CPPUNIT_ASSERT_EQUAL(pData->maEnd, aOldEnd);
6622 CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNOldStart);
6623 CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNOldEnd);
6625 pUndoMgr->Redo();
6627 // Get anchor data
6628 pData = ScDrawLayer::GetObjData(pObj, false);
6629 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
6631 // Get non rotated anchor data
6632 pNData = ScDrawLayer::GetNonRotatedObjData( pObj );
6633 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
6635 // Check if data has moved to new rows
6636 CPPUNIT_ASSERT_EQUAL(pData->maStart, aNewStart);
6637 CPPUNIT_ASSERT_EQUAL(pData->maEnd, aNewEnd);
6639 CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNNewStart);
6640 CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNNewEnd);
6642 m_pDoc->DeleteTab(0);
6645 ScDocShell* Test::findLoadedDocShellByName(const OUString& rName)
6647 TypeId aType(TYPE(ScDocShell));
6648 ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(&aType, false));
6649 while (pShell)
6651 SfxMedium* pMedium = pShell->GetMedium();
6652 if (pMedium)
6654 OUString aName = pMedium->GetName();
6655 if (aName.equals(rName))
6656 return pShell;
6658 pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, &aType, false));
6660 return NULL;
6663 bool Test::insertRangeNames(
6664 ScDocument* pDoc, ScRangeName* pNames, const RangeNameDef* p, const RangeNameDef* pEnd)
6666 ScAddress aA1(0, 0, 0);
6667 for (; p != pEnd; ++p)
6669 ScRangeData* pNew = new ScRangeData(
6670 pDoc,
6671 OUString::createFromAscii(p->mpName),
6672 OUString::createFromAscii(p->mpExpr),
6673 aA1, 0, formula::FormulaGrammar::GRAM_ENGLISH);
6674 pNew->SetIndex(p->mnIndex);
6675 bool bSuccess = pNames->insert(pNew);
6676 if (!bSuccess)
6678 cerr << "Insertion failed." << endl;
6679 return false;
6683 return true;
6686 void Test::printRange(ScDocument* pDoc, const ScRange& rRange, const char* pCaption)
6688 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
6689 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
6690 svl::GridPrinter printer(nRow2 - nRow1 + 1, nCol2 - nCol1 + 1, CALC_DEBUG_OUTPUT != 0);
6691 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
6693 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
6695 OUString aVal = pDoc->GetString(nCol, nRow, rRange.aStart.Tab());
6696 printer.set(nRow-nRow1, nCol-nCol1, aVal);
6699 printer.print(pCaption);
6702 void Test::clearRange(ScDocument* pDoc, const ScRange& rRange)
6704 ScMarkData aMarkData;
6705 aMarkData.SetMarkArea(rRange);
6706 pDoc->DeleteArea(
6707 rRange.aStart.Col(), rRange.aStart.Row(),
6708 rRange.aEnd.Col(), rRange.aEnd.Row(), aMarkData, IDF_CONTENTS);
6711 void Test::clearSheet(ScDocument* pDoc, SCTAB nTab)
6713 ScRange aRange(0,0,nTab,MAXCOL,MAXROW,nTab);
6714 clearRange(pDoc, aRange);
6717 void Test::copyToClip(ScDocument* pSrcDoc, const ScRange& rRange, ScDocument* pClipDoc)
6719 ScClipParam aClipParam(rRange, false);
6720 ScMarkData aMark;
6721 aMark.SetMarkArea(rRange);
6722 pSrcDoc->CopyToClip(aClipParam, pClipDoc, &aMark);
6725 void Test::pasteFromClip(ScDocument* pDestDoc, const ScRange& rDestRange, ScDocument* pClipDoc)
6727 ScMarkData aMark;
6728 aMark.SetMarkArea(rDestRange);
6729 pDestDoc->CopyFromClip(rDestRange, aMark, IDF_ALL, NULL, pClipDoc);
6732 ScUndoPaste* Test::createUndoPaste(ScDocShell& rDocSh, const ScRange& rRange, ScDocument* pUndoDoc)
6734 ScDocument& rDoc = rDocSh.GetDocument();
6735 ScMarkData aMarkData;
6736 aMarkData.SetMarkArea(rRange);
6737 ScRefUndoData* pRefUndoData = new ScRefUndoData(&rDoc);
6739 return new ScUndoPaste(
6740 &rDocSh, rRange, aMarkData, pUndoDoc, NULL, IDF_ALL, pRefUndoData, false);
6743 void Test::setExpandRefs(bool bExpand)
6745 ScModule* pMod = SC_MOD();
6746 ScInputOptions aOpt = pMod->GetInputOptions();
6747 aOpt.SetExpandRefs(bExpand);
6748 pMod->SetInputOptions(aOpt);
6751 void Test::setCalcAsShown(ScDocument* pDoc, bool bCalcAsShown)
6753 ScDocOptions aOpt = pDoc->GetDocOptions();
6754 aOpt.SetCalcAsShown(bCalcAsShown);
6755 pDoc->SetDocOptions(aOpt);
6758 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
6760 CPPUNIT_PLUGIN_IMPLEMENT();
6762 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */