1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include "helper/debughelper.hxx"
11 #include "helper/qahelper.hxx"
13 #include <svl/asiancfg.hxx>
15 #include <simpleformulacalc.hxx>
16 #include <stringutil.hxx>
17 #include <scmatrix.hxx>
18 #include <scitems.hxx>
19 #include <reffind.hxx>
20 #include <clipparam.hxx>
21 #include <undoblk.hxx>
22 #include <undotab.hxx>
25 #include <reftokenhelper.hxx>
26 #include <userdat.hxx>
27 #include <refdata.hxx>
29 #include <docfunc.hxx>
30 #include <funcdesc.hxx>
32 #include <columniterator.hxx>
33 #include <scopetools.hxx>
34 #include <dociter.hxx>
35 #include <edittextiterator.hxx>
36 #include <editutil.hxx>
37 #include <asciiopt.hxx>
39 #include <docpool.hxx>
40 #include <globalnames.hxx>
41 #include <columnspanset.hxx>
43 #include <editable.hxx>
45 #include <tabprotection.hxx>
46 #include <undomanager.hxx>
48 #include <formula/IFunctionDescription.hxx>
50 #include <editeng/borderline.hxx>
51 #include <editeng/brushitem.hxx>
52 #include <editeng/eeitem.hxx>
53 #include <editeng/wghtitem.hxx>
54 #include <editeng/postitem.hxx>
55 #include <editeng/lineitem.hxx>
57 #include <svx/svdpage.hxx>
58 #include <svx/svdocirc.hxx>
59 #include <svx/svdopath.hxx>
60 #include <svx/svdocapt.hxx>
61 #include <svl/numformat.hxx>
62 #include <svl/srchitem.hxx>
63 #include <svl/sharedstringpool.hxx>
64 #include <unotools/collatorwrapper.hxx>
66 #include <sfx2/sfxsids.hrc>
82 class Test
: public ScUcalcTestBase
85 void checkPrecisionAsShown(OUString
& rCode
, double fValue
, double fExpectedRoundVal
);
87 /** Get a separate new ScDocShell with ScDocument that suits unit test needs. */
88 void getNewDocShell(ScDocShellRef
& rDocShellRef
);
91 void testSharedStringPool();
92 void testSharedStringPoolUndoDoc();
96 void testColumnIterator();
100 void testTdf134490();
101 void testTdf135249();
102 void testDocStatistics();
103 void testRowForHeight();
106 * The 'data entries' data is a list of strings used for suggestions as
107 * the user types in new cell value.
109 void testDataEntries();
112 * Selection function is responsible for displaying quick calculation
113 * results in the status bar.
115 void testSelectionFunction();
117 void testMarkedCellIteration();
119 void testCopyToDocument();
121 void testHorizontalIterator();
122 void testValueIterator();
123 void testHorizontalAttrIterator();
124 void testIteratorsUnallocatedColumnsAttributes();
125 void testIteratorsDefPattern();
126 void testLastChangedColFlagsWidth();
129 * More direct test for cell broadcaster management, used to track formula
132 void testCellBroadcaster();
134 void testFuncParam();
135 void testNamedRange();
136 void testInsertNameList();
139 void testMatrixComparisonWithErrors();
140 void testMatrixConditionalBooleanResult();
141 void testEnterMixedMatrix();
142 void testMatrixEditable();
145 void testSheetCopy();
146 void testSheetMove();
148 void testAutofilter();
149 void testAutoFilterTimeValue();
150 void testAutofilterOptimizations();
153 void testTdf142186();
154 void testTdf137063();
155 void testTdf126342();
156 void testAdvancedFilter();
157 void testDateFilterContains();
159 void testMergedCells();
160 void testUpdateReference();
161 void testSearchCells();
162 void testFormulaPosition();
163 void testFormulaWizardSubformula();
164 void testDiagonalBorders();
165 void testWholeDocBorders();
168 * Make sure the sheet streams are invalidated properly.
170 void testStreamValid();
173 * Test built-in cell functions to make sure their categories and order
176 void testFunctionLists();
178 void testGraphicsInGroup();
179 void testGraphicsOnSheetMove();
182 * Test toggling relative/absolute flag of cell and cell range references.
183 * This corresponds with hitting Shift-F4 while the cursor is on a formula
186 void testToggleRefFlag();
189 * Test to make sure correct precedent / dependent cells are obtained when
190 * preparing to jump to them.
192 void testJumpToPrecedentsDependents();
194 void testSetBackgroundColor();
195 void testRenameTable();
197 void testTdf149665();
200 void testAutoFillSimple();
202 void testFindAreaPosVertical();
203 void testFindAreaPosColRight();
204 void testShiftCells();
206 void testNoteBasic();
207 void testNoteDeleteRow();
208 void testNoteDeleteCol();
209 void testNoteLifeCycle();
210 void testNoteCopyPaste();
211 void testNoteContainsNotesInRange();
212 void testAreasWithNotes();
213 void testAnchoredRotatedShape();
214 void testCellTextWidth();
215 void testEditTextIterator();
217 void testImportStream();
218 void testDeleteContents();
219 void testTransliterateText();
221 void testFormulaToValue();
222 void testFormulaToValue2();
224 void testColumnFindEditCells();
225 void testSetStringAndNote();
227 void testUndoDataAnchor();
228 void testSetFormula();
229 void testMultipleDataCellsInRange();
231 void testEmptyCalcDocDefaults();
233 void testPrecisionAsShown();
234 void testProtectedSheetEditByRow();
235 void testProtectedSheetEditByColumn();
237 void testInsertColumnsWithFormulaCells();
239 CPPUNIT_TEST_SUITE(Test
);
240 CPPUNIT_TEST(testCollator
);
241 CPPUNIT_TEST(testSharedStringPool
);
242 CPPUNIT_TEST(testSharedStringPoolUndoDoc
);
243 CPPUNIT_TEST(testRangeList
);
244 CPPUNIT_TEST(testMarkData
);
245 CPPUNIT_TEST(testInput
);
246 CPPUNIT_TEST(testColumnIterator
);
247 CPPUNIT_TEST(testTdf90698
);
248 CPPUNIT_TEST(testTdf114406
);
249 CPPUNIT_TEST(testTdf93951
);
250 CPPUNIT_TEST(testTdf134490
);
251 CPPUNIT_TEST(testTdf135249
);
252 CPPUNIT_TEST(testDocStatistics
);
253 CPPUNIT_TEST(testRowForHeight
);
254 CPPUNIT_TEST(testDataEntries
);
255 CPPUNIT_TEST(testSelectionFunction
);
256 CPPUNIT_TEST(testMarkedCellIteration
);
257 CPPUNIT_TEST(testCopyToDocument
);
258 CPPUNIT_TEST(testHorizontalIterator
);
259 CPPUNIT_TEST(testValueIterator
);
260 CPPUNIT_TEST(testHorizontalAttrIterator
);
261 CPPUNIT_TEST(testIteratorsUnallocatedColumnsAttributes
);
262 CPPUNIT_TEST(testIteratorsDefPattern
);
263 CPPUNIT_TEST(testLastChangedColFlagsWidth
);
264 CPPUNIT_TEST(testCellBroadcaster
);
265 CPPUNIT_TEST(testFuncParam
);
266 CPPUNIT_TEST(testNamedRange
);
267 CPPUNIT_TEST(testInsertNameList
);
268 CPPUNIT_TEST(testCSV
);
269 CPPUNIT_TEST(testMatrix
);
270 CPPUNIT_TEST(testMatrixComparisonWithErrors
);
271 CPPUNIT_TEST(testMatrixConditionalBooleanResult
);
272 CPPUNIT_TEST(testEnterMixedMatrix
);
273 CPPUNIT_TEST(testMatrixEditable
);
274 CPPUNIT_TEST(testCellCopy
);
275 CPPUNIT_TEST(testSheetCopy
);
276 CPPUNIT_TEST(testSheetMove
);
277 CPPUNIT_TEST(testDataArea
);
278 CPPUNIT_TEST(testGraphicsInGroup
);
279 CPPUNIT_TEST(testGraphicsOnSheetMove
);
280 CPPUNIT_TEST(testStreamValid
);
281 CPPUNIT_TEST(testFunctionLists
);
282 CPPUNIT_TEST(testToggleRefFlag
);
283 CPPUNIT_TEST(testAutofilter
);
284 CPPUNIT_TEST(testAutoFilterTimeValue
);
285 CPPUNIT_TEST(testAutofilterOptimizations
);
286 CPPUNIT_TEST(testTdf76836
);
287 CPPUNIT_TEST(testTdf76441
);
288 CPPUNIT_TEST(testTdf142186
);
289 CPPUNIT_TEST(testTdf137063
);
290 CPPUNIT_TEST(testTdf126342
);
291 CPPUNIT_TEST(testAdvancedFilter
);
292 CPPUNIT_TEST(testDateFilterContains
);
293 CPPUNIT_TEST(testTdf98642
);
294 CPPUNIT_TEST(testMergedCells
);
295 CPPUNIT_TEST(testUpdateReference
);
296 CPPUNIT_TEST(testSearchCells
);
297 CPPUNIT_TEST(testFormulaPosition
);
298 CPPUNIT_TEST(testFormulaWizardSubformula
);
299 CPPUNIT_TEST(testDiagonalBorders
);
300 CPPUNIT_TEST(testWholeDocBorders
);
301 CPPUNIT_TEST(testJumpToPrecedentsDependents
);
302 CPPUNIT_TEST(testSetBackgroundColor
);
303 CPPUNIT_TEST(testRenameTable
);
304 CPPUNIT_TEST(testTdf149665
);
305 CPPUNIT_TEST(testTdf64001
);
306 CPPUNIT_TEST(testAutoFill
);
307 CPPUNIT_TEST(testAutoFillSimple
);
308 CPPUNIT_TEST(testFindAreaPosVertical
);
309 CPPUNIT_TEST(testFindAreaPosColRight
);
310 CPPUNIT_TEST(testShiftCells
);
311 CPPUNIT_TEST(testNoteBasic
);
312 CPPUNIT_TEST(testNoteDeleteRow
);
313 CPPUNIT_TEST(testNoteDeleteCol
);
314 CPPUNIT_TEST(testNoteLifeCycle
);
315 CPPUNIT_TEST(testNoteCopyPaste
);
316 CPPUNIT_TEST(testNoteContainsNotesInRange
);
317 CPPUNIT_TEST(testAreasWithNotes
);
318 CPPUNIT_TEST(testAnchoredRotatedShape
);
319 CPPUNIT_TEST(testCellTextWidth
);
320 CPPUNIT_TEST(testEditTextIterator
);
321 CPPUNIT_TEST(testImportStream
);
322 CPPUNIT_TEST(testDeleteContents
);
323 CPPUNIT_TEST(testTransliterateText
);
324 CPPUNIT_TEST(testFormulaToValue
);
325 CPPUNIT_TEST(testFormulaToValue2
);
326 CPPUNIT_TEST(testColumnFindEditCells
);
327 CPPUNIT_TEST(testSetStringAndNote
);
328 CPPUNIT_TEST(testUndoDataAnchor
);
329 CPPUNIT_TEST(testSetFormula
);
330 CPPUNIT_TEST(testMultipleDataCellsInRange
);
331 CPPUNIT_TEST(testEmptyCalcDocDefaults
);
332 CPPUNIT_TEST(testPrecisionAsShown
);
333 CPPUNIT_TEST(testProtectedSheetEditByRow
);
334 CPPUNIT_TEST(testProtectedSheetEditByColumn
);
335 CPPUNIT_TEST(testInsertColumnsWithFormulaCells
);
336 CPPUNIT_TEST_SUITE_END();
339 bool checkHorizontalIterator(ScDocument
& rDoc
, const std::vector
<std::vector
<const char*>>& rData
,
340 const HoriIterCheck
* pChecks
, size_t nCheckCount
);
343 void Test::getNewDocShell( ScDocShellRef
& rDocShellRef
)
345 rDocShellRef
= new ScDocShell(
346 SfxModelFlags::EMBEDDED_OBJECT
|
347 SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS
|
348 SfxModelFlags::DISABLE_DOCUMENT_RECOVERY
);
350 rDocShellRef
->DoInitUnitTest();
353 void Test::testCollator()
355 sal_Int32 nRes
= ScGlobal::GetCollator().compareString("A", "B");
356 CPPUNIT_ASSERT_MESSAGE("these strings are supposed to be different!", nRes
!= 0);
359 void Test::testSharedStringPool()
361 m_pDoc
->InsertTab(0, "foo");
363 svl::SharedStringPool
& rPool
= m_pDoc
->GetSharedStringPool();
364 size_t extraCount
= rPool
.getCount(); // internal items such as SharedString::getEmptyString()
365 size_t extraCountIgnoreCase
= rPool
.getCountIgnoreCase();
367 // Strings that are identical.
368 m_pDoc
->SetString(ScAddress(0,0,0), "Andy"); // A1
369 m_pDoc
->SetString(ScAddress(0,1,0), "Andy"); // A2
370 m_pDoc
->SetString(ScAddress(0,2,0), "Bruce"); // A3
371 m_pDoc
->SetString(ScAddress(0,3,0), "andy"); // A4
372 m_pDoc
->SetString(ScAddress(0,4,0), "BRUCE"); // A5
375 // These two shared string objects must go out of scope before the purge test.
376 svl::SharedString aSS1
= m_pDoc
->GetSharedString(ScAddress(0,0,0));
377 svl::SharedString aSS2
= m_pDoc
->GetSharedString(ScAddress(0,1,0));
378 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS1
.isValid());
379 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS2
.isValid());
380 CPPUNIT_ASSERT_EQUAL(aSS1
.getData(), aSS2
.getData());
382 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,2,0));
383 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
385 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,3,0));
386 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
388 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,4,0));
389 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
391 // A3 and A5 should differ but should be equal case-insensitively.
392 aSS1
= m_pDoc
->GetSharedString(ScAddress(0,2,0));
393 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,4,0));
394 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
395 CPPUNIT_ASSERT_EQUAL_MESSAGE("They must be equal when cases are ignored.", aSS1
.getDataIgnoreCase(), aSS2
.getDataIgnoreCase());
397 // A2 and A4 should be equal when ignoring cases.
398 aSS1
= m_pDoc
->GetSharedString(ScAddress(0,1,0));
399 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,3,0));
400 CPPUNIT_ASSERT_EQUAL_MESSAGE("They must be equal when cases are ignored.", aSS1
.getDataIgnoreCase(), aSS2
.getDataIgnoreCase());
403 // Check the string counts after purging. Purging shouldn't remove any strings in this case.
405 CPPUNIT_ASSERT_EQUAL(5+extraCount
, rPool
.getCount());
406 CPPUNIT_ASSERT_EQUAL(2+extraCountIgnoreCase
, rPool
.getCountIgnoreCase());
409 clearRange(m_pDoc
, ScAddress(0,0,0));
411 clearRange(m_pDoc
, ScAddress(0,1,0));
413 clearRange(m_pDoc
, ScAddress(0,2,0));
415 clearRange(m_pDoc
, ScAddress(0,3,0));
416 // Clear A5 and the pool should be completely empty.
417 clearRange(m_pDoc
, ScAddress(0,4,0));
419 CPPUNIT_ASSERT_EQUAL(extraCount
, rPool
.getCount());
420 CPPUNIT_ASSERT_EQUAL(extraCountIgnoreCase
, rPool
.getCountIgnoreCase());
422 // Now, compare string and edit text cells.
423 m_pDoc
->SetString(ScAddress(0,0,0), "Andy and Bruce"); // A1
424 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
425 rEE
.SetTextCurrentDefaults("Andy and Bruce");
428 aSel
.nStartPara
= aSel
.nEndPara
= 0;
432 SfxItemSet aItemSet
= rEE
.GetEmptyItemSet();
435 SvxWeightItem
aWeight(WEIGHT_BOLD
, EE_CHAR_WEIGHT
);
436 aItemSet
.Put(aWeight
);
437 rEE
.QuickSetAttribs(aItemSet
, aSel
);
441 // Set 'Bruce' italic.
442 SfxItemSet aItemSet
= rEE
.GetEmptyItemSet();
443 SvxPostureItem
aItalic(ITALIC_NORMAL
, EE_CHAR_ITALIC
);
444 aItemSet
.Put(aItalic
);
447 rEE
.QuickSetAttribs(aItemSet
, aSel
);
450 m_pDoc
->SetEditText(ScAddress(1,0,0), rEE
.CreateTextObject()); // B1
452 // These two should be equal.
453 svl::SharedString aSS1
= m_pDoc
->GetSharedString(ScAddress(0,0,0));
454 svl::SharedString aSS2
= m_pDoc
->GetSharedString(ScAddress(1,0,0));
455 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1
.isValid());
456 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2
.isValid());
457 CPPUNIT_ASSERT_EQUAL(aSS1
.getData(), aSS2
.getData());
459 rEE
.SetTextCurrentDefaults("ANDY and BRUCE");
460 m_pDoc
->SetEditText(ScAddress(2,0,0), rEE
.CreateTextObject()); // C1
461 aSS2
= m_pDoc
->GetSharedString(ScAddress(2,0,0));
462 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2
.isValid());
463 CPPUNIT_ASSERT_MESSAGE("These two should be different when cases are considered.", aSS1
.getData() != aSS2
.getData());
465 // But they should be considered equal when cases are ignored.
466 aSS1
= m_pDoc
->GetSharedString(ScAddress(0,0,0));
467 aSS2
= m_pDoc
->GetSharedString(ScAddress(2,0,0));
468 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1
.isValid());
469 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2
.isValid());
470 CPPUNIT_ASSERT_EQUAL(aSS1
.getDataIgnoreCase(), aSS2
.getDataIgnoreCase());
472 m_pDoc
->DeleteTab(0);
475 void Test::testSharedStringPoolUndoDoc()
479 bool check( const ScDocument
& rSrcDoc
, ScDocument
& rCopyDoc
)
481 // Copy A1:A4 to the undo document.
482 for (SCROW i
= 0; i
<= 4; ++i
)
484 ScAddress
aPos(0,i
,0);
485 rCopyDoc
.SetString(aPos
, rSrcDoc
.GetString(aPos
));
488 // String values in A1:A4 should have identical hash.
489 for (SCROW i
= 0; i
<= 4; ++i
)
491 ScAddress
aPos(0,i
,0);
492 svl::SharedString aSS1
= rSrcDoc
.GetSharedString(aPos
);
493 svl::SharedString aSS2
= rCopyDoc
.GetSharedString(aPos
);
494 if (aSS1
.getDataIgnoreCase() != aSS2
.getDataIgnoreCase())
496 cerr
<< "String hash values are not equal at row " << (i
+1)
497 << " for string '" << aSS1
.getString() << "'" << endl
;
507 m_pDoc
->InsertTab(0, "Test");
509 m_pDoc
->SetString(ScAddress(0,0,0), "Header");
510 m_pDoc
->SetString(ScAddress(0,1,0), "A1");
511 m_pDoc
->SetString(ScAddress(0,2,0), "A2");
512 m_pDoc
->SetString(ScAddress(0,3,0), "A3");
514 ScDocument
aUndoDoc(SCDOCMODE_UNDO
);
515 aUndoDoc
.InitUndo(*m_pDoc
, 0, 0);
517 bool bSuccess
= aTest
.check(*m_pDoc
, aUndoDoc
);
518 CPPUNIT_ASSERT_MESSAGE("Check failed with undo document.", bSuccess
);
520 // Test the clip document as well.
521 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
522 aClipDoc
.ResetClip(m_pDoc
, static_cast<SCTAB
>(0));
524 bSuccess
= aTest
.check(*m_pDoc
, aClipDoc
);
525 CPPUNIT_ASSERT_MESSAGE("Check failed with clip document.", bSuccess
);
527 m_pDoc
->DeleteTab(0);
530 void Test::testRangeList()
532 m_pDoc
->InsertTab(0, "foo");
535 aRL
.push_back(ScRange(1,1,0,3,10,0));
536 CPPUNIT_ASSERT_EQUAL_MESSAGE("List should have one range.", size_t(1), aRL
.size());
537 const ScRange
* p
= &aRL
[0];
538 CPPUNIT_ASSERT_MESSAGE("Failed to get the range object.", p
);
539 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong range.", ScAddress(1,1,0), p
->aStart
);
540 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong range.", ScAddress(3,10,0), p
->aEnd
);
542 // TODO: Add more tests here.
544 m_pDoc
->DeleteTab(0);
547 void Test::testMarkData()
549 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
551 // Empty mark. Nothing is selected.
552 std::vector
<sc::ColRowSpan
> aSpans
= aMarkData
.GetMarkedRowSpans();
553 CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans
.empty());
554 aSpans
= aMarkData
.GetMarkedColSpans();
555 CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans
.empty());
558 aMarkData
.SetMarkArea(ScRange(1,2,0,5,6,0));
559 aSpans
= aMarkData
.GetMarkedRowSpans();
560 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected row span.", size_t(1), aSpans
.size());
561 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(2), aSpans
[0].mnStart
);
562 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(6), aSpans
[0].mnEnd
);
564 aSpans
= aMarkData
.GetMarkedColSpans();
565 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected column span.", size_t(1), aSpans
.size());
566 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(1), aSpans
[0].mnStart
);
567 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(5), aSpans
[0].mnEnd
);
570 aMarkData
.SetMultiMarkArea(ScRange(0,10,0,1,12,0));
571 aSpans
= aMarkData
.GetMarkedRowSpans();
572 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 2 selected row spans.", size_t(2), aSpans
.size());
573 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(2), aSpans
[0].mnStart
);
574 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(6), aSpans
[0].mnEnd
);
575 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(10), aSpans
[1].mnStart
);
576 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(12), aSpans
[1].mnEnd
);
578 aSpans
= aMarkData
.GetMarkedColSpans();
579 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected column span.", size_t(1), aSpans
.size());
580 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(0), aSpans
[0].mnStart
);
581 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(5), aSpans
[0].mnEnd
);
584 aMarkData
.SetMultiMarkArea(ScRange(2,7,0,2,9,0));
585 aSpans
= aMarkData
.GetMarkedRowSpans();
586 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected row span.", size_t(1), aSpans
.size());
587 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(2), aSpans
[0].mnStart
);
588 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(12), aSpans
[0].mnEnd
);
590 aSpans
= aMarkData
.GetMarkedColSpans();
591 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected column span.", size_t(1), aSpans
.size());
592 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(0), aSpans
[0].mnStart
);
593 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(5), aSpans
[0].mnEnd
);
596 void Test::testInput()
599 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
600 m_pDoc
->InsertTab (0, "foo"));
603 m_pDoc
->SetString(0, 0, 0, "'10.5");
604 test
= m_pDoc
->GetString(0, 0, 0);
605 bool bTest
= test
== "10.5";
606 CPPUNIT_ASSERT_MESSAGE("String number should have the first apostrophe stripped.", bTest
);
607 m_pDoc
->SetString(0, 0, 0, "'apple'");
608 test
= m_pDoc
->GetString(0, 0, 0);
609 bTest
= test
== "apple'";
610 CPPUNIT_ASSERT_MESSAGE("Text content should have the first apostrophe stripped.", bTest
);
612 // Customized string handling policy.
613 ScSetStringParam aParam
;
614 aParam
.setTextInput();
615 m_pDoc
->SetString(0, 0, 0, "000123", &aParam
);
616 test
= m_pDoc
->GetString(0, 0, 0);
617 CPPUNIT_ASSERT_EQUAL_MESSAGE("Text content should have been treated as string, not number.", OUString("000123"), test
);
619 m_pDoc
->DeleteTab(0);
622 void Test::testColumnIterator() // tdf#118620
624 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
625 m_pDoc
->InsertTab (0, "foo"));
627 m_pDoc
->SetString(0, 0, 0, "'10.5");
628 m_pDoc
->SetString(0, m_pDoc
->MaxRow()-5, 0, "42.0");
629 std::optional
<sc::ColumnIterator
> it
= m_pDoc
->GetColumnIterator(0, 0, m_pDoc
->MaxRow() - 10, m_pDoc
->MaxRow());
630 while (it
->hasCell())
636 m_pDoc
->DeleteTab(0);
639 void Test::testTdf90698()
641 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
642 m_pDoc
->SetString(ScAddress(0,0,0), "=(1;2)");
644 // Without the fix in place, this would have failed with
645 // - Expected: =(1;2)
647 OUString aFormula
= m_pDoc
->GetFormula(0,0,0);
648 CPPUNIT_ASSERT_EQUAL(OUString("=(1;2)"), aFormula
);
650 m_pDoc
->DeleteTab(0);
653 void Test::testTdf114406()
655 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
656 m_pDoc
->SetString(ScAddress(0,0,0), "5");
657 m_pDoc
->SetString(ScAddress(1,0,0), "=A1/100%");
659 // Without the fix in place, this would have failed with
660 // - Expected: =A1/100%
662 OUString aFormula
= m_pDoc
->GetFormula(1,0,0);
663 CPPUNIT_ASSERT_EQUAL(OUString("=A1/100%"), aFormula
);
665 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
667 m_pDoc
->DeleteTab(0);
670 void Test::testTdf93951()
672 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
673 m_pDoc
->SetString(ScAddress(0,0,0), u
"=2*§*2");
675 OUString aFormula
= m_pDoc
->GetFormula(0,0,0);
677 // Without the fix in place, this test would have failed with
678 // - Expected: =2*§*2
680 CPPUNIT_ASSERT_EQUAL(OUString(u
"=2*§*2"), aFormula
);
682 m_pDoc
->DeleteTab(0);
685 void Test::testTdf134490()
687 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
689 m_pDoc
->SetString(ScAddress(0,0,0), "--1");
690 m_pDoc
->SetString(ScAddress(0,1,0), "---1");
691 m_pDoc
->SetString(ScAddress(0,2,0), "+-1");
692 m_pDoc
->SetString(ScAddress(0,3,0), "+--1");
694 // Without the fix in place, this test would have failed with
697 CPPUNIT_ASSERT_EQUAL(OUString("--1"), m_pDoc
->GetString(ScAddress(0,0,0)));
698 CPPUNIT_ASSERT_EQUAL(OUString("---1"), m_pDoc
->GetString(ScAddress(0,1,0)));
699 CPPUNIT_ASSERT_EQUAL(OUString("+-1"), m_pDoc
->GetString(ScAddress(0,2,0)));
700 CPPUNIT_ASSERT_EQUAL(OUString("+--1"), m_pDoc
->GetString(ScAddress(0,3,0)));
702 m_pDoc
->DeleteTab(0);
705 void Test::testTdf135249()
707 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, "Test"));
709 m_pDoc
->SetString(ScAddress(0,0,0), "1:60");
710 m_pDoc
->SetString(ScAddress(0,1,0), "1:123");
711 m_pDoc
->SetString(ScAddress(0,2,0), "1:1:123");
712 m_pDoc
->SetString(ScAddress(0,3,0), "0:123");
713 m_pDoc
->SetString(ScAddress(0,4,0), "0:0:123");
714 m_pDoc
->SetString(ScAddress(0,5,0), "0:123:59");
716 // These are not valid duration inputs
717 CPPUNIT_ASSERT_EQUAL(OUString("1:60"), m_pDoc
->GetString(ScAddress(0,0,0)));
718 CPPUNIT_ASSERT_EQUAL(OUString("1:123"), m_pDoc
->GetString(ScAddress(0,1,0)));
719 CPPUNIT_ASSERT_EQUAL(OUString("1:1:123"), m_pDoc
->GetString(ScAddress(0,2,0)));
721 // These are valid duration inputs
722 // Without the fix in place, this test would have failed with
723 // - Expected: 02:03:00 AM
725 CPPUNIT_ASSERT_EQUAL(OUString("02:03:00 AM"), m_pDoc
->GetString(ScAddress(0,3,0)));
726 CPPUNIT_ASSERT_EQUAL(OUString("12:02:03 AM"), m_pDoc
->GetString(ScAddress(0,4,0)));
727 CPPUNIT_ASSERT_EQUAL(OUString("02:03:59 AM"), m_pDoc
->GetString(ScAddress(0,5,0)));
729 m_pDoc
->DeleteTab(0);
732 void Test::testDocStatistics()
734 SCTAB nStartTabs
= m_pDoc
->GetTableCount();
735 m_pDoc
->InsertTab(0, "Sheet1");
736 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to increment sheet count.",
737 static_cast<SCTAB
>(nStartTabs
+1), m_pDoc
->GetTableCount());
738 m_pDoc
->InsertTab(1, "Sheet2");
739 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to increment sheet count.",
740 static_cast<SCTAB
>(nStartTabs
+2), m_pDoc
->GetTableCount());
742 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(0), m_pDoc
->GetCellCount());
743 m_pDoc
->SetValue(ScAddress(0,0,0), 2.0);
744 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetCellCount());
745 m_pDoc
->SetValue(ScAddress(2,2,0), 2.5);
746 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(2), m_pDoc
->GetCellCount());
747 m_pDoc
->SetString(ScAddress(1,1,1), "Test");
748 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(3), m_pDoc
->GetCellCount());
750 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(0), m_pDoc
->GetFormulaGroupCount());
751 m_pDoc
->SetString(ScAddress(3,0,1), "=A1");
752 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetFormulaGroupCount());
753 m_pDoc
->SetString(ScAddress(3,1,1), "=A2");
754 m_pDoc
->SetString(ScAddress(3,2,1), "=A3");
755 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetFormulaGroupCount());
756 m_pDoc
->SetString(ScAddress(3,3,1), "=A5");
757 m_pDoc
->SetString(ScAddress(3,4,1), "=A6");
758 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(2), m_pDoc
->GetFormulaGroupCount());
759 m_pDoc
->SetString(ScAddress(3,1,1), "=A3");
760 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(4), m_pDoc
->GetFormulaGroupCount());
762 m_pDoc
->DeleteTab(1);
763 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to decrement sheet count.",
764 static_cast<SCTAB
>(nStartTabs
+1), m_pDoc
->GetTableCount());
765 m_pDoc
->DeleteTab(0); // This may fail in case there is only one sheet in the document.
768 void Test::testRowForHeight()
770 m_pDoc
->InsertTab(0, "Sheet1");
771 m_pDoc
->SetRowHeightRange( 0, 9, 0, 100);
772 m_pDoc
->SetRowHeightRange(10, 19, 0, 200);
773 m_pDoc
->SetRowHeightRange(20, 29, 0, 300);
776 m_pDoc
->SetRowHidden(3, 5, 0, true);
777 m_pDoc
->SetRowHidden(8, 12, 0, true);
785 std::vector
<Check
> aChecks
= {
796 for (const Check
& rCheck
: aChecks
)
798 SCROW nRow
= m_pDoc
->GetRowForHeight(0, rCheck
.nHeight
);
799 CPPUNIT_ASSERT_EQUAL(rCheck
.nRow
, nRow
);
803 void Test::testDataEntries()
805 m_pDoc
->InsertTab(0, "Test");
807 m_pDoc
->SetString(ScAddress(0,5,0), "Andy");
808 m_pDoc
->SetString(ScAddress(0,6,0), "Bruce");
809 m_pDoc
->SetString(ScAddress(0,7,0), "Charlie");
810 m_pDoc
->SetString(ScAddress(0,10,0), "Andy");
812 std::vector
<ScTypedStrData
> aEntries
;
813 m_pDoc
->GetDataEntries(0, 0, 0, aEntries
); // Try at the very top.
815 // Entries are supposed to be sorted in ascending order, and are all unique.
816 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries
.size());
817 std::vector
<ScTypedStrData
>::const_iterator it
= aEntries
.begin();
818 CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it
->GetString());
820 CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it
->GetString());
822 CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it
->GetString());
824 CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", bool(it
== aEntries
.end()));
827 m_pDoc
->GetDataEntries(0, m_pDoc
->MaxRow(), 0, aEntries
); // Try at the very bottom.
828 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries
.size());
830 // Make sure we get the same set of suggestions.
831 it
= aEntries
.begin();
832 CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it
->GetString());
834 CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it
->GetString());
836 CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it
->GetString());
838 CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", bool(it
== aEntries
.end()));
840 m_pDoc
->DeleteTab(0);
843 void Test::testSelectionFunction()
845 m_pDoc
->InsertTab(0, "Test");
847 // Insert values into B2:B4.
848 m_pDoc
->SetString(ScAddress(1,1,0), "=1"); // formula
849 m_pDoc
->SetValue(ScAddress(1,2,0), 2.0);
850 m_pDoc
->SetValue(ScAddress(1,3,0), 3.0);
852 // Insert strings into B5:B8.
853 m_pDoc
->SetString(ScAddress(1,4,0), "A");
854 m_pDoc
->SetString(ScAddress(1,5,0), "B");
855 m_pDoc
->SetString(ScAddress(1,6,0), "=\"C\""); // formula
856 m_pDoc
->SetString(ScAddress(1,7,0), "D");
858 // Insert values into D2:D4.
859 m_pDoc
->SetValue(ScAddress(3,1,0), 4.0);
860 m_pDoc
->SetValue(ScAddress(3,2,0), 5.0);
861 m_pDoc
->SetValue(ScAddress(3,3,0), 6.0);
863 // Insert edit text into D5.
864 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
865 rEE
.SetTextCurrentDefaults("Rich Text");
866 m_pDoc
->SetEditText(ScAddress(3,4,0), rEE
.CreateTextObject());
868 // Insert Another string into D6.
869 m_pDoc
->SetString(ScAddress(3,5,0), "E");
871 // Select B2:B8 & D2:D8 disjoint region.
873 aRanges
.push_back(ScRange(1,1,0,1,7,0)); // B2:B8
874 aRanges
.push_back(ScRange(3,1,0,3,7,0)); // D2:D8
875 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
876 aMark
.MarkFromRangeList(aRanges
, true);
880 ScSubTotalFunc meFunc
;
885 static const Check aChecks
[] =
887 { SUBTOTAL_FUNC_AVE
, 3.5 },
888 { SUBTOTAL_FUNC_CNT2
, 12.0 },
889 { SUBTOTAL_FUNC_CNT
, 6.0 },
890 { SUBTOTAL_FUNC_MAX
, 6.0 },
891 { SUBTOTAL_FUNC_MIN
, 1.0 },
892 { SUBTOTAL_FUNC_SUM
, 21.0 },
893 { SUBTOTAL_FUNC_SELECTION_COUNT
, 14.0 }
896 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aChecks
); ++i
)
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 // Hide rows 4 and 6 and check the results again.
907 m_pDoc
->SetRowHidden(3, 3, 0, true);
908 m_pDoc
->SetRowHidden(5, 5, 0, true);
909 CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc
->RowHidden(3, 0));
910 CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc
->RowHidden(5, 0));
913 static const Check aChecks
[] =
915 { SUBTOTAL_FUNC_AVE
, 3.0 },
916 { SUBTOTAL_FUNC_CNT2
, 8.0 },
917 { SUBTOTAL_FUNC_CNT
, 4.0 },
918 { SUBTOTAL_FUNC_MAX
, 5.0 },
919 { SUBTOTAL_FUNC_MIN
, 1.0 },
920 { SUBTOTAL_FUNC_SUM
, 12.0 },
921 { SUBTOTAL_FUNC_SELECTION_COUNT
, 10.0 }
924 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aChecks
); ++i
)
927 bool bRes
= m_pDoc
->GetSelectionFunction(aChecks
[i
].meFunc
, ScAddress(), aMark
, fRes
);
928 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
929 CPPUNIT_ASSERT_EQUAL(aChecks
[i
].mfExpected
, fRes
);
933 // Make sure that when no selection is present, use the current cursor position.
934 ScMarkData
aEmpty(m_pDoc
->GetSheetLimits());
937 // D3 (numeric cell containing 5.)
938 ScAddress
aPos(3, 2, 0);
940 static const Check aChecks
[] =
942 { SUBTOTAL_FUNC_AVE
, 5.0 },
943 { SUBTOTAL_FUNC_CNT2
, 1.0 },
944 { SUBTOTAL_FUNC_CNT
, 1.0 },
945 { SUBTOTAL_FUNC_MAX
, 5.0 },
946 { SUBTOTAL_FUNC_MIN
, 5.0 },
947 { SUBTOTAL_FUNC_SUM
, 5.0 },
948 { SUBTOTAL_FUNC_SELECTION_COUNT
, 1.0 }
951 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aChecks
); ++i
)
954 bool bRes
= m_pDoc
->GetSelectionFunction(aChecks
[i
].meFunc
, aPos
, aEmpty
, fRes
);
955 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
956 CPPUNIT_ASSERT_EQUAL(aChecks
[i
].mfExpected
, fRes
);
961 // B7 (string formula cell containing ="C".)
962 ScAddress
aPos(1, 6, 0);
964 static const Check aChecks
[] =
966 { SUBTOTAL_FUNC_CNT2
, 1.0 },
967 { SUBTOTAL_FUNC_SELECTION_COUNT
, 1.0 }
970 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aChecks
); ++i
)
973 bool bRes
= m_pDoc
->GetSelectionFunction(aChecks
[i
].meFunc
, aPos
, aEmpty
, fRes
);
974 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
975 CPPUNIT_ASSERT_EQUAL(aChecks
[i
].mfExpected
, fRes
);
979 // Calculate function across selected sheets.
980 clearSheet(m_pDoc
, 0);
981 m_pDoc
->InsertTab(1, "Test2");
982 m_pDoc
->InsertTab(2, "Test3");
984 // Set values at B2 and C3 on each sheet.
985 m_pDoc
->SetValue(ScAddress(1,1,0), 1.0);
986 m_pDoc
->SetValue(ScAddress(2,2,0), 2.0);
987 m_pDoc
->SetValue(ScAddress(1,1,1), 4.0);
988 m_pDoc
->SetValue(ScAddress(2,2,1), 8.0);
989 m_pDoc
->SetValue(ScAddress(1,1,2), 16.0);
990 m_pDoc
->SetValue(ScAddress(2,2,2), 32.0);
992 // Mark B2 and C3 on first sheet.
994 aRanges
.push_back(ScRange(1,1,0)); // B2
995 aRanges
.push_back(ScRange(2,2,0)); // C3
996 aMark
.MarkFromRangeList(aRanges
, true);
997 // Additionally select third sheet.
998 aMark
.SelectTable(2, true);
1002 bool bRes
= m_pDoc
->GetSelectionFunction( SUBTOTAL_FUNC_SUM
, ScAddress(), aMark
, fRes
);
1003 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
1004 CPPUNIT_ASSERT_EQUAL_MESSAGE("1+2+16+32=", 51.0, fRes
);
1007 m_pDoc
->DeleteTab(2);
1008 m_pDoc
->DeleteTab(1);
1009 m_pDoc
->DeleteTab(0);
1012 void Test::testMarkedCellIteration()
1014 m_pDoc
->InsertTab(0, "Test");
1016 // Insert cells to A1, A5, B2 and C3.
1017 m_pDoc
->SetString(ScAddress(0,0,0), "California");
1018 m_pDoc
->SetValue(ScAddress(0,4,0), 1.2);
1019 m_pDoc
->SetEditText(ScAddress(1,1,0), "Boston");
1020 m_pDoc
->SetFormula(ScAddress(2,2,0), "=SUM(1,2,3)", m_pDoc
->GetGrammar());
1023 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
1024 aMarkData
.SetMarkArea(ScRange(0,0,0,2,4,0));
1025 aMarkData
.MarkToMulti(); // TODO : we shouldn't have to do this.
1033 const std::vector
<Check
> aChecks
= {
1040 SCROW nRow
= -1; // Start from the imaginary row before A1.
1043 for (const Check
& rCheck
: aChecks
)
1045 bool bFound
= m_pDoc
->GetNextMarkedCell(nCol
, nRow
, 0, aMarkData
);
1048 std::ostringstream os
;
1049 os
<< ScAddress(rCheck
.mnCol
, rCheck
.mnRow
, 0).GetColRowString() << " was expected, but not found.";
1050 CPPUNIT_FAIL(os
.str());
1053 CPPUNIT_ASSERT_EQUAL(rCheck
.mnRow
, nRow
);
1054 CPPUNIT_ASSERT_EQUAL(rCheck
.mnCol
, nCol
);
1057 // No more marked cells on this sheet.
1058 bool bFound
= m_pDoc
->GetNextMarkedCell(nCol
, nRow
, 0, aMarkData
);
1059 CPPUNIT_ASSERT(!bFound
);
1061 m_pDoc
->DeleteTab(0);
1064 void Test::testCopyToDocument()
1066 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (0, "src"));
1068 // We need a drawing layer in order to create caption objects.
1069 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
1071 m_pDoc
->SetString(0, 0, 0, "Header");
1072 m_pDoc
->SetString(0, 1, 0, "1");
1073 m_pDoc
->SetString(0, 2, 0, "2");
1074 m_pDoc
->SetString(0, 3, 0, "3");
1075 m_pDoc
->SetString(0, 4, 0, "=4/2");
1079 ScAddress
aAdrA1 (0, 0, 0); // numerical cell content
1080 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aAdrA1
);
1081 pNote
->SetText(aAdrA1
, "Hello world in A1");
1083 // Copy statically to another document.
1085 ScDocShellRef xDocSh2
;
1086 getNewDocShell(xDocSh2
);
1087 ScDocument
* pDestDoc
= &xDocSh2
->GetDocument();
1088 pDestDoc
->InsertTab(0, "src");
1089 pDestDoc
->InitDrawLayer(xDocSh2
.get()); // for note caption objects
1091 m_pDoc
->CopyStaticToDocument(ScRange(0,1,0,0,3,0), 0, *pDestDoc
); // Copy A2:A4
1092 m_pDoc
->CopyStaticToDocument(ScAddress(0,0,0), 0, *pDestDoc
); // Copy A1
1093 m_pDoc
->CopyStaticToDocument(ScRange(0,4,0,0,7,0), 0, *pDestDoc
); // Copy A5:A8
1095 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,0,0), pDestDoc
->GetString(0,0,0));
1096 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,1,0), pDestDoc
->GetString(0,1,0));
1097 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,2,0), pDestDoc
->GetString(0,2,0));
1098 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,3,0), pDestDoc
->GetString(0,3,0));
1099 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,4,0), pDestDoc
->GetString(0,4,0));
1102 CPPUNIT_ASSERT_MESSAGE("There should be a note in A1 destDocument", pDestDoc
->HasNote(ScAddress(0, 0, 0)));
1103 CPPUNIT_ASSERT_EQUAL_MESSAGE("The notes content should be the same on both documents",
1104 m_pDoc
->GetNote(ScAddress(0, 0, 0))->GetText(), pDestDoc
->GetNote(ScAddress(0, 0, 0))->GetText());
1106 pDestDoc
->DeleteTab(0);
1110 m_pDoc
->DeleteTab(0);
1113 bool Test::checkHorizontalIterator(ScDocument
& rDoc
, const std::vector
<std::vector
<const char*>>& rData
, const HoriIterCheck
* pChecks
, size_t nCheckCount
)
1115 ScAddress
aPos(0,0,0);
1116 insertRangeData(&rDoc
, aPos
, rData
);
1117 ScHorizontalCellIterator
aIter(rDoc
, 0, 0, 0, 1, rData
.size() - 1);
1122 for (ScRefCellValue
* pCell
= aIter
.GetNext(nCol
, nRow
); pCell
; pCell
= aIter
.GetNext(nCol
, nRow
), ++i
)
1124 if (i
>= nCheckCount
)
1126 cerr
<< "hit invalid check " << i
<< " of " << nCheckCount
<< endl
;
1127 CPPUNIT_FAIL("Iterator claims there is more data than there should be.");
1131 if (pChecks
[i
].nCol
!= nCol
)
1133 cerr
<< "Column mismatch " << pChecks
[i
].nCol
<< " vs. " << nCol
<< endl
;
1137 if (pChecks
[i
].nRow
!= nRow
)
1139 cerr
<< "Row mismatch " << pChecks
[i
].nRow
<< " vs. " << nRow
<< endl
;
1143 if (OUString::createFromAscii(pChecks
[i
].pVal
) != pCell
->getString(&rDoc
))
1145 cerr
<< "String mismatch " << pChecks
[i
].pVal
<< " vs. " <<
1146 pCell
->getString(&rDoc
) << endl
;
1154 void Test::testHorizontalIterator()
1156 m_pDoc
->InsertTab(0, "test");
1159 // Raw data - mixed types
1160 std::vector
<std::vector
<const char*>> aData
= {
1167 static const HoriIterCheck aChecks
[] = {
1178 bool bRes
= checkHorizontalIterator(
1179 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1182 CPPUNIT_FAIL("Failed on test mixed.");
1186 // Raw data - 'hole' data
1187 std::vector
<std::vector
<const char*>> aData
= {
1193 static const HoriIterCheck aChecks
[] = {
1201 bool bRes
= checkHorizontalIterator(
1202 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1205 CPPUNIT_FAIL("Failed on test hole.");
1210 std::vector
<std::vector
<const char*>> aData
= {
1212 { nullptr, nullptr },
1219 { nullptr, nullptr },
1222 static const HoriIterCheck aChecks
[] = {
1234 bool bRes
= checkHorizontalIterator(
1235 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1238 CPPUNIT_FAIL("Failed on test holy.");
1243 std::vector
<std::vector
<const char*>> aData
= {
1244 { nullptr, nullptr },
1245 { nullptr, nullptr },
1246 { nullptr, nullptr },
1249 bool bRes
= checkHorizontalIterator(
1250 *m_pDoc
, aData
, nullptr, 0);
1253 CPPUNIT_FAIL("Failed on test degenerate.");
1258 std::vector
<std::vector
<const char*>> aData
= {
1259 { nullptr, nullptr },
1260 { nullptr, nullptr },
1264 static const HoriIterCheck aChecks
[] = {
1268 bool bRes
= checkHorizontalIterator(
1269 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1272 CPPUNIT_FAIL("Failed on test at end.");
1277 std::vector
<std::vector
<const char*>> aData
= {
1278 { nullptr, nullptr },
1279 { nullptr, nullptr },
1282 { nullptr, nullptr },
1285 static const HoriIterCheck aChecks
[] = {
1290 bool bRes
= checkHorizontalIterator(
1291 *m_pDoc
, aData
, aChecks
, SAL_N_ELEMENTS(aChecks
));
1294 CPPUNIT_FAIL("Failed on test in middle.");
1297 m_pDoc
->DeleteTab(0);
1300 void Test::testValueIterator()
1302 m_pDoc
->InsertTab(0, "Test");
1304 // Turn on "precision as shown" option.
1305 ScDocOptions aOpt
= m_pDoc
->GetDocOptions();
1306 aOpt
.SetCalcAsShown(true);
1307 m_pDoc
->SetDocOptions(aOpt
);
1309 ScInterpreterContext
aContext(*m_pDoc
, m_pDoc
->GetFormatTable());
1311 // Purely horizontal data layout with numeric data.
1312 for (SCCOL i
= 1; i
<= 3; ++i
)
1313 m_pDoc
->SetValue(ScAddress(i
,2,0), i
);
1316 const double aChecks
[] = { 1.0, 2.0, 3.0 };
1317 size_t const nCheckLen
= SAL_N_ELEMENTS(aChecks
);
1318 ScValueIterator
aIter(aContext
, ScRange(1,2,0,3,2,0));
1320 size_t nCheckPos
= 0;
1323 for (bHas
= aIter
.GetFirst(fVal
, nErr
); bHas
; bHas
= aIter
.GetNext(fVal
, nErr
), ++nCheckPos
)
1325 CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos
< nCheckLen
);
1326 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
], fVal
);
1327 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(nErr
));
1331 m_pDoc
->DeleteTab(0);
1334 void Test::testHorizontalAttrIterator()
1336 m_pDoc
->InsertTab(0, "Test");
1338 // Set the background color of B2:C3,D2,E3,C4:D4,B5:D5 to blue
1339 ScPatternAttr
aCellBackColor(m_pDoc
->GetPool());
1340 aCellBackColor
.GetItemSet().Put(SvxBrushItem(COL_BLUE
, ATTR_BACKGROUND
));
1341 m_pDoc
->ApplyPatternAreaTab(1, 1, 2, 2, 0, aCellBackColor
);
1342 m_pDoc
->ApplyPatternAreaTab(3, 1, 3, 1, 0, aCellBackColor
);
1343 m_pDoc
->ApplyPatternAreaTab(4, 2, 4, 2, 0, aCellBackColor
);
1344 m_pDoc
->ApplyPatternAreaTab(2, 3, 3, 3, 0, aCellBackColor
);
1345 m_pDoc
->ApplyPatternAreaTab(1, 4, 4, 4, 0, aCellBackColor
);
1347 // some numeric data
1348 for (SCCOL i
= 1; i
<= 4; ++i
)
1349 for (SCROW j
= 1; j
<= 4; ++j
)
1350 m_pDoc
->SetValue(ScAddress(i
,j
,0), i
*10+j
);
1353 const int aChecks
[][3] = { {1, 3, 1}, {1, 2, 2}, {4, 4, 2}, {2, 3, 3}, {1, 4, 4} };
1354 const size_t nCheckLen
= SAL_N_ELEMENTS(aChecks
);
1356 ScHorizontalAttrIterator
aIter(*m_pDoc
, 0, 0, 0, 5, 5);
1359 size_t nCheckPos
= 0;
1360 for (const ScPatternAttr
* pAttr
= aIter
.GetNext(nCol1
, nCol2
, nRow
); pAttr
; pAttr
= aIter
.GetNext(nCol1
, nCol2
, nRow
))
1362 if( pAttr
== m_pDoc
->GetDefPattern())
1364 CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos
< nCheckLen
);
1365 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
][0], static_cast<int>(nCol1
));
1366 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
][1], static_cast<int>(nCol2
));
1367 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
][2], static_cast<int>(nRow
));
1372 m_pDoc
->DeleteTab(0);
1375 void Test::testIteratorsUnallocatedColumnsAttributes()
1377 m_pDoc
->InsertTab(0, "Tab1");
1379 // Set values in first two columns, to ensure allocation of those columns.
1380 m_pDoc
->SetValue(ScAddress(0,1,0), 1);
1381 m_pDoc
->SetValue(ScAddress(1,1,0), 2);
1382 constexpr SCCOL allocatedColsCount
= 2;
1383 assert( allocatedColsCount
>= INITIALCOLCOUNT
);
1384 CPPUNIT_ASSERT_EQUAL(allocatedColsCount
, m_pDoc
->GetAllocatedColumnsCount(0));
1386 // Make entire second row and third row bold.
1387 ScPatternAttr
boldAttr(m_pDoc
->GetPool());
1388 boldAttr
.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD
, ATTR_FONT_WEIGHT
));
1389 m_pDoc
->ApplyPatternAreaTab(0, 1, m_pDoc
->MaxCol(), 2, 0, boldAttr
);
1391 // That shouldn't need allocating more columns, just changing the default attribute.
1392 CPPUNIT_ASSERT_EQUAL(allocatedColsCount
, m_pDoc
->GetAllocatedColumnsCount(0));
1394 const ScPatternAttr
* pattern
= m_pDoc
->GetPattern(m_pDoc
->MaxCol(), 1, 0);
1395 pattern
->GetFont(aFont
, SC_AUTOCOL_RAW
);
1396 CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD
, aFont
.GetWeight());
1399 ScDocAttrIterator
docit( *m_pDoc
, 0, allocatedColsCount
- 1, 1, allocatedColsCount
, 2 );
1402 CPPUNIT_ASSERT_EQUAL( pattern
, docit
.GetNext( col1
, row1
, row2
));
1403 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1404 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1405 CPPUNIT_ASSERT_EQUAL( SCROW(2), row2
);
1406 CPPUNIT_ASSERT_EQUAL( pattern
, docit
.GetNext( col1
, row1
, row2
));
1407 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col1
);
1408 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1409 CPPUNIT_ASSERT_EQUAL( SCROW(2), row2
);
1410 CPPUNIT_ASSERT( docit
.GetNext( col1
, row1
, row2
) == nullptr );
1412 ScAttrRectIterator
rectit( *m_pDoc
, 0, allocatedColsCount
- 1, 1, allocatedColsCount
, 2 );
1413 CPPUNIT_ASSERT_EQUAL( pattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1414 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1415 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col2
);
1416 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1417 CPPUNIT_ASSERT_EQUAL( SCROW(2), row2
);
1418 CPPUNIT_ASSERT( rectit
.GetNext( col1
, col2
, row1
, row2
) == nullptr );
1420 ScHorizontalAttrIterator
horit( *m_pDoc
, 0, allocatedColsCount
- 1, 1, allocatedColsCount
, 2 );
1421 CPPUNIT_ASSERT_EQUAL( pattern
, horit
.GetNext( col1
, col2
, row1
));
1422 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1423 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col2
);
1424 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1425 CPPUNIT_ASSERT_EQUAL( pattern
, horit
.GetNext( col1
, col2
, row1
));
1426 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1427 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col2
);
1428 CPPUNIT_ASSERT_EQUAL( SCROW(2), row1
);
1429 CPPUNIT_ASSERT( horit
.GetNext( col1
, col2
, row1
) == nullptr );
1431 m_pDoc
->DeleteTab(0);
1434 void Test::testIteratorsDefPattern()
1436 m_pDoc
->InsertTab(0, "Tab1");
1438 // The default pattern is the default style, which can be edited by the user.
1439 // As such iterators should not ignore it by default, because it might contain
1440 // some attributes set.
1442 // Set cells as bold, default allocated, bold, default unallocated.
1443 SCCOL firstCol
= 100;
1444 SCCOL lastCol
= 103;
1445 ScPatternAttr
boldAttr(m_pDoc
->GetPool());
1446 boldAttr
.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD
, ATTR_FONT_WEIGHT
));
1447 m_pDoc
->ApplyPattern(100, 0, 0, boldAttr
);
1448 m_pDoc
->ApplyPattern(102, 0, 0, boldAttr
);
1450 CPPUNIT_ASSERT_EQUAL(SCCOL(102 + 1), m_pDoc
->GetAllocatedColumnsCount(0));
1451 const ScPatternAttr
* pattern
= m_pDoc
->GetPattern(100, 0, 0);
1452 const ScPatternAttr
* defPattern
= m_pDoc
->GetDefPattern();
1453 CPPUNIT_ASSERT(pattern
!= defPattern
);
1454 CPPUNIT_ASSERT_EQUAL(pattern
, m_pDoc
->GetPattern(102, 0, 0));
1455 CPPUNIT_ASSERT_EQUAL(defPattern
, m_pDoc
->GetPattern(101, 0, 0));
1456 CPPUNIT_ASSERT_EQUAL(defPattern
, m_pDoc
->GetPattern(103, 0, 0));
1459 ScDocAttrIterator
docit( *m_pDoc
, 0, firstCol
, 0, lastCol
, 0 );
1462 CPPUNIT_ASSERT_EQUAL(pattern
, docit
.GetNext( col1
, row1
, row2
));
1463 CPPUNIT_ASSERT_EQUAL(defPattern
, docit
.GetNext( col1
, row1
, row2
));
1464 CPPUNIT_ASSERT_EQUAL(pattern
, docit
.GetNext( col1
, row1
, row2
));
1465 CPPUNIT_ASSERT_EQUAL(defPattern
, docit
.GetNext( col1
, row1
, row2
));
1466 CPPUNIT_ASSERT(docit
.GetNext( col1
, row1
, row2
) == nullptr );
1468 ScAttrRectIterator
rectit( *m_pDoc
, 0, firstCol
, 0, lastCol
, 0 );
1469 CPPUNIT_ASSERT_EQUAL(pattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1470 CPPUNIT_ASSERT_EQUAL(defPattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1471 CPPUNIT_ASSERT_EQUAL(pattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1472 CPPUNIT_ASSERT_EQUAL(defPattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1473 CPPUNIT_ASSERT(rectit
.GetNext( col1
, col2
, row1
, row2
) == nullptr );
1475 ScHorizontalAttrIterator
horit( *m_pDoc
, 0, firstCol
, 0, lastCol
, 0 );
1476 CPPUNIT_ASSERT_EQUAL(pattern
, horit
.GetNext( col1
, col2
, row1
));
1477 CPPUNIT_ASSERT_EQUAL(defPattern
, horit
.GetNext( col1
, col2
, row1
));
1478 CPPUNIT_ASSERT_EQUAL(pattern
, horit
.GetNext( col1
, col2
, row1
));
1479 CPPUNIT_ASSERT_EQUAL(defPattern
, horit
.GetNext( col1
, col2
, row1
));
1480 CPPUNIT_ASSERT(horit
.GetNext( col1
, col2
, row1
) == nullptr );
1482 m_pDoc
->DeleteTab(0);
1485 void Test::testLastChangedColFlagsWidth()
1487 m_pDoc
->InsertTab(0, "Tab1");
1489 constexpr SCCOL firstChangedCol
= 100;
1490 assert( firstChangedCol
> m_pDoc
->GetAllocatedColumnsCount(0));
1491 CPPUNIT_ASSERT_EQUAL(INITIALCOLCOUNT
, m_pDoc
->GetAllocatedColumnsCount(0));
1492 for( SCCOL col
= firstChangedCol
; col
<= m_pDoc
->MaxCol(); ++col
)
1493 m_pDoc
->SetColWidth( col
, 0, 10 );
1495 // That shouldn't need allocating more columns, just changing column flags.
1496 CPPUNIT_ASSERT_EQUAL(INITIALCOLCOUNT
, m_pDoc
->GetAllocatedColumnsCount(0));
1497 // But the flags are changed.
1498 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxCol(), m_pDoc
->GetLastChangedColFlagsWidth(0));
1500 m_pDoc
->DeleteTab(0);
1505 bool broadcasterShifted(const ScDocument
& rDoc
, const ScAddress
& rFrom
, const ScAddress
& rTo
)
1507 const SvtBroadcaster
* pBC
= rDoc
.GetBroadcaster(rFrom
);
1510 cerr
<< "Broadcaster shouldn't be here." << endl
;
1514 pBC
= rDoc
.GetBroadcaster(rTo
);
1517 cerr
<< "Broadcaster should be here." << endl
;
1523 formula::FormulaToken
* getSingleRefToken(ScDocument
& rDoc
, const ScAddress
& rPos
)
1525 ScFormulaCell
* pFC
= rDoc
.GetFormulaCell(rPos
);
1528 cerr
<< "Formula cell expected, but not found." << endl
;
1532 ScTokenArray
* pTokens
= pFC
->GetCode();
1535 cerr
<< "Token array is not present." << endl
;
1539 formula::FormulaToken
* pToken
= pTokens
->FirstToken();
1540 if (!pToken
|| pToken
->GetType() != formula::svSingleRef
)
1542 cerr
<< "Not a single reference token." << endl
;
1549 bool checkRelativeRefToken(ScDocument
& rDoc
, const ScAddress
& rPos
, SCCOL nRelCol
, SCROW nRelRow
)
1551 formula::FormulaToken
* pToken
= getSingleRefToken(rDoc
, rPos
);
1555 ScSingleRefData
& rRef
= *pToken
->GetSingleRef();
1556 if (!rRef
.IsColRel() || rRef
.Col() != nRelCol
)
1558 cerr
<< "Unexpected relative column address." << endl
;
1562 if (!rRef
.IsRowRel() || rRef
.Row() != nRelRow
)
1564 cerr
<< "Unexpected relative row address." << endl
;
1571 bool checkDeletedRefToken(ScDocument
& rDoc
, const ScAddress
& rPos
)
1573 formula::FormulaToken
* pToken
= getSingleRefToken(rDoc
, rPos
);
1577 ScSingleRefData
& rRef
= *pToken
->GetSingleRef();
1578 if (!rRef
.IsDeleted())
1580 cerr
<< "Deleted reference is expected, but it's still a valid reference." << endl
;
1589 void Test::testCellBroadcaster()
1591 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (0, "foo"));
1593 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calculation.
1594 m_pDoc
->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
1595 double val
= m_pDoc
->GetValue(ScAddress(1,0,0)); // A1 is empty, so the result should be 0.
1596 CPPUNIT_ASSERT_EQUAL(0.0, val
);
1598 const SvtBroadcaster
* pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1599 CPPUNIT_ASSERT_MESSAGE("Cell A1 should have a broadcaster.", pBC
);
1601 // Change the value of A1 and make sure that B1 follows.
1602 m_pDoc
->SetValue(ScAddress(0,0,0), 1.23);
1603 val
= m_pDoc
->GetValue(ScAddress(1,0,0));
1604 CPPUNIT_ASSERT_EQUAL(1.23, val
);
1606 // Move column A down 5 cells. Make sure B1 now references A6, not A1.
1607 m_pDoc
->InsertRow(0, 0, 0, 0, 0, 5);
1608 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1609 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 5));
1611 // Make sure the broadcaster has also moved.
1612 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1613 broadcasterShifted(*m_pDoc
, ScAddress(0,0,0), ScAddress(0,5,0)));
1615 // Set new value to A6 and make sure B1 gets updated.
1616 m_pDoc
->SetValue(ScAddress(0,5,0), 45.6);
1617 val
= m_pDoc
->GetValue(ScAddress(1,0,0));
1618 CPPUNIT_ASSERT_EQUAL(45.6, val
);
1620 // Move column A up 3 cells, and make sure B1 now references A3, not A6.
1621 m_pDoc
->DeleteRow(0, 0, 0, 0, 0, 3);
1622 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1623 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 2));
1625 // The broadcaster should also have been relocated from A6 to A3.
1626 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1627 broadcasterShifted(*m_pDoc
, ScAddress(0,5,0), ScAddress(0,2,0)));
1629 // Insert cells over A1:A10 and shift cells to right.
1630 m_pDoc
->InsertCol(ScRange(0, 0, 0, 0, 10, 0));
1631 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1632 checkRelativeRefToken(*m_pDoc
, ScAddress(2,0,0), -1, 2));
1633 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1634 broadcasterShifted(*m_pDoc
, ScAddress(0,2,0), ScAddress(1,2,0)));
1636 // Delete formula in C2, which should remove the broadcaster in B3.
1637 pBC
= m_pDoc
->GetBroadcaster(ScAddress(1,2,0));
1638 CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should still exist.", pBC
);
1639 clearRange(m_pDoc
, ScAddress(2,0,0));
1640 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE
, m_pDoc
->GetCellType(ScAddress(2,0,0))); // C2 should be empty.
1641 pBC
= m_pDoc
->GetBroadcaster(ScAddress(1,2,0));
1642 CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should have been removed.", !pBC
);
1644 // Clear everything and start over.
1645 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1647 m_pDoc
->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
1648 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1649 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", pBC
);
1651 // While column A is still empty, move column A down 2 cells. This should
1652 // move the broadcaster from A1 to A3.
1653 m_pDoc
->InsertRow(0, 0, 0, 0, 0, 2);
1654 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1655 broadcasterShifted(*m_pDoc
, ScAddress(0,0,0), ScAddress(0,2,0)));
1657 // Move it back while column A is still empty.
1658 m_pDoc
->DeleteRow(0, 0, 0, 0, 0, 2);
1659 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1660 broadcasterShifted(*m_pDoc
, ScAddress(0,2,0), ScAddress(0,0,0)));
1662 // Clear everything again
1663 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1665 // B1:B3 depends on A1:A3
1666 m_pDoc
->SetString(ScAddress(1,0,0), "=A1");
1667 m_pDoc
->SetString(ScAddress(1,1,0), "=A2");
1668 m_pDoc
->SetString(ScAddress(1,2,0), "=A3");
1669 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1670 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 0));
1671 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1672 checkRelativeRefToken(*m_pDoc
, ScAddress(1,1,0), -1, 0));
1673 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B3 failed.",
1674 checkRelativeRefToken(*m_pDoc
, ScAddress(1,2,0), -1, 0));
1675 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc
->GetBroadcaster(ScAddress(0,0,0)));
1676 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A2.", m_pDoc
->GetBroadcaster(ScAddress(0,1,0)));
1677 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A3.", m_pDoc
->GetBroadcaster(ScAddress(0,2,0)));
1679 // Insert Rows at row 2, down 5 rows.
1680 m_pDoc
->InsertRow(0, 0, 0, 0, 1, 5);
1681 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc
->GetBroadcaster(ScAddress(0,0,0)));
1682 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1683 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 0));
1685 // Broadcasters in A2 and A3 should shift down by 5 rows.
1686 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1687 broadcasterShifted(*m_pDoc
, ScAddress(0,1,0), ScAddress(0,6,0)));
1688 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1689 broadcasterShifted(*m_pDoc
, ScAddress(0,2,0), ScAddress(0,7,0)));
1691 // B2 and B3 should reference shifted cells.
1692 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1693 checkRelativeRefToken(*m_pDoc
, ScAddress(1,1,0), -1, 5));
1694 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1695 checkRelativeRefToken(*m_pDoc
, ScAddress(1,2,0), -1, 5));
1697 // Delete cells with broadcasters.
1698 m_pDoc
->DeleteRow(0, 0, 0, 0, 4, 6);
1699 CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A7.", !m_pDoc
->GetBroadcaster(ScAddress(0,6,0)));
1700 CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A8.", !m_pDoc
->GetBroadcaster(ScAddress(0,7,0)));
1702 // References in B2 and B3 should be invalid.
1703 CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B2 failed.",
1704 checkDeletedRefToken(*m_pDoc
, ScAddress(1,1,0)));
1705 CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B3 failed.",
1706 checkDeletedRefToken(*m_pDoc
, ScAddress(1,2,0)));
1708 // Clear everything again
1709 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1712 // Switch to R1C1 to make it easier to input relative references in multiple cells.
1713 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
1715 // Have B1:B20 reference A1:A20.
1717 for (SCROW i
= 0; i
< 20; ++i
)
1719 m_pDoc
->SetValue(ScAddress(0,i
,0), val
++);
1720 m_pDoc
->SetString(ScAddress(1,i
,0), "=RC[-1]");
1724 // Ensure that the formula cells show correct values, and the referenced
1725 // cells have broadcasters.
1727 for (SCROW i
= 0; i
< 20; ++i
, ++val
)
1729 CPPUNIT_ASSERT_EQUAL(val
, m_pDoc
->GetValue(ScAddress(1,i
,0)));
1730 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,i
,0));
1731 CPPUNIT_ASSERT_MESSAGE("Broadcast should exist here.", pBC
);
1734 // Delete formula cells in B2:B19.
1735 clearRange(m_pDoc
, ScRange(1,1,0,1,18,0));
1736 // Ensure that A2:A19 no longer have broadcasters, but A1 and A20 still do.
1737 CPPUNIT_ASSERT_MESSAGE("A1 should still have broadcaster.", m_pDoc
->GetBroadcaster(ScAddress(0,0,0)));
1738 CPPUNIT_ASSERT_MESSAGE("A20 should still have broadcaster.", m_pDoc
->GetBroadcaster(ScAddress(0,19,0)));
1739 for (SCROW i
= 1; i
<= 18; ++i
)
1741 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,i
,0));
1742 CPPUNIT_ASSERT_MESSAGE("Broadcaster should have been deleted.", !pBC
);
1745 // Clear everything again
1746 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1748 m_pDoc
->SetValue(ScAddress(0,0,0), 2.0);
1749 m_pDoc
->SetString(ScAddress(1,0,0), "=A1");
1750 m_pDoc
->SetString(ScAddress(2,0,0), "=B1");
1751 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(0,0,0));
1752 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(1,0,0));
1753 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(2,0,0));
1755 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1756 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1757 pBC
= m_pDoc
->GetBroadcaster(ScAddress(1,0,0));
1758 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1760 // Change the value of A1 and make sure everyone follows suit.
1761 m_pDoc
->SetValue(ScAddress(0,0,0), 3.5);
1762 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc
->GetValue(0,0,0));
1763 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc
->GetValue(1,0,0));
1764 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc
->GetValue(2,0,0));
1766 // Insert a column at column B.
1767 m_pDoc
->InsertCol(ScRange(1,0,0,1,m_pDoc
->MaxRow(),0));
1768 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1769 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1770 pBC
= m_pDoc
->GetBroadcaster(ScAddress(2,0,0));
1771 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1773 // Change the value of A1 again.
1774 m_pDoc
->SetValue(ScAddress(0,0,0), 5.5);
1775 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc
->GetValue(0,0,0));
1776 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc
->GetValue(2,0,0));
1777 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc
->GetValue(3,0,0));
1779 m_pDoc
->DeleteTab(0);
1782 void Test::testFuncParam()
1785 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
1786 m_pDoc
->InsertTab (0, "foo"));
1788 // First, the normal case, with no missing parameters.
1789 m_pDoc
->SetString(0, 0, 0, "=AVERAGE(1;2;3)");
1790 m_pDoc
->CalcFormulaTree(false, false);
1791 double val
= m_pDoc
->GetValue(0, 0, 0);
1792 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 2.0, val
);
1794 // Now function with missing parameters. Missing values should be treated
1796 m_pDoc
->SetString(0, 0, 0, "=AVERAGE(1;;;)");
1797 m_pDoc
->CalcFormulaTree(false, false);
1798 val
= m_pDoc
->GetValue(0, 0, 0);
1799 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 0.25, val
);
1801 // Conversion of string to numeric argument.
1802 m_pDoc
->SetString(0, 0, 0, "=\"\"+3"); // empty string
1803 m_pDoc
->SetString(0, 1, 0, "=\" \"+3"); // only blank
1804 m_pDoc
->SetString(0, 2, 0, "=\" 4 \"+3"); // number in blanks
1805 m_pDoc
->SetString(0, 3, 0, "=\" x \"+3"); // non-numeric
1806 m_pDoc
->SetString(0, 4, 0, "=\"4.4\"+3"); // locale dependent
1809 ScCalcConfig aConfig
;
1811 // With "Convert also locale dependent" and "Empty string as zero"=True option.
1812 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::LOCALE
;
1813 aConfig
.mbEmptyStringAsZero
= true;
1814 m_pDoc
->SetCalcConfig(aConfig
);
1816 val
= m_pDoc
->GetValue(0, 0, 0);
1817 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1818 val
= m_pDoc
->GetValue(0, 1, 0);
1819 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1820 val
= m_pDoc
->GetValue(0, 2, 0);
1821 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1822 aVal
= m_pDoc
->GetString( 0, 3, 0);
1823 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1824 val
= m_pDoc
->GetValue(0, 4, 0);
1825 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.4, val
);
1827 // With "Convert also locale dependent" and "Empty string as zero"=False option.
1828 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::LOCALE
;
1829 aConfig
.mbEmptyStringAsZero
= false;
1830 m_pDoc
->SetCalcConfig(aConfig
);
1832 aVal
= m_pDoc
->GetString( 0, 0, 0);
1833 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1834 aVal
= m_pDoc
->GetString( 0, 1, 0);
1835 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1836 val
= m_pDoc
->GetValue(0, 2, 0);
1837 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1838 aVal
= m_pDoc
->GetString( 0, 3, 0);
1839 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1840 val
= m_pDoc
->GetValue(0, 4, 0);
1841 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.4, val
);
1843 // With "Convert only unambiguous" and "Empty string as zero"=True option.
1844 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::UNAMBIGUOUS
;
1845 aConfig
.mbEmptyStringAsZero
= true;
1846 m_pDoc
->SetCalcConfig(aConfig
);
1848 val
= m_pDoc
->GetValue(0, 0, 0);
1849 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1850 val
= m_pDoc
->GetValue(0, 1, 0);
1851 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1852 val
= m_pDoc
->GetValue(0, 2, 0);
1853 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1854 aVal
= m_pDoc
->GetString( 0, 3, 0);
1855 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1856 aVal
= m_pDoc
->GetString( 0, 4, 0);
1857 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1859 // With "Convert only unambiguous" and "Empty string as zero"=False option.
1860 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::UNAMBIGUOUS
;
1861 aConfig
.mbEmptyStringAsZero
= false;
1862 m_pDoc
->SetCalcConfig(aConfig
);
1864 aVal
= m_pDoc
->GetString( 0, 0, 0);
1865 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1866 aVal
= m_pDoc
->GetString( 0, 1, 0);
1867 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1868 m_pDoc
->GetValue(0, 2, 0);
1869 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1870 aVal
= m_pDoc
->GetString( 0, 3, 0);
1871 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1872 aVal
= m_pDoc
->GetString( 0, 4, 0);
1873 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1875 // With "Treat as zero" ("Empty string as zero" is ignored).
1876 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::ZERO
;
1877 aConfig
.mbEmptyStringAsZero
= true;
1878 m_pDoc
->SetCalcConfig(aConfig
);
1880 val
= m_pDoc
->GetValue(0, 0, 0);
1881 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1882 val
= m_pDoc
->GetValue(0, 1, 0);
1883 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1884 val
= m_pDoc
->GetValue(0, 2, 0);
1885 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1886 val
= m_pDoc
->GetValue(0, 3, 0);
1887 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1888 val
= m_pDoc
->GetValue(0, 4, 0);
1889 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1891 // With "Generate #VALUE! error" ("Empty string as zero" is ignored).
1892 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::ILLEGAL
;
1893 aConfig
.mbEmptyStringAsZero
= false;
1894 m_pDoc
->SetCalcConfig(aConfig
);
1896 aVal
= m_pDoc
->GetString( 0, 0, 0);
1897 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1898 aVal
= m_pDoc
->GetString( 0, 1, 0);
1899 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1900 aVal
= m_pDoc
->GetString( 0, 2, 0);
1901 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1902 aVal
= m_pDoc
->GetString( 0, 3, 0);
1903 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1904 aVal
= m_pDoc
->GetString( 0, 4, 0);
1905 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", OUString("#VALUE!"), aVal
);
1907 m_pDoc
->DeleteTab(0);
1910 void Test::testNamedRange()
1912 static const RangeNameDef aNames
[] = {
1913 { "Divisor", "$Sheet1.$A$1:$A$1048576", 1 },
1914 { "MyRange1", "$Sheet1.$A$1:$A$100", 2 },
1915 { "MyRange2", "$Sheet1.$B$1:$B$100", 3 },
1916 { "MyRange3", "$Sheet1.$C$1:$C$100", 4 }
1919 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (0, "Sheet1"));
1921 m_pDoc
->SetValue (0, 0, 0, 101);
1923 std::unique_ptr
<ScRangeName
> pNames(new ScRangeName
);
1924 bool bSuccess
= insertRangeNames(m_pDoc
, pNames
.get(), aNames
, aNames
+ SAL_N_ELEMENTS(aNames
));
1925 CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess
);
1926 m_pDoc
->SetRangeName(std::move(pNames
));
1928 ScRangeName
* pNewRanges
= m_pDoc
->GetRangeName();
1929 CPPUNIT_ASSERT(pNewRanges
);
1931 // Make sure the index lookup does the right thing.
1932 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aNames
); ++i
)
1934 const ScRangeData
* p
= pNewRanges
->findByIndex(aNames
[i
].mnIndex
);
1935 CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed.", p
);
1936 OUString aName
= p
->GetName();
1937 CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved.", aName
.equalsAscii(aNames
[i
].mpName
));
1940 // Test usage in formula expression.
1941 m_pDoc
->SetString (1, 0, 0, "=A1/Divisor");
1944 double result
= m_pDoc
->GetValue (1, 0, 0);
1945 ASSERT_DOUBLES_EQUAL_MESSAGE ("calculation failed", 1.0, result
);
1947 // Test copy-ability of range names.
1948 std::unique_ptr
<ScRangeName
> pCopiedRanges(new ScRangeName(*pNewRanges
));
1949 m_pDoc
->SetRangeName(std::move(pCopiedRanges
));
1950 // Make sure the index lookup still works.
1951 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aNames
); ++i
)
1953 const ScRangeData
* p
= m_pDoc
->GetRangeName()->findByIndex(aNames
[i
].mnIndex
);
1954 CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed with the copied instance.", p
);
1955 OUString aName
= p
->GetName();
1956 CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved with the copied instance.", aName
.equalsAscii(aNames
[i
].mpName
));
1959 // Test using another-sheet-local name, scope Sheet1.
1960 ScRangeData
* pLocal1
= new ScRangeData( *m_pDoc
, "local1", ScAddress(0,0,0));
1961 ScRangeData
* pLocal2
= new ScRangeData( *m_pDoc
, "local2", "$Sheet1.$A$1");
1962 ScRangeData
* pLocal3
= new ScRangeData( *m_pDoc
, "local3", "Sheet1.$A$1");
1963 ScRangeData
* pLocal4
= new ScRangeData( *m_pDoc
, "local4", "$A$1"); // implicit relative sheet reference
1964 std::unique_ptr
<ScRangeName
> pLocalRangeName1(new ScRangeName
);
1965 pLocalRangeName1
->insert(pLocal1
);
1966 pLocalRangeName1
->insert(pLocal2
);
1967 pLocalRangeName1
->insert(pLocal3
);
1968 pLocalRangeName1
->insert(pLocal4
);
1969 m_pDoc
->SetRangeName(0, std::move(pLocalRangeName1
));
1971 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (1, "Sheet2"));
1973 // Use other-sheet-local name of Sheet1 on Sheet2.
1974 ScAddress
aPos(1,0,1);
1975 OUString
aFormula("=Sheet1.local1+Sheet1.local2+Sheet1.local3+Sheet1.local4");
1976 m_pDoc
->SetString(aPos
, aFormula
);
1977 OUString aString
= m_pDoc
->GetFormula(1,0,1);
1978 CPPUNIT_ASSERT_EQUAL_MESSAGE("formula string should be equal", aFormula
, aString
);
1979 double fValue
= m_pDoc
->GetValue(aPos
);
1980 ASSERT_DOUBLES_EQUAL_MESSAGE("value should be 4 times Sheet1.A1", 404.0, fValue
);
1982 m_pDoc
->DeleteTab(1);
1983 m_pDoc
->SetRangeName(0,nullptr); // Delete the names.
1984 m_pDoc
->SetRangeName(nullptr); // Delete the names.
1985 m_pDoc
->DeleteTab(0);
1988 void Test::testInsertNameList()
1990 m_pDoc
->InsertTab(0, "Test");
1992 static const RangeNameDef aNames
[] = {
1993 { "MyRange1", "$Test.$A$1:$A$100", 1 },
1994 { "MyRange2", "$Test.$B$1:$B$100", 2 },
1995 { "MyRange3", "$Test.$C$1:$C$100", 3 }
1998 std::unique_ptr
<ScRangeName
> pNames(new ScRangeName
);
1999 bool bSuccess
= insertRangeNames(m_pDoc
, pNames
.get(), aNames
, aNames
+ SAL_N_ELEMENTS(aNames
));
2000 CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess
);
2001 m_pDoc
->SetRangeName(std::move(pNames
));
2003 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
2004 ScAddress
aPos(1,1,0);
2005 rDocFunc
.InsertNameList(aPos
, true);
2007 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aNames
); ++i
, aPos
.IncRow())
2009 OUString aName
= m_pDoc
->GetString(aPos
);
2010 CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(aNames
[i
].mpName
), aName
);
2011 ScAddress aExprPos
= aPos
;
2013 OUString aExpr
= m_pDoc
->GetString(aExprPos
);
2014 OUString aExpected
= "=" + OUString::createFromAscii(aNames
[i
].mpExpr
);
2015 CPPUNIT_ASSERT_EQUAL(aExpected
, aExpr
);
2018 m_pDoc
->DeleteTab(0);
2021 void Test::testCSV()
2023 const int English
= 0, European
= 1;
2025 const char *pStr
; int eSep
; bool bResult
; double nValue
;
2027 { "foo", English
, false, 0.0 },
2028 { "1.0", English
, true, 1.0 },
2029 { "1,0", English
, false, 0.0 },
2030 { "1.0", European
, false, 0.0 },
2031 { "1.000", European
, true, 1000.0 },
2032 { "1,000", European
, true, 1.0 },
2033 { "1.000", English
, true, 1.0 },
2034 { "1,000", English
, true, 1000.0 },
2035 { " 1.0", English
, true, 1.0 },
2036 { " 1.0 ", English
, true, 1.0 },
2037 { "1.0 ", European
, false, 0.0 },
2038 { "1.000", European
, true, 1000.0 },
2039 { "1137.999", English
, true, 1137.999 },
2040 { "1.000.00", European
, false, 0.0 },
2041 { "+,123", English
, false, 0.0 },
2042 { "-,123", English
, false, 0.0 }
2044 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aTests
); i
++) {
2045 OUString
aStr(aTests
[i
].pStr
, strlen (aTests
[i
].pStr
), RTL_TEXTENCODING_UTF8
);
2046 double nValue
= 0.0;
2047 bool bResult
= ScStringUtil::parseSimpleNumber
2048 (aStr
, aTests
[i
].eSep
== English
? '.' : ',',
2049 aTests
[i
].eSep
== English
? ',' : '.',
2052 CPPUNIT_ASSERT_EQUAL_MESSAGE ("CSV numeric detection failure", aTests
[i
].bResult
, bResult
);
2053 CPPUNIT_ASSERT_EQUAL_MESSAGE ("CSV numeric value failure", aTests
[i
].nValue
, nValue
);
2057 template<typename Evaluator
>
2058 static void checkMatrixElements(const ScMatrix
& rMat
)
2061 rMat
.GetDimensions(nC
, nR
);
2063 for (SCSIZE i
= 0; i
< nC
; ++i
)
2065 for (SCSIZE j
= 0; j
< nR
; ++j
)
2067 aEval(i
, j
, rMat
.Get(i
, j
));
2074 struct AllZeroMatrix
2076 void operator() (SCSIZE
/*nCol*/, SCSIZE
/*nRow*/, const ScMatrixValue
& rVal
) const
2078 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of numeric type", int(ScMatValType::Value
), static_cast<int>(rVal
.nType
));
2079 ASSERT_DOUBLES_EQUAL_MESSAGE("element value must be zero", 0.0, rVal
.fVal
);
2083 struct PartiallyFilledZeroMatrix
2085 void operator() (SCSIZE nCol
, SCSIZE nRow
, const ScMatrixValue
& rVal
) const
2087 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of numeric type", int(ScMatValType::Value
), static_cast<int>(rVal
.nType
));
2088 if (1 <= nCol
&& nCol
<= 2 && 2 <= nRow
&& nRow
<= 8)
2090 ASSERT_DOUBLES_EQUAL_MESSAGE("element value must be 3.0", 3.0, rVal
.fVal
);
2094 ASSERT_DOUBLES_EQUAL_MESSAGE("element value must be zero", 0.0, rVal
.fVal
);
2099 struct AllEmptyMatrix
2101 void operator() (SCSIZE
/*nCol*/, SCSIZE
/*nRow*/, const ScMatrixValue
& rVal
) const
2103 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of empty type", int(ScMatValType::Empty
), static_cast<int>(rVal
.nType
));
2104 ASSERT_DOUBLES_EQUAL_MESSAGE("value of \"empty\" element is expected to be zero", 0.0, rVal
.fVal
);
2108 struct PartiallyFilledEmptyMatrix
2110 void operator() (SCSIZE nCol
, SCSIZE nRow
, const ScMatrixValue
& rVal
) const
2112 if (nCol
== 1 && nRow
== 1)
2114 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of boolean type", int(ScMatValType::Boolean
), static_cast<int>(rVal
.nType
));
2115 ASSERT_DOUBLES_EQUAL_MESSAGE("element value is not what is expected", 1.0, rVal
.fVal
);
2117 else if (nCol
== 4 && nRow
== 5)
2119 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of value type", int(ScMatValType::Value
), static_cast<int>(rVal
.nType
));
2120 ASSERT_DOUBLES_EQUAL_MESSAGE("element value is not what is expected", -12.5, rVal
.fVal
);
2122 else if (nCol
== 8 && nRow
== 2)
2124 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of value type", int(ScMatValType::String
), static_cast<int>(rVal
.nType
));
2125 CPPUNIT_ASSERT_EQUAL_MESSAGE("element value is not what is expected", OUString("Test"), rVal
.aStr
.getString());
2127 else if (nCol
== 8 && nRow
== 11)
2129 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of empty path type", int(ScMatValType::EmptyPath
), static_cast<int>(rVal
.nType
));
2130 ASSERT_DOUBLES_EQUAL_MESSAGE("value of \"empty\" element is expected to be zero", 0.0, rVal
.fVal
);
2134 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of empty type", int(ScMatValType::Empty
), static_cast<int>(rVal
.nType
));
2135 ASSERT_DOUBLES_EQUAL_MESSAGE("value of \"empty\" element is expected to be zero", 0.0, rVal
.fVal
);
2142 void Test::testMatrix()
2144 svl::SharedStringPool
& rPool
= m_pDoc
->GetSharedStringPool();
2145 ScMatrixRef pMat
, pMat2
;
2147 // First, test the zero matrix type.
2148 pMat
= new ScMatrix(0, 0, 0.0);
2150 pMat
->GetDimensions(nC
, nR
);
2151 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix is not empty", SCSIZE(0), nC
);
2152 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix is not empty", SCSIZE(0), nR
);
2153 pMat
->Resize(4, 10, 0.0);
2154 pMat
->GetDimensions(nC
, nR
);
2155 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(4), nC
);
2156 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(10), nR
);
2157 CPPUNIT_ASSERT_MESSAGE("both 'and' and 'or' should evaluate to false",
2159 CPPUNIT_ASSERT_MESSAGE("both 'and' and 'or' should evaluate to false",
2162 // Resizing into a larger matrix should fill the void space with zeros.
2163 checkMatrixElements
<AllZeroMatrix
>(*pMat
);
2165 pMat
->FillDouble(3.0, 1, 2, 2, 8);
2166 checkMatrixElements
<PartiallyFilledZeroMatrix
>(*pMat
);
2167 CPPUNIT_ASSERT_MESSAGE("matrix is expected to be numeric", pMat
->IsNumeric());
2168 CPPUNIT_ASSERT_MESSAGE("partially non-zero matrix should evaluate false on 'and' and true on 'or",
2170 CPPUNIT_ASSERT_MESSAGE("partially non-zero matrix should evaluate false on 'and' and true on 'or",
2172 pMat
->FillDouble(5.0, 0, 0, nC
-1, nR
-1);
2173 CPPUNIT_ASSERT_MESSAGE("fully non-zero matrix should evaluate true both on 'and' and 'or",
2175 CPPUNIT_ASSERT_MESSAGE("fully non-zero matrix should evaluate true both on 'and' and 'or",
2178 // Test the AND and OR evaluations.
2179 pMat
= new ScMatrix(2, 2, 0.0);
2181 // Only some of the elements are non-zero.
2182 pMat
->PutBoolean(true, 0, 0);
2183 pMat
->PutDouble(1.0, 1, 1);
2184 CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat
->Or());
2185 CPPUNIT_ASSERT_MESSAGE("incorrect AND result", !pMat
->And());
2187 // All of the elements are non-zero.
2188 pMat
->PutBoolean(true, 0, 1);
2189 pMat
->PutDouble(2.3, 1, 0);
2190 CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat
->Or());
2191 CPPUNIT_ASSERT_MESSAGE("incorrect AND result", pMat
->And());
2193 // Now test the empty matrix type.
2194 pMat
= new ScMatrix(10, 20);
2195 pMat
->GetDimensions(nC
, nR
);
2196 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(10), nC
);
2197 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(20), nR
);
2198 checkMatrixElements
<AllEmptyMatrix
>(*pMat
);
2200 pMat
->PutBoolean(true, 1, 1);
2201 pMat
->PutDouble(-12.5, 4, 5);
2202 pMat
->PutString(rPool
.intern("Test"), 8, 2);
2203 pMat
->PutEmptyPath(8, 11);
2204 checkMatrixElements
<PartiallyFilledEmptyMatrix
>(*pMat
);
2207 pMat
= new ScMatrix(0, 0);
2208 pMat
->Resize(2, 2, 1.5);
2209 pMat
->PutEmpty(1, 1);
2211 CPPUNIT_ASSERT_EQUAL(1.5, pMat
->GetDouble(0, 0));
2212 CPPUNIT_ASSERT_EQUAL(1.5, pMat
->GetDouble(0, 1));
2213 CPPUNIT_ASSERT_EQUAL(1.5, pMat
->GetDouble(1, 0));
2214 CPPUNIT_ASSERT_MESSAGE("PutEmpty() call failed.", pMat
->IsEmpty(1, 1));
2216 // Max and min values.
2217 pMat
= new ScMatrix(2, 2, 0.0);
2218 pMat
->PutDouble(-10, 0, 0);
2219 pMat
->PutDouble(-12, 0, 1);
2220 pMat
->PutDouble(-8, 1, 0);
2221 pMat
->PutDouble(-25, 1, 1);
2222 CPPUNIT_ASSERT_EQUAL(-25.0, pMat
->GetMinValue(false));
2223 CPPUNIT_ASSERT_EQUAL(-8.0, pMat
->GetMaxValue(false));
2224 pMat
->PutString(rPool
.intern("Test"), 0, 0);
2225 CPPUNIT_ASSERT_EQUAL(0.0, pMat
->GetMaxValue(true)); // text as zero.
2226 CPPUNIT_ASSERT_EQUAL(-8.0, pMat
->GetMaxValue(false)); // ignore text.
2227 pMat
->PutBoolean(true, 0, 0);
2228 CPPUNIT_ASSERT_EQUAL(1.0, pMat
->GetMaxValue(false));
2229 pMat
= new ScMatrix(2, 2, 10.0);
2230 pMat
->PutBoolean(false, 0, 0);
2231 pMat
->PutDouble(12.5, 1, 1);
2232 CPPUNIT_ASSERT_EQUAL(0.0, pMat
->GetMinValue(false));
2233 CPPUNIT_ASSERT_EQUAL(12.5, pMat
->GetMaxValue(false));
2235 // Convert matrix into a linear double array. String elements become NaN
2236 // and empty elements become 0.
2237 pMat
= new ScMatrix(3, 3);
2238 pMat
->PutDouble(2.5, 0, 0);
2239 pMat
->PutDouble(1.2, 0, 1);
2240 pMat
->PutString(rPool
.intern("A"), 1, 1);
2241 pMat
->PutDouble(2.3, 2, 1);
2242 pMat
->PutDouble(-20, 2, 2);
2244 static const double fNaN
= std::numeric_limits
<double>::quiet_NaN();
2246 std::vector
<double> aDoubles
;
2247 pMat
->GetDoubleArray(aDoubles
);
2250 const double pChecks
[] = { 2.5, 1.2, 0, 0, fNaN
, 0, 0, 2.3, -20 };
2251 CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks
), aDoubles
.size());
2252 for (size_t i
= 0, n
= aDoubles
.size(); i
< n
; ++i
)
2254 if (std::isnan(pChecks
[i
]))
2255 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", std::isnan(aDoubles
[i
]));
2257 CPPUNIT_ASSERT_EQUAL(pChecks
[i
], aDoubles
[i
]);
2261 pMat2
= new ScMatrix(3, 3, 10.0);
2262 pMat2
->PutString(rPool
.intern("B"), 1, 0);
2263 pMat2
->MergeDoubleArrayMultiply(aDoubles
);
2266 const double pChecks
[] = { 25, 12, 0, fNaN
, fNaN
, 0, 0, 23, -200 };
2267 CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks
), aDoubles
.size());
2268 for (size_t i
= 0, n
= aDoubles
.size(); i
< n
; ++i
)
2270 if (std::isnan(pChecks
[i
]))
2271 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", std::isnan(aDoubles
[i
]));
2273 CPPUNIT_ASSERT_EQUAL(pChecks
[i
], aDoubles
[i
]);
2278 void Test::testMatrixComparisonWithErrors()
2280 m_pDoc
->InsertTab(0, "foo");
2282 // Insert the source values in A1:A2.
2283 m_pDoc
->SetString(0, 0, 0, "=1/0");
2284 m_pDoc
->SetValue( 0, 1, 0, 1.0);
2286 // Create a matrix formula in B3:B4 referencing A1:A2 and doing a greater
2287 // than comparison on it's values. Error value must be propagated.
2288 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2289 aMark
.SelectOneTable(0);
2290 m_pDoc
->InsertMatrixFormula(1, 2, 1, 3, aMark
, "=A1:A2>0");
2292 CPPUNIT_ASSERT_EQUAL(OUString("#DIV/0!"), m_pDoc
->GetString(0,0,0));
2293 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue( 0,1,0));
2294 CPPUNIT_ASSERT_EQUAL(OUString("#DIV/0!"), m_pDoc
->GetString(1,2,0));
2295 CPPUNIT_ASSERT_EQUAL(OUString("TRUE"), m_pDoc
->GetString(1,3,0));
2297 m_pDoc
->DeleteTab(0);
2300 void Test::testMatrixConditionalBooleanResult()
2302 m_pDoc
->InsertTab(0, "foo");
2304 // Create matrix formulas in A1:B1,A2:B2,A3:B3,A4:B4 producing mixed
2305 // boolean and numeric results in an unformatted area.
2306 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2307 aMark
.SelectOneTable(0);
2308 m_pDoc
->InsertMatrixFormula( 0,0, 1,0, aMark
, "=IF({1;0};TRUE();42)"); // {TRUE,42}
2309 m_pDoc
->InsertMatrixFormula( 0,1, 1,1, aMark
, "=IF({0;1};TRUE();42)"); // {42,1} aim for {42,TRUE}
2310 m_pDoc
->InsertMatrixFormula( 0,2, 1,2, aMark
, "=IF({1;0};42;FALSE())"); // {42,0} aim for {42,FALSE}
2311 m_pDoc
->InsertMatrixFormula( 0,3, 1,3, aMark
, "=IF({0;1};42;FALSE())"); // {FALSE,42}
2313 CPPUNIT_ASSERT_EQUAL( OUString("TRUE"), m_pDoc
->GetString(0,0,0));
2314 CPPUNIT_ASSERT_EQUAL( OUString("42"), m_pDoc
->GetString(1,0,0));
2315 CPPUNIT_ASSERT_EQUAL( OUString("42"), m_pDoc
->GetString(0,1,0));
2316 //CPPUNIT_ASSERT_EQUAL( OUString("TRUE"), m_pDoc->GetString(1,1,0)); // not yet
2317 CPPUNIT_ASSERT_EQUAL( OUString("42"), m_pDoc
->GetString(0,2,0));
2318 //CPPUNIT_ASSERT_EQUAL( OUString("FALSE"), m_pDoc->GetString(1,2,0)); // not yet
2319 CPPUNIT_ASSERT_EQUAL( OUString("FALSE"), m_pDoc
->GetString(0,3,0));
2320 CPPUNIT_ASSERT_EQUAL( OUString("42"), m_pDoc
->GetString(1,3,0));
2322 m_pDoc
->DeleteTab(0);
2325 void Test::testEnterMixedMatrix()
2327 m_pDoc
->InsertTab(0, "foo");
2329 // Insert the source values in A1:B2.
2330 m_pDoc
->SetString(0, 0, 0, "A");
2331 m_pDoc
->SetString(1, 0, 0, "B");
2333 m_pDoc
->SetValue(0, 1, 0, val
);
2335 m_pDoc
->SetValue(1, 1, 0, val
);
2337 // Create a matrix range in A4:B5 referencing A1:B2.
2338 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2339 aMark
.SelectOneTable(0);
2340 m_pDoc
->InsertMatrixFormula(0, 3, 1, 4, aMark
, "=A1:B2");
2342 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,0,0), m_pDoc
->GetString(0,3,0));
2343 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(1,0,0), m_pDoc
->GetString(1,3,0));
2344 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetValue(0,1,0), m_pDoc
->GetValue(0,4,0));
2345 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetValue(1,1,0), m_pDoc
->GetValue(1,4,0));
2347 m_pDoc
->DeleteTab(0);
2350 void Test::testMatrixEditable()
2352 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2354 m_pDoc
->InsertTab(0, "Test");
2357 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
2358 m_pDoc
->SetValue(ScAddress(1,0,0), 2.0);
2360 // A2 is a normal formula.
2361 m_pDoc
->SetString(ScAddress(0,1,0), "=5");
2363 // A3:A4 is a matrix.
2364 ScRange
aMatRange(0,2,0,0,3,0);
2365 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2366 aMark
.SetMarkArea(aMatRange
);
2367 m_pDoc
->InsertMatrixFormula(0, 2, 0, 3, aMark
, "=TRANSPOSE(A1:B1)");
2369 // Check their values.
2370 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
2371 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
2372 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
2374 // Make sure A3:A4 is a matrix.
2375 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,2,0));
2376 CPPUNIT_ASSERT(pFC
);
2377 CPPUNIT_ASSERT_EQUAL_MESSAGE("A3 should be matrix origin.",
2378 ScMatrixMode::Formula
, pFC
->GetMatrixFlag());
2380 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,3,0));
2381 CPPUNIT_ASSERT(pFC
);
2382 CPPUNIT_ASSERT_EQUAL_MESSAGE("A4 should be matrix reference.",
2383 ScMatrixMode::Reference
, pFC
->GetMatrixFlag());
2385 // Check to make sure A3:A4 combined is editable.
2386 ScEditableTester aTester
;
2387 aTester
.TestSelection(*m_pDoc
, aMark
);
2388 CPPUNIT_ASSERT(aTester
.IsEditable());
2390 m_pDoc
->DeleteTab(0);
2393 void Test::testCellCopy()
2395 m_pDoc
->InsertTab(0, "TestTab");
2396 ScAddress
aSrc(0,0,0);
2397 ScAddress
aDest(0,1,0);
2398 OUString
aStr("please copy me");
2399 m_pDoc
->SetString(aSrc
, "please copy me");
2400 CPPUNIT_ASSERT_EQUAL(aStr
, m_pDoc
->GetString(aSrc
));
2401 // copy to self - why not ?
2402 m_pDoc
->CopyCellToDocument(aSrc
,aDest
,*m_pDoc
);
2403 CPPUNIT_ASSERT_EQUAL(aStr
, m_pDoc
->GetString(aDest
));
2406 void Test::testSheetCopy()
2408 m_pDoc
->InsertTab(0, "TestTab");
2409 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.",
2410 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
2412 // We need a drawing layer in order to create caption objects.
2413 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
2415 // Insert text in A1.
2416 m_pDoc
->SetString(ScAddress(0,0,0), "copy me");
2418 // Insert edit cells in B1:B3.
2419 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
2420 rEE
.SetTextCurrentDefaults("Edit 1");
2421 m_pDoc
->SetEditText(ScAddress(1,0,0), rEE
.CreateTextObject());
2422 rEE
.SetTextCurrentDefaults("Edit 2");
2423 m_pDoc
->SetEditText(ScAddress(1,1,0), rEE
.CreateTextObject());
2424 rEE
.SetTextCurrentDefaults("Edit 3");
2425 m_pDoc
->SetEditText(ScAddress(1,2,0), rEE
.CreateTextObject());
2428 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2429 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
2430 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
2431 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
2434 ScAddress
aAdrA1 (0,2,0); // empty cell content.
2435 ScPostIt
*pNoteA1
= m_pDoc
->GetOrCreateNote(aAdrA1
);
2436 pNoteA1
->SetText(aAdrA1
, "Hello world in A3");
2438 // Copy and test the result.
2439 m_pDoc
->CopyTab(0, 1);
2440 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.",
2441 static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2443 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2444 CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden
);
2445 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", SCROW(0), nRow1
);
2446 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", m_pDoc
->MaxRow(), nRow2
);
2447 CPPUNIT_ASSERT_MESSAGE("There should be note on A3 in new sheet", m_pDoc
->HasNote(ScAddress(0,2,1)));
2448 CPPUNIT_ASSERT_EQUAL(OUString("copy me"), m_pDoc
->GetString(ScAddress(0,0,1)));
2450 // Check the copied edit cells.
2451 const EditTextObject
* pEditObj
= m_pDoc
->GetEditText(ScAddress(1,0,1));
2452 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B1.", pEditObj
);
2453 CPPUNIT_ASSERT_EQUAL(OUString("Edit 1"), pEditObj
->GetText(0));
2454 pEditObj
= m_pDoc
->GetEditText(ScAddress(1,1,1));
2455 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B2.", pEditObj
);
2456 CPPUNIT_ASSERT_EQUAL(OUString("Edit 2"), pEditObj
->GetText(0));
2457 pEditObj
= m_pDoc
->GetEditText(ScAddress(1,2,1));
2458 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B3.", pEditObj
);
2459 CPPUNIT_ASSERT_EQUAL(OUString("Edit 3"), pEditObj
->GetText(0));
2461 m_pDoc
->DeleteTab(1);
2463 m_pDoc
->SetRowHidden(5, 10, 0, true);
2464 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2465 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2466 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2467 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2468 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
2469 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2470 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2471 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2472 bHidden
= m_pDoc
->RowHidden(11, 0, &nRow1
, &nRow2
);
2473 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2474 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2475 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2477 // Copy the sheet once again.
2478 m_pDoc
->CopyTab(0, 1);
2479 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.",
2480 static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2481 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2482 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2483 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2484 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2485 bHidden
= m_pDoc
->RowHidden(5, 1, &nRow1
, &nRow2
);
2486 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2487 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2488 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2489 bHidden
= m_pDoc
->RowHidden(11, 1, &nRow1
, &nRow2
);
2490 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2491 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2492 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2493 m_pDoc
->DeleteTab(1);
2494 m_pDoc
->DeleteTab(0);
2497 void Test::testSheetMove()
2499 m_pDoc
->InsertTab(0, "TestTab1");
2500 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.", static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
2502 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2503 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
2504 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
2505 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
2507 //test if inserting before another sheet works
2508 m_pDoc
->InsertTab(0, "TestTab2");
2509 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have two sheets", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2510 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2511 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
2512 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
2513 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
2515 // Move and test the result.
2516 m_pDoc
->MoveTab(0, 1);
2517 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2518 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2519 CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden
);
2520 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", SCROW(0), nRow1
);
2521 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", m_pDoc
->MaxRow(), nRow2
);
2523 m_pDoc
->GetName(0, aName
);
2524 CPPUNIT_ASSERT_EQUAL_MESSAGE( "sheets should have changed places", OUString("TestTab1"), aName
);
2526 m_pDoc
->SetRowHidden(5, 10, 0, true);
2527 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2528 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2529 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2530 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2531 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
2532 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2533 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2534 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2535 bHidden
= m_pDoc
->RowHidden(11, 0, &nRow1
, &nRow2
);
2536 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2537 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2538 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2540 // Move the sheet once again.
2541 m_pDoc
->MoveTab(1, 0);
2542 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2543 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2544 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2545 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2546 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2547 bHidden
= m_pDoc
->RowHidden(5, 1, &nRow1
, &nRow2
);
2548 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2549 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2550 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2551 bHidden
= m_pDoc
->RowHidden(11, 1, &nRow1
, &nRow2
);
2552 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2553 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2554 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2555 m_pDoc
->GetName(0, aName
);
2556 CPPUNIT_ASSERT_EQUAL_MESSAGE( "sheets should have changed places", OUString("TestTab2"), aName
);
2557 m_pDoc
->DeleteTab(1);
2558 m_pDoc
->DeleteTab(0);
2561 void Test::testDataArea()
2563 m_pDoc
->InsertTab(0, "Data");
2565 // Totally empty sheet should be rightfully considered empty in all accounts.
2566 CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc
->IsPrintEmpty(0, 0, 100, 100, 0));
2567 CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
2569 // Now, set borders in some cells...
2570 ::editeng::SvxBorderLine
aLine(nullptr, 50, SvxBorderLineStyle::SOLID
);
2571 SvxBoxItem
aBorderItem(ATTR_BORDER
);
2572 aBorderItem
.SetLine(&aLine
, SvxBoxItemLine::LEFT
);
2573 aBorderItem
.SetLine(&aLine
, SvxBoxItemLine::RIGHT
);
2574 for (SCROW i
= 0; i
< 100; ++i
)
2575 // Set borders from row 1 to 100.
2576 m_pDoc
->ApplyAttr(0, i
, 0, aBorderItem
);
2578 // Now the sheet is considered non-empty for printing purposes, but still
2579 // be empty in all the other cases.
2580 CPPUNIT_ASSERT_MESSAGE("Empty sheet with borders should be printable.",
2581 !m_pDoc
->IsPrintEmpty(0, 0, 0, 100, 100));
2582 CPPUNIT_ASSERT_MESSAGE("But it should still be considered empty in all the other cases.",
2583 m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
2585 // Adding a real cell content should turn the block non-empty.
2586 m_pDoc
->SetString(0, 0, 0, "Some text");
2587 CPPUNIT_ASSERT_MESSAGE("Now the block should not be empty with a real cell content.",
2588 !m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
2590 // TODO: Add more tests for normal data area calculation.
2592 m_pDoc
->DeleteTab(0);
2595 void Test::testStreamValid()
2597 m_pDoc
->InsertTab(0, "Sheet1");
2598 m_pDoc
->InsertTab(1, "Sheet2");
2599 m_pDoc
->InsertTab(2, "Sheet3");
2600 m_pDoc
->InsertTab(3, "Sheet4");
2601 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have 4 sheet instances.", static_cast<SCTAB
>(4), m_pDoc
->GetTableCount());
2607 // Put values into Sheet1.
2608 m_pDoc
->SetString(0, 0, 0, a1
);
2609 m_pDoc
->SetString(0, 1, 0, a2
);
2610 test
= m_pDoc
->GetString(0, 0, 0);
2611 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet1.A1", test
, a1
);
2612 test
= m_pDoc
->GetString(0, 1, 0);
2613 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet1.A2", test
, a2
);
2615 // Put formulas into Sheet2 to Sheet4 to reference values from Sheet1.
2616 m_pDoc
->SetString(0, 0, 1, "=Sheet1.A1");
2617 m_pDoc
->SetString(0, 1, 1, "=Sheet1.A2");
2618 m_pDoc
->SetString(0, 0, 2, "=Sheet1.A1");
2619 m_pDoc
->SetString(0, 0, 3, "=Sheet1.A2");
2621 test
= m_pDoc
->GetString(0, 0, 1);
2622 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet2.A1", test
, a1
);
2623 test
= m_pDoc
->GetString(0, 1, 1);
2624 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet2.A2", test
, a2
);
2625 test
= m_pDoc
->GetString(0, 0, 2);
2626 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet3.A1", test
, a1
);
2627 test
= m_pDoc
->GetString(0, 0, 3);
2628 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet3.A1", test
, a2
);
2630 // Set all sheet streams valid after all the initial cell values are in
2631 // place. In reality we need to have real XML streams stored in order to
2632 // claim they are valid, but we are just testing the flag values here.
2633 m_pDoc
->SetStreamValid(0, true);
2634 m_pDoc
->SetStreamValid(1, true);
2635 m_pDoc
->SetStreamValid(2, true);
2636 m_pDoc
->SetStreamValid(3, true);
2637 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(0));
2638 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(1));
2639 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(2));
2640 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(3));
2642 // Now, insert a new row at row 2 position on Sheet1. This will move cell
2643 // A2 downward but cell A1 remains unmoved.
2644 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 2);
2645 test
= m_pDoc
->GetString(0, 0, 0);
2646 CPPUNIT_ASSERT_EQUAL_MESSAGE("Cell A1 should not have moved.", test
, a1
);
2647 test
= m_pDoc
->GetString(0, 3, 0);
2648 CPPUNIT_ASSERT_EQUAL_MESSAGE("the old cell A2 should now be at A4.", test
, a2
);
2649 ScRefCellValue aCell
;
2650 aCell
.assign(*m_pDoc
, ScAddress(0,1,0));
2651 CPPUNIT_ASSERT_MESSAGE("Cell A2 should be empty.", aCell
.isEmpty());
2652 aCell
.assign(*m_pDoc
, ScAddress(0,2,0));
2653 CPPUNIT_ASSERT_MESSAGE("Cell A3 should be empty.", aCell
.isEmpty());
2655 // After the move, Sheet1, Sheet2, and Sheet4 should have their stream
2656 // invalidated, whereas Sheet3's stream should still be valid.
2657 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc
->IsStreamValid(0));
2658 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc
->IsStreamValid(1));
2659 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc
->IsStreamValid(3));
2660 CPPUNIT_ASSERT_MESSAGE("Stream should still be valid.", m_pDoc
->IsStreamValid(2));
2662 m_pDoc
->DeleteTab(3);
2663 m_pDoc
->DeleteTab(2);
2664 m_pDoc
->DeleteTab(1);
2665 m_pDoc
->DeleteTab(0);
2668 void Test::testFunctionLists()
2670 const char* aDataBase
[] = {
2686 const char* aDateTime
[] = {
2720 const char* aFinancial
[] = {
2750 const char* aInformation
[] = {
2773 const char* aLogical
[] = {
2788 const char* aMathematical
[] = {
2866 const char* aArray
[] = {
2885 const char* aStatistical
[] = {
2938 "FORECAST.ETS.MULT",
2939 "FORECAST.ETS.PI.ADD",
2940 "FORECAST.ETS.PI.MULT",
2941 "FORECAST.ETS.SEASONALITY",
2942 "FORECAST.ETS.STAT.ADD",
2943 "FORECAST.ETS.STAT.MULT",
3040 const char* aSpreadsheet
[] = {
3066 const char* aText
[] = {
3118 const char* Category
; const char** Functions
;
3120 { "Database", aDataBase
},
3121 { "Date&Time", aDateTime
},
3122 { "Financial", aFinancial
},
3123 { "Information", aInformation
},
3124 { "Logical", aLogical
},
3125 { "Mathematical", aMathematical
},
3126 { "Array", aArray
},
3127 { "Statistical", aStatistical
},
3128 { "Spreadsheet", aSpreadsheet
},
3130 { "Add-in", nullptr },
3131 { nullptr, nullptr }
3134 ScFunctionMgr
* pFuncMgr
= ScGlobal::GetStarCalcFunctionMgr();
3135 sal_uInt32 n
= pFuncMgr
->getCount();
3136 for (sal_uInt32 i
= 0; i
< n
; ++i
)
3138 const formula::IFunctionCategory
* pCat
= pFuncMgr
->getCategory(i
);
3139 CPPUNIT_ASSERT_MESSAGE("Unexpected category name", pCat
->getName().equalsAscii(aTests
[i
].Category
));
3140 sal_uInt32 nFuncCount
= pCat
->getCount();
3141 for (sal_uInt32 j
= 0; j
< nFuncCount
; ++j
)
3143 const formula::IFunctionDescription
* pFunc
= pCat
->getFunction(j
);
3144 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected function name", OUString::createFromAscii(aTests
[i
].Functions
[j
]), pFunc
->getFunctionName());
3149 void Test::testGraphicsInGroup()
3151 m_pDoc
->InsertTab(0, "TestTab");
3152 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.",
3153 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
3155 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3156 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
3157 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
3158 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
3160 m_pDoc
->InitDrawLayer();
3161 ScDrawLayer
*pDrawLayer
= m_pDoc
->GetDrawLayer();
3162 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer
!= nullptr);
3163 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
3164 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage
!= nullptr);
3168 tools::Rectangle
aOrigRect(2,2,100,100);
3169 rtl::Reference
<SdrRectObj
> pObj
= new SdrRectObj(*pDrawLayer
, aOrigRect
);
3170 pPage
->InsertObject(pObj
.get());
3171 const tools::Rectangle
&rNewRect
= pObj
->GetLogicRect();
3172 CPPUNIT_ASSERT_EQUAL_MESSAGE("must have equal position and size",
3173 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3175 ScDrawLayer::SetPageAnchored(*pObj
);
3177 //Use a range of rows guaranteed to include all of the square
3178 m_pDoc
->ShowRows(0, 100, 0, false);
3179 m_pDoc
->SetDrawPageSize(0);
3180 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when page anchored",
3181 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3182 m_pDoc
->ShowRows(0, 100, 0, true);
3183 m_pDoc
->SetDrawPageSize(0);
3184 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when page anchored",
3185 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3187 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, true);
3188 CPPUNIT_ASSERT_EQUAL_MESSAGE("That shouldn't change size or positioning",
3189 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3191 m_pDoc
->ShowRows(0, 100, 0, false);
3192 m_pDoc
->SetDrawPageSize(0);
3194 CPPUNIT_ASSERT_EQUAL_MESSAGE("Hiding should not change the logic rectangle",
3195 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3196 CPPUNIT_ASSERT_MESSAGE("Hiding should make invisible", !pObj
->IsVisible());
3198 m_pDoc
->ShowRows(0, 100, 0, true);
3199 m_pDoc
->SetDrawPageSize(0);
3200 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when cell anchored",
3201 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3202 CPPUNIT_ASSERT_MESSAGE("Show should make visible", pObj
->IsVisible());
3207 tools::Rectangle
aOrigRect(10,10,210,210); // 200 x 200
3208 rtl::Reference
<SdrCircObj
> pObj
= new SdrCircObj(*pDrawLayer
, SdrCircKind::Full
, aOrigRect
);
3209 pPage
->InsertObject(pObj
.get());
3210 const tools::Rectangle
& rNewRect
= pObj
->GetLogicRect();
3211 CPPUNIT_ASSERT_EQUAL_MESSAGE("Position and size of the circle shouldn't change when inserted into the page.",
3212 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3214 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3215 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size changed when cell anchored. Not good.",
3216 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3218 // Insert 2 rows at the top. This should push the circle object down.
3219 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3220 m_pDoc
->SetDrawPageSize(0);
3222 // Make sure the size of the circle is still identical.
3223 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size of the circle has changed, but shouldn't!",
3224 aOrigRect
.GetSize(), rNewRect
.GetSize());
3226 // Delete 2 rows at the top. This should bring the circle object to its original position.
3227 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3228 m_pDoc
->SetDrawPageSize(0);
3229 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to move back to its original position.",
3230 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3235 basegfx::B2DPolygon aTempPoly
;
3236 Point
aStartPos(10,300), aEndPos(110,200); // bottom-left to top-right.
3237 tools::Rectangle
aOrigRect(10,200,110,300); // 100 x 100
3238 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
3239 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
3240 rtl::Reference
<SdrPathObj
> pObj
= new SdrPathObj(*pDrawLayer
, SdrObjKind::Line
, basegfx::B2DPolyPolygon(aTempPoly
));
3241 pObj
->NbcSetLogicRect(aOrigRect
);
3242 pPage
->InsertObject(pObj
.get());
3243 const tools::Rectangle
& rNewRect
= pObj
->GetLogicRect();
3244 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size differ.",
3245 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3247 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3248 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size changed when cell-anchored. Not good.",
3249 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3251 // Insert 2 rows at the top and delete them immediately.
3252 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3253 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3254 m_pDoc
->SetDrawPageSize(0);
3255 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size of a line object changed after row insertion and removal.",
3256 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3258 sal_Int32 n
= pObj
->GetPointCount();
3259 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 2 points in a line object.", static_cast<sal_Int32
>(2), n
);
3260 CPPUNIT_ASSERT_EQUAL_MESSAGE("Line shape has changed.",
3261 aStartPos
, pObj
->GetPoint(0));
3262 CPPUNIT_ASSERT_EQUAL_MESSAGE("Line shape has changed.",
3263 aEndPos
, pObj
->GetPoint(1));
3266 m_pDoc
->DeleteTab(0);
3269 void Test::testGraphicsOnSheetMove()
3271 m_pDoc
->InsertTab(0, "Tab1");
3272 m_pDoc
->InsertTab(1, "Tab2");
3273 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only 2 sheets to begin with", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
3275 m_pDoc
->InitDrawLayer();
3276 ScDrawLayer
* pDrawLayer
= m_pDoc
->GetDrawLayer();
3277 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer
);
3278 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
3279 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage
);
3281 // Insert an object.
3282 tools::Rectangle
aObjRect(2,2,100,100);
3283 rtl::Reference
<SdrObject
> pObj
= new SdrRectObj(*pDrawLayer
, aObjRect
);
3284 pPage
->InsertObject(pObj
.get());
3285 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3287 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one object on the 1st sheet.", static_cast<size_t>(1), pPage
->GetObjCount());
3289 const ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pObj
.get());
3290 CPPUNIT_ASSERT_MESSAGE("Object meta-data doesn't exist.", pData
);
3291 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maStart
.Tab());
3292 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maEnd
.Tab());
3294 pPage
= pDrawLayer
->GetPage(1);
3295 CPPUNIT_ASSERT_MESSAGE("No page instance for the 2nd sheet.", pPage
);
3296 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet shouldn't have any object.", static_cast<size_t>(0), pPage
->GetObjCount());
3298 // Insert a new sheet at left-end, and make sure the object has moved to
3300 m_pDoc
->InsertTab(0, "NewTab");
3301 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 3 sheets.", static_cast<SCTAB
>(3), m_pDoc
->GetTableCount());
3302 pPage
= pDrawLayer
->GetPage(0);
3303 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage
);
3304 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have no object.", size_t(0), pPage
->GetObjCount());
3305 pPage
= pDrawLayer
->GetPage(1);
3306 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage
);
3307 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet should have one object.", size_t(1), pPage
->GetObjCount());
3308 pPage
= pDrawLayer
->GetPage(2);
3309 CPPUNIT_ASSERT_MESSAGE("3rd sheet should have no object.", pPage
);
3310 CPPUNIT_ASSERT_EQUAL_MESSAGE("3rd sheet should have no object.", size_t(0), pPage
->GetObjCount());
3312 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maStart
.Tab());
3313 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maEnd
.Tab());
3315 // Now, delete the sheet that just got inserted. The object should be back
3316 // on the 1st sheet.
3317 m_pDoc
->DeleteTab(0);
3318 pPage
= pDrawLayer
->GetPage(0);
3319 CPPUNIT_ASSERT_MESSAGE("1st sheet should have one object.", pPage
);
3320 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have one object.", size_t(1), pPage
->GetObjCount());
3321 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size and position of the object shouldn't change.",
3322 aObjRect
, pObj
->GetLogicRect());
3324 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maStart
.Tab());
3325 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maEnd
.Tab());
3327 // Move the 1st sheet to the last position.
3328 m_pDoc
->MoveTab(0, 1);
3329 pPage
= pDrawLayer
->GetPage(0);
3330 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage
);
3331 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have no object.", size_t(0), pPage
->GetObjCount());
3332 pPage
= pDrawLayer
->GetPage(1);
3333 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage
);
3334 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet should have one object.", size_t(1), pPage
->GetObjCount());
3335 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maStart
.Tab());
3336 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maEnd
.Tab());
3338 // Copy the 2nd sheet, which has one drawing object to the last position.
3339 m_pDoc
->CopyTab(1, 2);
3340 pPage
= pDrawLayer
->GetPage(2);
3341 CPPUNIT_ASSERT_MESSAGE("Copied sheet should have one object.", pPage
);
3342 CPPUNIT_ASSERT_EQUAL_MESSAGE("Copied sheet should have one object.", size_t(1), pPage
->GetObjCount());
3343 pObj
= pPage
->GetObj(0);
3344 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj
);
3345 pData
= ScDrawLayer::GetObjData(pObj
.get());
3346 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData
);
3347 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(2), pData
->maStart
.Tab());
3348 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(2), pData
->maEnd
.Tab());
3350 m_pDoc
->DeleteTab(2);
3351 m_pDoc
->DeleteTab(1);
3352 m_pDoc
->DeleteTab(0);
3355 void Test::testToggleRefFlag()
3357 // In this test, there is no need to insert formula string into a cell in
3358 // the document, as ScRefFinder does not depend on the content of the
3359 // document except for the sheet names.
3361 m_pDoc
->InsertTab(0, "Test");
3364 // Calc A1: basic 2D reference
3366 OUString
aFormula("=B100");
3367 ScAddress
aPos(1, 5, 0);
3368 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
3371 CPPUNIT_ASSERT_EQUAL_MESSAGE("Does not equal the original text.", aFormula
, aFinder
.GetText());
3373 // column relative / row relative -> column absolute / row absolute
3374 aFinder
.ToggleRel(0, aFormula
.getLength());
3375 aFormula
= aFinder
.GetText();
3376 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", OUString("=$B$100"), aFormula
);
3378 // column absolute / row absolute -> column relative / row absolute
3379 aFinder
.ToggleRel(0, aFormula
.getLength());
3380 aFormula
= aFinder
.GetText();
3381 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", OUString("=B$100"), aFormula
);
3383 // column relative / row absolute -> column absolute / row relative
3384 aFinder
.ToggleRel(0, aFormula
.getLength());
3385 aFormula
= aFinder
.GetText();
3386 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", OUString("=$B100"), aFormula
);
3388 // column absolute / row relative -> column relative / row relative
3389 aFinder
.ToggleRel(0, aFormula
.getLength());
3390 aFormula
= aFinder
.GetText();
3391 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", OUString("=B100"), aFormula
);
3395 // Excel R1C1: basic 2D reference
3397 OUString
aFormula("=R2C1");
3398 ScAddress
aPos(3, 5, 0);
3399 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
3402 CPPUNIT_ASSERT_EQUAL_MESSAGE("Does not equal the original text.", aFormula
, aFinder
.GetText());
3404 // column absolute / row absolute -> column relative / row absolute
3405 aFinder
.ToggleRel(0, aFormula
.getLength());
3406 aFormula
= aFinder
.GetText();
3407 CPPUNIT_ASSERT_EQUAL(OUString("=R2C[-3]"), aFormula
);
3409 // column relative / row absolute - > column absolute / row relative
3410 aFinder
.ToggleRel(0, aFormula
.getLength());
3411 aFormula
= aFinder
.GetText();
3412 CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C1"), aFormula
);
3414 // column absolute / row relative -> column relative / row relative
3415 aFinder
.ToggleRel(0, aFormula
.getLength());
3416 aFormula
= aFinder
.GetText();
3417 CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C[-3]"), aFormula
);
3419 // column relative / row relative -> column absolute / row absolute
3420 aFinder
.ToggleRel(0, aFormula
.getLength());
3421 aFormula
= aFinder
.GetText();
3422 CPPUNIT_ASSERT_EQUAL(OUString("=R2C1"), aFormula
);
3426 // Excel R1C1: Selection at the end of the formula string and does not
3427 // overlap the formula string at all (inspired by fdo#39135).
3428 OUString
aFormula("=R1C1");
3429 ScAddress
aPos(1, 1, 0);
3430 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
3433 CPPUNIT_ASSERT_EQUAL(aFormula
, aFinder
.GetText());
3435 // Make the column relative.
3436 sal_Int32 n
= aFormula
.getLength();
3437 aFinder
.ToggleRel(n
, n
);
3438 aFormula
= aFinder
.GetText();
3439 CPPUNIT_ASSERT_EQUAL(OUString("=R1C[-1]"), aFormula
);
3441 // Make the row relative.
3442 n
= aFormula
.getLength();
3443 aFinder
.ToggleRel(n
, n
);
3444 aFormula
= aFinder
.GetText();
3445 CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C1"), aFormula
);
3447 // Make both relative.
3448 n
= aFormula
.getLength();
3449 aFinder
.ToggleRel(n
, n
);
3450 aFormula
= aFinder
.GetText();
3451 CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C[-1]"), aFormula
);
3453 // Back to the original.
3454 n
= aFormula
.getLength();
3455 aFinder
.ToggleRel(n
, n
);
3456 aFormula
= aFinder
.GetText();
3457 CPPUNIT_ASSERT_EQUAL(OUString("=R1C1"), aFormula
);
3462 OUString
aFormula("=A1+4");
3463 ScAddress
aPos(1, 1, 0);
3464 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
3467 CPPUNIT_ASSERT_EQUAL(aFormula
, aFinder
.GetText());
3469 // Set the cursor over the 'A1' part and toggle.
3470 aFinder
.ToggleRel(2, 2);
3471 aFormula
= aFinder
.GetText();
3472 CPPUNIT_ASSERT_EQUAL(OUString("=$A$1+4"), aFormula
);
3474 aFinder
.ToggleRel(2, 2);
3475 aFormula
= aFinder
.GetText();
3476 CPPUNIT_ASSERT_EQUAL(OUString("=A$1+4"), aFormula
);
3478 aFinder
.ToggleRel(2, 2);
3479 aFormula
= aFinder
.GetText();
3480 CPPUNIT_ASSERT_EQUAL(OUString("=$A1+4"), aFormula
);
3482 aFinder
.ToggleRel(2, 2);
3483 aFormula
= aFinder
.GetText();
3484 CPPUNIT_ASSERT_EQUAL(OUString("=A1+4"), aFormula
);
3487 // TODO: Add more test cases esp. for 3D references, Excel A1 syntax, and
3488 // partial selection within formula string.
3490 m_pDoc
->DeleteTab(0);
3493 void Test::testAutofilter()
3495 m_pDoc
->InsertTab( 0, "Test" );
3497 // cell contents (0 = empty cell)
3498 const char* aData
[][3] = {
3499 { "C1", "C2", "C3" },
3501 { "1", "2", nullptr },
3506 SCCOL nCols
= SAL_N_ELEMENTS(aData
[0]);
3507 SCROW nRows
= SAL_N_ELEMENTS(aData
);
3510 for (SCROW i
= 0; i
< nRows
; ++i
)
3511 for (SCCOL j
= 0; j
< nCols
; ++j
)
3513 m_pDoc
->SetString(j
, i
, 0, OUString::createFromAscii(aData
[i
][j
]));
3515 ScDBData
* pDBData
= new ScDBData("NONAME", 0, 0, 0, nCols
-1, nRows
-1);
3516 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3518 pDBData
->SetAutoFilter(true);
3520 pDBData
->GetArea(aRange
);
3521 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3522 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3523 aRange
.aStart
.Tab(), ScMF::Auto
);
3525 //create the query param
3526 ScQueryParam aParam
;
3527 pDBData
->GetQueryParam(aParam
);
3528 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3529 rEntry
.bDoQuery
= true;
3531 rEntry
.eOp
= SC_EQUAL
;
3532 rEntry
.GetQueryItem().mfVal
= 0;
3533 // add queryParam to database range.
3534 pDBData
->SetQueryParam(aParam
);
3536 // perform the query.
3537 m_pDoc
->Query(0, aParam
, true);
3541 bool bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3542 CPPUNIT_ASSERT_MESSAGE("rows 2 & 3 should be hidden", bHidden
);
3543 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2 & 3 should be hidden", SCROW(2), nRow1
);
3544 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2 & 3 should be hidden", SCROW(3), nRow2
);
3546 // Remove filtering.
3548 m_pDoc
->Query(0, aParam
, true);
3549 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3550 CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !bHidden
);
3551 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", SCROW(0), nRow1
);
3552 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", m_pDoc
->MaxRow(), nRow2
);
3554 // Filter for non-empty cells by column C.
3555 rEntry
.bDoQuery
= true;
3557 rEntry
.SetQueryByNonEmpty();
3558 m_pDoc
->Query(0, aParam
, true);
3560 // only row 3 should be hidden. The rest should be visible.
3561 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3562 CPPUNIT_ASSERT_MESSAGE("rows 1 & 2 should be visible.", !bHidden
);
3563 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 1 & 2 should be visible.", SCROW(0), nRow1
);
3564 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 1 & 2 should be visible.", SCROW(1), nRow2
);
3565 bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3566 CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden.", bHidden
);
3567 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be hidden.", SCROW(2), nRow1
);
3568 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be hidden.", SCROW(2), nRow2
);
3569 bHidden
= m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
);
3570 CPPUNIT_ASSERT_MESSAGE("row 4 and down should be visible.", !bHidden
);
3571 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 4 and down should be visible.", SCROW(3), nRow1
);
3572 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 4 and down should be visible.", m_pDoc
->MaxRow(), nRow2
);
3574 // Now, filter for empty cells by column C.
3575 rEntry
.SetQueryByEmpty();
3576 m_pDoc
->Query(0, aParam
, true);
3578 // Now, only row 1 and 3, and 6 and down should be visible.
3579 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3580 CPPUNIT_ASSERT_MESSAGE("row 1 should be visible.", !bHidden
);
3581 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 1 should be visible.", SCROW(0), nRow1
);
3582 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 1 should be visible.", SCROW(0), nRow2
);
3583 bHidden
= m_pDoc
->RowHidden(1, 0, &nRow1
, &nRow2
);
3584 CPPUNIT_ASSERT_MESSAGE("row 2 should be hidden.", bHidden
);
3585 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 2 should be hidden.", SCROW(1), nRow1
);
3586 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 2 should be hidden.", SCROW(1), nRow2
);
3587 bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3588 CPPUNIT_ASSERT_MESSAGE("row 3 should be visible.", !bHidden
);
3589 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be visible.", SCROW(2), nRow1
);
3590 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be visible.", SCROW(2), nRow2
);
3591 bHidden
= m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
);
3592 CPPUNIT_ASSERT_MESSAGE("rows 4 & 5 should be hidden.", bHidden
);
3593 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 4 & 5 should be hidden.", SCROW(3), nRow1
);
3594 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 4 & 5 should be hidden.", SCROW(4), nRow2
);
3595 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
3596 CPPUNIT_ASSERT_MESSAGE("rows 6 and down should be all visible.", !bHidden
);
3597 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 6 and down should be all visible.", SCROW(5), nRow1
);
3598 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 6 and down should be all visible.", m_pDoc
->MaxRow(), nRow2
);
3600 m_pDoc
->DeleteTab(0);
3603 void Test::testAutoFilterTimeValue()
3605 m_pDoc
->InsertTab(0, "Test");
3607 m_pDoc
->SetString(ScAddress(0,0,0), "Hours");
3608 m_pDoc
->SetValue(ScAddress(0,1,0), 72.3604166666671);
3609 m_pDoc
->SetValue(ScAddress(0,2,0), 265);
3611 ScDBData
* pDBData
= new ScDBData(STR_DB_GLOBAL_NONAME
, 0, 0, 0, 0, 2);
3612 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3614 // Apply the "hour:minute:second" format to A2:A3.
3615 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3616 sal_uInt32 nFormat
= pFormatter
->GetFormatIndex(NF_TIME_HH_MMSS
, LANGUAGE_ENGLISH_US
);
3617 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3618 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3619 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3621 m_pDoc
->ApplyPatternAreaTab(0, 1, 0, 2, 0, aNewAttrs
); // apply it to A2:A3.
3623 printRange(m_pDoc
, ScRange(0,0,0,0,2,0), "Data"); // A1:A3
3625 // Make sure the hour:minute:second format is really applied.
3626 CPPUNIT_ASSERT_EQUAL(OUString("1736:39:00"), m_pDoc
->GetString(ScAddress(0,1,0))); // A2
3627 CPPUNIT_ASSERT_EQUAL(OUString("6360:00:00"), m_pDoc
->GetString(ScAddress(0,2,0))); // A3
3629 // Filter by the A2 value. Only A1 and A2 should be visible.
3630 ScQueryParam aParam
;
3631 pDBData
->GetQueryParam(aParam
);
3632 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3633 rEntry
.bDoQuery
= true;
3635 rEntry
.eOp
= SC_EQUAL
;
3636 rEntry
.GetQueryItem().maString
= m_pDoc
->GetSharedStringPool().intern("1736:39:00");
3637 rEntry
.GetQueryItem().meType
= ScQueryEntry::ByString
;
3639 pDBData
->SetQueryParam(aParam
);
3641 // perform the query.
3642 m_pDoc
->Query(0, aParam
, true);
3644 // A1:A2 should be visible while A3 should be filtered out.
3645 CPPUNIT_ASSERT_MESSAGE("A1 should be visible.", !m_pDoc
->RowFiltered(0,0));
3646 CPPUNIT_ASSERT_MESSAGE("A2 should be visible.", !m_pDoc
->RowFiltered(1,0));
3647 CPPUNIT_ASSERT_MESSAGE("A3 should be filtered out.", m_pDoc
->RowFiltered(2,0));
3649 m_pDoc
->DeleteTab(0);
3652 void Test::testAutofilterOptimizations()
3654 m_pDoc
->InsertTab( 0, "Test" );
3656 constexpr SCCOL nCols
= 4;
3657 constexpr SCROW nRows
= 200;
3658 m_pDoc
->SetString(0, 0, 0, "Column1");
3659 m_pDoc
->SetString(1, 0, 0, "Column2");
3660 m_pDoc
->SetString(2, 0, 0, "Column3");
3661 m_pDoc
->SetString(3, 0, 0, "Column4");
3663 // Fill 1st column with 0-199, 2nd with 1-200, 3rd with "1000"-"1199", 4th with "1001-1200"
3664 // (the pairs are off by one to each other to check filtering out a value filters out
3665 // only the relevant column).
3666 for(SCROW i
= 0; i
< nRows
; ++i
)
3668 m_pDoc
->SetValue(0, i
+ 1, 0, i
);
3669 m_pDoc
->SetValue(1, i
+ 1, 0, i
+1);
3670 m_pDoc
->SetString(2, i
+ 1, 0, "val" + OUString::number(i
+1000));
3671 m_pDoc
->SetString(3, i
+ 1, 0, "val" + OUString::number(i
+1000+1));
3674 ScDBData
* pDBData
= new ScDBData("NONAME", 0, 0, 0, nCols
, nRows
);
3675 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3677 pDBData
->SetAutoFilter(true);
3679 pDBData
->GetArea(aRange
);
3680 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3681 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3682 aRange
.aStart
.Tab(), ScMF::Auto
);
3684 //create the query param
3685 ScQueryParam aParam
;
3686 pDBData
->GetQueryParam(aParam
);
3687 ScQueryEntry
& rEntry0
= aParam
.GetEntry(0);
3688 rEntry0
.bDoQuery
= true;
3690 rEntry0
.eOp
= SC_EQUAL
;
3691 rEntry0
.GetQueryItems().resize(nRows
);
3692 ScQueryEntry
& rEntry1
= aParam
.GetEntry(1);
3693 rEntry1
.bDoQuery
= true;
3695 rEntry1
.eOp
= SC_EQUAL
;
3696 rEntry1
.GetQueryItems().resize(nRows
);
3697 ScQueryEntry
& rEntry2
= aParam
.GetEntry(2);
3698 rEntry2
.bDoQuery
= true;
3700 rEntry2
.eOp
= SC_EQUAL
;
3701 rEntry2
.GetQueryItems().resize(nRows
);
3702 ScQueryEntry
& rEntry3
= aParam
.GetEntry(3);
3703 rEntry3
.bDoQuery
= true;
3705 rEntry3
.eOp
= SC_EQUAL
;
3706 rEntry3
.GetQueryItems().resize(nRows
);
3707 // Set up autofilter to select all values except one in each column.
3708 // This should only filter out 2nd, 3rd, 6th and 7th rows.
3709 for( int i
= 0; i
< nRows
; ++i
)
3712 rEntry0
.GetQueryItems()[i
].mfVal
= i
;
3714 rEntry1
.GetQueryItems()[i
].mfVal
= i
+ 1;
3717 rEntry2
.GetQueryItems()[i
].maString
= m_pDoc
->GetSharedStringPool().intern("val" + OUString::number(i
+1000));
3718 rEntry2
.GetQueryItems()[i
].meType
= ScQueryEntry::ByString
;
3722 rEntry3
.GetQueryItems()[i
].maString
= m_pDoc
->GetSharedStringPool().intern("val" + OUString::number(i
+1000+1));
3723 rEntry3
.GetQueryItems()[i
].meType
= ScQueryEntry::ByString
;
3726 // add queryParam to database range.
3727 pDBData
->SetQueryParam(aParam
);
3729 // perform the query.
3730 m_pDoc
->Query(0, aParam
, true);
3732 // check that only rows with filtered out values are hidden, and not rows that share
3733 // a value in a different column
3735 CPPUNIT_ASSERT_MESSAGE("row 2 should be visible", !m_pDoc
->RowHidden(1, 0, &nRow1
, &nRow2
));
3736 CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden", m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
));
3737 CPPUNIT_ASSERT_MESSAGE("row 4 should be hidden", m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
));
3738 CPPUNIT_ASSERT_MESSAGE("row 5 should be visible", !m_pDoc
->RowHidden(4, 0, &nRow1
, &nRow2
));
3739 CPPUNIT_ASSERT_MESSAGE("row 6 should be visible", !m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
));
3740 CPPUNIT_ASSERT_MESSAGE("row 7 should be hidden", m_pDoc
->RowHidden(6, 0, &nRow1
, &nRow2
));
3741 CPPUNIT_ASSERT_MESSAGE("row 8 should be hidden", m_pDoc
->RowHidden(7, 0, &nRow1
, &nRow2
));
3742 CPPUNIT_ASSERT_MESSAGE("row 9 should be visible", !m_pDoc
->RowHidden(8, 0, &nRow1
, &nRow2
));
3744 // Remove filtering.
3748 m_pDoc
->Query(0, aParam
, true);
3749 CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
));
3750 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", SCROW(0), nRow1
);
3751 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", m_pDoc
->MaxRow(), nRow2
);
3753 m_pDoc
->DeleteTab(0);
3756 void Test::testTdf76441()
3758 m_pDoc
->InsertTab(0, "Test");
3760 // The result will be different depending on whether the format is set before
3761 // or after inserting the string
3763 OUString aCode
= "MM:SS";
3764 sal_Int32 nCheckPos
;
3765 SvNumFormatType nType
;
3767 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3768 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3770 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3771 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3772 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3774 // First insert the string, then the format
3775 m_pDoc
->SetString(ScAddress(0,0,0), "01:20");
3777 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3779 CPPUNIT_ASSERT_EQUAL(OUString("20:00"), m_pDoc
->GetString(ScAddress(0,0,0)));
3783 // First set the format, then insert the string
3784 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3786 m_pDoc
->SetString(ScAddress(0,1,0), "01:20");
3788 // Without the fix in place, this test would have failed with
3789 // - Expected: 01:20
3791 CPPUNIT_ASSERT_EQUAL(OUString("01:20"), m_pDoc
->GetString(ScAddress(0,1,0)));
3794 m_pDoc
->DeleteTab(0);
3797 void Test::testTdf76836()
3799 m_pDoc
->InsertTab(0, "Test");
3801 OUString aCode
= "\"192.168.0.\"@";
3802 sal_Int32 nCheckPos
;
3803 SvNumFormatType nType
;
3805 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3806 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3808 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3809 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3810 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3812 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3813 m_pDoc
->SetValue(0,0,0, 10.0);
3815 // Without the fix in place, this test would have failed with
3817 // - Actual : 192.168.0.10
3818 CPPUNIT_ASSERT_EQUAL(OUString("10"), m_pDoc
->GetString(ScAddress(0,0,0)));
3820 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3821 m_pDoc
->SetString(ScAddress(0,1,0), "10");
3822 CPPUNIT_ASSERT_EQUAL(OUString("192.168.0.10"), m_pDoc
->GetString(ScAddress(0,1,0)));
3824 m_pDoc
->DeleteTab(0);
3827 void Test::testTdf142186()
3829 m_pDoc
->InsertTab(0, "Test");
3831 // The result will be different depending on whether the format is set before
3832 // or after inserting the string
3834 OUString aCode
= "0\".\"0";
3835 sal_Int32 nCheckPos
;
3836 SvNumFormatType nType
;
3838 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3839 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3841 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3842 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3843 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3845 // First insert the string, then the format
3846 m_pDoc
->SetString(ScAddress(0,0,0), "123.45");
3848 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3850 CPPUNIT_ASSERT_EQUAL(OUString("12.3"), m_pDoc
->GetString(ScAddress(0,0,0)));
3854 // First set the format, then insert the string
3855 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3857 m_pDoc
->SetString(ScAddress(0,1,0), "123.45");
3859 // Without the fix in place, this test would have failed with
3861 // - Actual : 1234.5
3862 CPPUNIT_ASSERT_EQUAL(OUString("12.3"), m_pDoc
->GetString(ScAddress(0,1,0)));
3865 m_pDoc
->DeleteTab(0);
3868 void Test::testTdf137063()
3870 m_pDoc
->InsertTab(0, "Test");
3872 m_pDoc
->SetValue(0,0,0, 0.000000006);
3873 m_pDoc
->SetValue(0,1,0, 0.0000000006);
3875 // Without the fix in place, this test would have failed with
3876 // - Expected: 0.000000006
3878 CPPUNIT_ASSERT_EQUAL(OUString("0.000000006"), m_pDoc
->GetString(ScAddress(0,0,0)));
3879 CPPUNIT_ASSERT_EQUAL(OUString("6E-10"), m_pDoc
->GetString(ScAddress(0,1,0)));
3881 m_pDoc
->DeleteTab(0);
3884 void Test::testTdf126342()
3886 m_pDoc
->InsertTab(0, "Test");
3888 OUString aCode
= "YYYY-MM-DD";
3889 sal_Int32 nCheckPos
;
3890 SvNumFormatType nType
;
3892 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3893 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3895 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
3896 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3897 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3898 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3900 m_pDoc
->SetString(ScAddress(0,0,0), "11/7/19");
3902 CPPUNIT_ASSERT_EQUAL(OUString("2019-11-07"), m_pDoc
->GetString(ScAddress(0,0,0)));
3904 // Overwrite the existing date with the exact same input
3905 m_pDoc
->SetString(ScAddress(0,0,0), "11/7/19");
3907 // Without the fix in place, this test would have failed with
3908 // - Expected: 2019-11-07
3909 // - Actual : 2011-07-19
3910 CPPUNIT_ASSERT_EQUAL(OUString("2019-11-07"), m_pDoc
->GetString(ScAddress(0,0,0)));
3912 m_pDoc
->DeleteTab(0);
3915 void Test::testAdvancedFilter()
3917 m_pDoc
->InsertTab(0, "Test");
3919 // cell contents (nullptr = empty cell)
3920 std::vector
<std::vector
<const char*>> aData
= {
3921 { "Value", "Tag" }, // A1:B11
3933 { "Value", "Tag" }, // A13:B14
3938 for (size_t nRow
= 0; nRow
< aData
.size(); ++nRow
)
3940 const std::vector
<const char*>& rRowData
= aData
[nRow
];
3941 for (size_t nCol
= 0; nCol
< rRowData
.size(); ++nCol
)
3943 const char* pCell
= rRowData
[nCol
];
3945 m_pDoc
->SetString(nCol
, nRow
, 0, OUString::createFromAscii(pCell
));
3949 ScDBData
* pDBData
= new ScDBData(STR_DB_GLOBAL_NONAME
, 0, 0, 0, 1, 10);
3950 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3952 ScRange
aDataRange(0,0,0,1,10,0);
3953 ScRange
aFilterRuleRange(0,12,0,1,13,0);
3955 printRange(m_pDoc
, aDataRange
, "Data");
3956 printRange(m_pDoc
, aFilterRuleRange
, "Filter Rule");
3958 ScQueryParam aQueryParam
;
3959 aQueryParam
.bHasHeader
= true;
3960 aQueryParam
.nCol1
= aDataRange
.aStart
.Col();
3961 aQueryParam
.nRow1
= aDataRange
.aStart
.Row();
3962 aQueryParam
.nCol2
= aDataRange
.aEnd
.Col();
3963 aQueryParam
.nRow2
= aDataRange
.aEnd
.Row();
3964 aQueryParam
.nTab
= aDataRange
.aStart
.Tab();
3966 bool bGood
= m_pDoc
->CreateQueryParam(aFilterRuleRange
, aQueryParam
);
3967 CPPUNIT_ASSERT_MESSAGE("failed to create query param.", bGood
);
3969 // First entry is for the 'Value' field, and is greater than 5.
3970 ScQueryEntry aEntry
= aQueryParam
.GetEntry(0);
3971 CPPUNIT_ASSERT(aEntry
.bDoQuery
);
3972 CPPUNIT_ASSERT_EQUAL(SCCOLROW(0), aEntry
.nField
);
3973 CPPUNIT_ASSERT_EQUAL(SC_GREATER
, aEntry
.eOp
);
3975 ScQueryEntry::QueryItemsType aItems
= aEntry
.GetQueryItems();
3976 CPPUNIT_ASSERT_EQUAL(size_t(1), aItems
.size());
3977 CPPUNIT_ASSERT_EQUAL(ScQueryEntry::ByValue
, aItems
[0].meType
);
3978 CPPUNIT_ASSERT_EQUAL(5.0, aItems
[0].mfVal
);
3980 // Second entry is for the 'Tag' field, and is == 'R'.
3981 aEntry
= aQueryParam
.GetEntry(1);
3982 CPPUNIT_ASSERT(aEntry
.bDoQuery
);
3983 CPPUNIT_ASSERT_EQUAL(SCCOLROW(1), aEntry
.nField
);
3984 CPPUNIT_ASSERT_EQUAL(SC_EQUAL
, aEntry
.eOp
);
3986 aItems
= aEntry
.GetQueryItems();
3987 CPPUNIT_ASSERT_EQUAL(size_t(1), aItems
.size());
3988 CPPUNIT_ASSERT_EQUAL(ScQueryEntry::ByString
, aItems
[0].meType
);
3989 CPPUNIT_ASSERT_EQUAL(OUString("R"), aItems
[0].maString
.getString());
3991 // perform the query.
3992 m_pDoc
->Query(0, aQueryParam
, true);
3994 // Only rows 1,8-10 should be visible.
3995 bool bFiltered
= m_pDoc
->RowFiltered(0, 0);
3996 CPPUNIT_ASSERT_MESSAGE("row 1 (header row) should be visible", !bFiltered
);
3998 SCROW nRow1
= -1, nRow2
= -1;
3999 bFiltered
= m_pDoc
->RowFiltered(1, 0, &nRow1
, &nRow2
);
4000 CPPUNIT_ASSERT_MESSAGE("rows 2-7 should be filtered out.", bFiltered
);
4001 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2-7 should be filtered out.", SCROW(1), nRow1
);
4002 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2-7 should be filtered out.", SCROW(6), nRow2
);
4004 bFiltered
= m_pDoc
->RowFiltered(7, 0, &nRow1
, &nRow2
);
4005 CPPUNIT_ASSERT_MESSAGE("rows 8-10 should be visible.", !bFiltered
);
4006 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 8-10 should be visible.", SCROW(7), nRow1
);
4007 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 8-10 should be visible.", SCROW(9), nRow2
);
4009 m_pDoc
->DeleteTab(0);
4012 void Test::testDateFilterContains()
4014 m_pDoc
->InsertTab(0, "Test");
4016 constexpr SCCOL nCols
= 1;
4017 constexpr SCROW nRows
= 5;
4018 m_pDoc
->SetString(0, 0, 0, "Date");
4019 m_pDoc
->SetString(0, 1, 0, "1/2/2021");
4020 m_pDoc
->SetString(0, 2, 0, "2/1/1999");
4021 m_pDoc
->SetString(0, 3, 0, "2/1/1997");
4022 m_pDoc
->SetString(0, 4, 0, "3/3/2001");
4023 m_pDoc
->SetString(0, 5, 0, "3/3/1996");
4025 // Set the fields as dates.
4026 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
4027 sal_uInt32 nFormat
= pFormatter
->GetFormatIndex(NF_DATE_DIN_YYMMDD
, LANGUAGE_ENGLISH_US
);
4028 ScPatternAttr
aNewAttrs(m_pDoc
->GetPool());
4029 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
4030 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
4031 m_pDoc
->ApplyPatternAreaTab(0, 1, 0, 5, 0, aNewAttrs
); // apply it to A1:A6
4033 ScDBData
* pDBData
= new ScDBData("NONAME", 0, 0, 0, nCols
, nRows
);
4034 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
4036 pDBData
->SetAutoFilter(true);
4038 pDBData
->GetArea(aRange
);
4039 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
4040 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
4041 aRange
.aStart
.Tab(), ScMF::Auto
);
4043 //create the query param
4044 ScQueryParam aParam
;
4045 pDBData
->GetQueryParam(aParam
);
4046 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
4047 rEntry
.bDoQuery
= true;
4049 rEntry
.eOp
= SC_CONTAINS
;
4050 rEntry
.GetQueryItem().maString
= m_pDoc
->GetSharedStringPool().intern("2");
4051 pDBData
->SetQueryParam(aParam
);
4053 // perform the query.
4054 m_pDoc
->Query(0, aParam
, true);
4056 // Dates in rows 2-4 contain '2', row 5 shows 2001 only as 01, and row 6 doesn't contain it at all.
4057 CPPUNIT_ASSERT_MESSAGE("row 2 should be visible", !m_pDoc
->RowHidden(1, 0));
4058 CPPUNIT_ASSERT_MESSAGE("row 3 should be visible", !m_pDoc
->RowHidden(2, 0));
4059 CPPUNIT_ASSERT_MESSAGE("row 4 should be visible", !m_pDoc
->RowHidden(3, 0));
4060 CPPUNIT_ASSERT_MESSAGE("row 5 should be hidden", m_pDoc
->RowHidden(4, 0));
4061 CPPUNIT_ASSERT_MESSAGE("row 6 should be hidden", m_pDoc
->RowHidden(5, 0));
4063 m_pDoc
->DeleteTab(0);
4066 void Test::testTdf98642()
4068 m_pDoc
->InsertTab(0, "Sheet1");
4069 m_pDoc
->SetString(0, 0, 0, "test");
4071 ScRangeData
* pName1
= new ScRangeData( *m_pDoc
, "name1", "$Sheet1.$A$1");
4072 ScRangeData
* pName2
= new ScRangeData( *m_pDoc
, "name2", "$Sheet1.$A$1");
4074 std::unique_ptr
<ScRangeName
> pGlobalRangeName(new ScRangeName());
4075 pGlobalRangeName
->insert(pName1
);
4076 pGlobalRangeName
->insert(pName2
);
4077 m_pDoc
->SetRangeName(std::move(pGlobalRangeName
));
4079 m_pDoc
->SetString(1, 0, 0, "=name1");
4080 m_pDoc
->SetString(1, 1, 0, "=name2");
4082 CPPUNIT_ASSERT_EQUAL(OUString("test"), m_pDoc
->GetString(1, 0, 0));
4083 CPPUNIT_ASSERT_EQUAL(OUString("test"), m_pDoc
->GetString(1, 1, 0));
4085 OUString aFormula
= m_pDoc
->GetFormula(1,0,0);
4086 CPPUNIT_ASSERT_EQUAL(OUString("=name1"), aFormula
);
4087 aFormula
= m_pDoc
->GetFormula(1,1,0);
4089 // Without the fix in place, this test would have failed with
4090 // - Expected: =name2
4091 // - Actual : =name1
4092 CPPUNIT_ASSERT_EQUAL(OUString("=name2"), aFormula
);
4094 m_pDoc
->DeleteTab(0);
4097 void Test::testMergedCells()
4099 //test merge and unmerge
4100 //TODO: an undo/redo test for this would be a good idea
4101 m_pDoc
->InsertTab(0, "Sheet1");
4102 m_pDoc
->DoMerge(1, 1, 3, 3, 0, false);
4105 m_pDoc
->ExtendMerge( 1, 1, nEndCol
, nEndRow
, 0);
4106 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not merge cells", SCCOL(3), nEndCol
);
4107 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not merge cells", SCROW(3), nEndRow
);
4108 ScRange
aRange(0,2,0,m_pDoc
->MaxCol(),2,0);
4109 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4110 aMark
.SetMarkArea(aRange
);
4111 m_xDocShell
->GetDocFunc().InsertCells(aRange
, &aMark
, INS_INSROWS_BEFORE
, true, true);
4112 m_pDoc
->ExtendMerge(1, 1, nEndCol
, nEndRow
, 0);
4113 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not increase merge area", SCCOL(3), nEndCol
);
4114 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not increase merge area", SCROW(4), nEndRow
);
4115 m_pDoc
->DeleteTab(0);
4118 void Test::testRenameTable()
4120 //test set rename table
4121 //TODO: set name1 and name2 and do an undo to check if name 1 is set now
4122 //TODO: also check if new name for table is same as another table
4124 m_pDoc
->InsertTab(0, "Sheet1");
4125 m_pDoc
->InsertTab(1, "Sheet2");
4127 //test case 1 , rename table2 to sheet 1, it should return error
4128 OUString nameToSet
= "Sheet1";
4129 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4130 CPPUNIT_ASSERT_MESSAGE("name same as another table is being set", !rDocFunc
.RenameTable(1,nameToSet
,false,true) );
4132 //test case 2 , simple rename to check name
4133 nameToSet
= "test1";
4134 m_xDocShell
->GetDocFunc().RenameTable(0,nameToSet
,false,true);
4135 OUString nameJustSet
;
4136 m_pDoc
->GetName(0,nameJustSet
);
4137 CPPUNIT_ASSERT_EQUAL_MESSAGE("table not renamed", nameToSet
, nameJustSet
);
4139 //test case 3 , rename again
4141 m_pDoc
->GetName(0,anOldName
);
4143 nameToSet
= "test2";
4144 rDocFunc
.RenameTable(0,nameToSet
,false,true);
4145 m_pDoc
->GetName(0,nameJustSet
);
4146 CPPUNIT_ASSERT_EQUAL_MESSAGE("table not renamed", nameToSet
, nameJustSet
);
4148 //test case 4 , check if undo works
4149 SfxUndoAction
* pUndo
= new ScUndoRenameTab(m_xDocShell
.get(),0,anOldName
,nameToSet
);
4151 m_pDoc
->GetName(0,nameJustSet
);
4152 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct name is not set after undo", nameJustSet
, anOldName
);
4155 m_pDoc
->GetName(0,nameJustSet
);
4156 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after redo", nameJustSet
, nameToSet
);
4159 m_pDoc
->DeleteTab(0);
4160 m_pDoc
->DeleteTab(1);
4163 void Test::testSetBackgroundColor()
4165 //test set background color
4166 //TODO: set color1 and set color2 and do an undo to check if color1 is set now.
4168 m_pDoc
->InsertTab(0, "Sheet1");
4173 m_xDocShell
->GetDocFunc().SetTabBgColor(0,aColor
,false, true);
4174 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set",
4175 aColor
, m_pDoc
->GetTabBgColor(0));
4177 Color aOldTabBgColor
=m_pDoc
->GetTabBgColor(0);
4179 m_xDocShell
->GetDocFunc().SetTabBgColor(0,aColor
,false, true);
4180 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set the second time",
4181 aColor
, m_pDoc
->GetTabBgColor(0));
4183 //now check for undo
4184 SfxUndoAction
* pUndo
= new ScUndoTabColor(m_xDocShell
.get(), 0, aOldTabBgColor
, aColor
);
4186 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after undo", aOldTabBgColor
, m_pDoc
->GetTabBgColor(0));
4188 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after undo", aColor
, m_pDoc
->GetTabBgColor(0));
4190 m_pDoc
->DeleteTab(0);
4193 void Test::testUpdateReference()
4195 //test that formulas are correctly updated during sheet delete
4196 //TODO: add tests for relative references, updating of named ranges, ...
4197 m_pDoc
->InsertTab(0, "Sheet1");
4198 m_pDoc
->InsertTab(1, "Sheet2");
4199 m_pDoc
->InsertTab(2, "Sheet3");
4200 m_pDoc
->InsertTab(3, "Sheet4");
4202 m_pDoc
->SetValue(0,0,2, 1);
4203 m_pDoc
->SetValue(1,0,2, 2);
4204 m_pDoc
->SetValue(1,1,3, 4);
4205 m_pDoc
->SetString(2,0,2, "=A1+B1");
4206 m_pDoc
->SetString(2,1,2, "=Sheet4.B2+A1");
4209 aValue
= m_pDoc
->GetValue(2,0,2);
4210 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", aValue
, 3);
4211 aValue
= m_pDoc
->GetValue(2,1,2);
4212 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", aValue
, 5);
4214 //test deleting both sheets: one is not directly before the sheet, the other one is
4215 m_pDoc
->DeleteTab(0);
4216 aValue
= m_pDoc
->GetValue(2,0,1);
4217 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", aValue
, 3);
4218 aValue
= m_pDoc
->GetValue(2,1,1);
4219 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", aValue
, 5);
4221 m_pDoc
->DeleteTab(0);
4222 aValue
= m_pDoc
->GetValue(2,0,0);
4223 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", aValue
, 3);
4224 aValue
= m_pDoc
->GetValue(2,1,0);
4225 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", aValue
, 5);
4227 //test adding two sheets
4228 m_pDoc
->InsertTab(0, "Sheet2");
4229 aValue
= m_pDoc
->GetValue(2,0,1);
4230 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", aValue
, 3);
4231 aValue
= m_pDoc
->GetValue(2,1,1);
4232 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", aValue
, 5);
4234 m_pDoc
->InsertTab(0, "Sheet1");
4235 aValue
= m_pDoc
->GetValue(2,0,2);
4236 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", aValue
, 3);
4237 aValue
= m_pDoc
->GetValue(2,1,2);
4238 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", aValue
, 5);
4240 //test new DeleteTabs/InsertTabs methods
4241 m_pDoc
->DeleteTabs(0, 2);
4242 aValue
= m_pDoc
->GetValue(2, 0, 0);
4243 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", aValue
, 3);
4244 aValue
= m_pDoc
->GetValue(2, 1, 0);
4245 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", aValue
, 5);
4247 std::vector
<OUString
> aSheets
;
4248 aSheets
.emplace_back("Sheet1");
4249 aSheets
.emplace_back("Sheet2");
4250 m_pDoc
->InsertTabs(0, aSheets
, true);
4251 aValue
= m_pDoc
->GetValue(2, 0, 2);
4253 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", aValue
, 3);
4254 aValue
= m_pDoc
->GetValue(2, 1, 2);
4255 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", aValue
, 5);
4257 m_pDoc
->DeleteTab(3);
4258 m_pDoc
->DeleteTab(2);
4259 m_pDoc
->DeleteTab(1);
4260 m_pDoc
->DeleteTab(0);
4262 // Test positional update and invalidation of lookup cache for insertion
4263 // and deletion within entire column reference.
4264 m_pDoc
->InsertTab(0, "Sheet1");
4265 m_pDoc
->InsertTab(1, "Sheet2");
4266 m_pDoc
->SetString(0,1,0, "s1");
4267 m_pDoc
->SetString(0,0,1, "=MATCH(\"s1\";Sheet1.A:A;0)");
4268 aValue
= m_pDoc
->GetValue(0,0,1);
4269 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 2, aValue
);
4270 m_pDoc
->InsertRow(0,0,m_pDoc
->MaxCol(),0,0,1); // insert 1 row before row 1 in Sheet1
4271 aValue
= m_pDoc
->GetValue(0,0,1);
4272 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 3, aValue
);
4273 m_pDoc
->DeleteRow(0,0,m_pDoc
->MaxCol(),0,0,1); // delete row 1 in Sheet1
4274 aValue
= m_pDoc
->GetValue(0,0,1);
4275 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 2, aValue
);
4276 m_pDoc
->DeleteTab(1);
4277 m_pDoc
->DeleteTab(0);
4280 void Test::testSearchCells()
4282 m_pDoc
->InsertTab(0, "Test");
4284 m_pDoc
->SetString(ScAddress(0,0,0), "A");
4285 m_pDoc
->SetString(ScAddress(0,1,0), "B");
4286 m_pDoc
->SetString(ScAddress(0,2,0), "A");
4288 m_pDoc
->SetString(ScAddress(0,4,0), "A");
4289 m_pDoc
->SetString(ScAddress(0,5,0), "B");
4290 m_pDoc
->SetString(ScAddress(0,6,0), "C");
4292 SvxSearchItem
aItem(SID_SEARCH_ITEM
);
4293 aItem
.SetSearchString("A");
4294 aItem
.SetCommand(SvxSearchCmd::FIND_ALL
);
4295 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4296 aMarkData
.SelectOneTable(0);
4300 ScRangeList aMatchedRanges
;
4302 bool bMatchedRangesWereClamped
= false;
4303 bool bSuccess
= m_pDoc
->SearchAndReplace(aItem
, nCol
, nRow
, nTab
, aMarkData
, aMatchedRanges
, aUndoStr
, nullptr, bMatchedRangesWereClamped
);
4305 CPPUNIT_ASSERT_MESSAGE("Search And Replace should succeed", bSuccess
);
4306 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 3 matching cells.", size_t(3), aMatchedRanges
.size());
4307 ScAddress
aHit(0,0,0);
4308 CPPUNIT_ASSERT_MESSAGE("A1 should be inside the matched range.", aMatchedRanges
.Contains(aHit
));
4310 CPPUNIT_ASSERT_MESSAGE("A3 should be inside the matched range.", aMatchedRanges
.Contains(aHit
));
4312 CPPUNIT_ASSERT_MESSAGE("A5 should be inside the matched range.", aMatchedRanges
.Contains(aHit
));
4314 m_pDoc
->DeleteTab(0);
4317 void Test::testFormulaPosition()
4319 m_pDoc
->InsertTab(0, "Test");
4321 ScAddress
aPos(0,0,0); // A1
4322 m_pDoc
->SetString(aPos
, "=ROW()");
4323 aPos
.IncRow(); // A2
4324 m_pDoc
->SetString(aPos
, "=ROW()");
4325 aPos
.SetRow(3); // A4;
4326 m_pDoc
->SetString(aPos
, "=ROW()");
4329 SCROW aRows
[] = { 0, 1, 3 };
4330 bool bRes
= checkFormulaPositions(*m_pDoc
, aPos
.Tab(), aPos
.Col(), aRows
, SAL_N_ELEMENTS(aRows
));
4331 CPPUNIT_ASSERT(bRes
);
4334 m_pDoc
->InsertRow(0,0,0,0,1,5); // Insert 5 rows at A2.
4336 SCROW aRows
[] = { 0, 6, 8 };
4337 bool bRes
= checkFormulaPositions(*m_pDoc
, aPos
.Tab(), aPos
.Col(), aRows
, SAL_N_ELEMENTS(aRows
));
4338 CPPUNIT_ASSERT(bRes
);
4341 m_pDoc
->DeleteTab(0);
4346 bool hasRange(const ScDocument
* pDoc
, const std::vector
<ScTokenRef
>& rRefTokens
, const ScRange
& rRange
, const ScAddress
& rPos
)
4348 for (const ScTokenRef
& p
: rRefTokens
)
4350 if (!ScRefTokenHelper::isRef(p
) || ScRefTokenHelper::isExternalRef(p
))
4353 switch (p
->GetType())
4355 case formula::svSingleRef
:
4357 ScSingleRefData aData
= *p
->GetSingleRef();
4358 if (rRange
.aStart
!= rRange
.aEnd
)
4361 ScAddress aThis
= aData
.toAbs(*pDoc
, rPos
);
4362 if (aThis
== rRange
.aStart
)
4366 case formula::svDoubleRef
:
4368 ScComplexRefData aData
= *p
->GetDoubleRef();
4369 ScRange aThis
= aData
.toAbs(*pDoc
, rPos
);
4370 if (aThis
== rRange
)
4383 void Test::testJumpToPrecedentsDependents()
4385 // Precedent is another cell that the cell references, while dependent is
4386 // another cell that references it.
4387 m_pDoc
->InsertTab(0, "Test");
4389 m_pDoc
->SetString(2, 0, 0, "=A1+A2+B3"); // C1
4390 m_pDoc
->SetString(2, 1, 0, "=A1"); // C2
4393 std::vector
<ScTokenRef
> aRefTokens
;
4394 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4397 // C1's precedent should be A1:A2,B3.
4398 ScAddress
aC1(2, 0, 0);
4399 ScRangeList
aRange(aC1
);
4400 rDocFunc
.DetectiveCollectAllPreds(aRange
, aRefTokens
);
4401 CPPUNIT_ASSERT_MESSAGE("A1:A2 should be a precedent of C1.",
4402 hasRange(m_pDoc
, aRefTokens
, ScRange(0, 0, 0, 0, 1, 0), aC1
));
4403 CPPUNIT_ASSERT_MESSAGE("B3 should be a precedent of C1.",
4404 hasRange(m_pDoc
, aRefTokens
, ScRange(1, 2, 0), aC1
));
4408 // C2's precedent should be A1 only.
4409 ScAddress
aC2(2, 1, 0);
4410 ScRangeList
aRange(aC2
);
4411 rDocFunc
.DetectiveCollectAllPreds(aRange
, aRefTokens
);
4412 CPPUNIT_ASSERT_EQUAL_MESSAGE("there should only be one reference token.",
4413 static_cast<size_t>(1), aRefTokens
.size());
4414 CPPUNIT_ASSERT_MESSAGE("A1 should be a precedent of C1.",
4415 hasRange(m_pDoc
, aRefTokens
, ScRange(0, 0, 0), aC2
));
4419 // A1's dependent should be C1:C2.
4420 ScAddress
aA1(0, 0, 0);
4421 ScRangeList
aRange(aA1
);
4422 rDocFunc
.DetectiveCollectAllSuccs(aRange
, aRefTokens
);
4423 CPPUNIT_ASSERT_EQUAL_MESSAGE("C1:C2 should be the only dependent of A1.",
4424 std::vector
<ScTokenRef
>::size_type(1), aRefTokens
.size());
4425 CPPUNIT_ASSERT_MESSAGE("C1:C2 should be the only dependent of A1.",
4426 hasRange(m_pDoc
, aRefTokens
, ScRange(2, 0, 0, 2, 1, 0), aA1
));
4429 m_pDoc
->DeleteTab(0);
4432 void Test::testTdf149665()
4434 m_pDoc
->InsertTab(0, "Test");
4436 m_pDoc
->SetString(0, 0, 0, "''1");
4438 // Without the fix in place, this test would have failed with
4441 CPPUNIT_ASSERT_EQUAL( OUString("'1"), m_pDoc
->GetString( 0, 0, 0 ) );
4443 m_pDoc
->DeleteTab(0);
4446 void Test::testTdf64001()
4448 m_pDoc
->InsertTab(0, "test");
4450 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4451 aMarkData
.SelectTable(0, true);
4453 m_pDoc
->SetString( 0, 0, 0, "TRUE" );
4454 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 9, FILL_TO_BOTTOM
, FILL_AUTO
);
4456 for (SCCOL i
= 0; i
< 10; ++i
)
4458 CPPUNIT_ASSERT_EQUAL( OUString("TRUE"), m_pDoc
->GetString( 0, i
, 0 ) );
4461 m_pDoc
->SetString( 0, 10, 0, "FALSE" );
4463 m_pDoc
->SetString( 1, 0, 0, "=COUNTIF(A1:A11;TRUE)" );
4465 // Without the fix in place, this test would have failed with
4468 CPPUNIT_ASSERT_EQUAL( 10.0, m_pDoc
->GetValue( 1, 0, 0 ) );
4470 m_pDoc
->DeleteTab(0);
4473 void Test::testAutoFill()
4475 m_pDoc
->InsertTab(0, "test");
4477 m_pDoc
->SetValue(0,0,0,1);
4479 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4480 aMarkData
.SelectTable(0, true);
4482 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 5);
4483 for (SCROW i
= 0; i
< 6; ++i
)
4484 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
+1.0), m_pDoc
->GetValue(0, i
, 0));
4486 // check that hidden rows are not affected by autofill
4487 // set values for hidden rows
4488 m_pDoc
->SetValue(0,1,0,10);
4489 m_pDoc
->SetValue(0,2,0,10);
4491 m_pDoc
->SetRowHidden(1, 2, 0, true);
4492 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 8);
4494 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,1,0));
4495 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,2,0));
4496 for (SCROW i
= 3; i
< 8; ++i
)
4497 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
-1.0), m_pDoc
->GetValue(0, i
, 0));
4499 m_pDoc
->Fill( 0, 0, 0, 8, nullptr, aMarkData
, 5, FILL_TO_RIGHT
);
4500 for (SCCOL i
= 0; i
< 5; ++i
)
4502 for(SCROW j
= 0; j
< 8; ++j
)
4506 ASSERT_DOUBLES_EQUAL(static_cast<double>(j
-1+i
), m_pDoc
->GetValue(i
, j
, 0));
4510 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
+1), m_pDoc
->GetValue(i
, 0, 0));
4512 else // j == 1 || j == 2
4515 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,j
,0));
4517 ASSERT_DOUBLES_EQUAL(0.0, m_pDoc
->GetValue(i
,j
,0));
4522 // test auto fill user data lists
4523 m_pDoc
->SetString( 0, 100, 0, "January" );
4524 m_pDoc
->Fill( 0, 100, 0, 100, nullptr, aMarkData
, 2, FILL_TO_BOTTOM
, FILL_AUTO
);
4525 OUString aTestValue
= m_pDoc
->GetString( 0, 101, 0 );
4526 CPPUNIT_ASSERT_EQUAL( OUString("February"), aTestValue
);
4527 aTestValue
= m_pDoc
->GetString( 0, 102, 0 );
4528 CPPUNIT_ASSERT_EQUAL( OUString("March"), aTestValue
);
4530 // test that two same user data list entries will not result in incremental fill
4531 m_pDoc
->SetString( 0, 101, 0, "January" );
4532 m_pDoc
->Fill( 0, 100, 0, 101, nullptr, aMarkData
, 2, FILL_TO_BOTTOM
, FILL_AUTO
);
4533 for ( SCROW i
= 102; i
<= 103; ++i
)
4535 aTestValue
= m_pDoc
->GetString( 0, i
, 0 );
4536 CPPUNIT_ASSERT_EQUAL( OUString("January"), aTestValue
);
4539 // Clear column A for a new test.
4540 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4541 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4543 // Fill A1:A6 with 1,2,3,4,5,6.
4544 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
4545 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
4546 ScRange
aRange(0,0,0,0,5,0);
4547 aMarkData
.SetMarkArea(aRange
);
4548 rFunc
.FillSeries(aRange
, &aMarkData
, FILL_TO_BOTTOM
, FILL_AUTO
, FILL_DAY
, MAXDOUBLE
, 1.0, MAXDOUBLE
, true);
4549 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4550 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4551 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
4552 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
4553 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
4554 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
4556 // Undo should clear the area except for the top cell.
4557 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
4558 CPPUNIT_ASSERT(pUndoMgr
);
4561 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4562 for (SCROW i
= 1; i
<= 5; ++i
)
4563 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE
, m_pDoc
->GetCellType(ScAddress(0,i
,0)));
4565 // Redo should put the serial values back in.
4567 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4568 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4569 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
4570 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
4571 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
4572 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
4574 // test that filling formulas vertically up does the right thing
4575 for(SCROW nRow
= 0; nRow
< 10; ++nRow
)
4576 m_pDoc
->SetValue(100, 100 + nRow
, 0, 1);
4578 m_pDoc
->SetString(100, 110, 0, "=A111");
4580 m_pDoc
->Fill(100, 110, 100, 110, nullptr, aMarkData
, 10, FILL_TO_TOP
, FILL_AUTO
);
4581 for(SCROW nRow
= 110; nRow
>= 100; --nRow
)
4583 OUString aExpected
= "=A" + OUString::number(nRow
+1);
4584 OUString aFormula
= m_pDoc
->GetFormula(100, nRow
, 0);
4585 CPPUNIT_ASSERT_EQUAL(aExpected
, aFormula
);
4588 // Clear column A for a new test.
4589 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4590 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4592 m_pDoc
->SetString( 0, 100, 0, "2012-10-31" );
4593 m_pDoc
->SetString( 0, 101, 0, "2012-10-31" );
4594 m_pDoc
->Fill( 0, 100, 0, 101, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4596 // tdf#89754, Without the fix in place, this test would have failed with
4597 // - Expected: 2012-10-31
4598 // - Actual : 2012-11-01
4599 CPPUNIT_ASSERT_EQUAL( OUString("2012-10-31"), m_pDoc
->GetString( 0, 102, 0 ) );
4600 CPPUNIT_ASSERT_EQUAL( OUString("2012-10-31"), m_pDoc
->GetString( 0, 103, 0 ) );
4601 CPPUNIT_ASSERT_EQUAL( OUString("2012-10-31"), m_pDoc
->GetString( 0, 104, 0 ) );
4603 // Clear column A for a new test.
4604 clearRange(m_pDoc
, ScRange(0, 0, 0, 0, m_pDoc
->MaxRow(), 0));
4605 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4607 m_pDoc
->SetString(0, 100, 0, "2019-10-31");
4608 m_pDoc
->SetString(0, 101, 0, "2019-11-30");
4609 m_pDoc
->SetString(0, 102, 0, "2019-12-31");
4610 m_pDoc
->Fill(0, 100, 0, 102, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4612 // tdf#58745, Without the fix in place, this test would have failed with
4613 // - Expected: 2020-01-31
4614 // - Actual : 2019-01-11
4615 CPPUNIT_ASSERT_EQUAL(OUString("2020-01-31"), m_pDoc
->GetString(0, 103, 0));
4616 CPPUNIT_ASSERT_EQUAL(OUString("2020-02-29"), m_pDoc
->GetString(0, 104, 0));
4617 CPPUNIT_ASSERT_EQUAL(OUString("2020-03-31"), m_pDoc
->GetString(0, 105, 0));
4619 // Clear column A for a new test.
4620 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4621 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4623 m_pDoc
->SetString( 0, 50, 0, "1.0" );
4624 m_pDoc
->SetString( 0, 51, 0, "1.1" );
4625 m_pDoc
->SetString( 0, 52, 0, "1.2" );
4626 m_pDoc
->SetString( 0, 53, 0, "1.3" );
4627 m_pDoc
->Fill( 0, 50, 0, 53, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4629 CPPUNIT_ASSERT_EQUAL( OUString("1.4"), m_pDoc
->GetString( 0, 54, 0 ) );
4630 CPPUNIT_ASSERT_EQUAL( OUString("1.5"), m_pDoc
->GetString( 0, 55, 0 ) );
4631 CPPUNIT_ASSERT_EQUAL( OUString("1.6"), m_pDoc
->GetString( 0, 56, 0 ) );
4633 m_pDoc
->SetString( 0, 60, 0, "4.0" );
4634 m_pDoc
->SetString( 0, 61, 0, "4.1" );
4635 m_pDoc
->SetString( 0, 62, 0, "4.2" );
4636 m_pDoc
->SetString( 0, 63, 0, "4.3" );
4637 m_pDoc
->Fill( 0, 60, 0, 63, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4639 // tdf#37424: Without the fix in place, this test would have failed with
4642 CPPUNIT_ASSERT_EQUAL( OUString("4.4"), m_pDoc
->GetString( 0, 64, 0 ) );
4643 CPPUNIT_ASSERT_EQUAL( OUString("4.5"), m_pDoc
->GetString( 0, 65, 0 ) );
4644 CPPUNIT_ASSERT_EQUAL( OUString("4.6"), m_pDoc
->GetString( 0, 66, 0 ) );
4646 // Clear column A for a new test.
4647 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4648 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4650 m_pDoc
->SetString( 0, 70, 0, "001-001-001" );
4651 m_pDoc
->Fill( 0, 70, 0, 70, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4653 // tdf#105268: Without the fix in place, this test would have failed with
4654 // - Expected: 001-001-002
4655 // - Actual : 001-001000
4656 CPPUNIT_ASSERT_EQUAL( OUString("001-001-002"), m_pDoc
->GetString( 0, 71, 0 ) );
4657 CPPUNIT_ASSERT_EQUAL( OUString("001-001-003"), m_pDoc
->GetString( 0, 72, 0 ) );
4658 CPPUNIT_ASSERT_EQUAL( OUString("001-001-004"), m_pDoc
->GetString( 0, 73, 0 ) );
4660 // Clear column A for a new test.
4661 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4662 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4664 m_pDoc
->SetString( 0, 80, 0, "1%" );
4665 m_pDoc
->Fill( 0, 80, 0, 80, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4667 // tdf#89998: Without the fix in place, this test would have failed with
4668 // - Expected: 2.00%
4669 // - Actual : 101.00%
4670 CPPUNIT_ASSERT_EQUAL( OUString("2.00%"), m_pDoc
->GetString( 0, 81, 0 ) );
4671 CPPUNIT_ASSERT_EQUAL( OUString("3.00%"), m_pDoc
->GetString( 0, 82, 0 ) );
4672 CPPUNIT_ASSERT_EQUAL( OUString("4.00%"), m_pDoc
->GetString( 0, 83, 0 ) );
4674 // Clear column A for a new test.
4675 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4676 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4678 m_pDoc
->SetString( 0, 0, 0, "1" );
4679 m_pDoc
->SetString( 0, 1, 0, "1.1" );
4680 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 60, FILL_TO_BOTTOM
, FILL_AUTO
);
4682 // tdf#129606: Without the fix in place, this test would have failed with
4684 // - Actual : 6.00000000000001
4685 CPPUNIT_ASSERT_EQUAL( OUString("6"), m_pDoc
->GetString( 0, 50, 0 ) );
4687 // Clear column A for a new test.
4688 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4689 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4691 m_pDoc
->SetString( 0, 0, 0, "2022-10-01 00:00:00.000" );
4692 m_pDoc
->SetString( 0, 1, 0, "2022-10-01 01:00:00.000" );
4693 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 25, FILL_TO_BOTTOM
, FILL_AUTO
);
4695 // tdf#151460: Without the fix in place, this test would have failed with
4696 // - Expected: 2022-10-01 20:00:00.000
4697 // - Actual : 2022-10-01 19:59:59.999
4698 CPPUNIT_ASSERT_EQUAL( OUString("2022-10-01 20:00:00.000"), m_pDoc
->GetString( 0, 20, 0 ) );
4700 // Clear column A for a new test.
4701 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4702 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4704 m_pDoc
->SetString( 0, 0, 0, "1st" );
4706 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 5, FILL_TO_BOTTOM
, FILL_AUTO
);
4708 CPPUNIT_ASSERT_EQUAL( OUString("1st"), m_pDoc
->GetString( 0, 0, 0 ) );
4709 CPPUNIT_ASSERT_EQUAL( OUString("2nd"), m_pDoc
->GetString( 0, 1, 0 ) );
4710 CPPUNIT_ASSERT_EQUAL( OUString("3rd"), m_pDoc
->GetString( 0, 2, 0 ) );
4712 m_pDoc
->DeleteTab(0);
4715 void Test::testAutoFillSimple()
4717 m_pDoc
->InsertTab(0, "test");
4719 m_pDoc
->SetValue(0, 0, 0, 1);
4720 m_pDoc
->SetString(0, 1, 0, "=10");
4722 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4723 aMarkData
.SelectTable(0, true);
4725 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 6, FILL_TO_BOTTOM
, FILL_AUTO
);
4727 for(SCROW nRow
= 0; nRow
< 8; ++nRow
)
4731 double nVal
= m_pDoc
->GetValue(0, nRow
, 0);
4732 CPPUNIT_ASSERT_EQUAL((nRow
+2)/2.0, nVal
);
4736 OString aMsg
= "wrong value in row: " + OString::number(nRow
);
4737 double nVal
= m_pDoc
->GetValue(0, nRow
, 0);
4738 CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg
.getStr(), 10.0, nVal
);
4742 m_pDoc
->DeleteTab(0);
4745 void Test::testFindAreaPosVertical()
4747 std::vector
<std::vector
<const char*>> aData
= {
4748 { nullptr, "1", "1" },
4749 { "1", nullptr, "1" },
4751 { nullptr, "1", "1" },
4753 { "1", nullptr, "1" },
4757 m_pDoc
->InsertTab(0, "Test1");
4758 clearRange( m_pDoc
, ScRange(0, 0, 0, 1, aData
.size(), 0));
4759 ScAddress
aPos(0,0,0);
4760 ScRange aDataRange
= insertRangeData( m_pDoc
, aPos
, aData
);
4761 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
4763 m_pDoc
->SetRowHidden(4,4,0,true);
4764 bool bHidden
= m_pDoc
->RowHidden(4,0);
4765 CPPUNIT_ASSERT(bHidden
);
4769 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4771 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4772 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4774 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4776 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), nRow
);
4777 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4779 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4781 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(5), nRow
);
4782 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4784 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4786 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), nRow
);
4787 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4789 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4791 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxRow(), nRow
);
4792 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4797 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4799 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), nRow
);
4800 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4802 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4804 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), nRow
);
4805 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4809 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_UP
);
4810 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4811 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), nCol
);
4813 m_pDoc
->DeleteTab(0);
4816 void Test::testFindAreaPosColRight()
4818 std::vector
<std::vector
<const char*>> aData
= {
4819 { "", "1", "1", "", "1", "1", "1" },
4820 { "", "", "1", "1", "1", "", "1" },
4823 m_pDoc
->InsertTab(0, "test1");
4824 clearRange( m_pDoc
, ScRange(0, 0, 0, 7, aData
.size(), 0));
4825 ScAddress
aPos(0,0,0);
4826 ScRange aDataRange
= insertRangeData( m_pDoc
, aPos
, aData
);
4827 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
4829 m_pDoc
->SetColHidden(4,4,0,true);
4830 bool bHidden
= m_pDoc
->ColHidden(4,0);
4831 CPPUNIT_ASSERT(bHidden
);
4835 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4837 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4838 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4840 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4842 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4843 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), nCol
);
4845 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4847 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4848 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(5), nCol
);
4850 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4852 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4853 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(6), nCol
);
4855 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4857 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4858 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxCol(), nCol
);
4863 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4865 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4866 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(3), nCol
);
4868 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4870 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4871 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(6), nCol
);
4873 m_pDoc
->DeleteTab(0);
4876 void Test::testShiftCells()
4878 m_pDoc
->InsertTab(0, "foo");
4880 // We need a drawing layer in order to create caption objects.
4881 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4883 OUString
aTestVal("Some Text");
4885 // Text into cell E5.
4886 m_pDoc
->SetString(4, 3, 0, aTestVal
);
4888 // put a Note in cell E5
4889 ScAddress
rAddr(4, 3, 0);
4890 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
4891 pNote
->SetText(rAddr
, "Hello");
4893 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(4, 3, 0));
4895 // Insert cell at D5. This should shift the string cell to right.
4896 m_pDoc
->InsertCol(3, 0, 3, 0, 3, 1);
4897 OUString aStr
= m_pDoc
->GetString(5, 3, 0);
4898 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have a string cell here.", aTestVal
, aStr
);
4899 CPPUNIT_ASSERT_MESSAGE("D5 is supposed to be blank.", m_pDoc
->IsBlockEmpty(3, 4, 3, 4, 0));
4901 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc
->HasNote(4, 3, 0));
4902 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(5, 3, 0));
4904 // Delete cell D5, to shift the text cell back into D5.
4905 m_pDoc
->DeleteCol(3, 0, 3, 0, 3, 1);
4906 aStr
= m_pDoc
->GetString(4, 3, 0);
4907 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have a string cell here.", aTestVal
, aStr
);
4908 CPPUNIT_ASSERT_MESSAGE("E5 is supposed to be blank.", m_pDoc
->IsBlockEmpty(4, 4, 4, 4, 0));
4910 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc
->HasNote(5, 3, 0));
4911 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(4, 3, 0));
4913 m_pDoc
->DeleteTab(0);
4916 void Test::testNoteBasic()
4918 m_pDoc
->InsertTab(0, "PostIts");
4920 // We need a drawing layer in order to create caption objects.
4921 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4923 CPPUNIT_ASSERT(!m_pDoc
->HasNotes());
4925 // Check for note's presence in all tables before inserting any notes.
4926 for (SCTAB i
= 0; i
<= MAXTAB
; ++i
)
4928 bool bHasNotes
= m_pDoc
->HasTabNotes(i
);
4929 CPPUNIT_ASSERT(!bHasNotes
);
4932 ScAddress
aAddr(2, 2, 0); // cell C3
4933 ScPostIt
*pNote
= m_pDoc
->GetOrCreateNote(aAddr
);
4935 pNote
->SetText(aAddr
, "Hello world");
4936 pNote
->SetAuthor("Jim Bob");
4938 ScPostIt
*pGetNote
= m_pDoc
->GetNote(aAddr
);
4939 CPPUNIT_ASSERT_EQUAL_MESSAGE("note should be itself", pNote
, pGetNote
);
4941 // Insert one row at row 1.
4942 bool bInsertRow
= m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 1);
4943 CPPUNIT_ASSERT_MESSAGE("failed to insert row", bInsertRow
);
4945 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
4946 aAddr
.IncRow(); // cell C4
4947 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4949 // Insert column at column A.
4950 bool bInsertCol
= m_pDoc
->InsertCol(0, 0, m_pDoc
->MaxRow(), 0, 1, 1);
4951 CPPUNIT_ASSERT_MESSAGE("failed to insert column", bInsertCol
);
4953 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
4954 aAddr
.IncCol(); // cell D4
4955 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4957 // Insert a new sheet to shift the current sheet to the right.
4958 m_pDoc
->InsertTab(0, "Table2");
4959 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
4960 aAddr
.IncTab(); // Move to the next sheet.
4961 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4963 m_pDoc
->DeleteTab(0);
4965 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
4967 // Insert cell at C4. This should NOT shift the note position.
4968 bInsertRow
= m_pDoc
->InsertRow(2, 0, 2, 0, 3, 1);
4969 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell at C4.", bInsertRow
);
4970 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note shouldn't have moved but it has.", pNote
, m_pDoc
->GetNote(aAddr
));
4972 // Delete cell at C4. Again, this should NOT shift the note position.
4973 m_pDoc
->DeleteRow(2, 0, 2, 0, 3, 1);
4974 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note shouldn't have moved but it has.", pNote
, m_pDoc
->GetNote(aAddr
));
4976 // Now, with the note at D4, delete cell D3. This should shift the note one cell up.
4977 m_pDoc
->DeleteRow(3, 0, 3, 0, 2, 1);
4978 aAddr
.IncRow(-1); // cell D3
4979 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at D4 should have shifted up to D3.", pNote
, m_pDoc
->GetNote(aAddr
));
4981 // Delete column C. This should shift the note one cell left.
4982 m_pDoc
->DeleteCol(0, 0, m_pDoc
->MaxRow(), 0, 2, 1);
4983 aAddr
.IncCol(-1); // cell C3
4984 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at D3 should have shifted left to C3.", pNote
, m_pDoc
->GetNote(aAddr
));
4986 // Insert a text where the note is.
4987 m_pDoc
->SetString(aAddr
, "Note is here.");
4989 // Delete row 1. This should shift the note from C3 to C2.
4990 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 1);
4991 aAddr
.IncRow(-1); // C2
4992 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at C3 should have shifted up to C2.", pNote
, m_pDoc
->GetNote(aAddr
));
4994 m_pDoc
->DeleteTab(0);
4997 void Test::testNoteDeleteRow()
4999 m_pDoc
->InsertTab(0, "Sheet1");
5001 // We need a drawing layer in order to create caption objects.
5002 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5004 ScAddress
aPos(1, 1, 0);
5005 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5006 pNote
->SetText(aPos
, "Hello");
5007 pNote
->SetAuthor("Jim Bob");
5009 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(1, 1, 0));
5011 // test with IsBlockEmpty
5012 CPPUNIT_ASSERT_MESSAGE("The Block should be detected as empty (no Notes)", m_pDoc
->IsEmptyData(0, 0, 100, 100, 0));
5013 CPPUNIT_ASSERT_MESSAGE("The Block should NOT be detected as empty", !m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
5015 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 1);
5017 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc
->HasNote(1, 1, 0));
5019 // Set values and notes into B3:B4.
5020 aPos
= ScAddress(1,2,0); // B3
5021 m_pDoc
->SetString(aPos
, "First");
5022 ScNoteUtil::CreateNoteFromString(*m_pDoc
, aPos
, "First Note", false, false);
5024 aPos
= ScAddress(1,3,0); // B4
5025 m_pDoc
->SetString(aPos
, "Second");
5026 ScNoteUtil::CreateNoteFromString(*m_pDoc
, aPos
, "Second Note", false, false);
5029 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
5030 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5031 aMark
.SelectOneTable(0);
5032 rDocFunc
.DeleteCells(ScRange(0,1,0,m_pDoc
->MaxCol(),1,0), &aMark
, DelCellCmd::CellsUp
, true);
5034 // Check to make sure the notes have shifted upward.
5035 pNote
= m_pDoc
->GetNote(ScAddress(1,1,0));
5036 CPPUNIT_ASSERT_MESSAGE("B2 should have a note.", pNote
);
5037 CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote
->GetText());
5038 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
5039 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
5040 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote
->GetText());
5041 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
5042 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote
);
5046 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5047 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr
);
5048 m_pDoc
->CreateAllNoteCaptions(); // to make sure that all notes have their corresponding caption objects...
5051 pNote
= m_pDoc
->GetNote(ScAddress(1,1,0));
5052 CPPUNIT_ASSERT_MESSAGE("B2 should NOT have a note.", !pNote
);
5053 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
5054 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
5055 CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote
->GetText());
5056 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
5057 CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote
);
5058 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote
->GetText());
5061 rDocFunc
.DeleteCells(ScRange(0,2,0,m_pDoc
->MaxCol(),2,0), &aMark
, DelCellCmd::CellsUp
, true);
5063 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
5064 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
5065 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote
->GetText());
5066 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
5067 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote
);
5069 // Undo and check the result.
5071 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
5072 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
5073 CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote
->GetText());
5074 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
5075 CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote
);
5076 CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote
->GetText());
5078 m_pDoc
->DeleteTab(0);
5081 void Test::testNoteDeleteCol()
5083 m_pDoc
->InsertTab(0, "Sheet1");
5085 // We need a drawing layer in order to create caption objects.
5086 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5088 ScAddress
rAddr(1, 1, 0);
5089 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
5090 pNote
->SetText(rAddr
, "Hello");
5091 pNote
->SetAuthor("Jim Bob");
5093 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(1, 1, 0));
5095 m_pDoc
->DeleteCol(0, 0, m_pDoc
->MaxRow(), 0, 1, 1);
5097 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc
->HasNote(1, 1, 0));
5099 m_pDoc
->DeleteTab(0);
5102 void Test::testNoteLifeCycle()
5104 m_pDoc
->InsertTab(0, "Test");
5106 // We need a drawing layer in order to create caption objects.
5107 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5109 ScAddress
aPos(1,1,0);
5110 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5111 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new cell comment.", pNote
);
5113 pNote
->SetText(aPos
, "New note");
5114 std::unique_ptr
<ScPostIt
> pNote2
= m_pDoc
->ReleaseNote(aPos
);
5115 CPPUNIT_ASSERT_EQUAL_MESSAGE("This note instance is expected to be identical to the original.", pNote
, pNote2
.get());
5116 CPPUNIT_ASSERT_MESSAGE("The note shouldn't be here after it's been released.", !m_pDoc
->HasNote(aPos
));
5118 // Modify the internal state of the note instance to make sure it's really
5120 pNote
->SetText(aPos
, "New content");
5122 // Re-insert the note back to the same place.
5123 m_pDoc
->SetNote(aPos
, std::move(pNote2
));
5124 SdrCaptionObj
* pCaption
= pNote
->GetOrCreateCaption(aPos
);
5125 CPPUNIT_ASSERT_MESSAGE("Failed to create a caption object.", pCaption
);
5126 CPPUNIT_ASSERT_EQUAL_MESSAGE("This caption should belong to the drawing layer of the document.",
5127 m_pDoc
->GetDrawLayer(), static_cast<ScDrawLayer
*>(&pCaption
->getSdrModelFromSdrObject()));
5129 // Copy B2 with note to a clipboard.
5131 ScClipParam
aClipParam(aPos
, false);
5132 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
5133 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
5134 aMarkData
.SelectOneTable(0);
5135 m_pDoc
->CopyToClip(aClipParam
, &aClipDoc
, &aMarkData
, false, true);
5137 ScPostIt
* pClipNote
= aClipDoc
.GetNote(aPos
);
5138 CPPUNIT_ASSERT_MESSAGE("Failed to copy note to the clipboard.", pClipNote
);
5139 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note on the clipboard should share the same caption object from the original.",
5140 pCaption
, pClipNote
->GetCaption());
5143 // Move B2 to B3 with note, which creates an ScUndoDragDrop, and Undo.
5145 ScAddress
aOrigPos(aPos
);
5146 ScAddress
aMovePos(1,2,0);
5147 ScPostIt
* pOrigNote
= m_pDoc
->GetNote(aOrigPos
);
5148 const SdrCaptionObj
* pOrigCaption
= pOrigNote
->GetOrCreateCaption(aOrigPos
);
5149 bool const bCut
= true; // like Drag&Drop
5150 bool bRecord
= true; // record Undo
5151 bool const bPaint
= false; // don't care about
5152 bool bApi
= true; // API to prevent dialogs
5153 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
5154 bool bMoveDone
= rDocFunc
.MoveBlock(ScRange(aOrigPos
, aOrigPos
), aMovePos
, bCut
, bRecord
, bPaint
, bApi
);
5155 CPPUNIT_ASSERT_MESSAGE("Cells not moved", bMoveDone
);
5157 // Verify the note move.
5158 ScPostIt
* pGoneNote
= m_pDoc
->GetNote(aOrigPos
);
5159 CPPUNIT_ASSERT_MESSAGE("Failed to move the note from source.", !pGoneNote
);
5160 ScPostIt
* pMoveNote
= m_pDoc
->GetNote(aMovePos
);
5161 CPPUNIT_ASSERT_MESSAGE("Failed to move the note to destination.", pMoveNote
);
5163 // The caption object should not be identical, it was newly created upon
5164 // Drop from clipboard.
5165 // pOrigCaption is a dangling pointer.
5166 const SdrCaptionObj
* pMoveCaption
= pMoveNote
->GetOrCreateCaption(aMovePos
);
5167 CPPUNIT_ASSERT_MESSAGE("Captions identical after move.", pOrigCaption
!= pMoveCaption
);
5169 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5170 CPPUNIT_ASSERT(pUndoMgr
);
5171 pUndoMgr
->Undo(); // this should not crash ... tdf#92995
5173 // Verify the note move Undo.
5174 pMoveNote
= m_pDoc
->GetNote(aMovePos
);
5175 CPPUNIT_ASSERT_MESSAGE("Failed to undo the note move from destination.", !pMoveNote
);
5176 pOrigNote
= m_pDoc
->GetNote(aOrigPos
);
5177 CPPUNIT_ASSERT_MESSAGE("Failed to undo the note move to source.", pOrigNote
);
5179 // The caption object still should not be identical.
5180 // pMoveCaption is a dangling pointer.
5181 pOrigCaption
= pOrigNote
->GetOrCreateCaption(aOrigPos
);
5182 CPPUNIT_ASSERT_MESSAGE("Captions identical after move undo.", pOrigCaption
!= pMoveCaption
);
5185 // Create a note at B4, merge B4 and B5 with ScUndoMerge, and Undo.
5187 ScAddress
aPosB4(1,3,0);
5188 ScPostIt
* pNoteB4
= m_pDoc
->GetOrCreateNote(aPosB4
);
5189 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B4.", pNoteB4
);
5190 const SdrCaptionObj
* pCaptionB4
= pNoteB4
->GetOrCreateCaption(aPosB4
);
5191 ScCellMergeOption
aCellMergeOption(1,3,2,3);
5192 rDocFunc
.MergeCells( aCellMergeOption
, true /*bContents*/, bRecord
, bApi
, false /*bEmptyMergedCells*/ );
5194 SfxUndoManager
* pMergeUndoManager
= m_pDoc
->GetUndoManager();
5195 CPPUNIT_ASSERT(pMergeUndoManager
);
5196 pMergeUndoManager
->Undo(); // this should not crash ... tdf#105667
5198 // Undo contained the original caption object pointer which was still alive
5199 // at B4 after the merge and not cloned nor recreated during Undo.
5200 ScPostIt
* pUndoNoteB4
= m_pDoc
->GetNote(aPosB4
);
5201 CPPUNIT_ASSERT_MESSAGE("No cell comment at B4 after Undo.", pUndoNoteB4
);
5202 const SdrCaptionObj
* pUndoCaptionB4
= pUndoNoteB4
->GetCaption();
5203 CPPUNIT_ASSERT_EQUAL_MESSAGE("Captions not identical after Merge Undo.", pCaptionB4
, pUndoCaptionB4
);
5206 // In a second document copy a note from B5 to clipboard, close the
5207 // document and then paste the note into this document.
5209 ScDocShellRef xDocSh2
;
5210 getNewDocShell(xDocSh2
);
5211 ScDocument
* pDoc2
= &xDocSh2
->GetDocument();
5212 pDoc2
->InsertTab(0, "OtherSheet1");
5213 pDoc2
->InitDrawLayer(xDocSh2
.get());
5215 ScAddress
aPosB5(1,4,0);
5216 ScPostIt
* pOtherNoteB5
= pDoc2
->GetOrCreateNote(aPosB5
);
5217 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B5.", pOtherNoteB5
);
5218 const SdrCaptionObj
* pOtherCaptionB5
= pOtherNoteB5
->GetOrCreateCaption(aPosB5
);
5219 CPPUNIT_ASSERT_MESSAGE("No caption at B5.", pOtherCaptionB5
);
5221 ScDocument
aClipDoc2(SCDOCMODE_CLIP
);
5222 copyToClip( pDoc2
, aPosB5
, &aClipDoc2
);
5224 // There's no ScTransferObject involved in the "fake" clipboard copy
5225 // and ScDocument dtor asking IsClipboardSource() gets no, so emulate
5226 // the part that normally is responsible for forgetting the caption
5228 aClipDoc2
.ClosingClipboardSource();
5230 pDoc2
->DeleteTab(0);
5234 pasteFromClip( m_pDoc
, aPosB5
, &aClipDoc2
); // should not crash... tdf#104967
5235 ScPostIt
* pNoteB5
= m_pDoc
->GetNote(aPosB5
);
5236 CPPUNIT_ASSERT_MESSAGE("Failed to paste cell comment at B5.", pNoteB5
);
5237 const SdrCaptionObj
* pCaptionB5
= pNoteB5
->GetOrCreateCaption(aPosB5
);
5238 CPPUNIT_ASSERT_MESSAGE("No caption at pasted B5.", pCaptionB5
);
5239 // Do not test if pCaptionB5 != pOtherCaptionB5 because since pDoc2
5240 // has been closed and the caption been deleted objects *may* be
5241 // allocated at the very same memory location.
5244 m_pDoc
->DeleteTab(0);
5247 void Test::testNoteCopyPaste()
5249 m_pDoc
->InsertTab(0, "Test");
5251 // We need a drawing layer in order to create caption objects.
5252 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5254 // Insert in B2 a text and cell comment.
5255 ScAddress
aPos(1,1,0);
5256 m_pDoc
->SetString(aPos
, "Text");
5257 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5258 CPPUNIT_ASSERT(pNote
);
5259 pNote
->SetText(aPos
, "Note1");
5261 // Insert in B4 a number and cell comment.
5263 m_pDoc
->SetValue(aPos
, 1.1);
5264 pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5265 CPPUNIT_ASSERT(pNote
);
5266 pNote
->SetText(aPos
, "Note2");
5268 // Copy B2:B4 to clipboard.
5269 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5270 aMark
.SelectOneTable(0);
5271 ScRange
aCopyRange(1,1,0,1,3,0);
5272 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
5273 aClipDoc
.ResetClip(m_pDoc
, &aMark
);
5274 ScClipParam
aClipParam(aCopyRange
, false);
5275 m_pDoc
->CopyToClip(aClipParam
, &aClipDoc
, &aMark
, false, false);
5277 // Make sure the notes are in the clipboard.
5278 pNote
= aClipDoc
.GetNote(ScAddress(1,1,0));
5279 CPPUNIT_ASSERT(pNote
);
5280 CPPUNIT_ASSERT_EQUAL(OUString("Note1"), pNote
->GetText());
5282 pNote
= aClipDoc
.GetNote(ScAddress(1,3,0));
5283 CPPUNIT_ASSERT(pNote
);
5284 CPPUNIT_ASSERT_EQUAL(OUString("Note2"), pNote
->GetText());
5286 // Paste to B6:B8 but only cell notes.
5287 ScRange
aDestRange(1,5,0,1,7,0);
5288 m_pDoc
->CopyFromClip(aDestRange
, aMark
, InsertDeleteFlags::NOTE
, nullptr, &aClipDoc
);
5290 // Make sure the notes are there.
5291 pNote
= m_pDoc
->GetNote(ScAddress(1,5,0));
5292 CPPUNIT_ASSERT(pNote
);
5293 CPPUNIT_ASSERT_EQUAL(OUString("Note1"), pNote
->GetText());
5295 pNote
= m_pDoc
->GetNote(ScAddress(1,7,0));
5296 CPPUNIT_ASSERT(pNote
);
5297 CPPUNIT_ASSERT_EQUAL(OUString("Note2"), pNote
->GetText());
5299 // Test that GetNotesInRange includes the end of its range
5300 // and so can find the note
5301 std::vector
<sc::NoteEntry
> aNotes
;
5302 m_pDoc
->GetNotesInRange(ScRange(1,7,0), aNotes
);
5303 CPPUNIT_ASSERT_EQUAL(size_t(1), aNotes
.size());
5305 m_pDoc
->DeleteTab(0);
5309 void Test::testNoteContainsNotesInRange() {
5310 m_pDoc
->InsertTab(0, "PostIts");
5312 // We need a drawing layer in order to create caption objects.
5313 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5315 ScAddress
aAddr(2, 2, 0); // cell C3
5317 CPPUNIT_ASSERT_MESSAGE("Claiming there's notes in a document that doesn't have any.",
5318 !m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), aAddr
))));
5320 m_pDoc
->GetOrCreateNote(aAddr
);
5322 CPPUNIT_ASSERT_MESSAGE("Claiming there's notes in range that doesn't have any.",
5323 !m_pDoc
->ContainsNotesInRange(ScRange(ScAddress(0, 0, 0), ScAddress(0, 1, 0))));
5324 CPPUNIT_ASSERT_MESSAGE("Note not detected that lies on border of range.",
5325 m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), aAddr
))));
5326 CPPUNIT_ASSERT_MESSAGE("Note not detected that lies in inner area of range.",
5327 m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), ScAddress(3, 3, 0)))));
5330 void Test::testAreasWithNotes()
5332 m_pDoc
->InsertTab(0, "Sheet1");
5334 // We need a drawing layer in order to create caption objects.
5335 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5337 ScAddress
rAddr(1, 5, 0);
5338 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
5339 pNote
->SetText(rAddr
, "Hello");
5340 pNote
->SetAuthor("Jim Bob");
5341 ScAddress
rAddrMin(2, 2, 0);
5342 ScPostIt
* pNoteMin
= m_pDoc
->GetOrCreateNote(rAddrMin
);
5343 pNoteMin
->SetText(rAddrMin
, "Hello");
5349 // only cell notes (empty content)
5351 dataFound
= m_pDoc
->GetDataStart(0,col
,row
);
5353 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound
);
5354 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong col for notes", static_cast<SCCOL
>(1), col
);
5355 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong row for notes", static_cast<SCROW
>(2), row
);
5357 dataFound
= m_pDoc
->GetCellArea(0,col
,row
);
5359 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound
);
5360 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong col for notes", static_cast<SCCOL
>(2), col
);
5361 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong row for notes", static_cast<SCROW
>(5), row
);
5364 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5366 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5367 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col for notes", static_cast<SCCOL
>(2), col
);
5368 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row for notes", static_cast<SCROW
>(5), row
);
5371 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5372 CPPUNIT_ASSERT_MESSAGE("No PrintArea should be found", !dataFound
);
5375 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5376 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5377 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(5), row
);
5379 dataFound
= m_pDoc
->GetPrintAreaVer(0,2,3,row
, bNotes
); // cols 2 & 3
5380 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5381 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(2), row
);
5384 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // col 0 & 1
5385 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer should be found", !dataFound
);
5387 // now add cells with value, check that notes are taken into account in good cases
5389 m_pDoc
->SetString(0, 3, 0, "Some Text");
5390 m_pDoc
->SetString(3, 3, 0, "Some Text");
5391 m_pDoc
->FetchTable(0)->InvalidateCellArea();
5393 dataFound
= m_pDoc
->GetDataStart(0,col
,row
);
5395 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound
);
5396 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong col", static_cast<SCCOL
>(0), col
);
5397 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong row", static_cast<SCROW
>(2), row
);
5399 dataFound
= m_pDoc
->GetCellArea(0,col
,row
);
5401 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound
);
5402 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong col", static_cast<SCCOL
>(3), col
);
5403 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong row", static_cast<SCROW
>(5), row
);
5406 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5408 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5409 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col", static_cast<SCCOL
>(3), col
);
5410 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row", static_cast<SCROW
>(5), row
);
5413 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5414 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5415 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col", static_cast<SCCOL
>(3), col
);
5416 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row", static_cast<SCROW
>(3), row
);
5419 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5420 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5421 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(5), row
);
5423 dataFound
= m_pDoc
->GetPrintAreaVer(0,2,3,row
, bNotes
); // cols 2 & 3
5424 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5425 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(3), row
);
5428 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5429 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5430 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(3), row
);
5432 m_pDoc
->DeleteTab(0);
5435 void Test::testAnchoredRotatedShape()
5437 m_pDoc
->InsertTab(0, "TestTab");
5439 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
5440 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
5441 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
5442 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
5444 m_pDoc
->InitDrawLayer();
5445 ScDrawLayer
*pDrawLayer
= m_pDoc
->GetDrawLayer();
5446 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer
!= nullptr);
5447 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
5448 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage
!= nullptr);
5449 m_pDoc
->SetRowHeightRange(0, m_pDoc
->MaxRow(), 0, o3tl::toTwips(1000, o3tl::Length::mm100
));
5450 constexpr tools::Long TOLERANCE
= 30; //30 hmm
5451 for ( SCCOL nCol
= 0; nCol
< m_pDoc
->MaxCol(); ++nCol
)
5452 m_pDoc
->SetColWidth(nCol
, 0, o3tl::toTwips(1000, o3tl::Length::mm100
));
5455 tools::Rectangle
aRect( 4000, 5000, 10000, 7000 );
5457 tools::Rectangle
aRotRect( 6000, 3000, 8000, 9000 );
5458 rtl::Reference
<SdrRectObj
> pObj
= new SdrRectObj(*pDrawLayer
, aRect
);
5459 pPage
->InsertObject(pObj
.get());
5460 Point
aRef1(pObj
->GetSnapRect().Center());
5461 Degree100 nAngle
= 9000_deg100
; //90 deg.
5462 double nSin
= 1.0; // sin(90 deg)
5463 double nCos
= 0.0; // cos(90 deg)
5464 pObj
->Rotate(aRef1
,nAngle
,nSin
,nCos
);
5466 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, true);
5468 tools::Rectangle aSnap
= pObj
->GetSnapRect();
5469 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetHeight(), aSnap
.GetHeight(), TOLERANCE
);
5470 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetWidth(), aSnap
.GetWidth(), TOLERANCE
);
5471 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.Left(), aSnap
.Left(), TOLERANCE
);
5472 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.Top(), aSnap
.Top(), TOLERANCE
);
5474 ScDrawObjData aAnchor
;
5475 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pObj
.get() );
5476 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData
);
5478 aAnchor
.maStart
= pData
->maStart
;
5479 aAnchor
.maEnd
= pData
->maEnd
;
5481 m_pDoc
->SetDrawPageSize(0);
5483 // increase row 5 by 2000 hmm
5484 m_pDoc
->SetRowHeight(5, 0, o3tl::toTwips(3000, o3tl::Length::mm100
));
5485 // increase col 6 by 1000 hmm
5486 m_pDoc
->SetColWidth(6, 0, o3tl::toTwips(2000, o3tl::Length::mm100
));
5488 aRotRect
.setWidth( aRotRect
.GetWidth() + 1000 );
5489 aRotRect
.setHeight( aRotRect
.GetHeight() + 2000 );
5491 m_pDoc
->SetDrawPageSize(0);
5493 aSnap
= pObj
->GetSnapRect();
5495 // ensure that width and height have been adjusted accordingly
5496 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetHeight(), aSnap
.GetHeight(), TOLERANCE
);
5497 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetWidth(), aSnap
.GetWidth(), TOLERANCE
);
5499 // ensure that anchor start and end addresses haven't changed
5500 CPPUNIT_ASSERT_EQUAL( aAnchor
.maStart
.Row(), pData
->maStart
.Row() ); // start row 0
5501 CPPUNIT_ASSERT_EQUAL( aAnchor
.maStart
.Col(), pData
->maStart
.Col() ); // start column 5
5502 CPPUNIT_ASSERT_EQUAL( aAnchor
.maEnd
.Row(), pData
->maEnd
.Row() ); // end row 3
5503 CPPUNIT_ASSERT_EQUAL( aAnchor
.maEnd
.Col(), pData
->maEnd
.Col() ); // end col 7
5505 m_pDoc
->DeleteTab(0);
5508 void Test::testCellTextWidth()
5510 m_pDoc
->InsertTab(0, "Test");
5512 ScAddress
aTopCell(0, 0, 0);
5515 std::unique_ptr
<ScColumnTextWidthIterator
> pIter(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5516 CPPUNIT_ASSERT_MESSAGE("Column should have no text widths stored.", !pIter
->hasCell());
5518 // Sheet only has one cell.
5519 m_pDoc
->SetString(0, 0, 0, "Only one cell");
5520 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5521 CPPUNIT_ASSERT_MESSAGE("Column should have a cell.", pIter
->hasCell());
5522 CPPUNIT_ASSERT_EQUAL(SCROW(0), pIter
->getPos());
5524 // Setting a text width here should commit it to the column.
5525 sal_uInt16 nTestVal
= 432;
5526 pIter
->setValue(nTestVal
);
5527 CPPUNIT_ASSERT_EQUAL(nTestVal
, m_pDoc
->GetTextWidth(aTopCell
));
5529 // Set values to row 2 through 6.
5530 for (SCROW i
= 2; i
<= 6; ++i
)
5531 m_pDoc
->SetString(0, i
, 0, "foo");
5533 // Set values to row 10 through 18.
5534 for (SCROW i
= 10; i
<= 18; ++i
)
5535 m_pDoc
->SetString(0, i
, 0, "foo");
5539 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5540 SCROW aRows
[] = { 0, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
5541 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5543 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5544 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5546 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5550 // Specify start and end rows (6 - 16)
5551 ScAddress aStart
= aTopCell
;
5553 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aStart
, 16));
5554 SCROW aRows
[] = { 6, 10, 11, 12, 13, 14, 15, 16 };
5555 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5557 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5558 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5560 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5563 // Clear from row 3 to row 17. After this, we should only have cells at rows 0, 2 and 18.
5564 clearRange(m_pDoc
, ScRange(0, 3, 0, 0, 17, 0));
5567 // Full range again.
5568 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5569 SCROW aRows
[] = { 0, 2, 18 };
5570 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5572 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5573 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5575 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5578 // Delete row 2 which shifts all cells below row 2 upward. After this, we
5579 // should only have cells at rows 0 and 17.
5580 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), MAXTAB
, 2, 1);
5582 // Full range again.
5583 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5584 SCROW aRows
[] = { 0, 17 };
5585 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aRows
); ++i
, pIter
->next())
5587 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5588 CPPUNIT_ASSERT_EQUAL(aRows
[i
], pIter
->getPos());
5590 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5593 m_pDoc
->DeleteTab(0);
5596 static bool checkEditTextIterator(sc::EditTextIterator
& rIter
, const char** pChecks
)
5598 const EditTextObject
* pText
= rIter
.first();
5599 const char* p
= *pChecks
;
5601 for (int i
= 0; i
< 100; ++i
) // cap it to 100 loops.
5604 // No more edit cells. The check string array should end too.
5605 return p
== nullptr;
5608 // More edit cell, but no more check string. Bad.
5611 if (pText
->GetParagraphCount() != 1)
5612 // For this test, we don't handle multi-paragraph text.
5615 if (pText
->GetText(0) != OUString::createFromAscii(p
))
5616 // Text differs from what's expected.
5619 pText
= rIter
.next();
5627 void Test::testEditTextIterator()
5629 m_pDoc
->InsertTab(0, "Test");
5632 // First, try with an empty sheet.
5633 sc::EditTextIterator
aIter(*m_pDoc
,0);
5634 const char* pChecks
[] = { nullptr };
5635 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5638 ScFieldEditEngine
& rEditEngine
= m_pDoc
->GetEditEngine();
5641 // Only set one edit cell.
5642 rEditEngine
.SetTextCurrentDefaults("A2");
5643 m_pDoc
->SetEditText(ScAddress(0,1,0), rEditEngine
.CreateTextObject());
5644 sc::EditTextIterator
aIter(*m_pDoc
,0);
5645 const char* pChecks
[] = { "A2", nullptr };
5646 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5650 // Add a series of edit cells.
5651 rEditEngine
.SetTextCurrentDefaults("A5");
5652 m_pDoc
->SetEditText(ScAddress(0,4,0), rEditEngine
.CreateTextObject());
5653 rEditEngine
.SetTextCurrentDefaults("A6");
5654 m_pDoc
->SetEditText(ScAddress(0,5,0), rEditEngine
.CreateTextObject());
5655 rEditEngine
.SetTextCurrentDefaults("A7");
5656 m_pDoc
->SetEditText(ScAddress(0,6,0), rEditEngine
.CreateTextObject());
5657 sc::EditTextIterator
aIter(*m_pDoc
,0);
5658 const char* pChecks
[] = { "A2", "A5", "A6", "A7", nullptr };
5659 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5663 // Add more edit cells to column C. Skip column B.
5664 rEditEngine
.SetTextCurrentDefaults("C1");
5665 m_pDoc
->SetEditText(ScAddress(2,0,0), rEditEngine
.CreateTextObject());
5666 rEditEngine
.SetTextCurrentDefaults("C3");
5667 m_pDoc
->SetEditText(ScAddress(2,2,0), rEditEngine
.CreateTextObject());
5668 rEditEngine
.SetTextCurrentDefaults("C4");
5669 m_pDoc
->SetEditText(ScAddress(2,3,0), rEditEngine
.CreateTextObject());
5670 sc::EditTextIterator
aIter(*m_pDoc
,0);
5671 const char* pChecks
[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", nullptr };
5672 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5676 // Add some numeric, string and formula cells. This shouldn't affect the outcome.
5677 m_pDoc
->SetString(ScAddress(0,99,0), "=ROW()");
5678 m_pDoc
->SetValue(ScAddress(1,3,0), 1.2);
5679 m_pDoc
->SetString(ScAddress(2,4,0), "Simple string");
5680 sc::EditTextIterator
aIter(*m_pDoc
,0);
5681 const char* pChecks
[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", nullptr };
5682 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5685 m_pDoc
->DeleteTab(0);
5688 void Test::testImportStream()
5690 sc::AutoCalcSwitch
aAC(*m_pDoc
, true); // turn on auto calc.
5691 sc::UndoSwitch
aUndo(*m_pDoc
, true); // enable undo.
5693 m_pDoc
->InsertTab(0, "Test");
5695 m_pDoc
->SetString(ScAddress(0,1,0), "=SUM(A1:C1)"); // A2
5697 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5699 // CSV import options.
5700 ScAsciiOptions aOpt
;
5701 aOpt
.SetFieldSeps(",");
5703 // Import values to A1:C1.
5704 ScImportExport
aObj(*m_pDoc
, ScAddress(0,0,0));
5705 aObj
.SetImportBroadcast(true);
5706 aObj
.SetExtOptions(aOpt
);
5707 aObj
.ImportString("1,2,3", SotClipboardFormatId::STRING
);
5709 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5710 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5711 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5713 // Formula value should have been updated.
5714 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5716 // Undo, and check the result.
5717 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5718 CPPUNIT_ASSERT_MESSAGE("Failed to get the undo manager.", pUndoMgr
);
5721 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5722 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5723 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5725 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,1,0))); // formula
5727 // Redo, and check the result.
5730 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5731 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5732 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5734 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0))); // formula
5738 m_pDoc
->DeleteTab(0);
5741 void Test::testDeleteContents()
5743 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
5744 sc::UndoSwitch
aUndoSwitch(*m_pDoc
, true); // enable undo.
5746 m_pDoc
->InsertTab(0, "Test");
5748 m_pDoc
->SetValue(ScAddress(3,1,0), 1.0);
5749 m_pDoc
->SetValue(ScAddress(3,2,0), 1.0);
5750 m_pDoc
->SetValue(ScAddress(3,3,0), 1.0);
5751 m_pDoc
->SetValue(ScAddress(3,4,0), 1.0);
5752 m_pDoc
->SetValue(ScAddress(3,5,0), 1.0);
5753 m_pDoc
->SetValue(ScAddress(3,6,0), 1.0);
5754 m_pDoc
->SetValue(ScAddress(3,7,0), 1.0);
5755 m_pDoc
->SetValue(ScAddress(3,8,0), 1.0);
5756 m_pDoc
->SetString(ScAddress(3,15,0), "=SUM(D2:D15)");
5758 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5761 ScRange
aRange(3,1,0,3,5,0);
5762 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5763 aMark
.SelectOneTable(0);
5764 aMark
.SetMarkArea(aRange
);
5766 ScDocumentUniquePtr
pUndoDoc(new ScDocument(SCDOCMODE_UNDO
));
5767 pUndoDoc
->InitUndo(*m_pDoc
, 0, 0);
5768 m_pDoc
->CopyToDocument(aRange
, InsertDeleteFlags::CONTENTS
, false, *pUndoDoc
, &aMark
);
5769 ScUndoDeleteContents
aUndo(m_xDocShell
.get(), aMark
, aRange
, std::move(pUndoDoc
), false, InsertDeleteFlags::CONTENTS
, true);
5771 clearRange(m_pDoc
, aRange
);
5772 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5775 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5778 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5780 m_pDoc
->DeleteTab(0);
5783 void Test::testTransliterateText()
5785 m_pDoc
->InsertTab(0, "Test");
5787 // Set texts to A1:A3.
5788 m_pDoc
->SetString(ScAddress(0,0,0), "Mike");
5789 m_pDoc
->SetString(ScAddress(0,1,0), "Noah");
5790 m_pDoc
->SetString(ScAddress(0,2,0), "Oscar");
5792 // Change them to uppercase.
5793 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5794 aMark
.SetMarkArea(ScRange(0,0,0,0,2,0));
5795 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5796 rFunc
.TransliterateText(
5797 aMark
, TransliterationFlags::LOWERCASE_UPPERCASE
, true);
5799 CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc
->GetString(ScAddress(0,0,0)));
5800 CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc
->GetString(ScAddress(0,1,0)));
5801 CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc
->GetString(ScAddress(0,2,0)));
5803 // Test the undo and redo.
5804 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5805 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr
);
5808 CPPUNIT_ASSERT_EQUAL(OUString("Mike"), m_pDoc
->GetString(ScAddress(0,0,0)));
5809 CPPUNIT_ASSERT_EQUAL(OUString("Noah"), m_pDoc
->GetString(ScAddress(0,1,0)));
5810 CPPUNIT_ASSERT_EQUAL(OUString("Oscar"), m_pDoc
->GetString(ScAddress(0,2,0)));
5813 CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc
->GetString(ScAddress(0,0,0)));
5814 CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc
->GetString(ScAddress(0,1,0)));
5815 CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc
->GetString(ScAddress(0,2,0)));
5817 m_pDoc
->DeleteTab(0);
5820 void Test::testFormulaToValue()
5822 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true);
5823 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
5825 m_pDoc
->InsertTab(0, "Test");
5827 std::vector
<std::vector
<const char*>> aData
= {
5828 { "=1", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5829 { "=2", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5830 { "=3", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5831 { "=4", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5832 { "=5", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5833 { "=6", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5836 ScAddress
aPos(1,2,0); // B3
5837 ScRange aDataRange
= insertRangeData(m_pDoc
, aPos
, aData
);
5838 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
5841 // Expected output table content. 0 = empty cell
5842 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5843 { "1", "2", "TRUE" },
5844 { "2", "4", "TRUE" },
5845 { "3", "6", "TRUE" },
5846 { "4", "8", "TRUE" },
5847 { "5", "10", "TRUE" },
5848 { "6", "12", "TRUE" },
5851 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5852 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5855 // Convert B5:C6 to static values, and check the result.
5856 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5857 ScRange
aConvRange(1,4,0,2,5,0); // B5:C6
5858 rFunc
.ConvertFormulaToValue(aConvRange
, false);
5861 // Expected output table content. 0 = empty cell
5862 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5863 { "1", "2", "TRUE" },
5864 { "2", "4", "TRUE" },
5865 { "3", "6", "FALSE" },
5866 { "4", "8", "FALSE" },
5867 { "5", "10", "TRUE" },
5868 { "6", "12", "TRUE" },
5871 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Converted");
5872 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5875 // Make sure that B3:B4 and B7:B8 are formula cells.
5876 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,2,0)));
5877 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,3,0)));
5878 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,6,0)));
5879 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,7,0)));
5881 // Make sure that B5:C6 are numeric cells.
5882 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,4,0)));
5883 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,5,0)));
5884 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,4,0)));
5885 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,5,0)));
5887 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
5888 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5889 CPPUNIT_ASSERT(pFC
);
5890 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5891 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5892 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,6,0));
5893 CPPUNIT_ASSERT(pFC
);
5894 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
5895 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5898 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5899 CPPUNIT_ASSERT(pUndoMgr
);
5903 // Expected output table content. 0 = empty cell
5904 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5905 { "1", "2", "TRUE" },
5906 { "2", "4", "TRUE" },
5907 { "3", "6", "TRUE" },
5908 { "4", "8", "TRUE" },
5909 { "5", "10", "TRUE" },
5910 { "6", "12", "TRUE" },
5913 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "After undo");
5914 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5917 // B3:B8 should all be (ungrouped) formula cells.
5918 for (SCROW i
= 2; i
<= 7; ++i
)
5920 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,i
,0));
5921 CPPUNIT_ASSERT(pFC
);
5922 CPPUNIT_ASSERT(!pFC
->IsShared());
5925 // C3:C8 should be shared formula cells.
5926 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5927 CPPUNIT_ASSERT(pFC
);
5928 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5929 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedLength());
5934 // Expected output table content. 0 = empty cell
5935 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5936 { "1", "2", "TRUE" },
5937 { "2", "4", "TRUE" },
5938 { "3", "6", "FALSE" },
5939 { "4", "8", "FALSE" },
5940 { "5", "10", "TRUE" },
5941 { "6", "12", "TRUE" },
5944 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Converted");
5945 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5948 // Make sure that B3:B4 and B7:B8 are formula cells.
5949 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,2,0)));
5950 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,3,0)));
5951 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,6,0)));
5952 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,7,0)));
5954 // Make sure that B5:C6 are numeric cells.
5955 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,4,0)));
5956 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,5,0)));
5957 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,4,0)));
5958 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,5,0)));
5960 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
5961 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5962 CPPUNIT_ASSERT(pFC
);
5963 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5964 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5965 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,6,0));
5966 CPPUNIT_ASSERT(pFC
);
5967 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
5968 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5970 // Undo again and make sure the recovered formulas in C5:C6 still track B5:B6.
5972 m_pDoc
->SetValue(ScAddress(1,4,0), 10);
5973 m_pDoc
->SetValue(ScAddress(1,5,0), 11);
5974 CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc
->GetValue(ScAddress(2,4,0)));
5975 CPPUNIT_ASSERT_EQUAL(22.0, m_pDoc
->GetValue(ScAddress(2,5,0)));
5977 m_pDoc
->DeleteTab(0);
5980 void Test::testFormulaToValue2()
5982 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true);
5983 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
5985 m_pDoc
->InsertTab(0, "Test");
5987 std::vector
<std::vector
<const char*>> aData
= {
5988 { "=1", "=ISFORMULA(RC[-1])" },
5989 { "=2", "=ISFORMULA(RC[-1])" },
5990 { "3", "=ISFORMULA(RC[-1])" },
5991 { "=4", "=ISFORMULA(RC[-1])" },
5992 { "=5", "=ISFORMULA(RC[-1])" },
5995 // Insert data into B2:C6.
5996 ScAddress
aPos(1,1,0); // B2
5997 ScRange aDataRange
= insertRangeData(m_pDoc
, aPos
, aData
);
5998 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
6001 // Expected output table content. 0 = empty cell
6002 std::vector
<std::vector
<const char*>> aOutputCheck
= {
6010 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
6011 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
6014 // Convert B3:B5 to a value.
6015 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
6016 ScRange
aConvRange(1,2,0,1,4,0); // B3:B5
6017 rFunc
.ConvertFormulaToValue(aConvRange
, false);
6020 // Expected output table content. 0 = empty cell
6021 std::vector
<std::vector
<const char*>> aOutputCheck
= {
6029 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
6030 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
6034 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
6035 CPPUNIT_ASSERT(pUndoMgr
);
6039 // Expected output table content. 0 = empty cell
6040 std::vector
<std::vector
<const char*>> aOutputCheck
= {
6048 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
6049 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
6052 m_pDoc
->DeleteTab(0);
6055 void Test::testColumnFindEditCells()
6057 m_pDoc
->InsertTab(0, "Test");
6059 // Test the basics with real edit cells, using Column A.
6061 SCROW nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
6062 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
6063 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,0,0));
6064 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
6065 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,10,0));
6066 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
6068 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
6069 rEE
.SetTextCurrentDefaults("Test");
6070 m_pDoc
->SetEditText(ScAddress(0,0,0), rEE
.CreateTextObject());
6071 const EditTextObject
* pObj
= m_pDoc
->GetEditText(ScAddress(0,0,0));
6072 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell here.", pObj
);
6074 ScRange
aRange(0,0,0,0,0,0);
6075 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6076 CPPUNIT_ASSERT_EQUAL_MESSAGE("There is an edit cell here.", SCROW(0), nResRow
);
6078 aRange
.aStart
.SetRow(1);
6079 aRange
.aEnd
.SetRow(1);
6080 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6081 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6083 aRange
.aStart
.SetRow(2);
6084 aRange
.aEnd
.SetRow(4);
6085 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6086 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6088 aRange
.aStart
.SetRow(0);
6089 aRange
.aEnd
.SetRow(m_pDoc
->MaxRow());
6090 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6091 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be an edit cell in specified range.", SCROW(0), nResRow
);
6093 m_pDoc
->SetString(ScAddress(0,0,0), "Test");
6094 m_pDoc
->SetValue(ScAddress(0,2,0), 1.0);
6095 ScRefCellValue aCell
;
6096 aCell
.assign(*m_pDoc
, ScAddress(0,0,0));
6097 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a string cell.", CELLTYPE_STRING
, aCell
.getType());
6098 aCell
.assign(*m_pDoc
, ScAddress(0,1,0));
6099 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be an empty cell.", CELLTYPE_NONE
, aCell
.getType());
6100 aCell
.assign(*m_pDoc
, ScAddress(0,2,0));
6101 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a numeric cell.", CELLTYPE_VALUE
, aCell
.getType());
6102 aCell
.assign(*m_pDoc
, ScAddress(0,3,0));
6103 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be an empty cell.", CELLTYPE_NONE
, aCell
.getType());
6105 aRange
.aStart
.SetRow(1);
6106 aRange
.aEnd
.SetRow(1);
6107 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6108 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6110 // Test with non-edit cell but with ambiguous script type.
6112 m_pDoc
->SetString(ScAddress(1,11,0), "Some text");
6113 m_pDoc
->SetString(ScAddress(1,12,0), "Some text");
6114 m_pDoc
->SetString(ScAddress(1,13,0), "Other text");
6116 m_pDoc
->SetScriptType(ScAddress(1,11,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6117 m_pDoc
->SetScriptType(ScAddress(1,12,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6118 m_pDoc
->SetScriptType(ScAddress(1,13,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6120 nResRow
= m_pDoc
->GetFirstEditTextRow(ScAddress(1,11,0));
6121 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(11), nResRow
);
6122 nResRow
= m_pDoc
->GetFirstEditTextRow(ScAddress(1,12,0));
6123 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(12), nResRow
);
6125 for (SCROW i
= 0; i
<= 5; ++i
)
6126 m_pDoc
->SetString(ScAddress(2,i
,0), "Text");
6128 m_pDoc
->SetScriptType(ScAddress(2,5,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6130 nResRow
= m_pDoc
->GetFirstEditTextRow(ScAddress(2,1,0));
6131 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(-1), nResRow
);
6133 m_pDoc
->DeleteTab(0);
6137 void Test::testSetFormula()
6139 m_pDoc
->InsertTab(0, "Test");
6141 static struct aInputs
6145 const char* aFormula1
; // Represents the formula that is input to SetFormula function.
6146 const char* aFormula2
; // Represents the formula that is actually stored in the cell.
6147 formula::FormulaGrammar::Grammar
const eGram
;
6150 { 5 , 4 , "=SUM($D$2:$F$3)" ,"=SUM($D$2:$F$3)" , formula::FormulaGrammar::Grammar::GRAM_ENGLISH
},
6151 { 5 , 5 , "=A1-$C2+B$3-$F$4" ,"=A1-$C2+B$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_NATIVE
},
6152 { 6 , 6 , "=A1-$C2+B$3-$F$4" ,"=A1-$C2+B$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_NATIVE_XL_A1
},
6153 { 7 , 8 , "=[.A1]-[.$C2]+[.G$3]-[.$F$4]","=A1-$C2+G$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_ODFF
}
6156 for(size_t i
= 0; i
< SAL_N_ELEMENTS(aTest
); ++i
)
6158 m_pDoc
->SetFormula(ScAddress(aTest
[i
].nCol
, aTest
[i
].nRow
, 0), OUString::createFromAscii(aTest
[i
].aFormula1
), aTest
[i
].eGram
);
6159 OUString aBuffer
= m_pDoc
->GetFormula(aTest
[i
].nCol
, aTest
[i
].nRow
, 0);
6161 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to set formula", OUString::createFromAscii(aTest
[i
].aFormula2
), aBuffer
);
6164 m_pDoc
->DeleteTab(0);
6167 void Test::testMultipleDataCellsInRange()
6169 m_pDoc
->InsertTab(0, "Test");
6171 ScRange
aRange(1,2,0); // B3
6172 sc::MultiDataCellState aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6173 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::Empty
, aState
.meState
);
6175 // Set a numeric value to B3.
6176 m_pDoc
->SetValue(ScAddress(1,2,0), 1.0);
6177 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6178 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6179 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6180 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6182 // Set another numeric value to B4.
6183 m_pDoc
->SetValue(ScAddress(1,3,0), 2.0);
6184 aRange
.aEnd
.SetRow(3); // B3:B4
6185 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6186 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasMultipleCells
, aState
.meState
);
6187 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6188 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6190 // Set the query range to B4:B5. Now it should only report one cell, with
6191 // B4 being the first non-empty cell.
6192 aRange
.aStart
.SetRow(3);
6193 aRange
.aEnd
.SetRow(4);
6194 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6195 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6196 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6197 CPPUNIT_ASSERT_EQUAL(SCROW(3), aState
.mnRow1
);
6199 // Set the query range to A1:C3. The first non-empty cell should be B3.
6200 aRange
= ScRange(0,0,0,2,2,0);
6201 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6202 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6203 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6204 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6206 // Set string cells to D4 and F5, and query D3:F5. D4 should be the first
6208 m_pDoc
->SetString(ScAddress(3,3,0), "foo");
6209 m_pDoc
->SetString(ScAddress(5,4,0), "bar");
6210 aRange
= ScRange(3,2,0,5,4,0);
6211 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6212 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasMultipleCells
, aState
.meState
);
6213 CPPUNIT_ASSERT_EQUAL(SCCOL(3), aState
.mnCol1
);
6214 CPPUNIT_ASSERT_EQUAL(SCROW(3), aState
.mnRow1
);
6216 // TODO : add more test cases as needed.
6218 m_pDoc
->DeleteTab(0);
6221 void Test::testFormulaWizardSubformula()
6223 m_pDoc
->InsertTab(0, "Test");
6225 m_pDoc
->SetString(ScAddress(1,0,0), "=1"); // B1
6226 m_pDoc
->SetString(ScAddress(1,1,0), "=1/0"); // B2
6227 m_pDoc
->SetString(ScAddress(1,2,0), "=gibberish"); // B3
6229 ScSimpleFormulaCalculator
aFCell1( *m_pDoc
, ScAddress(0,0,0), "=B1:B3", true );
6230 FormulaError nErrCode
= aFCell1
.GetErrCode();
6231 CPPUNIT_ASSERT( nErrCode
== FormulaError::NONE
|| aFCell1
.IsMatrix() );
6232 CPPUNIT_ASSERT_EQUAL( OUString("{1|#DIV/0!|#NAME?}"), aFCell1
.GetString().getString() );
6234 m_pDoc
->SetString(ScAddress(1,0,0), "=NA()"); // B1
6235 m_pDoc
->SetString(ScAddress(1,1,0), "2"); // B2
6236 m_pDoc
->SetString(ScAddress(1,2,0), "=1+2"); // B3
6237 ScSimpleFormulaCalculator
aFCell2( *m_pDoc
, ScAddress(0,0,0), "=B1:B3", true );
6238 nErrCode
= aFCell2
.GetErrCode();
6239 CPPUNIT_ASSERT( nErrCode
== FormulaError::NONE
|| aFCell2
.IsMatrix() );
6240 CPPUNIT_ASSERT_EQUAL( OUString("{#N/A|2|3}"), aFCell2
.GetString().getString() );
6242 m_pDoc
->DeleteTab(0);
6245 void Test::testDiagonalBorders()
6247 m_pDoc
->InsertTab(0, "Diagonal");
6250 const editeng::SvxBorderLine
* pLine
;
6251 const ScPatternAttr
* pPat
;
6253 // diagonal down border
6254 ::editeng::SvxBorderLine
dDownBorderLine(nullptr, 1);
6255 SvxLineItem
dDownLineItem(ATTR_BORDER_TLBR
);
6256 dDownLineItem
.SetLine(&dDownBorderLine
);
6258 // set diagonal down border to cell(A1)
6259 m_pDoc
->ApplyAttr(0, 0, 0, dDownLineItem
);
6262 pPat
= m_pDoc
->GetPattern(aPos
);
6263 CPPUNIT_ASSERT(pPat
);
6265 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6266 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was expected, but not found!", pLine
);
6268 // diagonal up border
6269 ::editeng::SvxBorderLine
dUpBorderLine(nullptr, 1);
6270 SvxLineItem
dUpLineItem(ATTR_BORDER_BLTR
);
6271 dUpLineItem
.SetLine(&dUpBorderLine
);
6273 // set diagonal up border to cell(A2)
6274 m_pDoc
->ApplyAttr(0, 1, 0, dUpLineItem
);
6277 pPat
= m_pDoc
->GetPattern(aPos
);
6278 CPPUNIT_ASSERT(pPat
);
6280 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6281 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was expected, but not found!", pLine
);
6283 // diagonal down and up border in the same cell (A5)
6284 m_pDoc
->ApplyAttr(0, 4, 0, dDownLineItem
);
6285 m_pDoc
->ApplyAttr(0, 4, 0, dUpLineItem
);
6287 // test if both borders are applied successfully in the same cell (A5)
6289 pPat
= m_pDoc
->GetPattern(aPos
);
6290 CPPUNIT_ASSERT(pPat
);
6292 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6293 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was expected, but not found!", pLine
);
6294 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6295 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was expected, but not found!", pLine
);
6297 // test if both borders are removed successfully
6298 dDownLineItem
.SetLine(nullptr);
6299 dUpLineItem
.SetLine(nullptr);
6301 // SetLine(nullptr) should remove the lines from (A5)
6302 m_pDoc
->ApplyAttr(0, 4, 0, dDownLineItem
);
6303 m_pDoc
->ApplyAttr(0, 4, 0, dUpLineItem
);
6305 pPat
= m_pDoc
->GetPattern(aPos
);
6306 CPPUNIT_ASSERT(pPat
);
6308 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6309 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was not expected, but is found!", !pLine
);
6310 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6311 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was not expected, but is found!", !pLine
);
6313 m_pDoc
->DeleteTab(0);
6316 void Test::testWholeDocBorders()
6318 m_pDoc
->InsertTab(0, "Borders");
6320 // Set outside border to be on all sides, and inside borders to be only vertical.
6321 // This should result in edge borders of the spreadsheets being set, but internal
6322 // borders between cells should be only vertical, not horizontal.
6323 ::editeng::SvxBorderLine
line(nullptr, 50, SvxBorderLineStyle::SOLID
);
6324 SvxBoxItem
borderItem(ATTR_BORDER
);
6325 borderItem
.SetLine(&line
, SvxBoxItemLine::LEFT
);
6326 borderItem
.SetLine(&line
, SvxBoxItemLine::RIGHT
);
6327 borderItem
.SetLine(&line
, SvxBoxItemLine::TOP
);
6328 borderItem
.SetLine(&line
, SvxBoxItemLine::BOTTOM
);
6329 SvxBoxInfoItem
boxInfoItem(ATTR_BORDER
);
6330 boxInfoItem
.SetLine(&line
, SvxBoxInfoItemLine::VERT
);
6332 ScMarkData
mark( m_pDoc
->GetSheetLimits(), ScRange( 0, 0, 0, m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 0 ));
6333 m_pDoc
->ApplySelectionFrame( mark
, borderItem
, &boxInfoItem
);
6335 const ScPatternAttr
* attr
;
6336 attr
= m_pDoc
->GetPattern( 0, 0, 0 );
6337 CPPUNIT_ASSERT(attr
);
6338 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6339 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6340 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6341 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6343 attr
= m_pDoc
->GetPattern( 1, 0, 0 );
6344 CPPUNIT_ASSERT(attr
);
6345 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6346 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6347 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6348 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6350 attr
= m_pDoc
->GetPattern( 0, 1, 0 );
6351 CPPUNIT_ASSERT(attr
);
6352 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6353 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6354 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6355 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6357 attr
= m_pDoc
->GetPattern( 1, 1, 0 );
6358 CPPUNIT_ASSERT(attr
);
6359 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6360 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6361 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6362 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6364 attr
= m_pDoc
->GetPattern( m_pDoc
->MaxCol(), 0, 0 );
6365 CPPUNIT_ASSERT(attr
);
6366 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6367 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6368 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6369 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6371 attr
= m_pDoc
->GetPattern( 0, m_pDoc
->MaxRow(), 0 );
6372 CPPUNIT_ASSERT(attr
);
6373 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6374 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6375 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6376 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetBottom());
6378 attr
= m_pDoc
->GetPattern( m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 0 );
6379 CPPUNIT_ASSERT(attr
);
6380 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6381 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6382 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6383 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetBottom());
6385 m_pDoc
->DeleteTab(0);
6388 void Test::testSetStringAndNote()
6390 m_pDoc
->InsertTab(0, "Test");
6392 // We need a drawing layer in order to create caption objects.
6393 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
6396 ScAddress
aAdrA1 (0, 0, 0);
6397 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aAdrA1
);
6398 pNote
->SetText(aAdrA1
, "Hello world in A1");
6400 m_pDoc
->SetString(0, 0, 0, "");
6402 pNote
= m_pDoc
->GetNote(aAdrA1
);
6403 CPPUNIT_ASSERT(pNote
);
6405 m_pDoc
->DeleteTab(0);
6408 void Test::testUndoDataAnchor()
6410 m_pDoc
->InsertTab(0, "Tab1");
6411 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only 1 sheets to begin with",
6412 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
6414 m_pDoc
->InitDrawLayer();
6415 ScDrawLayer
* pDrawLayer
= m_pDoc
->GetDrawLayer();
6416 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer
);
6417 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
6418 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage
);
6420 // Insert an object.
6421 tools::Rectangle
aObjRect(2,1000,100,1100);
6422 rtl::Reference
<SdrObject
> pObj
= new SdrRectObj(*pDrawLayer
, aObjRect
);
6423 pPage
->InsertObject(pObj
.get());
6424 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
6427 ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pObj
.get());
6428 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6430 ScAddress aOldStart
= pData
->maStart
;
6431 ScAddress aOldEnd
= pData
->maEnd
;
6433 // Get non rotated anchor data
6434 ScDrawObjData
* pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6435 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6437 ScAddress aNOldStart
= pNData
->maStart
;
6438 ScAddress aNOldEnd
= pNData
->maEnd
;
6439 CPPUNIT_ASSERT_EQUAL(aOldStart
, aNOldStart
);
6440 CPPUNIT_ASSERT_EQUAL(aOldEnd
, aNOldEnd
);
6442 //pDrawLayer->BeginCalcUndo(false);
6443 // Insert a new row at row 3.
6444 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
6445 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6446 aMark
.SelectOneTable(0);
6447 rFunc
.InsertCells(ScRange( 0, aOldStart
.Row() - 1, 0, m_pDoc
->MaxCol(), aOldStart
.Row(), 0 ), &aMark
, INS_INSROWS_BEFORE
, true, true);
6449 pData
= ScDrawLayer::GetObjData(pObj
.get());
6450 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6452 ScAddress aNewStart
= pData
->maStart
;
6453 ScAddress aNewEnd
= pData
->maEnd
;
6455 // Get non rotated anchor data
6456 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6457 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6459 ScAddress aNNewStart
= pNData
->maStart
;
6460 ScAddress aNNewEnd
= pNData
->maEnd
;
6461 CPPUNIT_ASSERT_EQUAL(aNewStart
, aNNewStart
);
6462 CPPUNIT_ASSERT_EQUAL(aNewEnd
, aNNewEnd
);
6463 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewStart
!= aOldStart
);
6464 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewEnd
!= aOldEnd
);
6465 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNNewStart
!= aNOldStart
);
6466 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNNewEnd
!= aNOldEnd
);
6468 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
6469 CPPUNIT_ASSERT(pUndoMgr
);
6473 ScAnchorType oldType
= ScDrawLayer::GetAnchorType(*pObj
);
6474 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to check state SCA_CELL.", SCA_CELL
, oldType
);
6477 pData
= ScDrawLayer::GetObjData(pObj
.get());
6478 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6480 // Get non rotated anchor data
6481 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6482 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6484 // Check if data has moved to new rows
6485 CPPUNIT_ASSERT_EQUAL(pData
->maStart
, aOldStart
);
6486 CPPUNIT_ASSERT_EQUAL(pData
->maEnd
, aOldEnd
);
6488 CPPUNIT_ASSERT_EQUAL(pNData
->maStart
, aNOldStart
);
6489 CPPUNIT_ASSERT_EQUAL(pNData
->maEnd
, aNOldEnd
);
6494 pData
= ScDrawLayer::GetObjData(pObj
.get());
6495 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6497 // Get non rotated anchor data
6498 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6499 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6501 // Check if data has moved to new rows
6502 CPPUNIT_ASSERT_EQUAL(pData
->maStart
, aNewStart
);
6503 CPPUNIT_ASSERT_EQUAL(pData
->maEnd
, aNewEnd
);
6505 CPPUNIT_ASSERT_EQUAL(pNData
->maStart
, aNNewStart
);
6506 CPPUNIT_ASSERT_EQUAL(pNData
->maEnd
, aNNewEnd
);
6508 m_pDoc
->DeleteTab(0);
6512 void Test::testEmptyCalcDocDefaults()
6514 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetCellCount() );
6515 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetFormulaGroupCount() );
6516 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetCodeCount() );
6517 CPPUNIT_ASSERT_EQUAL( int(CharCompressType::NONE
), static_cast<int>(m_pDoc
->GetAsianCompression()) );
6519 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasPrintRange() );
6520 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInVBAMode() );
6521 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasNotes() );
6522 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCutMode() );
6524 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedFonts() );
6525 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedUsedFontsOnly() );
6526 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptLatin() );
6527 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptAsian() );
6528 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptComplex() );
6529 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedded() );
6531 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsDocEditable() );
6532 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDocProtected() );
6533 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDocVisible() );
6534 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsUserInteractionEnabled() );
6536 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasAnyCalcNotification() );
6537 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsAutoCalcShellDisabled() );
6538 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsForcedFormulaPending() );
6539 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCalculatingFormulaTree() );
6541 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipOrUndo() );
6542 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipboard() );
6543 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsUndo() );
6544 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsUndoEnabled() );
6545 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCutMode() );
6546 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipboardSource() );
6547 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInsertingFromOtherDoc() );
6548 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->PastingDrawFromOtherDoc() );
6550 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsAdjustHeightLocked() );
6551 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsExecuteLinkEnabled() );
6552 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsChangeReadOnlyEnabled() );
6554 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IdleCalcTextWidth() );
6555 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsIdleEnabled() );
6556 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDetectiveDirty() );
6557 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasLinkFormulaNeedingCheck() );
6558 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsChartListenerCollectionNeedsUpdate() );
6560 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasRangeOverflow() );
6561 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsImportingXML() );
6562 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCalcingAfterLoad() );
6563 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->GetNoListening() );
6565 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsValidAsianCompression() );
6566 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->GetAsianKerning() );
6567 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsValidAsianKerning() );
6569 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInInterpreter() );
6570 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInInterpreterTableOp() );
6571 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInDtorClear() );
6572 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsExpandRefs() );
6573 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInLinkUpdate() );
6575 SCTAB tab
= m_pDoc
->GetVisibleTab();
6577 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsVisible(tab
) );
6578 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsDefaultTabBgColor(tab
) );
6579 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasTable(tab
) );
6581 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsActiveScenario(tab
) );
6582 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasCalcNotification(tab
) );
6583 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasManualBreaks(tab
) );
6586 void Test::checkPrecisionAsShown( OUString
& rCode
, double fValue
, double fExpectedRoundVal
)
6588 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
6589 sal_uInt32 nFormat
= pFormatter
->GetEntryKey( rCode
);
6590 if ( nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
6592 sal_Int32 nCheckPos
= 0;
6593 SvNumFormatType nType
;
6594 pFormatter
->PutEntry( rCode
, nCheckPos
, nType
, nFormat
);
6595 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), nCheckPos
);
6597 double fRoundValue
= m_pDoc
->RoundValueAsShown( fValue
, nFormat
);
6598 OString aMessage
= "Format \"" +
6599 OUStringToOString( rCode
, RTL_TEXTENCODING_ASCII_US
) +
6600 "\" is not correctly rounded";
6601 CPPUNIT_ASSERT_EQUAL_MESSAGE( aMessage
.getStr(), fExpectedRoundVal
, fRoundValue
);
6604 void Test::testPrecisionAsShown()
6606 m_pDoc
->InsertTab(0, "Test");
6608 // Turn on "precision as shown" option.
6609 setCalcAsShown( m_pDoc
, true);
6612 double fValue
, fExpectedRoundVal
;
6613 { // decimal rounding
6616 fExpectedRoundVal
= 0.33;
6617 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6618 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6620 fExpectedRoundVal
= 10.0;
6621 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6622 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6624 { // thousand rounding tdf#106253
6626 fValue
= 4.0e9
/ 7.0;
6627 fExpectedRoundVal
= 571e6
;
6628 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6629 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6630 aCode
= "\"k\"[$$-409]* #,;[RED]-\"k\"[$$-409]* #,";
6631 fValue
= 4.0e8
/ 7.0;
6632 fExpectedRoundVal
= 57.143e6
;
6633 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6634 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6636 { // percent rounding
6639 fExpectedRoundVal
= 0.5714;
6640 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6641 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6642 fValue
= 40.0 / 7.0;
6643 fExpectedRoundVal
= 5.7143;
6644 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6645 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6647 { // scientific rounding
6649 fValue
= 400000.0 / 7.0;
6650 fExpectedRoundVal
= 57100.0;
6651 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6652 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6653 fValue
= 4.0 / 70000.0;
6654 fExpectedRoundVal
= 5.71e-5;
6655 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6656 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6657 // engineering rounding tdf#106252
6658 aCode
= "##0.000E0";
6659 fValue
= 400000.0 / 7.0;
6660 fExpectedRoundVal
= 57.143e3
;
6661 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6662 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6663 fValue
= 4000000.0 / 7.0;
6664 fExpectedRoundVal
= 571.429e3
;
6665 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6666 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6667 fValue
= 40000000.0 / 7.0;
6668 fExpectedRoundVal
= 5.714e6
;
6669 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6670 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6671 fValue
= 4.0 / 70000.0;
6672 fExpectedRoundVal
= 57.143e-6;
6673 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6674 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6675 fValue
= 4.0 / 7000.0;
6676 fExpectedRoundVal
= 571.429e-6;
6677 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6678 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6679 fValue
= 4.0 / 700.0;
6680 fExpectedRoundVal
= 5.714e-3;
6681 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6682 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6683 aCode
= "##?0.0#E0";
6684 fValue
= 400000.0 / 7.0;
6685 fExpectedRoundVal
= 5.71e4
;
6686 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6687 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6688 fValue
= 4000000.0 / 7.0;
6689 fExpectedRoundVal
= 57.14e4
;
6690 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6691 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6692 fValue
= 40000000.0 / 7.0;
6693 fExpectedRoundVal
= 571.43e4
;
6694 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6695 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6696 fValue
= 400000000.0 / 7.0;
6697 fExpectedRoundVal
= 5714.29e4
;
6698 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6699 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6700 fValue
= 4.0 / 70000.0;
6701 fExpectedRoundVal
= 5714.29e-8;
6702 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6703 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6704 fValue
= 4.0 / 7000.0;
6705 fExpectedRoundVal
= 5.71e-4;
6706 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6707 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6708 fValue
= 4.0 / 700.0;
6709 fExpectedRoundVal
= 57.14e-4;
6710 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6711 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6712 fValue
= 4.0 / 70.0;
6713 fExpectedRoundVal
= 571.43e-4;
6714 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6715 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6717 { // fraction rounding tdf#105657
6720 fExpectedRoundVal
= 1.0/3.0;
6721 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6722 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6727 fExpectedRoundVal
= 0.35;
6728 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6729 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6731 { // several sub-formats tdf#106052
6732 aCode
= "0.00;-0.000";
6734 fExpectedRoundVal
= 0.33;
6735 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6737 fExpectedRoundVal
= -0.333;
6738 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6741 setCalcAsShown( m_pDoc
, false);
6742 m_pDoc
->DeleteTab(0);
6745 void Test::testProtectedSheetEditByRow()
6747 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
6748 m_pDoc
->InsertTab(0, "Protected");
6751 // Remove protected flags from rows 2-5.
6752 ScPatternAttr
aAttr(m_pDoc
->GetPool());
6753 aAttr
.GetItemSet().Put(ScProtectionAttr(false));
6754 m_pDoc
->ApplyPatternAreaTab(0, 1, m_pDoc
->MaxCol(), 4, 0, aAttr
);
6756 // Protect the sheet without any options.
6757 ScTableProtection aProtect
;
6758 aProtect
.setProtected(true);
6759 m_pDoc
->SetTabProtection(0, &aProtect
);
6761 // Try to delete row 3. It should fail.
6762 ScRange
aRow3(0,2,0,m_pDoc
->MaxCol(),2,0);
6763 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6764 aMark
.SelectOneTable(0);
6765 bool bDeleted
= rDocFunc
.DeleteCells(aRow3
, &aMark
, DelCellCmd::Rows
, true);
6766 CPPUNIT_ASSERT_MESSAGE("deletion of row 3 should fail.", !bDeleted
);
6768 // Protect the sheet but allow row deletion.
6769 aProtect
.setOption(ScTableProtection::DELETE_ROWS
, true);
6770 m_pDoc
->SetTabProtection(0, &aProtect
);
6772 // Now we should be able to delete row 3.
6773 bDeleted
= rDocFunc
.DeleteCells(aRow3
, &aMark
, DelCellCmd::Rows
, true);
6774 CPPUNIT_ASSERT_MESSAGE("deletion of row 3 should succeed.", bDeleted
);
6776 // But, row deletion should still fail on a protected row.
6777 ScRange
aRow10(0,9,0,m_pDoc
->MaxCol(),9,0);
6778 bDeleted
= rDocFunc
.DeleteCells(aRow10
, &aMark
, DelCellCmd::Rows
, true);
6779 CPPUNIT_ASSERT_MESSAGE("deletion of row 10 should not be allowed.", !bDeleted
);
6781 // Try inserting a new row. It should fail.
6782 bool bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_AFTER
, true, true);
6783 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should fail.", !bInserted
);
6785 // Allow row insertions.
6786 aProtect
.setOption(ScTableProtection::INSERT_ROWS
, true);
6787 m_pDoc
->SetTabProtection(0, &aProtect
);
6789 bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_AFTER
, true, true);
6790 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should succeed.", bInserted
);
6792 // Row insertion is allowed even when the rows above and below have protected flags set.
6793 bInserted
= rDocFunc
.InsertCells(aRow10
, &aMark
, INS_INSROWS_AFTER
, true, true);
6794 CPPUNIT_ASSERT_MESSAGE("row insertion at row 10 should succeed.", bInserted
);
6797 m_pDoc
->InsertTab(1, "Matrix"); // This sheet is unprotected.
6800 // Insert matrix into B2:C3.
6801 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6802 aMark
.SelectOneTable(1);
6803 m_pDoc
->InsertMatrixFormula(1, 1, 2, 2, aMark
, "={1;2|3;4}");
6805 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,1)));
6806 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,1)));
6807 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,1)));
6808 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(2,2,1)));
6810 // Try to insert a row at row 3. It should fail because of matrix's presence.
6812 ScRange
aRow3(0,2,1,m_pDoc
->MaxCol(),2,1);
6813 bool bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_BEFORE
, true, true);
6814 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should fail.", !bInserted
);
6817 m_pDoc
->DeleteTab(1);
6818 m_pDoc
->DeleteTab(0);
6821 void Test::testProtectedSheetEditByColumn()
6823 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
6824 m_pDoc
->InsertTab(0, "Protected");
6827 // Remove protected flags from columns B to E.
6828 ScPatternAttr
aAttr(m_pDoc
->GetPool());
6829 aAttr
.GetItemSet().Put(ScProtectionAttr(false));
6830 m_pDoc
->ApplyPatternAreaTab(1, 0, 4, m_pDoc
->MaxRow(), 0, aAttr
);
6832 // Protect the sheet without any options.
6833 ScTableProtection aProtect
;
6834 aProtect
.setProtected(true);
6835 m_pDoc
->SetTabProtection(0, &aProtect
);
6837 // Try to delete column C. It should fail.
6838 ScRange
aCol3(2,0,0,2,m_pDoc
->MaxRow(),0);
6839 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6840 aMark
.SelectOneTable(0);
6841 bool bDeleted
= rDocFunc
.DeleteCells(aCol3
, &aMark
, DelCellCmd::Cols
, true);
6842 CPPUNIT_ASSERT_MESSAGE("deletion of column 3 should fail.", !bDeleted
);
6844 // Protect the sheet but allow column deletion.
6845 aProtect
.setOption(ScTableProtection::DELETE_COLUMNS
, true);
6846 m_pDoc
->SetTabProtection(0, &aProtect
);
6848 // Now we should be able to delete column C.
6849 bDeleted
= rDocFunc
.DeleteCells(aCol3
, &aMark
, DelCellCmd::Cols
, true);
6850 CPPUNIT_ASSERT_MESSAGE("deletion of column 3 should succeed.", bDeleted
);
6852 // But, column deletion should still fail on a protected column.
6853 ScRange
aCol10(9,0,0,9,m_pDoc
->MaxRow(),0);
6854 bDeleted
= rDocFunc
.DeleteCells(aCol10
, &aMark
, DelCellCmd::Cols
, true);
6855 CPPUNIT_ASSERT_MESSAGE("deletion of column 10 should not be allowed.", !bDeleted
);
6857 // Try inserting a new column. It should fail.
6858 bool bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6859 CPPUNIT_ASSERT_MESSAGE("column insertion at column 3 should fail.", !bInserted
);
6861 // Allow column insertions.
6862 aProtect
.setOption(ScTableProtection::INSERT_COLUMNS
, true);
6863 m_pDoc
->SetTabProtection(0, &aProtect
);
6865 bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6866 CPPUNIT_ASSERT_MESSAGE("column insertion at column 3 should succeed.", bInserted
);
6868 // Column insertion is allowed even when the columns above and below have protected flags set.
6869 bInserted
= rDocFunc
.InsertCells(aCol10
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6870 CPPUNIT_ASSERT_MESSAGE("column insertion at column 10 should succeed.", bInserted
);
6873 m_pDoc
->InsertTab(1, "Matrix"); // This sheet is unprotected.
6876 // Insert matrix into B2:C3.
6877 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6878 aMark
.SelectOneTable(1);
6879 m_pDoc
->InsertMatrixFormula(1, 1, 2, 2, aMark
, "={1;2|3;4}");
6881 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,1)));
6882 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,1)));
6883 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,1)));
6884 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(2,2,1)));
6886 // Try to insert a column at column C. It should fail because of matrix's presence.
6888 ScRange
aCol3(2,0,1,2,m_pDoc
->MaxRow(),1);
6889 bool bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_BEFORE
, true, true);
6890 CPPUNIT_ASSERT_MESSAGE("column insertion at column C should fail.", !bInserted
);
6893 m_pDoc
->DeleteTab(1);
6894 m_pDoc
->DeleteTab(0);
6897 void Test::testInsertColumnsWithFormulaCells()
6899 m_pDoc
->InsertTab(0, "Tab1");
6901 std::set
<SCCOL
> aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
6902 CPPUNIT_ASSERT_MESSAGE("empty sheet should contain no formula cells.", aCols
.empty());
6904 auto equals
= [](const std::set
<SCCOL
>& left
, const std::set
<SCCOL
>& right
)
6906 return left
== right
;
6909 // insert formula cells in columns 2, 4 and 6.
6910 m_pDoc
->SetFormula(ScAddress(2, 2, 0), "=1", m_pDoc
->GetGrammar());
6911 m_pDoc
->SetFormula(ScAddress(4, 2, 0), "=1", m_pDoc
->GetGrammar());
6912 m_pDoc
->SetFormula(ScAddress(6, 2, 0), "=1", m_pDoc
->GetGrammar());
6914 aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
6916 std::set
<SCCOL
> aExpected
= { 2, 4, 6 };
6917 CPPUNIT_ASSERT_MESSAGE("Columns 2, 4 and 6 should contain formula cells.", equals(aExpected
, aCols
));
6919 // Insert 2 columns at column A to shift everything to right by 2.
6920 m_pDoc
->InsertCol(0, 0, m_pDoc
->MaxRow(), 0, 0, 2);
6922 aExpected
= { 4, 6, 8 };
6923 aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
6924 CPPUNIT_ASSERT_MESSAGE("Columns 4, 6 and 8 should contain formula cells.", equals(aExpected
, aCols
));
6928 m_pDoc
->CheckIntegrity(0);
6930 catch (const std::exception
& e
)
6932 std::ostringstream os
;
6933 os
<< "document integrity check failed: " << e
.what();
6934 CPPUNIT_FAIL(os
.str());
6937 m_pDoc
->DeleteTab(0);
6940 CPPUNIT_TEST_SUITE_REGISTRATION(Test
);
6942 CPPUNIT_PLUGIN_IMPLEMENT();
6944 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */