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>
31 #include <globstr.hrc>
32 #include <scresid.hxx>
34 #include <columniterator.hxx>
35 #include <scopetools.hxx>
36 #include <dociter.hxx>
37 #include <edittextiterator.hxx>
38 #include <editutil.hxx>
39 #include <asciiopt.hxx>
41 #include <globalnames.hxx>
42 #include <columnspanset.hxx>
44 #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 <o3tl/nonstaticstring.hxx>
58 #include <svx/svdpage.hxx>
59 #include <svx/svdocirc.hxx>
60 #include <svx/svdopath.hxx>
61 #include <svx/svdocapt.hxx>
62 #include <svl/numformat.hxx>
63 #include <svl/srchitem.hxx>
64 #include <svl/sharedstringpool.hxx>
65 #include <unotools/collatorwrapper.hxx>
66 #include <sfx2/IDocumentModelAccessor.hxx>
68 #include <sfx2/sfxsids.hrc>
86 class Test
: public ScUcalcTestBase
89 void checkPrecisionAsShown(OUString
& rCode
, double fValue
, double fExpectedRoundVal
);
91 /** Get a separate new ScDocShell with ScDocument that suits unit test needs. */
92 void getNewDocShell(ScDocShellRef
& rDocShellRef
);
94 bool checkHorizontalIterator(ScDocument
& rDoc
, const std::vector
<std::vector
<const char*>>& rData
,
95 const HoriIterCheck
* pChecks
, size_t nCheckCount
);
98 void Test::getNewDocShell( ScDocShellRef
& rDocShellRef
)
100 rDocShellRef
= new ScDocShell(
101 SfxModelFlags::EMBEDDED_OBJECT
|
102 SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS
|
103 SfxModelFlags::DISABLE_DOCUMENT_RECOVERY
);
105 rDocShellRef
->DoInitUnitTest();
108 CPPUNIT_TEST_FIXTURE(Test
, testCollator
)
110 sal_Int32 nRes
= ScGlobal::GetCollator().compareString(u
"A"_ustr
, u
"B"_ustr
);
111 CPPUNIT_ASSERT_MESSAGE("these strings are supposed to be different!", nRes
!= 0);
114 CPPUNIT_TEST_FIXTURE(Test
, testUndoBackgroundColorInsertRow
)
116 m_pDoc
->InsertTab(0, u
"Table1"_ustr
);
118 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
120 // Set Values to B1, C2, D5
121 m_pDoc
->SetValue(ScAddress(1, 0, 0), 1.0); // B1
122 m_pDoc
->SetValue(ScAddress(2, 1, 0), 2.0); // C2
123 m_pDoc
->SetValue(ScAddress(3, 4, 0), 3.0); // D5
126 ScPatternAttr
aCellBlueColor(m_pDoc
->getCellAttributeHelper());
127 aCellBlueColor
.GetItemSet().Put(SvxBrushItem(COL_BLUE
, ATTR_BACKGROUND
));
128 m_pDoc
->ApplyPatternAreaTab(0, 3, m_pDoc
->MaxCol(), 3, 0, aCellBlueColor
);
130 // Insert a new row at row 3
131 ScRange
aRowOne(0, 2, 0, m_pDoc
->MaxCol(), 2, 0);
132 aMark
.SetMarkArea(aRowOne
);
133 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
134 rFunc
.InsertCells(aRowOne
, &aMark
, INS_INSROWS_BEFORE
, true, true);
137 const SfxPoolItem
* pItem
= nullptr;
138 m_pDoc
->GetPattern(ScAddress(1000, 4, 0))->GetItemSet().HasItem(ATTR_BACKGROUND
, &pItem
);
139 CPPUNIT_ASSERT(pItem
);
140 CPPUNIT_ASSERT_EQUAL(COL_BLUE
, static_cast<const SvxBrushItem
*>(pItem
)->GetColor());
143 m_pDoc
->GetUndoManager()->Undo();
146 // Failed if row 3 is not blue all the way through
148 m_pDoc
->GetPattern(ScAddress(1000, 3, 0))->GetItemSet().HasItem(ATTR_BACKGROUND
, &pItem
);
149 CPPUNIT_ASSERT(pItem
);
150 CPPUNIT_ASSERT_EQUAL(COL_BLUE
, static_cast<const SvxBrushItem
*>(pItem
)->GetColor());
152 m_pDoc
->DeleteTab(0);
155 CPPUNIT_TEST_FIXTURE(Test
, testUndoBackgroundColorInsertColumn
)
157 m_pDoc
->InsertTab(0, u
"Table1"_ustr
);
159 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
161 // Set Values to B1, C2, D5
162 m_pDoc
->SetValue(ScAddress(1, 0, 0), 1.0); // B1
163 m_pDoc
->SetValue(ScAddress(2, 1, 0), 2.0); // C2
164 m_pDoc
->SetValue(ScAddress(3, 4, 0), 3.0); // D5
167 ScPatternAttr
aCellBlueColor(m_pDoc
->getCellAttributeHelper());
168 aCellBlueColor
.GetItemSet().Put(SvxBrushItem(COL_BLUE
, ATTR_BACKGROUND
));
169 m_pDoc
->ApplyPatternAreaTab(3, 0, 3, m_pDoc
->MaxRow(), 0, aCellBlueColor
);
171 // Insert a new column at column 3
172 ScRange
aColumnOne(2, 0, 0, 2, m_pDoc
->MaxRow(), 0);
173 aMark
.SetMarkArea(aColumnOne
);
174 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
175 rFunc
.InsertCells(aColumnOne
, &aMark
, INS_INSCOLS_BEFORE
, true, true);
178 const SfxPoolItem
* pItem
= nullptr;
179 m_pDoc
->GetPattern(ScAddress(4, 1000, 0))->GetItemSet().HasItem(ATTR_BACKGROUND
, &pItem
);
180 CPPUNIT_ASSERT(pItem
);
181 CPPUNIT_ASSERT_EQUAL(COL_BLUE
, static_cast<const SvxBrushItem
*>(pItem
)->GetColor());
183 // Undo the new column
184 m_pDoc
->GetUndoManager()->Undo();
187 // Failed if column 3 is not blue all the way through
189 m_pDoc
->GetPattern(ScAddress(3, 1000, 0))->GetItemSet().HasItem(ATTR_BACKGROUND
, &pItem
);
190 CPPUNIT_ASSERT(pItem
);
191 CPPUNIT_ASSERT_EQUAL(COL_BLUE
, static_cast<const SvxBrushItem
*>(pItem
)->GetColor());
193 m_pDoc
->DeleteTab(0);
196 CPPUNIT_TEST_FIXTURE(Test
, testMergedHyperlink
)
198 m_pDoc
->InsertTab(0, u
"Table1"_ustr
);
199 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
201 ScFieldEditEngine
& pEE
= m_pDoc
->GetEditEngine();
202 pEE
.SetTextCurrentDefaults(u
"https://libreoffice.org/"_ustr
);
203 m_pDoc
->SetEditText(ScAddress(1, 0, 0), pEE
.CreateTextObject()); // B1
205 m_pDoc
->DoMergeContents(0, 0, 1, 0, 0); // A1:B1
207 CPPUNIT_ASSERT_EQUAL(CELLTYPE_EDIT
, m_pDoc
->GetCellType(ScAddress(0, 0, 0))); // A1
208 const EditTextObject
* pEditObj
= m_pDoc
->GetEditText(ScAddress(0, 0, 0)); // A1
209 CPPUNIT_ASSERT(pEditObj
);
210 CPPUNIT_ASSERT_EQUAL(u
"https://libreoffice.org/"_ustr
, pEditObj
->GetText(0));
213 CPPUNIT_TEST_FIXTURE(Test
, testSharedStringPool
)
215 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
217 svl::SharedStringPool
& rPool
= m_pDoc
->GetSharedStringPool();
218 size_t extraCount
= rPool
.getCount(); // internal items such as SharedString::getEmptyString()
219 size_t extraCountIgnoreCase
= rPool
.getCountIgnoreCase();
221 // Strings that are identical.
222 m_pDoc
->SetString(ScAddress(0,0,0), o3tl::nonStaticString(u
"Andy")); // A1
223 m_pDoc
->SetString(ScAddress(0,1,0), o3tl::nonStaticString(u
"Andy")); // A2
224 m_pDoc
->SetString(ScAddress(0,2,0), o3tl::nonStaticString(u
"Bruce")); // A3
225 m_pDoc
->SetString(ScAddress(0,3,0), o3tl::nonStaticString(u
"andy")); // A4
226 m_pDoc
->SetString(ScAddress(0,4,0), o3tl::nonStaticString(u
"BRUCE")); // A5
229 // These two shared string objects must go out of scope before the purge test.
230 svl::SharedString aSS1
= m_pDoc
->GetSharedString(ScAddress(0,0,0));
231 svl::SharedString aSS2
= m_pDoc
->GetSharedString(ScAddress(0,1,0));
232 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS1
.isValid());
233 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS2
.isValid());
234 CPPUNIT_ASSERT_EQUAL(aSS1
.getData(), aSS2
.getData());
236 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,2,0));
237 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
239 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,3,0));
240 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
242 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,4,0));
243 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
245 // A3 and A5 should differ but should be equal case-insensitively.
246 aSS1
= m_pDoc
->GetSharedString(ScAddress(0,2,0));
247 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,4,0));
248 CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1
.getData() != aSS2
.getData());
249 CPPUNIT_ASSERT_EQUAL_MESSAGE("They must be equal when cases are ignored.", aSS1
.getDataIgnoreCase(), aSS2
.getDataIgnoreCase());
251 // A2 and A4 should be equal when ignoring cases.
252 aSS1
= m_pDoc
->GetSharedString(ScAddress(0,1,0));
253 aSS2
= m_pDoc
->GetSharedString(ScAddress(0,3,0));
254 CPPUNIT_ASSERT_EQUAL_MESSAGE("They must be equal when cases are ignored.", aSS1
.getDataIgnoreCase(), aSS2
.getDataIgnoreCase());
257 // Check the string counts after purging. Purging shouldn't remove any strings in this case.
259 CPPUNIT_ASSERT_EQUAL(5+extraCount
, rPool
.getCount());
260 CPPUNIT_ASSERT_EQUAL(2+extraCountIgnoreCase
, rPool
.getCountIgnoreCase());
263 clearRange(m_pDoc
, ScRange(ScAddress(0,0,0)));
265 clearRange(m_pDoc
, ScRange(ScAddress(0,1,0)));
267 clearRange(m_pDoc
, ScRange(ScAddress(0,2,0)));
269 clearRange(m_pDoc
, ScRange(ScAddress(0,3,0)));
270 // Clear A5 and the pool should be completely empty.
271 clearRange(m_pDoc
, ScRange(ScAddress(0,4,0)));
273 CPPUNIT_ASSERT_EQUAL(extraCount
, rPool
.getCount());
274 CPPUNIT_ASSERT_EQUAL(extraCountIgnoreCase
, rPool
.getCountIgnoreCase());
276 // Now, compare string and edit text cells.
277 m_pDoc
->SetString(ScAddress(0,0,0), "Andy and Bruce"); // A1 // [-loplugin:ostr]
278 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
279 rEE
.SetTextCurrentDefaults(u
"Andy and Bruce"_ustr
);
283 SfxItemSet aItemSet
= rEE
.GetEmptyItemSet();
284 SvxWeightItem
aWeight(WEIGHT_BOLD
, EE_CHAR_WEIGHT
);
285 aItemSet
.Put(aWeight
);
286 rEE
.QuickSetAttribs(aItemSet
, ESelection(0, 0, 0, 4));
290 // Set 'Bruce' italic.
291 SfxItemSet aItemSet
= rEE
.GetEmptyItemSet();
292 SvxPostureItem
aItalic(ITALIC_NORMAL
, EE_CHAR_ITALIC
);
293 aItemSet
.Put(aItalic
);
294 rEE
.QuickSetAttribs(aItemSet
, ESelection(0, 9, 0, 14));
297 m_pDoc
->SetEditText(ScAddress(1,0,0), rEE
.CreateTextObject()); // B1
299 // These two should be equal.
300 svl::SharedString aSS1
= m_pDoc
->GetSharedString(ScAddress(0,0,0));
301 svl::SharedString aSS2
= m_pDoc
->GetSharedString(ScAddress(1,0,0));
302 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1
.isValid());
303 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2
.isValid());
304 CPPUNIT_ASSERT_EQUAL(aSS1
.getData(), aSS2
.getData());
306 rEE
.SetTextCurrentDefaults(u
"ANDY and BRUCE"_ustr
);
307 m_pDoc
->SetEditText(ScAddress(2,0,0), rEE
.CreateTextObject()); // C1
308 aSS2
= m_pDoc
->GetSharedString(ScAddress(2,0,0));
309 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2
.isValid());
310 CPPUNIT_ASSERT_MESSAGE("These two should be different when cases are considered.", aSS1
.getData() != aSS2
.getData());
312 // But they should be considered equal when cases are ignored.
313 aSS1
= m_pDoc
->GetSharedString(ScAddress(0,0,0));
314 aSS2
= m_pDoc
->GetSharedString(ScAddress(2,0,0));
315 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1
.isValid());
316 CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2
.isValid());
317 CPPUNIT_ASSERT_EQUAL(aSS1
.getDataIgnoreCase(), aSS2
.getDataIgnoreCase());
319 m_pDoc
->DeleteTab(0);
322 CPPUNIT_TEST_FIXTURE(Test
, testBackgroundColorDeleteColumn
)
324 m_pDoc
->InsertTab(0, u
"Table1"_ustr
);
326 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
328 // Set Values to B1, C2, D5
329 m_pDoc
->SetValue(ScAddress(1, 0, 0), 1.0); // B1
330 m_pDoc
->SetValue(ScAddress(2, 1, 0), 2.0); // C2
331 m_pDoc
->SetValue(ScAddress(3, 4, 0), 3.0); // D5
334 ScPatternAttr
aCellBlueColor(m_pDoc
->getCellAttributeHelper());
335 aCellBlueColor
.GetItemSet().Put(SvxBrushItem(COL_BLUE
, ATTR_BACKGROUND
));
336 m_pDoc
->ApplyPatternAreaTab(3, 0, 3, m_pDoc
->MaxRow(), 0, aCellBlueColor
);
339 m_pDoc
->DeleteCol(ScRange(9,0,0,9,m_pDoc
->MaxRow(),0));
342 const SfxPoolItem
* pItem
= nullptr;
343 m_pDoc
->GetPattern(ScAddress(3, 1000, 0))->GetItemSet().HasItem(ATTR_BACKGROUND
, &pItem
);
344 CPPUNIT_ASSERT(pItem
);
345 CPPUNIT_ASSERT_EQUAL(COL_BLUE
, static_cast<const SvxBrushItem
*>(pItem
)->GetColor());
348 m_pDoc
->DeleteCol(ScRange(1,0,0,1,m_pDoc
->MaxRow(),0));
352 m_pDoc
->GetPattern(ScAddress(2, 1000, 0))->GetItemSet().HasItem(ATTR_BACKGROUND
, &pItem
);
353 CPPUNIT_ASSERT(pItem
);
354 CPPUNIT_ASSERT_EQUAL(COL_BLUE
, static_cast<const SvxBrushItem
*>(pItem
)->GetColor());
356 m_pDoc
->DeleteTab(0);
359 CPPUNIT_TEST_FIXTURE(Test
, testBackgroundColorDeleteRow
)
361 m_pDoc
->InsertTab(0, u
"Table1"_ustr
);
363 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
365 // Set Values to B1, C2, D5
366 m_pDoc
->SetValue(ScAddress(1, 0, 0), 1.0); // B1
367 m_pDoc
->SetValue(ScAddress(2, 1, 0), 2.0); // C2
368 m_pDoc
->SetValue(ScAddress(3, 4, 0), 3.0); // D5
371 ScPatternAttr
aCellBlueColor(m_pDoc
->getCellAttributeHelper());
372 aCellBlueColor
.GetItemSet().Put(SvxBrushItem(COL_BLUE
, ATTR_BACKGROUND
));
373 m_pDoc
->ApplyPatternAreaTab(0, 3, m_pDoc
->MaxCol(), 3, 0, aCellBlueColor
);
376 m_pDoc
->DeleteRow(ScRange(0,9,0,m_pDoc
->MaxCol(),9,0));
379 const SfxPoolItem
* pItem
= nullptr;
380 m_pDoc
->GetPattern(ScAddress(1000, 3, 0))->GetItemSet().HasItem(ATTR_BACKGROUND
, &pItem
);
381 CPPUNIT_ASSERT(pItem
);
382 CPPUNIT_ASSERT_EQUAL(COL_BLUE
, static_cast<const SvxBrushItem
*>(pItem
)->GetColor());
385 m_pDoc
->DeleteRow(ScRange(0,1,0,m_pDoc
->MaxCol(),1,0));
389 m_pDoc
->GetPattern(ScAddress(1000, 2, 0))->GetItemSet().HasItem(ATTR_BACKGROUND
, &pItem
);
390 CPPUNIT_ASSERT(pItem
);
391 CPPUNIT_ASSERT_EQUAL(COL_BLUE
, static_cast<const SvxBrushItem
*>(pItem
)->GetColor());
393 m_pDoc
->DeleteTab(0);
396 CPPUNIT_TEST_FIXTURE(Test
, testSharedStringPoolUndoDoc
)
400 bool check( const ScDocument
& rSrcDoc
, ScDocument
& rCopyDoc
)
402 // Copy A1:A4 to the undo document.
403 for (SCROW i
= 0; i
<= 4; ++i
)
405 ScAddress
aPos(0,i
,0);
406 rCopyDoc
.SetString(aPos
, rSrcDoc
.GetString(aPos
));
409 // String values in A1:A4 should have identical hash.
410 for (SCROW i
= 0; i
<= 4; ++i
)
412 ScAddress
aPos(0,i
,0);
413 svl::SharedString aSS1
= rSrcDoc
.GetSharedString(aPos
);
414 svl::SharedString aSS2
= rCopyDoc
.GetSharedString(aPos
);
415 if (aSS1
.getDataIgnoreCase() != aSS2
.getDataIgnoreCase())
417 cerr
<< "String hash values are not equal at row " << (i
+1)
418 << " for string '" << aSS1
.getString() << "'" << endl
;
428 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
430 m_pDoc
->SetString(ScAddress(0,0,0), u
"Header"_ustr
);
431 m_pDoc
->SetString(ScAddress(0,1,0), u
"A1"_ustr
);
432 m_pDoc
->SetString(ScAddress(0,2,0), u
"A2"_ustr
);
433 m_pDoc
->SetString(ScAddress(0,3,0), u
"A3"_ustr
);
435 ScDocument
aUndoDoc(SCDOCMODE_UNDO
);
436 aUndoDoc
.InitUndo(*m_pDoc
, 0, 0);
438 bool bSuccess
= aTest
.check(*m_pDoc
, aUndoDoc
);
439 CPPUNIT_ASSERT_MESSAGE("Check failed with undo document.", bSuccess
);
441 // Test the clip document as well.
442 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
443 aClipDoc
.ResetClip(m_pDoc
, static_cast<SCTAB
>(0));
445 bSuccess
= aTest
.check(*m_pDoc
, aClipDoc
);
446 CPPUNIT_ASSERT_MESSAGE("Check failed with clip document.", bSuccess
);
448 m_pDoc
->DeleteTab(0);
451 CPPUNIT_TEST_FIXTURE(Test
, testRangeList
)
453 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
456 aRL
.push_back(ScRange(1,1,0,3,10,0));
457 CPPUNIT_ASSERT_EQUAL_MESSAGE("List should have one range.", size_t(1), aRL
.size());
458 const ScRange
* p
= &aRL
[0];
459 CPPUNIT_ASSERT_MESSAGE("Failed to get the range object.", p
);
460 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong range.", ScAddress(1,1,0), p
->aStart
);
461 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong range.", ScAddress(3,10,0), p
->aEnd
);
463 // TODO: Add more tests here.
465 m_pDoc
->DeleteTab(0);
468 CPPUNIT_TEST_FIXTURE(Test
, testMarkData
)
470 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
472 // Empty mark. Nothing is selected.
473 std::vector
<sc::ColRowSpan
> aSpans
= aMarkData
.GetMarkedRowSpans();
474 CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans
.empty());
475 aSpans
= aMarkData
.GetMarkedColSpans();
476 CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans
.empty());
479 aMarkData
.SetMarkArea(ScRange(1,2,0,5,6,0));
480 aSpans
= aMarkData
.GetMarkedRowSpans();
481 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected row span.", size_t(1), aSpans
.size());
482 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(2), aSpans
[0].mnStart
);
483 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(6), aSpans
[0].mnEnd
);
485 aSpans
= aMarkData
.GetMarkedColSpans();
486 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected column span.", size_t(1), aSpans
.size());
487 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(1), aSpans
[0].mnStart
);
488 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(5), aSpans
[0].mnEnd
);
491 aMarkData
.SetMultiMarkArea(ScRange(0,10,0,1,12,0));
492 aSpans
= aMarkData
.GetMarkedRowSpans();
493 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 2 selected row spans.", size_t(2), aSpans
.size());
494 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(2), aSpans
[0].mnStart
);
495 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(6), aSpans
[0].mnEnd
);
496 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(10), aSpans
[1].mnStart
);
497 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(12), aSpans
[1].mnEnd
);
499 aSpans
= aMarkData
.GetMarkedColSpans();
500 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected column span.", size_t(1), aSpans
.size());
501 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(0), aSpans
[0].mnStart
);
502 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(5), aSpans
[0].mnEnd
);
505 aMarkData
.SetMultiMarkArea(ScRange(2,7,0,2,9,0));
506 aSpans
= aMarkData
.GetMarkedRowSpans();
507 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected row span.", size_t(1), aSpans
.size());
508 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(2), aSpans
[0].mnStart
);
509 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(12), aSpans
[0].mnEnd
);
511 aSpans
= aMarkData
.GetMarkedColSpans();
512 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one selected column span.", size_t(1), aSpans
.size());
513 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(0), aSpans
[0].mnStart
);
514 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW
>(5), aSpans
[0].mnEnd
);
517 CPPUNIT_TEST_FIXTURE(Test
, testInput
)
520 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
521 m_pDoc
->InsertTab (0, u
"foo"_ustr
));
524 m_pDoc
->SetString(0, 0, 0, u
"'10.5"_ustr
);
525 test
= m_pDoc
->GetString(0, 0, 0);
526 bool bTest
= test
== "10.5";
527 CPPUNIT_ASSERT_MESSAGE("String number should have the first apostrophe stripped.", bTest
);
528 m_pDoc
->SetString(0, 0, 0, u
"'apple'"_ustr
);
529 test
= m_pDoc
->GetString(0, 0, 0);
530 bTest
= test
== "apple'";
531 CPPUNIT_ASSERT_MESSAGE("Text content should have the first apostrophe stripped.", bTest
);
533 // Customized string handling policy.
534 ScSetStringParam aParam
;
535 aParam
.setTextInput();
536 m_pDoc
->SetString(0, 0, 0, u
"000123"_ustr
, &aParam
);
537 test
= m_pDoc
->GetString(0, 0, 0);
538 CPPUNIT_ASSERT_EQUAL_MESSAGE("Text content should have been treated as string, not number.", u
"000123"_ustr
, test
);
540 m_pDoc
->DeleteTab(0);
543 CPPUNIT_TEST_FIXTURE(Test
, testColumnIterator
) // tdf#118620
545 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
546 m_pDoc
->InsertTab (0, u
"foo"_ustr
));
548 m_pDoc
->SetString(0, 0, 0, u
"'10.5"_ustr
);
549 m_pDoc
->SetString(0, m_pDoc
->MaxRow()-5, 0, u
"42.0"_ustr
);
550 std::optional
<sc::ColumnIterator
> it
= m_pDoc
->GetColumnIterator(0, 0, m_pDoc
->MaxRow() - 10, m_pDoc
->MaxRow());
551 while (it
->hasCell())
557 m_pDoc
->DeleteTab(0);
560 CPPUNIT_TEST_FIXTURE(Test
, testTdf66613
)
562 // Create different print ranges and col/row repetitions for two tabs
563 const SCTAB nFirstTab
= 0;
564 CPPUNIT_ASSERT(m_pDoc
->InsertTab(nFirstTab
, u
"FirstPrintRange"_ustr
));
565 ScRange
aFirstPrintRange(0, 0, nFirstTab
, 2, 2, nFirstTab
);
566 m_pDoc
->AddPrintRange(nFirstTab
, aFirstPrintRange
);
567 ScRange
aFirstRepeatColRange(0, 0, nFirstTab
, 0, 0, nFirstTab
);
568 m_pDoc
->SetRepeatColRange(nFirstTab
, aFirstRepeatColRange
);
569 ScRange
aFirstRepeatRowRange(1, 1, nFirstTab
, 1, 1, nFirstTab
);
570 m_pDoc
->SetRepeatRowRange(nFirstTab
, aFirstRepeatRowRange
);
572 const SCTAB nSecondTab
= 1;
573 CPPUNIT_ASSERT(m_pDoc
->InsertTab(nSecondTab
, u
"SecondPrintRange"_ustr
));
574 ScRange
aSecondPrintRange(0, 0, nSecondTab
, 3, 3, nSecondTab
);
575 m_pDoc
->AddPrintRange(nSecondTab
, aSecondPrintRange
);
576 ScRange
aSecondRepeatColRange(1, 1, nSecondTab
, 1, 1, nSecondTab
);
577 m_pDoc
->SetRepeatColRange(nSecondTab
, aSecondRepeatColRange
);
578 ScRange
aSecondRepeatRowRange(2, 2, nSecondTab
, 2, 2, nSecondTab
);
579 m_pDoc
->SetRepeatRowRange(nSecondTab
, aSecondRepeatRowRange
);
581 // Transfer generated tabs to a new document with different order
582 ScDocument aScDocument
;
583 aScDocument
.TransferTab(*m_pDoc
, nSecondTab
, nFirstTab
);
584 aScDocument
.TransferTab(*m_pDoc
, nFirstTab
, nSecondTab
);
586 // Check the number of print ranges in both documents
587 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), m_pDoc
->GetPrintRangeCount(nFirstTab
));
588 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), m_pDoc
->GetPrintRangeCount(nSecondTab
));
589 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), aScDocument
.GetPrintRangeCount(nFirstTab
));
590 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1), aScDocument
.GetPrintRangeCount(nSecondTab
));
592 // Check the print ranges and col/row repetitions in both documents
593 CPPUNIT_ASSERT_EQUAL(aFirstPrintRange
, *m_pDoc
->GetPrintRange(nFirstTab
, 0));
594 CPPUNIT_ASSERT_EQUAL(aFirstRepeatColRange
, *m_pDoc
->GetRepeatColRange(nFirstTab
));
595 CPPUNIT_ASSERT_EQUAL(aFirstRepeatRowRange
, *m_pDoc
->GetRepeatRowRange(nFirstTab
));
596 CPPUNIT_ASSERT_EQUAL(aSecondPrintRange
, *m_pDoc
->GetPrintRange(nSecondTab
, 0));
597 CPPUNIT_ASSERT_EQUAL(aSecondRepeatColRange
, *m_pDoc
->GetRepeatColRange(nSecondTab
));
598 CPPUNIT_ASSERT_EQUAL(aSecondRepeatRowRange
, *m_pDoc
->GetRepeatRowRange(nSecondTab
));
600 // Tabs have to be adjusted since the order of the tabs is inverted in the new document
601 std::vector
<ScRange
*> aScRanges
602 = { &aFirstPrintRange
, &aFirstRepeatColRange
, &aFirstRepeatRowRange
,
603 &aSecondPrintRange
, &aSecondRepeatColRange
, &aSecondRepeatRowRange
};
604 for (size_t i
= 0; i
< aScRanges
.size(); i
++)
606 const SCTAB nTab
= i
>= 3 ? nFirstTab
: nSecondTab
;
607 aScRanges
[i
]->aStart
.SetTab(nTab
);
608 aScRanges
[i
]->aEnd
.SetTab(nTab
);
611 // Without the fix in place, no print ranges and col/row repetitions would be present
612 CPPUNIT_ASSERT_EQUAL(aFirstPrintRange
, *aScDocument
.GetPrintRange(nSecondTab
, 0));
613 CPPUNIT_ASSERT_EQUAL(aFirstRepeatColRange
, *aScDocument
.GetRepeatColRange(nSecondTab
));
614 CPPUNIT_ASSERT_EQUAL(aFirstRepeatRowRange
, *aScDocument
.GetRepeatRowRange(nSecondTab
));
615 CPPUNIT_ASSERT_EQUAL(aSecondPrintRange
, *aScDocument
.GetPrintRange(nFirstTab
, 0));
616 CPPUNIT_ASSERT_EQUAL(aSecondRepeatColRange
, *aScDocument
.GetRepeatColRange(nFirstTab
));
617 CPPUNIT_ASSERT_EQUAL(aSecondRepeatRowRange
, *aScDocument
.GetRepeatRowRange(nFirstTab
));
619 m_pDoc
->DeleteTab(nFirstTab
);
620 m_pDoc
->DeleteTab(nSecondTab
);
623 CPPUNIT_TEST_FIXTURE(Test
, testTdf113027
)
625 // Insert some sheets including a whitespace in their name and switch the grammar to R1C1
626 CPPUNIT_ASSERT(m_pDoc
->InsertTab(0, u
"Sheet 1"_ustr
));
627 CPPUNIT_ASSERT(m_pDoc
->InsertTab(1, u
"Sheet 2"_ustr
));
628 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
630 // Add a formula containing a remote reference, i.e., to another sheet
631 const ScAddress
aScAddress(0, 0, 0);
632 static constexpr OUString aFormula
= u
"='Sheet 2'!RC"_ustr
;
633 m_pDoc
->SetString(aScAddress
, aFormula
);
635 // Switch from relative to absolute cell reference
636 ScRefFinder
aFinder(aFormula
, aScAddress
, *m_pDoc
, m_pDoc
->GetAddressConvention());
637 aFinder
.ToggleRel(0, aFormula
.getLength());
639 // Without the fix in place, this test would have failed with
640 // - Expected: ='Sheet 2'!R1C1
641 // - Actual : ='Sheet 2'!RC
642 // i.e. the cell reference was not changed from relative to absolute
643 CPPUNIT_ASSERT_EQUAL(u
"='Sheet 2'!R1C1"_ustr
, aFinder
.GetText());
645 m_pDoc
->DeleteTab(0);
646 m_pDoc
->DeleteTab(1);
649 CPPUNIT_TEST_FIXTURE(Test
, testTdf90698
)
651 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, u
"Test"_ustr
));
652 m_pDoc
->SetString(ScAddress(0,0,0), u
"=(1;2)"_ustr
);
654 // Without the fix in place, this would have failed with
655 // - Expected: =(1;2)
657 OUString aFormula
= m_pDoc
->GetFormula(0,0,0);
658 CPPUNIT_ASSERT_EQUAL(u
"=(1;2)"_ustr
, aFormula
);
660 m_pDoc
->DeleteTab(0);
663 CPPUNIT_TEST_FIXTURE(Test
, testTdf114406
)
665 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, u
"Test"_ustr
));
666 m_pDoc
->SetString(ScAddress(0,0,0), u
"5"_ustr
);
667 m_pDoc
->SetString(ScAddress(1,0,0), u
"=A1/100%"_ustr
);
669 // Without the fix in place, this would have failed with
670 // - Expected: =A1/100%
672 OUString aFormula
= m_pDoc
->GetFormula(1,0,0);
673 CPPUNIT_ASSERT_EQUAL(u
"=A1/100%"_ustr
, aFormula
);
675 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
677 m_pDoc
->DeleteTab(0);
680 CPPUNIT_TEST_FIXTURE(Test
, testTdf93951
)
682 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, u
"Test"_ustr
));
683 m_pDoc
->SetString(ScAddress(0,0,0), u
"=2*§*2"_ustr
);
685 OUString aFormula
= m_pDoc
->GetFormula(0,0,0);
687 // Without the fix in place, this test would have failed with
688 // - Expected: =2*§*2
690 CPPUNIT_ASSERT_EQUAL(u
"=2*§*2"_ustr
, aFormula
);
692 m_pDoc
->DeleteTab(0);
695 CPPUNIT_TEST_FIXTURE(Test
, testTdf134490
)
697 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, u
"Test"_ustr
));
699 m_pDoc
->SetString(ScAddress(0,0,0), u
"--1"_ustr
);
700 m_pDoc
->SetString(ScAddress(0,1,0), u
"---1"_ustr
);
701 m_pDoc
->SetString(ScAddress(0,2,0), u
"+-1"_ustr
);
702 m_pDoc
->SetString(ScAddress(0,3,0), u
"+--1"_ustr
);
704 // Without the fix in place, this test would have failed with
707 CPPUNIT_ASSERT_EQUAL(u
"--1"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
708 CPPUNIT_ASSERT_EQUAL(u
"---1"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
709 CPPUNIT_ASSERT_EQUAL(u
"+-1"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0)));
710 CPPUNIT_ASSERT_EQUAL(u
"+--1"_ustr
, m_pDoc
->GetString(ScAddress(0,3,0)));
712 m_pDoc
->DeleteTab(0);
715 CPPUNIT_TEST_FIXTURE(Test
, testTdf135249
)
717 CPPUNIT_ASSERT(m_pDoc
->InsertTab (0, u
"Test"_ustr
));
719 m_pDoc
->SetString(ScAddress(0,0,0), u
"1:60"_ustr
);
720 m_pDoc
->SetString(ScAddress(0,1,0), u
"1:123"_ustr
);
721 m_pDoc
->SetString(ScAddress(0,2,0), u
"1:1:123"_ustr
);
722 m_pDoc
->SetString(ScAddress(0,3,0), u
"0:123"_ustr
);
723 m_pDoc
->SetString(ScAddress(0,4,0), u
"0:0:123"_ustr
);
724 m_pDoc
->SetString(ScAddress(0,5,0), u
"0:123:59"_ustr
);
726 // These are not valid duration inputs
727 CPPUNIT_ASSERT_EQUAL(u
"1:60"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
728 CPPUNIT_ASSERT_EQUAL(u
"1:123"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
729 CPPUNIT_ASSERT_EQUAL(u
"1:1:123"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0)));
731 // These are valid duration inputs
732 // Without the fix in place, this test would have failed with
733 // - Expected: 02:03:00 AM
735 CPPUNIT_ASSERT_EQUAL(u
"02:03:00 AM"_ustr
, m_pDoc
->GetString(ScAddress(0,3,0)));
736 CPPUNIT_ASSERT_EQUAL(u
"12:02:03 AM"_ustr
, m_pDoc
->GetString(ScAddress(0,4,0)));
737 CPPUNIT_ASSERT_EQUAL(u
"02:03:59 AM"_ustr
, m_pDoc
->GetString(ScAddress(0,5,0)));
739 m_pDoc
->DeleteTab(0);
742 CPPUNIT_TEST_FIXTURE(Test
, testDocStatistics
)
744 SCTAB nStartTabs
= m_pDoc
->GetTableCount();
745 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
746 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to increment sheet count.",
747 static_cast<SCTAB
>(nStartTabs
+1), m_pDoc
->GetTableCount());
748 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
749 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to increment sheet count.",
750 static_cast<SCTAB
>(nStartTabs
+2), m_pDoc
->GetTableCount());
752 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(0), m_pDoc
->GetCellCount());
753 m_pDoc
->SetValue(ScAddress(0,0,0), 2.0);
754 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetCellCount());
755 m_pDoc
->SetValue(ScAddress(2,2,0), 2.5);
756 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(2), m_pDoc
->GetCellCount());
757 m_pDoc
->SetString(ScAddress(1,1,1), u
"Test"_ustr
);
758 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(3), m_pDoc
->GetCellCount());
760 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(0), m_pDoc
->GetFormulaGroupCount());
761 m_pDoc
->SetString(ScAddress(3,0,1), u
"=A1"_ustr
);
762 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetFormulaGroupCount());
763 m_pDoc
->SetString(ScAddress(3,1,1), u
"=A2"_ustr
);
764 m_pDoc
->SetString(ScAddress(3,2,1), u
"=A3"_ustr
);
765 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(1), m_pDoc
->GetFormulaGroupCount());
766 m_pDoc
->SetString(ScAddress(3,3,1), u
"=A5"_ustr
);
767 m_pDoc
->SetString(ScAddress(3,4,1), u
"=A6"_ustr
);
768 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(2), m_pDoc
->GetFormulaGroupCount());
769 m_pDoc
->SetString(ScAddress(3,1,1), u
"=A3"_ustr
);
770 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt64
>(4), m_pDoc
->GetFormulaGroupCount());
772 m_pDoc
->DeleteTab(1);
773 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to decrement sheet count.",
774 static_cast<SCTAB
>(nStartTabs
+1), m_pDoc
->GetTableCount());
775 m_pDoc
->DeleteTab(0); // This may fail in case there is only one sheet in the document.
778 CPPUNIT_TEST_FIXTURE(Test
, testRowForHeight
)
780 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
781 m_pDoc
->SetRowHeightRange( 0, 9, 0, 100);
782 m_pDoc
->SetRowHeightRange(10, 19, 0, 200);
783 m_pDoc
->SetRowHeightRange(20, 29, 0, 300);
786 m_pDoc
->SetRowHidden(3, 5, 0, true);
787 m_pDoc
->SetRowHidden(8, 12, 0, true);
795 std::vector
<Check
> aChecks
= {
806 for (const Check
& rCheck
: aChecks
)
808 SCROW nRow
= m_pDoc
->GetRowForHeight(0, rCheck
.nHeight
);
809 CPPUNIT_ASSERT_EQUAL(rCheck
.nRow
, nRow
);
813 CPPUNIT_TEST_FIXTURE(Test
, testDataEntries
)
816 * The 'data entries' data is a list of strings used for suggestions as
817 * the user types in new cell value.
819 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
821 m_pDoc
->SetString(ScAddress(0,5,0), u
"Andy"_ustr
);
822 m_pDoc
->SetString(ScAddress(0,6,0), u
"Bruce"_ustr
);
823 m_pDoc
->SetString(ScAddress(0,7,0), u
"Charlie"_ustr
);
824 m_pDoc
->SetString(ScAddress(0,10,0), u
"Andy"_ustr
);
826 std::vector
<ScTypedStrData
> aEntries
;
827 m_pDoc
->GetDataEntries(0, 0, 0, aEntries
); // Try at the very top.
829 // Entries are supposed to be sorted in ascending order, and are all unique.
830 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries
.size());
831 std::vector
<ScTypedStrData
>::const_iterator it
= aEntries
.begin();
832 CPPUNIT_ASSERT_EQUAL(u
"Andy"_ustr
, it
->GetString());
834 CPPUNIT_ASSERT_EQUAL(u
"Bruce"_ustr
, it
->GetString());
836 CPPUNIT_ASSERT_EQUAL(u
"Charlie"_ustr
, it
->GetString());
838 CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", bool(it
== aEntries
.end()));
841 m_pDoc
->GetDataEntries(0, m_pDoc
->MaxRow(), 0, aEntries
); // Try at the very bottom.
842 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries
.size());
844 // Make sure we get the same set of suggestions.
845 it
= aEntries
.begin();
846 CPPUNIT_ASSERT_EQUAL(u
"Andy"_ustr
, it
->GetString());
848 CPPUNIT_ASSERT_EQUAL(u
"Bruce"_ustr
, it
->GetString());
850 CPPUNIT_ASSERT_EQUAL(u
"Charlie"_ustr
, it
->GetString());
852 CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", bool(it
== aEntries
.end()));
854 m_pDoc
->DeleteTab(0);
857 CPPUNIT_TEST_FIXTURE(Test
, testSelectionFunction
)
860 * Selection function is responsible for displaying quick calculation
861 * results in the status bar.
863 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
865 // Insert values into B2:B4.
866 m_pDoc
->SetString(ScAddress(1,1,0), u
"=1"_ustr
); // formula
867 m_pDoc
->SetValue(ScAddress(1,2,0), 2.0);
868 m_pDoc
->SetValue(ScAddress(1,3,0), 3.0);
870 // Insert strings into B5:B8.
871 m_pDoc
->SetString(ScAddress(1,4,0), u
"A"_ustr
);
872 m_pDoc
->SetString(ScAddress(1,5,0), u
"B"_ustr
);
873 m_pDoc
->SetString(ScAddress(1,6,0), u
"=\"C\""_ustr
); // formula
874 m_pDoc
->SetString(ScAddress(1,7,0), u
"D"_ustr
);
876 // Insert values into D2:D4.
877 m_pDoc
->SetValue(ScAddress(3,1,0), 4.0);
878 m_pDoc
->SetValue(ScAddress(3,2,0), 5.0);
879 m_pDoc
->SetValue(ScAddress(3,3,0), 6.0);
881 // Insert edit text into D5.
882 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
883 rEE
.SetTextCurrentDefaults(u
"Rich Text"_ustr
);
884 m_pDoc
->SetEditText(ScAddress(3,4,0), rEE
.CreateTextObject());
886 // Insert Another string into D6.
887 m_pDoc
->SetString(ScAddress(3,5,0), u
"E"_ustr
);
889 // Select B2:B8 & D2:D8 disjoint region.
891 aRanges
.push_back(ScRange(1,1,0,1,7,0)); // B2:B8
892 aRanges
.push_back(ScRange(3,1,0,3,7,0)); // D2:D8
893 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
894 aMark
.MarkFromRangeList(aRanges
, true);
898 ScSubTotalFunc meFunc
;
903 static const Check aChecks
[] =
905 { SUBTOTAL_FUNC_AVE
, 3.5 },
906 { SUBTOTAL_FUNC_CNT2
, 12.0 },
907 { SUBTOTAL_FUNC_CNT
, 6.0 },
908 { SUBTOTAL_FUNC_MAX
, 6.0 },
909 { SUBTOTAL_FUNC_MIN
, 1.0 },
910 { SUBTOTAL_FUNC_SUM
, 21.0 },
911 { SUBTOTAL_FUNC_SELECTION_COUNT
, 14.0 }
914 for (const auto& rCheck
: aChecks
)
917 bool bRes
= m_pDoc
->GetSelectionFunction(rCheck
.meFunc
, ScAddress(), aMark
, fRes
);
918 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
919 CPPUNIT_ASSERT_EQUAL(rCheck
.mfExpected
, fRes
);
923 // Hide rows 4 and 6 and check the results again.
925 m_pDoc
->SetRowHidden(3, 3, 0, true);
926 m_pDoc
->SetRowHidden(5, 5, 0, true);
927 CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc
->RowHidden(3, 0));
928 CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc
->RowHidden(5, 0));
931 static const Check aChecks
[] =
933 { SUBTOTAL_FUNC_AVE
, 3.0 },
934 { SUBTOTAL_FUNC_CNT2
, 8.0 },
935 { SUBTOTAL_FUNC_CNT
, 4.0 },
936 { SUBTOTAL_FUNC_MAX
, 5.0 },
937 { SUBTOTAL_FUNC_MIN
, 1.0 },
938 { SUBTOTAL_FUNC_SUM
, 12.0 },
939 { SUBTOTAL_FUNC_SELECTION_COUNT
, 10.0 }
942 for (const auto& rCheck
: aChecks
)
945 bool bRes
= m_pDoc
->GetSelectionFunction(rCheck
.meFunc
, ScAddress(), aMark
, fRes
);
946 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
947 CPPUNIT_ASSERT_EQUAL(rCheck
.mfExpected
, fRes
);
951 // Make sure that when no selection is present, use the current cursor position.
952 ScMarkData
aEmpty(m_pDoc
->GetSheetLimits());
955 // D3 (numeric cell containing 5.)
956 ScAddress
aPos(3, 2, 0);
958 static const Check aChecks
[] =
960 { SUBTOTAL_FUNC_AVE
, 5.0 },
961 { SUBTOTAL_FUNC_CNT2
, 1.0 },
962 { SUBTOTAL_FUNC_CNT
, 1.0 },
963 { SUBTOTAL_FUNC_MAX
, 5.0 },
964 { SUBTOTAL_FUNC_MIN
, 5.0 },
965 { SUBTOTAL_FUNC_SUM
, 5.0 },
966 { SUBTOTAL_FUNC_SELECTION_COUNT
, 1.0 }
969 for (const auto& rCheck
: aChecks
)
972 bool bRes
= m_pDoc
->GetSelectionFunction(rCheck
.meFunc
, aPos
, aEmpty
, fRes
);
973 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
974 CPPUNIT_ASSERT_EQUAL(rCheck
.mfExpected
, fRes
);
979 // B7 (string formula cell containing ="C".)
980 ScAddress
aPos(1, 6, 0);
982 static const Check aChecks
[] =
984 { SUBTOTAL_FUNC_CNT2
, 1.0 },
985 { SUBTOTAL_FUNC_SELECTION_COUNT
, 1.0 }
988 for (const auto& rCheck
: aChecks
)
991 bool bRes
= m_pDoc
->GetSelectionFunction(rCheck
.meFunc
, aPos
, aEmpty
, fRes
);
992 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
993 CPPUNIT_ASSERT_EQUAL(rCheck
.mfExpected
, fRes
);
997 // Calculate function across selected sheets.
998 clearSheet(m_pDoc
, 0);
999 m_pDoc
->InsertTab(1, u
"Test2"_ustr
);
1000 m_pDoc
->InsertTab(2, u
"Test3"_ustr
);
1002 // Set values at B2 and C3 on each sheet.
1003 m_pDoc
->SetValue(ScAddress(1,1,0), 1.0);
1004 m_pDoc
->SetValue(ScAddress(2,2,0), 2.0);
1005 m_pDoc
->SetValue(ScAddress(1,1,1), 4.0);
1006 m_pDoc
->SetValue(ScAddress(2,2,1), 8.0);
1007 m_pDoc
->SetValue(ScAddress(1,1,2), 16.0);
1008 m_pDoc
->SetValue(ScAddress(2,2,2), 32.0);
1010 // Mark B2 and C3 on first sheet.
1011 aRanges
.RemoveAll();
1012 aRanges
.push_back(ScRange(1,1,0)); // B2
1013 aRanges
.push_back(ScRange(2,2,0)); // C3
1014 aMark
.MarkFromRangeList(aRanges
, true);
1015 // Additionally select third sheet.
1016 aMark
.SelectTable(2, true);
1020 bool bRes
= m_pDoc
->GetSelectionFunction( SUBTOTAL_FUNC_SUM
, ScAddress(), aMark
, fRes
);
1021 CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes
);
1022 CPPUNIT_ASSERT_EQUAL_MESSAGE("1+2+16+32=", 51.0, fRes
);
1025 m_pDoc
->DeleteTab(2);
1026 m_pDoc
->DeleteTab(1);
1027 m_pDoc
->DeleteTab(0);
1030 CPPUNIT_TEST_FIXTURE(Test
, testMarkedCellIteration
)
1032 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
1034 // Insert cells to A1, A5, B2 and C3.
1035 m_pDoc
->SetString(ScAddress(0,0,0), u
"California"_ustr
);
1036 m_pDoc
->SetValue(ScAddress(0,4,0), 1.2);
1037 m_pDoc
->SetEditText(ScAddress(1,1,0), u
"Boston"_ustr
);
1038 m_pDoc
->SetFormula(ScAddress(2,2,0), u
"=SUM(1,2,3)"_ustr
, m_pDoc
->GetGrammar());
1041 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
1042 aMarkData
.SetMarkArea(ScRange(0,0,0,2,4,0));
1043 aMarkData
.MarkToMulti(); // TODO : we shouldn't have to do this.
1051 const std::vector
<Check
> aChecks
= {
1058 SCROW nRow
= -1; // Start from the imaginary row before A1.
1061 for (const Check
& rCheck
: aChecks
)
1063 bool bFound
= m_pDoc
->GetNextMarkedCell(nCol
, nRow
, 0, aMarkData
);
1066 std::ostringstream os
;
1067 os
<< ScAddress(rCheck
.mnCol
, rCheck
.mnRow
, 0).GetColRowString() << " was expected, but not found.";
1068 CPPUNIT_FAIL(os
.str());
1071 CPPUNIT_ASSERT_EQUAL(rCheck
.mnRow
, nRow
);
1072 CPPUNIT_ASSERT_EQUAL(rCheck
.mnCol
, nCol
);
1075 // No more marked cells on this sheet.
1076 bool bFound
= m_pDoc
->GetNextMarkedCell(nCol
, nRow
, 0, aMarkData
);
1077 CPPUNIT_ASSERT(!bFound
);
1079 m_pDoc
->DeleteTab(0);
1082 CPPUNIT_TEST_FIXTURE(Test
, testCopyToDocument
)
1084 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (0, u
"src"_ustr
));
1086 // We need a drawing layer in order to create caption objects.
1087 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
1089 m_pDoc
->SetString(0, 0, 0, u
"Header"_ustr
);
1090 m_pDoc
->SetString(0, 1, 0, u
"1"_ustr
);
1091 m_pDoc
->SetString(0, 2, 0, u
"2"_ustr
);
1092 m_pDoc
->SetString(0, 3, 0, u
"3"_ustr
);
1093 m_pDoc
->SetString(0, 4, 0, u
"=4/2"_ustr
);
1097 ScAddress
aAdrA1 (0, 0, 0); // numerical cell content
1098 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aAdrA1
);
1099 pNote
->SetText(aAdrA1
, u
"Hello world in A1"_ustr
);
1101 // Copy statically to another document.
1103 ScDocShellRef xDocSh2
;
1104 getNewDocShell(xDocSh2
);
1105 ScDocument
* pDestDoc
= &xDocSh2
->GetDocument();
1106 pDestDoc
->InsertTab(0, u
"src"_ustr
);
1107 pDestDoc
->InitDrawLayer(xDocSh2
.get()); // for note caption objects
1109 m_pDoc
->CopyStaticToDocument(ScRange(0,1,0,0,3,0), 0, *pDestDoc
); // Copy A2:A4
1110 m_pDoc
->CopyStaticToDocument(ScRange(ScAddress(0,0,0)), 0, *pDestDoc
); // Copy A1
1111 m_pDoc
->CopyStaticToDocument(ScRange(0,4,0,0,7,0), 0, *pDestDoc
); // Copy A5:A8
1113 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,0,0), pDestDoc
->GetString(0,0,0));
1114 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,1,0), pDestDoc
->GetString(0,1,0));
1115 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,2,0), pDestDoc
->GetString(0,2,0));
1116 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,3,0), pDestDoc
->GetString(0,3,0));
1117 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,4,0), pDestDoc
->GetString(0,4,0));
1120 CPPUNIT_ASSERT_MESSAGE("There should be a note in A1 destDocument", pDestDoc
->HasNote(ScAddress(0, 0, 0)));
1121 CPPUNIT_ASSERT_EQUAL_MESSAGE("The notes content should be the same on both documents",
1122 m_pDoc
->GetNote(ScAddress(0, 0, 0))->GetText(), pDestDoc
->GetNote(ScAddress(0, 0, 0))->GetText());
1124 pDestDoc
->DeleteTab(0);
1128 m_pDoc
->DeleteTab(0);
1131 bool Test::checkHorizontalIterator(ScDocument
& rDoc
, const std::vector
<std::vector
<const char*>>& rData
, const HoriIterCheck
* pChecks
, size_t nCheckCount
)
1133 ScAddress
aPos(0,0,0);
1134 insertRangeData(&rDoc
, aPos
, rData
);
1135 ScHorizontalCellIterator
aIter(rDoc
, 0, 0, 0, 1, rData
.size() - 1);
1140 for (ScRefCellValue
* pCell
= aIter
.GetNext(nCol
, nRow
); pCell
; pCell
= aIter
.GetNext(nCol
, nRow
), ++i
)
1142 if (i
>= nCheckCount
)
1144 cerr
<< "hit invalid check " << i
<< " of " << nCheckCount
<< endl
;
1145 CPPUNIT_FAIL("Iterator claims there is more data than there should be.");
1149 if (pChecks
[i
].nCol
!= nCol
)
1151 cerr
<< "Column mismatch " << pChecks
[i
].nCol
<< " vs. " << nCol
<< endl
;
1155 if (pChecks
[i
].nRow
!= nRow
)
1157 cerr
<< "Row mismatch " << pChecks
[i
].nRow
<< " vs. " << nRow
<< endl
;
1161 if (OUString::createFromAscii(pChecks
[i
].pVal
) != pCell
->getString(&rDoc
))
1163 cerr
<< "String mismatch " << pChecks
[i
].pVal
<< " vs. " <<
1164 pCell
->getString(&rDoc
) << endl
;
1172 CPPUNIT_TEST_FIXTURE(Test
, testHorizontalIterator
)
1174 m_pDoc
->InsertTab(0, u
"test"_ustr
);
1177 // Raw data - mixed types
1178 std::vector
<std::vector
<const char*>> aData
= {
1185 static const HoriIterCheck aChecks
[] = {
1196 bool bRes
= checkHorizontalIterator(
1197 *m_pDoc
, aData
, aChecks
, std::size(aChecks
));
1200 CPPUNIT_FAIL("Failed on test mixed.");
1204 // Raw data - 'hole' data
1205 std::vector
<std::vector
<const char*>> aData
= {
1211 static const HoriIterCheck aChecks
[] = {
1219 bool bRes
= checkHorizontalIterator(
1220 *m_pDoc
, aData
, aChecks
, std::size(aChecks
));
1223 CPPUNIT_FAIL("Failed on test hole.");
1228 std::vector
<std::vector
<const char*>> aData
= {
1230 { nullptr, nullptr },
1237 { nullptr, nullptr },
1240 static const HoriIterCheck aChecks
[] = {
1252 bool bRes
= checkHorizontalIterator(
1253 *m_pDoc
, aData
, aChecks
, std::size(aChecks
));
1256 CPPUNIT_FAIL("Failed on test holy.");
1261 std::vector
<std::vector
<const char*>> aData
= {
1262 { nullptr, nullptr },
1263 { nullptr, nullptr },
1264 { nullptr, nullptr },
1267 bool bRes
= checkHorizontalIterator(
1268 *m_pDoc
, aData
, nullptr, 0);
1271 CPPUNIT_FAIL("Failed on test degenerate.");
1276 std::vector
<std::vector
<const char*>> aData
= {
1277 { nullptr, nullptr },
1278 { nullptr, nullptr },
1282 static const HoriIterCheck aChecks
[] = {
1286 bool bRes
= checkHorizontalIterator(
1287 *m_pDoc
, aData
, aChecks
, std::size(aChecks
));
1290 CPPUNIT_FAIL("Failed on test at end.");
1295 std::vector
<std::vector
<const char*>> aData
= {
1296 { nullptr, nullptr },
1297 { nullptr, nullptr },
1300 { nullptr, nullptr },
1303 static const HoriIterCheck aChecks
[] = {
1308 bool bRes
= checkHorizontalIterator(
1309 *m_pDoc
, aData
, aChecks
, std::size(aChecks
));
1312 CPPUNIT_FAIL("Failed on test in middle.");
1315 m_pDoc
->DeleteTab(0);
1318 CPPUNIT_TEST_FIXTURE(Test
, testValueIterator
)
1320 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
1322 // Turn on "precision as shown" option.
1323 ScDocOptions aOpt
= m_pDoc
->GetDocOptions();
1324 aOpt
.SetCalcAsShown(true);
1325 m_pDoc
->SetDocOptions(aOpt
);
1327 ScInterpreterContext
aContext(*m_pDoc
, m_pDoc
->GetFormatTable());
1329 // Purely horizontal data layout with numeric data.
1330 for (SCCOL i
= 1; i
<= 3; ++i
)
1331 m_pDoc
->SetValue(ScAddress(i
,2,0), i
);
1334 const double aChecks
[] = { 1.0, 2.0, 3.0 };
1335 size_t const nCheckLen
= std::size(aChecks
);
1336 ScValueIterator
aIter(aContext
, ScRange(1,2,0,3,2,0));
1338 size_t nCheckPos
= 0;
1341 for (bHas
= aIter
.GetFirst(fVal
, nErr
); bHas
; bHas
= aIter
.GetNext(fVal
, nErr
), ++nCheckPos
)
1343 CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos
< nCheckLen
);
1344 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
], fVal
);
1345 CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(nErr
));
1349 m_pDoc
->DeleteTab(0);
1352 CPPUNIT_TEST_FIXTURE(Test
, testHorizontalAttrIterator
)
1354 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
1356 // Set the background color of B2:C3,D2,E3,C4:D4,B5:D5 to blue
1357 ScPatternAttr
aCellBackColor(m_pDoc
->getCellAttributeHelper());
1358 aCellBackColor
.GetItemSet().Put(SvxBrushItem(COL_BLUE
, ATTR_BACKGROUND
));
1359 m_pDoc
->ApplyPatternAreaTab(1, 1, 2, 2, 0, aCellBackColor
);
1360 m_pDoc
->ApplyPatternAreaTab(3, 1, 3, 1, 0, aCellBackColor
);
1361 m_pDoc
->ApplyPatternAreaTab(4, 2, 4, 2, 0, aCellBackColor
);
1362 m_pDoc
->ApplyPatternAreaTab(2, 3, 3, 3, 0, aCellBackColor
);
1363 m_pDoc
->ApplyPatternAreaTab(1, 4, 4, 4, 0, aCellBackColor
);
1365 // some numeric data
1366 for (SCCOL i
= 1; i
<= 4; ++i
)
1367 for (SCROW j
= 1; j
<= 4; ++j
)
1368 m_pDoc
->SetValue(ScAddress(i
,j
,0), i
*10+j
);
1371 const int aChecks
[][3] = { {1, 3, 1}, {1, 2, 2}, {4, 4, 2}, {2, 3, 3}, {1, 4, 4} };
1372 const size_t nCheckLen
= std::size(aChecks
);
1374 ScHorizontalAttrIterator
aIter(*m_pDoc
, 0, 0, 0, 5, 5);
1377 size_t nCheckPos
= 0;
1378 for (const ScPatternAttr
* pAttr
= aIter
.GetNext(nCol1
, nCol2
, nRow
); pAttr
; pAttr
= aIter
.GetNext(nCol1
, nCol2
, nRow
))
1380 if (pAttr
->isDefault())
1382 CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos
< nCheckLen
);
1383 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
][0], static_cast<int>(nCol1
));
1384 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
][1], static_cast<int>(nCol2
));
1385 CPPUNIT_ASSERT_EQUAL(aChecks
[nCheckPos
][2], static_cast<int>(nRow
));
1390 m_pDoc
->DeleteTab(0);
1393 CPPUNIT_TEST_FIXTURE(Test
, testIteratorsUnallocatedColumnsAttributes
)
1395 m_pDoc
->InsertTab(0, u
"Tab1"_ustr
);
1397 // Set values in first two columns, to ensure allocation of those columns.
1398 m_pDoc
->SetValue(ScAddress(0,1,0), 1);
1399 m_pDoc
->SetValue(ScAddress(1,1,0), 2);
1400 constexpr SCCOL allocatedColsCount
= 2;
1401 assert( allocatedColsCount
>= INITIALCOLCOUNT
);
1402 CPPUNIT_ASSERT_EQUAL(allocatedColsCount
, m_pDoc
->GetAllocatedColumnsCount(0));
1404 // Make entire second row and third row bold.
1405 ScPatternAttr
boldAttr(m_pDoc
->getCellAttributeHelper());
1406 boldAttr
.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD
, ATTR_FONT_WEIGHT
));
1407 m_pDoc
->ApplyPatternAreaTab(0, 1, m_pDoc
->MaxCol(), 2, 0, boldAttr
);
1409 // That shouldn't need allocating more columns, just changing the default attribute.
1410 CPPUNIT_ASSERT_EQUAL(allocatedColsCount
, m_pDoc
->GetAllocatedColumnsCount(0));
1412 const ScPatternAttr
* pattern
= m_pDoc
->GetPattern(m_pDoc
->MaxCol(), 1, 0);
1413 pattern
->fillFontOnly(aFont
);
1414 CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD
, aFont
.GetWeight());
1417 ScDocAttrIterator
docit( *m_pDoc
, 0, allocatedColsCount
- 1, 1, allocatedColsCount
, 2 );
1420 CPPUNIT_ASSERT_EQUAL( pattern
, docit
.GetNext( col1
, row1
, row2
));
1421 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1422 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1423 CPPUNIT_ASSERT_EQUAL( SCROW(2), row2
);
1424 CPPUNIT_ASSERT_EQUAL( pattern
, docit
.GetNext( col1
, row1
, row2
));
1425 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col1
);
1426 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1427 CPPUNIT_ASSERT_EQUAL( SCROW(2), row2
);
1428 CPPUNIT_ASSERT( docit
.GetNext( col1
, row1
, row2
) == nullptr );
1430 ScAttrRectIterator
rectit( *m_pDoc
, 0, allocatedColsCount
- 1, 1, allocatedColsCount
, 2 );
1431 CPPUNIT_ASSERT_EQUAL( pattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1432 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1433 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col2
);
1434 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1435 CPPUNIT_ASSERT_EQUAL( SCROW(2), row2
);
1436 CPPUNIT_ASSERT( rectit
.GetNext( col1
, col2
, row1
, row2
) == nullptr );
1438 ScHorizontalAttrIterator
horit( *m_pDoc
, 0, allocatedColsCount
- 1, 1, allocatedColsCount
, 2 );
1439 CPPUNIT_ASSERT_EQUAL( pattern
, horit
.GetNext( col1
, col2
, row1
));
1440 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1441 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col2
);
1442 CPPUNIT_ASSERT_EQUAL( SCROW(1), row1
);
1443 CPPUNIT_ASSERT_EQUAL( pattern
, horit
.GetNext( col1
, col2
, row1
));
1444 CPPUNIT_ASSERT_EQUAL( SCCOL(allocatedColsCount
- 1), col1
);
1445 CPPUNIT_ASSERT_EQUAL( allocatedColsCount
, col2
);
1446 CPPUNIT_ASSERT_EQUAL( SCROW(2), row1
);
1447 CPPUNIT_ASSERT( horit
.GetNext( col1
, col2
, row1
) == nullptr );
1449 m_pDoc
->DeleteTab(0);
1452 CPPUNIT_TEST_FIXTURE(Test
, testIteratorsDefPattern
)
1454 m_pDoc
->InsertTab(0, u
"Tab1"_ustr
);
1456 // The default pattern is the default style, which can be edited by the user.
1457 // As such iterators should not ignore it by default, because it might contain
1458 // some attributes set.
1460 // Set cells as bold, default allocated, bold, default unallocated.
1461 SCCOL firstCol
= 100;
1462 SCCOL lastCol
= 103;
1463 ScPatternAttr
boldAttr(m_pDoc
->getCellAttributeHelper());
1464 boldAttr
.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD
, ATTR_FONT_WEIGHT
));
1465 m_pDoc
->ApplyPattern(100, 0, 0, boldAttr
);
1466 m_pDoc
->ApplyPattern(102, 0, 0, boldAttr
);
1468 CPPUNIT_ASSERT_EQUAL(SCCOL(102 + 1), m_pDoc
->GetAllocatedColumnsCount(0));
1469 const ScPatternAttr
* pattern
= m_pDoc
->GetPattern(100, 0, 0);
1470 const ScPatternAttr
* defPattern(&m_pDoc
->getCellAttributeHelper().getDefaultCellAttribute()); //GetDefPattern();
1471 CPPUNIT_ASSERT(!ScPatternAttr::areSame(pattern
, defPattern
));
1472 CPPUNIT_ASSERT_EQUAL(pattern
, m_pDoc
->GetPattern(102, 0, 0));
1473 CPPUNIT_ASSERT_EQUAL(defPattern
, m_pDoc
->GetPattern(101, 0, 0));
1474 CPPUNIT_ASSERT_EQUAL(defPattern
, m_pDoc
->GetPattern(103, 0, 0));
1477 ScDocAttrIterator
docit( *m_pDoc
, 0, firstCol
, 0, lastCol
, 0 );
1480 CPPUNIT_ASSERT_EQUAL(pattern
, docit
.GetNext( col1
, row1
, row2
));
1481 CPPUNIT_ASSERT_EQUAL(defPattern
, docit
.GetNext( col1
, row1
, row2
));
1482 CPPUNIT_ASSERT_EQUAL(pattern
, docit
.GetNext( col1
, row1
, row2
));
1483 CPPUNIT_ASSERT_EQUAL(defPattern
, docit
.GetNext( col1
, row1
, row2
));
1484 CPPUNIT_ASSERT(docit
.GetNext( col1
, row1
, row2
) == nullptr );
1486 ScAttrRectIterator
rectit( *m_pDoc
, 0, firstCol
, 0, lastCol
, 0 );
1487 CPPUNIT_ASSERT_EQUAL(pattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1488 CPPUNIT_ASSERT_EQUAL(defPattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1489 CPPUNIT_ASSERT_EQUAL(pattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1490 CPPUNIT_ASSERT_EQUAL(defPattern
, rectit
.GetNext( col1
, col2
, row1
, row2
));
1491 CPPUNIT_ASSERT(rectit
.GetNext( col1
, col2
, row1
, row2
) == nullptr );
1493 ScHorizontalAttrIterator
horit( *m_pDoc
, 0, firstCol
, 0, lastCol
, 0 );
1494 CPPUNIT_ASSERT_EQUAL(pattern
, horit
.GetNext( col1
, col2
, row1
));
1495 CPPUNIT_ASSERT_EQUAL(defPattern
, horit
.GetNext( col1
, col2
, row1
));
1496 CPPUNIT_ASSERT_EQUAL(pattern
, horit
.GetNext( col1
, col2
, row1
));
1497 CPPUNIT_ASSERT_EQUAL(defPattern
, horit
.GetNext( col1
, col2
, row1
));
1498 CPPUNIT_ASSERT(horit
.GetNext( col1
, col2
, row1
) == nullptr );
1500 m_pDoc
->DeleteTab(0);
1503 CPPUNIT_TEST_FIXTURE(Test
, testLastChangedColFlagsWidth
)
1505 m_pDoc
->InsertTab(0, u
"Tab1"_ustr
);
1507 constexpr SCCOL firstChangedCol
= 100;
1508 assert( firstChangedCol
> m_pDoc
->GetAllocatedColumnsCount(0));
1509 CPPUNIT_ASSERT_EQUAL(INITIALCOLCOUNT
, m_pDoc
->GetAllocatedColumnsCount(0));
1510 for( SCCOL col
= firstChangedCol
; col
<= m_pDoc
->MaxCol(); ++col
)
1511 m_pDoc
->SetColWidth( col
, 0, 10 );
1513 // That shouldn't need allocating more columns, just changing column flags.
1514 CPPUNIT_ASSERT_EQUAL(INITIALCOLCOUNT
, m_pDoc
->GetAllocatedColumnsCount(0));
1515 // But the flags are changed.
1516 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxCol(), m_pDoc
->GetLastChangedColFlagsWidth(0));
1518 m_pDoc
->DeleteTab(0);
1523 bool broadcasterShifted(const ScDocument
& rDoc
, const ScAddress
& rFrom
, const ScAddress
& rTo
)
1525 const SvtBroadcaster
* pBC
= rDoc
.GetBroadcaster(rFrom
);
1528 cerr
<< "Broadcaster shouldn't be here." << endl
;
1532 pBC
= rDoc
.GetBroadcaster(rTo
);
1535 cerr
<< "Broadcaster should be here." << endl
;
1541 formula::FormulaToken
* getSingleRefToken(ScDocument
& rDoc
, const ScAddress
& rPos
)
1543 ScFormulaCell
* pFC
= rDoc
.GetFormulaCell(rPos
);
1546 cerr
<< "Formula cell expected, but not found." << endl
;
1550 ScTokenArray
* pTokens
= pFC
->GetCode();
1553 cerr
<< "Token array is not present." << endl
;
1557 formula::FormulaToken
* pToken
= pTokens
->FirstToken();
1558 if (!pToken
|| pToken
->GetType() != formula::svSingleRef
)
1560 cerr
<< "Not a single reference token." << endl
;
1567 bool checkRelativeRefToken(ScDocument
& rDoc
, const ScAddress
& rPos
, SCCOL nRelCol
, SCROW nRelRow
)
1569 formula::FormulaToken
* pToken
= getSingleRefToken(rDoc
, rPos
);
1573 ScSingleRefData
& rRef
= *pToken
->GetSingleRef();
1574 if (!rRef
.IsColRel() || rRef
.Col() != nRelCol
)
1576 cerr
<< "Unexpected relative column address." << endl
;
1580 if (!rRef
.IsRowRel() || rRef
.Row() != nRelRow
)
1582 cerr
<< "Unexpected relative row address." << endl
;
1589 bool checkDeletedRefToken(ScDocument
& rDoc
, const ScAddress
& rPos
)
1591 formula::FormulaToken
* pToken
= getSingleRefToken(rDoc
, rPos
);
1595 ScSingleRefData
& rRef
= *pToken
->GetSingleRef();
1596 if (!rRef
.IsDeleted())
1598 cerr
<< "Deleted reference is expected, but it's still a valid reference." << endl
;
1607 CPPUNIT_TEST_FIXTURE(Test
, testCellBroadcaster
)
1610 * More direct test for cell broadcaster management, used to track formula
1613 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (0, u
"foo"_ustr
));
1615 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calculation.
1616 m_pDoc
->SetString(ScAddress(1,0,0), u
"=A1"_ustr
); // B1 depends on A1.
1617 double val
= m_pDoc
->GetValue(ScAddress(1,0,0)); // A1 is empty, so the result should be 0.
1618 CPPUNIT_ASSERT_EQUAL(0.0, val
);
1620 const SvtBroadcaster
* pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1621 CPPUNIT_ASSERT_MESSAGE("Cell A1 should have a broadcaster.", pBC
);
1623 // Change the value of A1 and make sure that B1 follows.
1624 m_pDoc
->SetValue(ScAddress(0,0,0), 1.23);
1625 val
= m_pDoc
->GetValue(ScAddress(1,0,0));
1626 CPPUNIT_ASSERT_EQUAL(1.23, val
);
1628 // Move column A down 5 cells. Make sure B1 now references A6, not A1.
1629 m_pDoc
->InsertRow(0, 0, 0, 0, 0, 5);
1630 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1631 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 5));
1633 // Make sure the broadcaster has also moved.
1634 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1635 broadcasterShifted(*m_pDoc
, ScAddress(0,0,0), ScAddress(0,5,0)));
1637 // Set new value to A6 and make sure B1 gets updated.
1638 m_pDoc
->SetValue(ScAddress(0,5,0), 45.6);
1639 val
= m_pDoc
->GetValue(ScAddress(1,0,0));
1640 CPPUNIT_ASSERT_EQUAL(45.6, val
);
1642 // Move column A up 3 cells, and make sure B1 now references A3, not A6.
1643 m_pDoc
->DeleteRow(0, 0, 0, 0, 0, 3);
1644 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1645 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 2));
1647 // The broadcaster should also have been relocated from A6 to A3.
1648 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1649 broadcasterShifted(*m_pDoc
, ScAddress(0,5,0), ScAddress(0,2,0)));
1651 // Insert cells over A1:A10 and shift cells to right.
1652 m_pDoc
->InsertCol(ScRange(0, 0, 0, 0, 10, 0));
1653 CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1654 checkRelativeRefToken(*m_pDoc
, ScAddress(2,0,0), -1, 2));
1655 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1656 broadcasterShifted(*m_pDoc
, ScAddress(0,2,0), ScAddress(1,2,0)));
1658 // Delete formula in C2, which should remove the broadcaster in B3.
1659 pBC
= m_pDoc
->GetBroadcaster(ScAddress(1,2,0));
1660 CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should still exist.", pBC
);
1661 clearRange(m_pDoc
, ScRange(ScAddress(2,0,0)));
1662 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE
, m_pDoc
->GetCellType(ScAddress(2,0,0))); // C2 should be empty.
1663 pBC
= m_pDoc
->GetBroadcaster(ScAddress(1,2,0));
1664 CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should have been removed.", !pBC
);
1666 // Clear everything and start over.
1667 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1669 m_pDoc
->SetString(ScAddress(1,0,0), u
"=A1"_ustr
); // B1 depends on A1.
1670 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1671 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", pBC
);
1673 // While column A is still empty, move column A down 2 cells. This should
1674 // move the broadcaster from A1 to A3.
1675 m_pDoc
->InsertRow(0, 0, 0, 0, 0, 2);
1676 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1677 broadcasterShifted(*m_pDoc
, ScAddress(0,0,0), ScAddress(0,2,0)));
1679 // Move it back while column A is still empty.
1680 m_pDoc
->DeleteRow(0, 0, 0, 0, 0, 2);
1681 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1682 broadcasterShifted(*m_pDoc
, ScAddress(0,2,0), ScAddress(0,0,0)));
1684 // Clear everything again
1685 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1687 // B1:B3 depends on A1:A3
1688 m_pDoc
->SetString(ScAddress(1,0,0), u
"=A1"_ustr
);
1689 m_pDoc
->SetString(ScAddress(1,1,0), u
"=A2"_ustr
);
1690 m_pDoc
->SetString(ScAddress(1,2,0), u
"=A3"_ustr
);
1691 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1692 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 0));
1693 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1694 checkRelativeRefToken(*m_pDoc
, ScAddress(1,1,0), -1, 0));
1695 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B3 failed.",
1696 checkRelativeRefToken(*m_pDoc
, ScAddress(1,2,0), -1, 0));
1697 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc
->GetBroadcaster(ScAddress(0,0,0)));
1698 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A2.", m_pDoc
->GetBroadcaster(ScAddress(0,1,0)));
1699 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A3.", m_pDoc
->GetBroadcaster(ScAddress(0,2,0)));
1701 // Insert Rows at row 2, down 5 rows.
1702 m_pDoc
->InsertRow(0, 0, 0, 0, 1, 5);
1703 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc
->GetBroadcaster(ScAddress(0,0,0)));
1704 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1705 checkRelativeRefToken(*m_pDoc
, ScAddress(1,0,0), -1, 0));
1707 // Broadcasters in A2 and A3 should shift down by 5 rows.
1708 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1709 broadcasterShifted(*m_pDoc
, ScAddress(0,1,0), ScAddress(0,6,0)));
1710 CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1711 broadcasterShifted(*m_pDoc
, ScAddress(0,2,0), ScAddress(0,7,0)));
1713 // B2 and B3 should reference shifted cells.
1714 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1715 checkRelativeRefToken(*m_pDoc
, ScAddress(1,1,0), -1, 5));
1716 CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1717 checkRelativeRefToken(*m_pDoc
, ScAddress(1,2,0), -1, 5));
1719 // Delete cells with broadcasters.
1720 m_pDoc
->DeleteRow(0, 0, 0, 0, 4, 6);
1721 CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A7.", !m_pDoc
->GetBroadcaster(ScAddress(0,6,0)));
1722 CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A8.", !m_pDoc
->GetBroadcaster(ScAddress(0,7,0)));
1724 // References in B2 and B3 should be invalid.
1725 CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B2 failed.",
1726 checkDeletedRefToken(*m_pDoc
, ScAddress(1,1,0)));
1727 CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B3 failed.",
1728 checkDeletedRefToken(*m_pDoc
, ScAddress(1,2,0)));
1730 // Clear everything again
1731 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1734 // Switch to R1C1 to make it easier to input relative references in multiple cells.
1735 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
1737 // Have B1:B20 reference A1:A20.
1739 for (SCROW i
= 0; i
< 20; ++i
)
1741 m_pDoc
->SetValue(ScAddress(0,i
,0), val
++);
1742 m_pDoc
->SetString(ScAddress(1,i
,0), u
"=RC[-1]"_ustr
);
1746 // Ensure that the formula cells show correct values, and the referenced
1747 // cells have broadcasters.
1749 for (SCROW i
= 0; i
< 20; ++i
, ++val
)
1751 CPPUNIT_ASSERT_EQUAL(val
, m_pDoc
->GetValue(ScAddress(1,i
,0)));
1752 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,i
,0));
1753 CPPUNIT_ASSERT_MESSAGE("Broadcast should exist here.", pBC
);
1756 // Delete formula cells in B2:B19.
1757 clearRange(m_pDoc
, ScRange(1,1,0,1,18,0));
1758 // Ensure that A2:A19 no longer have broadcasters, but A1 and A20 still do.
1759 CPPUNIT_ASSERT_MESSAGE("A1 should still have broadcaster.", m_pDoc
->GetBroadcaster(ScAddress(0,0,0)));
1760 CPPUNIT_ASSERT_MESSAGE("A20 should still have broadcaster.", m_pDoc
->GetBroadcaster(ScAddress(0,19,0)));
1761 for (SCROW i
= 1; i
<= 18; ++i
)
1763 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,i
,0));
1764 CPPUNIT_ASSERT_MESSAGE("Broadcaster should have been deleted.", !pBC
);
1767 // Clear everything again
1768 clearRange(m_pDoc
, ScRange(0,0,0,10,100,0));
1770 m_pDoc
->SetValue(ScAddress(0,0,0), 2.0);
1771 m_pDoc
->SetString(ScAddress(1,0,0), u
"=A1"_ustr
);
1772 m_pDoc
->SetString(ScAddress(2,0,0), u
"=B1"_ustr
);
1773 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(0,0,0));
1774 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(1,0,0));
1775 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(2,0,0));
1777 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1778 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1779 pBC
= m_pDoc
->GetBroadcaster(ScAddress(1,0,0));
1780 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1782 // Change the value of A1 and make sure everyone follows suit.
1783 m_pDoc
->SetValue(ScAddress(0,0,0), 3.5);
1784 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc
->GetValue(0,0,0));
1785 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc
->GetValue(1,0,0));
1786 CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc
->GetValue(2,0,0));
1788 // Insert a column at column B.
1789 m_pDoc
->InsertCol(ScRange(1,0,0,1,m_pDoc
->MaxRow(),0));
1790 pBC
= m_pDoc
->GetBroadcaster(ScAddress(0,0,0));
1791 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1792 pBC
= m_pDoc
->GetBroadcaster(ScAddress(2,0,0));
1793 CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC
);
1795 // Change the value of A1 again.
1796 m_pDoc
->SetValue(ScAddress(0,0,0), 5.5);
1797 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc
->GetValue(0,0,0));
1798 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc
->GetValue(2,0,0));
1799 CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc
->GetValue(3,0,0));
1801 m_pDoc
->DeleteTab(0);
1804 CPPUNIT_TEST_FIXTURE(Test
, testFuncParam
)
1807 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
1808 m_pDoc
->InsertTab (0, u
"foo"_ustr
));
1810 // First, the normal case, with no missing parameters.
1811 m_pDoc
->SetString(0, 0, 0, u
"=AVERAGE(1;2;3)"_ustr
);
1812 m_pDoc
->CalcFormulaTree(false, false);
1813 double val
= m_pDoc
->GetValue(0, 0, 0);
1814 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 2.0, val
);
1816 // Now function with missing parameters. Missing values should be treated
1818 m_pDoc
->SetString(0, 0, 0, u
"=AVERAGE(1;;;)"_ustr
);
1819 m_pDoc
->CalcFormulaTree(false, false);
1820 val
= m_pDoc
->GetValue(0, 0, 0);
1821 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 0.25, val
);
1823 // Conversion of string to numeric argument.
1824 m_pDoc
->SetString(0, 0, 0, u
"=\"\"+3"_ustr
); // empty string
1825 m_pDoc
->SetString(0, 1, 0, u
"=\" \"+3"_ustr
); // only blank
1826 m_pDoc
->SetString(0, 2, 0, u
"=\" 4 \"+3"_ustr
); // number in blanks
1827 m_pDoc
->SetString(0, 3, 0, u
"=\" x \"+3"_ustr
); // non-numeric
1828 m_pDoc
->SetString(0, 4, 0, u
"=\"4.4\"+3"_ustr
); // locale dependent
1831 ScCalcConfig aConfig
;
1833 // With "Convert also locale dependent" and "Empty string as zero"=True option.
1834 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::LOCALE
;
1835 aConfig
.mbEmptyStringAsZero
= true;
1836 m_pDoc
->SetCalcConfig(aConfig
);
1838 val
= m_pDoc
->GetValue(0, 0, 0);
1839 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1840 val
= m_pDoc
->GetValue(0, 1, 0);
1841 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1842 val
= m_pDoc
->GetValue(0, 2, 0);
1843 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1844 aVal
= m_pDoc
->GetString( 0, 3, 0);
1845 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1846 val
= m_pDoc
->GetValue(0, 4, 0);
1847 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.4, val
);
1849 // With "Convert also locale dependent" and "Empty string as zero"=False option.
1850 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::LOCALE
;
1851 aConfig
.mbEmptyStringAsZero
= false;
1852 m_pDoc
->SetCalcConfig(aConfig
);
1854 aVal
= m_pDoc
->GetString( 0, 0, 0);
1855 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1856 aVal
= m_pDoc
->GetString( 0, 1, 0);
1857 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1858 val
= m_pDoc
->GetValue(0, 2, 0);
1859 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1860 aVal
= m_pDoc
->GetString( 0, 3, 0);
1861 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1862 val
= m_pDoc
->GetValue(0, 4, 0);
1863 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.4, val
);
1865 // With "Convert only unambiguous" and "Empty string as zero"=True option.
1866 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::UNAMBIGUOUS
;
1867 aConfig
.mbEmptyStringAsZero
= true;
1868 m_pDoc
->SetCalcConfig(aConfig
);
1870 val
= m_pDoc
->GetValue(0, 0, 0);
1871 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1872 val
= m_pDoc
->GetValue(0, 1, 0);
1873 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1874 val
= m_pDoc
->GetValue(0, 2, 0);
1875 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1876 aVal
= m_pDoc
->GetString( 0, 3, 0);
1877 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1878 aVal
= m_pDoc
->GetString( 0, 4, 0);
1879 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1881 // With "Convert only unambiguous" and "Empty string as zero"=False option.
1882 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::UNAMBIGUOUS
;
1883 aConfig
.mbEmptyStringAsZero
= false;
1884 m_pDoc
->SetCalcConfig(aConfig
);
1886 aVal
= m_pDoc
->GetString( 0, 0, 0);
1887 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1888 aVal
= m_pDoc
->GetString( 0, 1, 0);
1889 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1890 m_pDoc
->GetValue(0, 2, 0);
1891 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 7.0, val
);
1892 aVal
= m_pDoc
->GetString( 0, 3, 0);
1893 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1894 aVal
= m_pDoc
->GetString( 0, 4, 0);
1895 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1897 // With "Treat as zero" ("Empty string as zero" is ignored).
1898 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::ZERO
;
1899 aConfig
.mbEmptyStringAsZero
= true;
1900 m_pDoc
->SetCalcConfig(aConfig
);
1902 val
= m_pDoc
->GetValue(0, 0, 0);
1903 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1904 val
= m_pDoc
->GetValue(0, 1, 0);
1905 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1906 val
= m_pDoc
->GetValue(0, 2, 0);
1907 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1908 val
= m_pDoc
->GetValue(0, 3, 0);
1909 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1910 val
= m_pDoc
->GetValue(0, 4, 0);
1911 ASSERT_DOUBLES_EQUAL_MESSAGE("incorrect result", 3.0, val
);
1913 // With "Generate #VALUE! error" ("Empty string as zero" is ignored).
1914 aConfig
.meStringConversion
= ScCalcConfig::StringConversion::ILLEGAL
;
1915 aConfig
.mbEmptyStringAsZero
= false;
1916 m_pDoc
->SetCalcConfig(aConfig
);
1918 aVal
= m_pDoc
->GetString( 0, 0, 0);
1919 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1920 aVal
= m_pDoc
->GetString( 0, 1, 0);
1921 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1922 aVal
= m_pDoc
->GetString( 0, 2, 0);
1923 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1924 aVal
= m_pDoc
->GetString( 0, 3, 0);
1925 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1926 aVal
= m_pDoc
->GetString( 0, 4, 0);
1927 CPPUNIT_ASSERT_EQUAL_MESSAGE("incorrect result", u
"#VALUE!"_ustr
, aVal
);
1929 m_pDoc
->DeleteTab(0);
1932 CPPUNIT_TEST_FIXTURE(Test
, testNamedRange
)
1934 static const RangeNameDef aNames
[] = {
1935 { "Divisor", "$Sheet1.$A$1:$A$1048576", 1 },
1936 { "MyRange1", "$Sheet1.$A$1:$A$100", 2 },
1937 { "MyRange2", "$Sheet1.$B$1:$B$100", 3 },
1938 { "MyRange3", "$Sheet1.$C$1:$C$100", 4 }
1941 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (0, u
"Sheet1"_ustr
));
1943 m_pDoc
->SetValue (0, 0, 0, 101);
1945 std::unique_ptr
<ScRangeName
> pNames(new ScRangeName
);
1946 bool bSuccess
= insertRangeNames(m_pDoc
, pNames
.get(), aNames
, aNames
+ std::size(aNames
));
1947 CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess
);
1948 m_pDoc
->SetRangeName(std::move(pNames
));
1950 ScRangeName
* pNewRanges
= m_pDoc
->GetRangeName();
1951 CPPUNIT_ASSERT(pNewRanges
);
1953 // Make sure the index lookup does the right thing.
1954 for (const auto& rName
: aNames
)
1956 const ScRangeData
* p
= pNewRanges
->findByIndex(rName
.mnIndex
);
1957 CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed.", p
);
1958 OUString aName
= p
->GetName();
1959 CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved.", aName
.equalsAscii(rName
.mpName
));
1962 // Test usage in formula expression.
1963 m_pDoc
->SetString (1, 0, 0, u
"=A1/Divisor"_ustr
);
1966 double result
= m_pDoc
->GetValue (1, 0, 0);
1967 ASSERT_DOUBLES_EQUAL_MESSAGE ("calculation failed", 1.0, result
);
1969 // Test copy-ability of range names.
1970 std::unique_ptr
<ScRangeName
> pCopiedRanges(new ScRangeName(*pNewRanges
));
1971 m_pDoc
->SetRangeName(std::move(pCopiedRanges
));
1972 // Make sure the index lookup still works.
1973 for (const auto& rName
: aNames
)
1975 const ScRangeData
* p
= m_pDoc
->GetRangeName()->findByIndex(rName
.mnIndex
);
1976 CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed with the copied instance.", p
);
1977 OUString aName
= p
->GetName();
1978 CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved with the copied instance.", aName
.equalsAscii(rName
.mpName
));
1981 // Test using another-sheet-local name, scope Sheet1.
1982 ScRangeData
* pLocal1
= new ScRangeData( *m_pDoc
, u
"local1"_ustr
, ScAddress(0,0,0));
1983 ScRangeData
* pLocal2
= new ScRangeData( *m_pDoc
, u
"local2"_ustr
, u
"$Sheet1.$A$1"_ustr
);
1984 ScRangeData
* pLocal3
= new ScRangeData( *m_pDoc
, u
"local3"_ustr
, u
"Sheet1.$A$1"_ustr
);
1985 ScRangeData
* pLocal4
= new ScRangeData( *m_pDoc
, u
"local4"_ustr
, u
"$A$1"_ustr
); // implicit relative sheet reference
1986 std::unique_ptr
<ScRangeName
> pLocalRangeName1(new ScRangeName
);
1987 pLocalRangeName1
->insert(pLocal1
);
1988 pLocalRangeName1
->insert(pLocal2
);
1989 pLocalRangeName1
->insert(pLocal3
);
1990 pLocalRangeName1
->insert(pLocal4
);
1991 m_pDoc
->SetRangeName(0, std::move(pLocalRangeName1
));
1993 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab (1, u
"Sheet2"_ustr
));
1995 // Use other-sheet-local name of Sheet1 on Sheet2.
1996 ScAddress
aPos(1,0,1);
1997 OUString
aFormula(u
"=Sheet1.local1+Sheet1.local2+Sheet1.local3+Sheet1.local4"_ustr
);
1998 m_pDoc
->SetString(aPos
, aFormula
);
1999 OUString aString
= m_pDoc
->GetFormula(1,0,1);
2000 CPPUNIT_ASSERT_EQUAL_MESSAGE("formula string should be equal", aFormula
, aString
);
2001 double fValue
= m_pDoc
->GetValue(aPos
);
2002 ASSERT_DOUBLES_EQUAL_MESSAGE("value should be 4 times Sheet1.A1", 404.0, fValue
);
2004 m_pDoc
->DeleteTab(1);
2005 m_pDoc
->SetRangeName(0,nullptr); // Delete the names.
2006 m_pDoc
->SetRangeName(nullptr); // Delete the names.
2007 m_pDoc
->DeleteTab(0);
2010 CPPUNIT_TEST_FIXTURE(Test
, testInsertNameList
)
2012 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
2014 static const RangeNameDef aNames
[] = {
2015 { "MyRange1", "$Test.$A$1:$A$100", 1 },
2016 { "MyRange2", "$Test.$B$1:$B$100", 2 },
2017 { "MyRange3", "$Test.$C$1:$C$100", 3 }
2020 std::unique_ptr
<ScRangeName
> pNames(new ScRangeName
);
2021 bool bSuccess
= insertRangeNames(m_pDoc
, pNames
.get(), aNames
, aNames
+ std::size(aNames
));
2022 CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess
);
2023 m_pDoc
->SetRangeName(std::move(pNames
));
2025 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
2026 ScAddress
aPos(1,1,0);
2027 rDocFunc
.InsertNameList(aPos
, true);
2029 for (auto const& rName
: aNames
)
2031 OUString aName
= m_pDoc
->GetString(aPos
);
2032 CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(rName
.mpName
), aName
);
2033 ScAddress aExprPos
= aPos
;
2035 OUString aExpr
= m_pDoc
->GetString(aExprPos
);
2036 OUString aExpected
= "=" + OUString::createFromAscii(rName
.mpExpr
);
2037 CPPUNIT_ASSERT_EQUAL(aExpected
, aExpr
);
2041 m_pDoc
->DeleteTab(0);
2044 CPPUNIT_TEST_FIXTURE(Test
, testCSV
)
2046 const int English
= 0, European
= 1;
2048 const char *pStr
; int eSep
; bool bResult
; double nValue
;
2050 { "foo", English
, false, 0.0 },
2051 { "1.0", English
, true, 1.0 },
2052 { "1,0", English
, false, 0.0 },
2053 { "1.0", European
, false, 0.0 },
2054 { "1.000", European
, true, 1000.0 },
2055 { "1,000", European
, true, 1.0 },
2056 { "1.000", English
, true, 1.0 },
2057 { "1,000", English
, true, 1000.0 },
2058 { " 1.0", English
, true, 1.0 },
2059 { " 1.0 ", English
, true, 1.0 },
2060 { "1.0 ", European
, false, 0.0 },
2061 { "1.000", European
, true, 1000.0 },
2062 { "1137.999", English
, true, 1137.999 },
2063 { "1.000.00", European
, false, 0.0 },
2064 { "+,123", English
, false, 0.0 },
2065 { "-,123", English
, false, 0.0 }
2067 for (const auto& rTest
: aTests
) {
2068 OUString
aStr(rTest
.pStr
, strlen (rTest
.pStr
), RTL_TEXTENCODING_UTF8
);
2069 double nValue
= 0.0;
2070 bool bResult
= ScStringUtil::parseSimpleNumber
2071 (aStr
, rTest
.eSep
== English
? '.' : ',',
2072 rTest
.eSep
== English
? ',' : '.',
2075 CPPUNIT_ASSERT_EQUAL_MESSAGE ("CSV numeric detection failure", rTest
.bResult
, bResult
);
2076 CPPUNIT_ASSERT_EQUAL_MESSAGE ("CSV numeric value failure", rTest
.nValue
, nValue
);
2080 template<typename Evaluator
>
2081 static void checkMatrixElements(const ScMatrix
& rMat
)
2084 rMat
.GetDimensions(nC
, nR
);
2086 for (SCSIZE i
= 0; i
< nC
; ++i
)
2088 for (SCSIZE j
= 0; j
< nR
; ++j
)
2090 aEval(i
, j
, rMat
.Get(i
, j
));
2097 struct AllZeroMatrix
2099 void operator() (SCSIZE
/*nCol*/, SCSIZE
/*nRow*/, const ScMatrixValue
& rVal
) const
2101 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of numeric type", int(ScMatValType::Value
), static_cast<int>(rVal
.nType
));
2102 ASSERT_DOUBLES_EQUAL_MESSAGE("element value must be zero", 0.0, rVal
.fVal
);
2106 struct PartiallyFilledZeroMatrix
2108 void operator() (SCSIZE nCol
, SCSIZE nRow
, const ScMatrixValue
& rVal
) const
2110 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of numeric type", int(ScMatValType::Value
), static_cast<int>(rVal
.nType
));
2111 if (1 <= nCol
&& nCol
<= 2 && 2 <= nRow
&& nRow
<= 8)
2113 ASSERT_DOUBLES_EQUAL_MESSAGE("element value must be 3.0", 3.0, rVal
.fVal
);
2117 ASSERT_DOUBLES_EQUAL_MESSAGE("element value must be zero", 0.0, rVal
.fVal
);
2122 struct AllEmptyMatrix
2124 void operator() (SCSIZE
/*nCol*/, SCSIZE
/*nRow*/, const ScMatrixValue
& rVal
) const
2126 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of empty type", int(ScMatValType::Empty
), static_cast<int>(rVal
.nType
));
2127 ASSERT_DOUBLES_EQUAL_MESSAGE("value of \"empty\" element is expected to be zero", 0.0, rVal
.fVal
);
2131 struct PartiallyFilledEmptyMatrix
2133 void operator() (SCSIZE nCol
, SCSIZE nRow
, const ScMatrixValue
& rVal
) const
2135 if (nCol
== 1 && nRow
== 1)
2137 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of boolean type", int(ScMatValType::Boolean
), static_cast<int>(rVal
.nType
));
2138 ASSERT_DOUBLES_EQUAL_MESSAGE("element value is not what is expected", 1.0, rVal
.fVal
);
2140 else if (nCol
== 4 && nRow
== 5)
2142 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of value type", int(ScMatValType::Value
), static_cast<int>(rVal
.nType
));
2143 ASSERT_DOUBLES_EQUAL_MESSAGE("element value is not what is expected", -12.5, rVal
.fVal
);
2145 else if (nCol
== 8 && nRow
== 2)
2147 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of value type", int(ScMatValType::String
), static_cast<int>(rVal
.nType
));
2148 CPPUNIT_ASSERT_EQUAL_MESSAGE("element value is not what is expected", u
"Test"_ustr
, rVal
.aStr
.getString());
2150 else if (nCol
== 8 && nRow
== 11)
2152 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of empty path type", int(ScMatValType::EmptyPath
), static_cast<int>(rVal
.nType
));
2153 ASSERT_DOUBLES_EQUAL_MESSAGE("value of \"empty\" element is expected to be zero", 0.0, rVal
.fVal
);
2157 CPPUNIT_ASSERT_EQUAL_MESSAGE("element is not of empty type", int(ScMatValType::Empty
), static_cast<int>(rVal
.nType
));
2158 ASSERT_DOUBLES_EQUAL_MESSAGE("value of \"empty\" element is expected to be zero", 0.0, rVal
.fVal
);
2165 CPPUNIT_TEST_FIXTURE(Test
, testMatrix
)
2167 svl::SharedStringPool
& rPool
= m_pDoc
->GetSharedStringPool();
2168 ScMatrixRef pMat
, pMat2
;
2170 // First, test the zero matrix type.
2171 pMat
= new ScMatrix(0, 0, 0.0);
2173 pMat
->GetDimensions(nC
, nR
);
2174 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix is not empty", SCSIZE(0), nC
);
2175 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix is not empty", SCSIZE(0), nR
);
2176 pMat
->Resize(4, 10, 0.0);
2177 pMat
->GetDimensions(nC
, nR
);
2178 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(4), nC
);
2179 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(10), nR
);
2180 CPPUNIT_ASSERT_MESSAGE("both 'and' and 'or' should evaluate to false",
2182 CPPUNIT_ASSERT_MESSAGE("both 'and' and 'or' should evaluate to false",
2185 // Resizing into a larger matrix should fill the void space with zeros.
2186 checkMatrixElements
<AllZeroMatrix
>(*pMat
);
2188 pMat
->FillDouble(3.0, 1, 2, 2, 8);
2189 checkMatrixElements
<PartiallyFilledZeroMatrix
>(*pMat
);
2190 CPPUNIT_ASSERT_MESSAGE("matrix is expected to be numeric", pMat
->IsNumeric());
2191 CPPUNIT_ASSERT_MESSAGE("partially non-zero matrix should evaluate false on 'and' and true on 'or",
2193 CPPUNIT_ASSERT_MESSAGE("partially non-zero matrix should evaluate false on 'and' and true on 'or",
2195 pMat
->FillDouble(5.0, 0, 0, nC
-1, nR
-1);
2196 CPPUNIT_ASSERT_MESSAGE("fully non-zero matrix should evaluate true both on 'and' and 'or",
2198 CPPUNIT_ASSERT_MESSAGE("fully non-zero matrix should evaluate true both on 'and' and 'or",
2201 // Test the AND and OR evaluations.
2202 pMat
= new ScMatrix(2, 2, 0.0);
2204 // Only some of the elements are non-zero.
2205 pMat
->PutBoolean(true, 0, 0);
2206 pMat
->PutDouble(1.0, 1, 1);
2207 CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat
->Or());
2208 CPPUNIT_ASSERT_MESSAGE("incorrect AND result", !pMat
->And());
2210 // All of the elements are non-zero.
2211 pMat
->PutBoolean(true, 0, 1);
2212 pMat
->PutDouble(2.3, 1, 0);
2213 CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat
->Or());
2214 CPPUNIT_ASSERT_MESSAGE("incorrect AND result", pMat
->And());
2216 // Now test the empty matrix type.
2217 pMat
= new ScMatrix(10, 20);
2218 pMat
->GetDimensions(nC
, nR
);
2219 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(10), nC
);
2220 CPPUNIT_ASSERT_EQUAL_MESSAGE("matrix size is not as expected", SCSIZE(20), nR
);
2221 checkMatrixElements
<AllEmptyMatrix
>(*pMat
);
2223 pMat
->PutBoolean(true, 1, 1);
2224 pMat
->PutDouble(-12.5, 4, 5);
2225 pMat
->PutString(rPool
.intern(u
"Test"_ustr
), 8, 2);
2226 pMat
->PutEmptyPath(8, 11);
2227 checkMatrixElements
<PartiallyFilledEmptyMatrix
>(*pMat
);
2230 pMat
= new ScMatrix(0, 0);
2231 pMat
->Resize(2, 2, 1.5);
2232 pMat
->PutEmpty(1, 1);
2234 CPPUNIT_ASSERT_EQUAL(1.5, pMat
->GetDouble(0, 0));
2235 CPPUNIT_ASSERT_EQUAL(1.5, pMat
->GetDouble(0, 1));
2236 CPPUNIT_ASSERT_EQUAL(1.5, pMat
->GetDouble(1, 0));
2237 CPPUNIT_ASSERT_MESSAGE("PutEmpty() call failed.", pMat
->IsEmpty(1, 1));
2239 // Max and min values.
2240 pMat
= new ScMatrix(2, 2, 0.0);
2241 pMat
->PutDouble(-10, 0, 0);
2242 pMat
->PutDouble(-12, 0, 1);
2243 pMat
->PutDouble(-8, 1, 0);
2244 pMat
->PutDouble(-25, 1, 1);
2245 CPPUNIT_ASSERT_EQUAL(-25.0, pMat
->GetMinValue(false));
2246 CPPUNIT_ASSERT_EQUAL(-8.0, pMat
->GetMaxValue(false));
2247 pMat
->PutString(rPool
.intern(u
"Test"_ustr
), 0, 0);
2248 CPPUNIT_ASSERT_EQUAL(0.0, pMat
->GetMaxValue(true)); // text as zero.
2249 CPPUNIT_ASSERT_EQUAL(-8.0, pMat
->GetMaxValue(false)); // ignore text.
2250 pMat
->PutBoolean(true, 0, 0);
2251 CPPUNIT_ASSERT_EQUAL(1.0, pMat
->GetMaxValue(false));
2252 pMat
= new ScMatrix(2, 2, 10.0);
2253 pMat
->PutBoolean(false, 0, 0);
2254 pMat
->PutDouble(12.5, 1, 1);
2255 CPPUNIT_ASSERT_EQUAL(0.0, pMat
->GetMinValue(false));
2256 CPPUNIT_ASSERT_EQUAL(12.5, pMat
->GetMaxValue(false));
2258 // Convert matrix into a linear double array. String elements become NaN
2259 // and empty elements become 0.
2260 pMat
= new ScMatrix(3, 3);
2261 pMat
->PutDouble(2.5, 0, 0);
2262 pMat
->PutDouble(1.2, 0, 1);
2263 pMat
->PutString(rPool
.intern(u
"A"_ustr
), 1, 1);
2264 pMat
->PutDouble(2.3, 2, 1);
2265 pMat
->PutDouble(-20, 2, 2);
2267 static const double fNaN
= std::numeric_limits
<double>::quiet_NaN();
2269 std::vector
<double> aDoubles
;
2270 pMat
->GetDoubleArray(aDoubles
);
2273 const double pChecks
[] = { 2.5, 1.2, 0, 0, fNaN
, 0, 0, 2.3, -20 };
2274 CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks
), aDoubles
.size());
2275 for (size_t i
= 0, n
= aDoubles
.size(); i
< n
; ++i
)
2277 if (std::isnan(pChecks
[i
]))
2278 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", std::isnan(aDoubles
[i
]));
2280 CPPUNIT_ASSERT_EQUAL(pChecks
[i
], aDoubles
[i
]);
2284 pMat2
= new ScMatrix(3, 3, 10.0);
2285 pMat2
->PutString(rPool
.intern(u
"B"_ustr
), 1, 0);
2286 pMat2
->MergeDoubleArrayMultiply(aDoubles
);
2289 const double pChecks
[] = { 25, 12, 0, fNaN
, fNaN
, 0, 0, 23, -200 };
2290 CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks
), aDoubles
.size());
2291 for (size_t i
= 0, n
= aDoubles
.size(); i
< n
; ++i
)
2293 if (std::isnan(pChecks
[i
]))
2294 CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", std::isnan(aDoubles
[i
]));
2296 CPPUNIT_ASSERT_EQUAL(pChecks
[i
], aDoubles
[i
]);
2301 CPPUNIT_TEST_FIXTURE(Test
, testMatrixComparisonWithErrors
)
2303 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
2305 // Insert the source values in A1:A2.
2306 m_pDoc
->SetString(0, 0, 0, u
"=1/0"_ustr
);
2307 m_pDoc
->SetValue( 0, 1, 0, 1.0);
2309 // Create a matrix formula in B3:B4 referencing A1:A2 and doing a greater
2310 // than comparison on it's values. Error value must be propagated.
2311 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2312 aMark
.SelectOneTable(0);
2313 m_pDoc
->InsertMatrixFormula(1, 2, 1, 3, aMark
, u
"=A1:A2>0"_ustr
);
2315 CPPUNIT_ASSERT_EQUAL(u
"#DIV/0!"_ustr
, m_pDoc
->GetString(0,0,0));
2316 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue( 0,1,0));
2317 CPPUNIT_ASSERT_EQUAL(u
"#DIV/0!"_ustr
, m_pDoc
->GetString(1,2,0));
2318 CPPUNIT_ASSERT_EQUAL(u
"TRUE"_ustr
, m_pDoc
->GetString(1,3,0));
2320 m_pDoc
->DeleteTab(0);
2323 CPPUNIT_TEST_FIXTURE(Test
, testMatrixConditionalBooleanResult
)
2325 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
2327 // Create matrix formulas in A1:B1,A2:B2,A3:B3,A4:B4 producing mixed
2328 // boolean and numeric results in an unformatted area.
2329 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2330 aMark
.SelectOneTable(0);
2331 m_pDoc
->InsertMatrixFormula( 0,0, 1,0, aMark
, u
"=IF({1;0};TRUE();42)"_ustr
); // {TRUE,42}
2332 m_pDoc
->InsertMatrixFormula( 0,1, 1,1, aMark
, u
"=IF({0;1};TRUE();42)"_ustr
); // {42,1} aim for {42,TRUE}
2333 m_pDoc
->InsertMatrixFormula( 0,2, 1,2, aMark
, u
"=IF({1;0};42;FALSE())"_ustr
); // {42,0} aim for {42,FALSE}
2334 m_pDoc
->InsertMatrixFormula( 0,3, 1,3, aMark
, u
"=IF({0;1};42;FALSE())"_ustr
); // {FALSE,42}
2336 CPPUNIT_ASSERT_EQUAL( u
"TRUE"_ustr
, m_pDoc
->GetString(0,0,0));
2337 CPPUNIT_ASSERT_EQUAL( u
"42"_ustr
, m_pDoc
->GetString(1,0,0));
2338 CPPUNIT_ASSERT_EQUAL( u
"42"_ustr
, m_pDoc
->GetString(0,1,0));
2339 //CPPUNIT_ASSERT_EQUAL( OUString("TRUE"), m_pDoc->GetString(1,1,0)); // not yet
2340 CPPUNIT_ASSERT_EQUAL( u
"42"_ustr
, m_pDoc
->GetString(0,2,0));
2341 //CPPUNIT_ASSERT_EQUAL( OUString("FALSE"), m_pDoc->GetString(1,2,0)); // not yet
2342 CPPUNIT_ASSERT_EQUAL( u
"FALSE"_ustr
, m_pDoc
->GetString(0,3,0));
2343 CPPUNIT_ASSERT_EQUAL( u
"42"_ustr
, m_pDoc
->GetString(1,3,0));
2345 m_pDoc
->DeleteTab(0);
2348 CPPUNIT_TEST_FIXTURE(Test
, testEnterMixedMatrix
)
2350 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
2352 // Insert the source values in A1:B2.
2353 m_pDoc
->SetString(0, 0, 0, u
"A"_ustr
);
2354 m_pDoc
->SetString(1, 0, 0, u
"B"_ustr
);
2356 m_pDoc
->SetValue(0, 1, 0, val
);
2358 m_pDoc
->SetValue(1, 1, 0, val
);
2360 // Create a matrix range in A4:B5 referencing A1:B2.
2361 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2362 aMark
.SelectOneTable(0);
2363 m_pDoc
->InsertMatrixFormula(0, 3, 1, 4, aMark
, u
"=A1:B2"_ustr
);
2365 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(0,0,0), m_pDoc
->GetString(0,3,0));
2366 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetString(1,0,0), m_pDoc
->GetString(1,3,0));
2367 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetValue(0,1,0), m_pDoc
->GetValue(0,4,0));
2368 CPPUNIT_ASSERT_EQUAL(m_pDoc
->GetValue(1,1,0), m_pDoc
->GetValue(1,4,0));
2370 m_pDoc
->DeleteTab(0);
2373 CPPUNIT_TEST_FIXTURE(Test
, testMatrixEditable
)
2375 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2377 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
2380 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
2381 m_pDoc
->SetValue(ScAddress(1,0,0), 2.0);
2383 // A2 is a normal formula.
2384 m_pDoc
->SetString(ScAddress(0,1,0), u
"=5"_ustr
);
2386 // A3:A4 is a matrix.
2387 ScRange
aMatRange(0,2,0,0,3,0);
2388 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2389 aMark
.SetMarkArea(aMatRange
);
2390 m_pDoc
->InsertMatrixFormula(0, 2, 0, 3, aMark
, u
"=TRANSPOSE(A1:B1)"_ustr
);
2392 // Check their values.
2393 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
2394 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
2395 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
2397 // Make sure A3:A4 is a matrix.
2398 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,2,0));
2399 CPPUNIT_ASSERT(pFC
);
2400 CPPUNIT_ASSERT_EQUAL_MESSAGE("A3 should be matrix origin.",
2401 ScMatrixMode::Formula
, pFC
->GetMatrixFlag());
2403 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,3,0));
2404 CPPUNIT_ASSERT(pFC
);
2405 CPPUNIT_ASSERT_EQUAL_MESSAGE("A4 should be matrix reference.",
2406 ScMatrixMode::Reference
, pFC
->GetMatrixFlag());
2408 // Check to make sure A3:A4 combined is editable.
2409 ScEditableTester aTester
;
2410 aTester
.TestSelection(*m_pDoc
, aMark
);
2411 CPPUNIT_ASSERT(aTester
.IsEditable());
2413 m_pDoc
->DeleteTab(0);
2416 CPPUNIT_TEST_FIXTURE(Test
, testCellCopy
)
2418 m_pDoc
->InsertTab(0, u
"TestTab"_ustr
);
2419 ScAddress
aSrc(0,0,0);
2420 ScAddress
aDest(0,1,0);
2421 OUString
aStr(u
"please copy me"_ustr
);
2422 m_pDoc
->SetString(aSrc
, u
"please copy me"_ustr
);
2423 CPPUNIT_ASSERT_EQUAL(aStr
, m_pDoc
->GetString(aSrc
));
2424 // copy to self - why not ?
2425 m_pDoc
->CopyCellToDocument(aSrc
,aDest
,*m_pDoc
);
2426 CPPUNIT_ASSERT_EQUAL(aStr
, m_pDoc
->GetString(aDest
));
2429 CPPUNIT_TEST_FIXTURE(Test
, testSheetCopy
)
2431 m_pDoc
->InsertTab(0, u
"TestTab"_ustr
);
2432 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.",
2433 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
2435 // We need a drawing layer in order to create caption objects.
2436 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
2438 // Insert text in A1.
2439 m_pDoc
->SetString(ScAddress(0,0,0), u
"copy me"_ustr
);
2441 // Insert edit cells in B1:B3.
2442 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
2443 rEE
.SetTextCurrentDefaults(u
"Edit 1"_ustr
);
2444 m_pDoc
->SetEditText(ScAddress(1,0,0), rEE
.CreateTextObject());
2445 rEE
.SetTextCurrentDefaults(u
"Edit 2"_ustr
);
2446 m_pDoc
->SetEditText(ScAddress(1,1,0), rEE
.CreateTextObject());
2447 rEE
.SetTextCurrentDefaults(u
"Edit 3"_ustr
);
2448 m_pDoc
->SetEditText(ScAddress(1,2,0), rEE
.CreateTextObject());
2451 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2452 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
2453 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
2454 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
2457 ScAddress
aAdrA1 (0,2,0); // empty cell content.
2458 ScPostIt
*pNoteA1
= m_pDoc
->GetOrCreateNote(aAdrA1
);
2459 pNoteA1
->SetText(aAdrA1
, u
"Hello world in A3"_ustr
);
2461 // Copy and test the result.
2462 m_pDoc
->CopyTab(0, 1);
2463 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.",
2464 static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2466 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2467 CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden
);
2468 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", SCROW(0), nRow1
);
2469 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", m_pDoc
->MaxRow(), nRow2
);
2470 CPPUNIT_ASSERT_MESSAGE("There should be note on A3 in new sheet", m_pDoc
->HasNote(ScAddress(0,2,1)));
2471 CPPUNIT_ASSERT_EQUAL(u
"copy me"_ustr
, m_pDoc
->GetString(ScAddress(0,0,1)));
2473 // Check the copied edit cells.
2474 const EditTextObject
* pEditObj
= m_pDoc
->GetEditText(ScAddress(1,0,1));
2475 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B1.", pEditObj
);
2476 CPPUNIT_ASSERT_EQUAL(u
"Edit 1"_ustr
, pEditObj
->GetText(0));
2477 pEditObj
= m_pDoc
->GetEditText(ScAddress(1,1,1));
2478 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B2.", pEditObj
);
2479 CPPUNIT_ASSERT_EQUAL(u
"Edit 2"_ustr
, pEditObj
->GetText(0));
2480 pEditObj
= m_pDoc
->GetEditText(ScAddress(1,2,1));
2481 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B3.", pEditObj
);
2482 CPPUNIT_ASSERT_EQUAL(u
"Edit 3"_ustr
, pEditObj
->GetText(0));
2484 m_pDoc
->DeleteTab(1);
2486 m_pDoc
->SetRowHidden(5, 10, 0, true);
2487 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2488 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2489 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2490 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2491 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
2492 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2493 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2494 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2495 bHidden
= m_pDoc
->RowHidden(11, 0, &nRow1
, &nRow2
);
2496 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2497 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2498 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2500 // Copy the sheet once again.
2501 m_pDoc
->CopyTab(0, 1);
2502 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.",
2503 static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2504 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2505 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2506 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2507 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2508 bHidden
= m_pDoc
->RowHidden(5, 1, &nRow1
, &nRow2
);
2509 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2510 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2511 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2512 bHidden
= m_pDoc
->RowHidden(11, 1, &nRow1
, &nRow2
);
2513 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2514 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2515 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2516 m_pDoc
->DeleteTab(1);
2517 m_pDoc
->DeleteTab(0);
2520 CPPUNIT_TEST_FIXTURE(Test
, testSheetMove
)
2522 m_pDoc
->InsertTab(0, u
"TestTab1"_ustr
);
2523 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.", static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
2525 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2526 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
2527 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
2528 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
2530 //test if inserting before another sheet works
2531 m_pDoc
->InsertTab(0, u
"TestTab2"_ustr
);
2532 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have two sheets", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2533 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2534 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
2535 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
2536 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
2538 // Move and test the result.
2539 m_pDoc
->MoveTab(0, 1);
2540 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2541 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2542 CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden
);
2543 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", SCROW(0), nRow1
);
2544 CPPUNIT_ASSERT_EQUAL_MESSAGE("copied sheet should also have all rows visible as the original.", m_pDoc
->MaxRow(), nRow2
);
2546 m_pDoc
->GetName(0, aName
);
2547 CPPUNIT_ASSERT_EQUAL_MESSAGE( "sheets should have changed places", u
"TestTab1"_ustr
, aName
);
2549 m_pDoc
->SetRowHidden(5, 10, 0, true);
2550 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
2551 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2552 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2553 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2554 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
2555 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2556 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2557 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2558 bHidden
= m_pDoc
->RowHidden(11, 0, &nRow1
, &nRow2
);
2559 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2560 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2561 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2563 // Move the sheet once again.
2564 m_pDoc
->MoveTab(1, 0);
2565 CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
2566 bHidden
= m_pDoc
->RowHidden(0, 1, &nRow1
, &nRow2
);
2567 CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden
);
2568 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(0), nRow1
);
2569 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 0 - 4 should be visible", SCROW(4), nRow2
);
2570 bHidden
= m_pDoc
->RowHidden(5, 1, &nRow1
, &nRow2
);
2571 CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden
);
2572 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(5), nRow1
);
2573 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 5 - 10 should be hidden", SCROW(10), nRow2
);
2574 bHidden
= m_pDoc
->RowHidden(11, 1, &nRow1
, &nRow2
);
2575 CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden
);
2576 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", SCROW(11), nRow1
);
2577 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 11 - maxrow should be visible", m_pDoc
->MaxRow(), nRow2
);
2578 m_pDoc
->GetName(0, aName
);
2579 CPPUNIT_ASSERT_EQUAL_MESSAGE( "sheets should have changed places", u
"TestTab2"_ustr
, aName
);
2580 m_pDoc
->DeleteTab(1);
2581 m_pDoc
->DeleteTab(0);
2584 CPPUNIT_TEST_FIXTURE(Test
, testDataArea
)
2586 m_pDoc
->InsertTab(0, u
"Data"_ustr
);
2588 // Totally empty sheet should be rightfully considered empty in all accounts.
2589 CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc
->IsPrintEmpty(0, 0, 100, 100, 0));
2590 CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
2592 // Now, set borders in some cells...
2593 ::editeng::SvxBorderLine
aLine(nullptr, 50, SvxBorderLineStyle::SOLID
);
2594 SvxBoxItem
aBorderItem(ATTR_BORDER
);
2595 aBorderItem
.SetLine(&aLine
, SvxBoxItemLine::LEFT
);
2596 aBorderItem
.SetLine(&aLine
, SvxBoxItemLine::RIGHT
);
2597 for (SCROW i
= 0; i
< 100; ++i
)
2598 // Set borders from row 1 to 100.
2599 m_pDoc
->ApplyAttr(0, i
, 0, aBorderItem
);
2601 // Now the sheet is considered non-empty for printing purposes, but still
2602 // be empty in all the other cases.
2603 CPPUNIT_ASSERT_MESSAGE("Empty sheet with borders should be printable.",
2604 !m_pDoc
->IsPrintEmpty(0, 0, 0, 100, 100));
2605 CPPUNIT_ASSERT_MESSAGE("But it should still be considered empty in all the other cases.",
2606 m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
2608 // Adding a real cell content should turn the block non-empty.
2609 m_pDoc
->SetString(0, 0, 0, u
"Some text"_ustr
);
2610 CPPUNIT_ASSERT_MESSAGE("Now the block should not be empty with a real cell content.",
2611 !m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
2613 // TODO: Add more tests for normal data area calculation.
2615 m_pDoc
->DeleteTab(0);
2618 CPPUNIT_TEST_FIXTURE(Test
, testStreamValid
)
2621 * Make sure the sheet streams are invalidated properly.
2623 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
2624 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
2625 m_pDoc
->InsertTab(2, u
"Sheet3"_ustr
);
2626 m_pDoc
->InsertTab(3, u
"Sheet4"_ustr
);
2627 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have 4 sheet instances.", static_cast<SCTAB
>(4), m_pDoc
->GetTableCount());
2629 OUString
a1(u
"A1"_ustr
);
2630 OUString
a2(u
"A2"_ustr
);
2633 // Put values into Sheet1.
2634 m_pDoc
->SetString(0, 0, 0, a1
);
2635 m_pDoc
->SetString(0, 1, 0, a2
);
2636 test
= m_pDoc
->GetString(0, 0, 0);
2637 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet1.A1", test
, a1
);
2638 test
= m_pDoc
->GetString(0, 1, 0);
2639 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet1.A2", test
, a2
);
2641 // Put formulas into Sheet2 to Sheet4 to reference values from Sheet1.
2642 m_pDoc
->SetString(0, 0, 1, u
"=Sheet1.A1"_ustr
);
2643 m_pDoc
->SetString(0, 1, 1, u
"=Sheet1.A2"_ustr
);
2644 m_pDoc
->SetString(0, 0, 2, u
"=Sheet1.A1"_ustr
);
2645 m_pDoc
->SetString(0, 0, 3, u
"=Sheet1.A2"_ustr
);
2647 test
= m_pDoc
->GetString(0, 0, 1);
2648 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet2.A1", test
, a1
);
2649 test
= m_pDoc
->GetString(0, 1, 1);
2650 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet2.A2", test
, a2
);
2651 test
= m_pDoc
->GetString(0, 0, 2);
2652 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet3.A1", test
, a1
);
2653 test
= m_pDoc
->GetString(0, 0, 3);
2654 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected value in Sheet3.A1", test
, a2
);
2656 // Set all sheet streams valid after all the initial cell values are in
2657 // place. In reality we need to have real XML streams stored in order to
2658 // claim they are valid, but we are just testing the flag values here.
2659 m_pDoc
->SetStreamValid(0, true);
2660 m_pDoc
->SetStreamValid(1, true);
2661 m_pDoc
->SetStreamValid(2, true);
2662 m_pDoc
->SetStreamValid(3, true);
2663 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(0));
2664 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(1));
2665 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(2));
2666 CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc
->IsStreamValid(3));
2668 // Now, insert a new row at row 2 position on Sheet1. This will move cell
2669 // A2 downward but cell A1 remains unmoved.
2670 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 2);
2671 test
= m_pDoc
->GetString(0, 0, 0);
2672 CPPUNIT_ASSERT_EQUAL_MESSAGE("Cell A1 should not have moved.", test
, a1
);
2673 test
= m_pDoc
->GetString(0, 3, 0);
2674 CPPUNIT_ASSERT_EQUAL_MESSAGE("the old cell A2 should now be at A4.", test
, a2
);
2675 ScRefCellValue aCell
;
2676 aCell
.assign(*m_pDoc
, ScAddress(0,1,0));
2677 CPPUNIT_ASSERT_MESSAGE("Cell A2 should be empty.", aCell
.isEmpty());
2678 aCell
.assign(*m_pDoc
, ScAddress(0,2,0));
2679 CPPUNIT_ASSERT_MESSAGE("Cell A3 should be empty.", aCell
.isEmpty());
2681 // After the move, Sheet1, Sheet2, and Sheet4 should have their stream
2682 // invalidated, whereas Sheet3's stream should still be valid.
2683 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc
->IsStreamValid(0));
2684 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc
->IsStreamValid(1));
2685 CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc
->IsStreamValid(3));
2686 CPPUNIT_ASSERT_MESSAGE("Stream should still be valid.", m_pDoc
->IsStreamValid(2));
2688 m_pDoc
->DeleteTab(3);
2689 m_pDoc
->DeleteTab(2);
2690 m_pDoc
->DeleteTab(1);
2691 m_pDoc
->DeleteTab(0);
2694 CPPUNIT_TEST_FIXTURE(Test
, testFunctionLists
)
2697 * Test built-in cell functions to make sure their categories and order
2700 const char* aDataBase
[] = {
2716 const char* aDateTime
[] = {
2750 const char* aFinancial
[] = {
2780 const char* aInformation
[] = {
2803 const char* aLogical
[] = {
2818 const char* aMathematical
[] = {
2897 const char* aArray
[] = {
2917 const char* aStatistical
[] = {
2970 "FORECAST.ETS.MULT",
2971 "FORECAST.ETS.PI.ADD",
2972 "FORECAST.ETS.PI.MULT",
2973 "FORECAST.ETS.SEASONALITY",
2974 "FORECAST.ETS.STAT.ADD",
2975 "FORECAST.ETS.STAT.MULT",
3072 const char* aSpreadsheet
[] = {
3105 const char* aText
[] = {
3157 const char* Category
; const char** Functions
;
3159 { "Database", aDataBase
},
3160 { "Date&Time", aDateTime
},
3161 { "Financial", aFinancial
},
3162 { "Information", aInformation
},
3163 { "Logical", aLogical
},
3164 { "Mathematical", aMathematical
},
3165 { "Array", aArray
},
3166 { "Statistical", aStatistical
},
3167 { "Spreadsheet", aSpreadsheet
},
3169 { "Add-in", nullptr },
3170 { nullptr, nullptr }
3173 ScFunctionMgr
* pFuncMgr
= ScGlobal::GetStarCalcFunctionMgr();
3174 sal_uInt32 n
= pFuncMgr
->getCount();
3175 for (sal_uInt32 i
= 0; i
< n
; ++i
)
3177 const formula::IFunctionCategory
* pCat
= pFuncMgr
->getCategory(i
);
3178 CPPUNIT_ASSERT_MESSAGE("Unexpected category name", pCat
->getName().equalsAscii(aTests
[i
].Category
));
3179 sal_uInt32 nFuncCount
= pCat
->getCount();
3180 for (sal_uInt32 j
= 0; j
< nFuncCount
; ++j
)
3182 const formula::IFunctionDescription
* pFunc
= pCat
->getFunction(j
);
3183 CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected function name", OUString::createFromAscii(aTests
[i
].Functions
[j
]), pFunc
->getFunctionName());
3188 CPPUNIT_TEST_FIXTURE(Test
, testGraphicsInGroup
)
3190 m_pDoc
->InsertTab(0, u
"TestTab"_ustr
);
3191 CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.",
3192 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
3194 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3195 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
3196 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
3197 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
3199 m_pDoc
->InitDrawLayer();
3200 ScDrawLayer
*pDrawLayer
= m_pDoc
->GetDrawLayer();
3201 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer
!= nullptr);
3202 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
3203 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage
!= nullptr);
3207 tools::Rectangle
aOrigRect(2,2,100,100);
3208 rtl::Reference
<SdrRectObj
> pObj
= new SdrRectObj(*pDrawLayer
, aOrigRect
);
3209 pPage
->InsertObject(pObj
.get());
3210 const tools::Rectangle
&rNewRect
= pObj
->GetLogicRect();
3211 CPPUNIT_ASSERT_EQUAL_MESSAGE("must have equal position and size",
3212 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3214 ScDrawLayer::SetPageAnchored(*pObj
);
3216 //Use a range of rows guaranteed to include all of the square
3217 m_pDoc
->ShowRows(0, 100, 0, false);
3218 m_pDoc
->SetDrawPageSize(0);
3219 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when page anchored",
3220 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3221 m_pDoc
->ShowRows(0, 100, 0, true);
3222 m_pDoc
->SetDrawPageSize(0);
3223 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when page anchored",
3224 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3226 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, true);
3227 CPPUNIT_ASSERT_EQUAL_MESSAGE("That shouldn't change size or positioning",
3228 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3230 m_pDoc
->ShowRows(0, 100, 0, false);
3231 m_pDoc
->SetDrawPageSize(0);
3233 CPPUNIT_ASSERT_EQUAL_MESSAGE("Hiding should not change the logic rectangle",
3234 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3235 CPPUNIT_ASSERT_MESSAGE("Hiding should make invisible", !pObj
->IsVisible());
3237 m_pDoc
->ShowRows(0, 100, 0, true);
3238 m_pDoc
->SetDrawPageSize(0);
3239 CPPUNIT_ASSERT_EQUAL_MESSAGE("Should not change when cell anchored",
3240 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3241 CPPUNIT_ASSERT_MESSAGE("Show should make visible", pObj
->IsVisible());
3246 tools::Rectangle
aOrigRect(10,10,210,210); // 200 x 200
3247 rtl::Reference
<SdrCircObj
> pObj
= new SdrCircObj(*pDrawLayer
, SdrCircKind::Full
, aOrigRect
);
3248 pPage
->InsertObject(pObj
.get());
3249 const tools::Rectangle
& rNewRect
= pObj
->GetLogicRect();
3250 CPPUNIT_ASSERT_EQUAL_MESSAGE("Position and size of the circle shouldn't change when inserted into the page.",
3251 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3253 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3254 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size changed when cell anchored. Not good.",
3255 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3257 // Insert 2 rows at the top. This should push the circle object down.
3258 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3259 m_pDoc
->SetDrawPageSize(0);
3261 // Make sure the size of the circle is still identical.
3262 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size of the circle has changed, but shouldn't!",
3263 aOrigRect
.GetSize(), rNewRect
.GetSize());
3265 // Delete 2 rows at the top. This should bring the circle object to its original position.
3266 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3267 m_pDoc
->SetDrawPageSize(0);
3268 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to move back to its original position.",
3269 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3274 basegfx::B2DPolygon aTempPoly
;
3275 Point
aStartPos(10,300), aEndPos(110,200); // bottom-left to top-right.
3276 tools::Rectangle
aOrigRect(10,200,110,300); // 100 x 100
3277 aTempPoly
.append(basegfx::B2DPoint(aStartPos
.X(), aStartPos
.Y()));
3278 aTempPoly
.append(basegfx::B2DPoint(aEndPos
.X(), aEndPos
.Y()));
3279 rtl::Reference
<SdrPathObj
> pObj
= new SdrPathObj(*pDrawLayer
, SdrObjKind::Line
, basegfx::B2DPolyPolygon(aTempPoly
));
3280 pObj
->NbcSetLogicRect(aOrigRect
);
3281 pPage
->InsertObject(pObj
.get());
3282 const tools::Rectangle
& rNewRect
= pObj
->GetLogicRect();
3283 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size differ.",
3284 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3286 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3287 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size changed when cell-anchored. Not good.",
3288 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3290 // Insert 2 rows at the top and delete them immediately.
3291 m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3292 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 2);
3293 m_pDoc
->SetDrawPageSize(0);
3294 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size of a line object changed after row insertion and removal.",
3295 const_cast<const tools::Rectangle
&>(aOrigRect
), rNewRect
);
3297 sal_Int32 n
= pObj
->GetPointCount();
3298 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 2 points in a line object.", static_cast<sal_Int32
>(2), n
);
3299 CPPUNIT_ASSERT_EQUAL_MESSAGE("Line shape has changed.",
3300 aStartPos
, pObj
->GetPoint(0));
3301 CPPUNIT_ASSERT_EQUAL_MESSAGE("Line shape has changed.",
3302 aEndPos
, pObj
->GetPoint(1));
3305 m_pDoc
->DeleteTab(0);
3308 CPPUNIT_TEST_FIXTURE(Test
, testGraphicsOnSheetMove
)
3310 m_pDoc
->InsertTab(0, u
"Tab1"_ustr
);
3311 m_pDoc
->InsertTab(1, u
"Tab2"_ustr
);
3312 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only 2 sheets to begin with", static_cast<SCTAB
>(2), m_pDoc
->GetTableCount());
3314 m_pDoc
->InitDrawLayer();
3315 ScDrawLayer
* pDrawLayer
= m_pDoc
->GetDrawLayer();
3316 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer
);
3317 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
3318 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage
);
3320 // Insert an object.
3321 tools::Rectangle
aObjRect(2,2,100,100);
3322 rtl::Reference
<SdrObject
> pObj
= new SdrRectObj(*pDrawLayer
, aObjRect
);
3323 pPage
->InsertObject(pObj
.get());
3324 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
3326 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one object on the 1st sheet.", static_cast<size_t>(1), pPage
->GetObjCount());
3328 const ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pObj
.get());
3329 CPPUNIT_ASSERT_MESSAGE("Object meta-data doesn't exist.", pData
);
3330 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maStart
.Tab());
3331 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maEnd
.Tab());
3333 pPage
= pDrawLayer
->GetPage(1);
3334 CPPUNIT_ASSERT_MESSAGE("No page instance for the 2nd sheet.", pPage
);
3335 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet shouldn't have any object.", static_cast<size_t>(0), pPage
->GetObjCount());
3337 // Insert a new sheet at left-end, and make sure the object has moved to
3339 m_pDoc
->InsertTab(0, u
"NewTab"_ustr
);
3340 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 3 sheets.", static_cast<SCTAB
>(3), m_pDoc
->GetTableCount());
3341 pPage
= pDrawLayer
->GetPage(0);
3342 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage
);
3343 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have no object.", size_t(0), pPage
->GetObjCount());
3344 pPage
= pDrawLayer
->GetPage(1);
3345 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage
);
3346 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet should have one object.", size_t(1), pPage
->GetObjCount());
3347 pPage
= pDrawLayer
->GetPage(2);
3348 CPPUNIT_ASSERT_MESSAGE("3rd sheet should have no object.", pPage
);
3349 CPPUNIT_ASSERT_EQUAL_MESSAGE("3rd sheet should have no object.", size_t(0), pPage
->GetObjCount());
3351 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maStart
.Tab());
3352 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maEnd
.Tab());
3354 // Now, delete the sheet that just got inserted. The object should be back
3355 // on the 1st sheet.
3356 m_pDoc
->DeleteTab(0);
3357 pPage
= pDrawLayer
->GetPage(0);
3358 CPPUNIT_ASSERT_MESSAGE("1st sheet should have one object.", pPage
);
3359 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have one object.", size_t(1), pPage
->GetObjCount());
3360 CPPUNIT_ASSERT_EQUAL_MESSAGE("Size and position of the object shouldn't change.",
3361 aObjRect
, pObj
->GetLogicRect());
3363 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maStart
.Tab());
3364 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(0), pData
->maEnd
.Tab());
3366 // Move the 1st sheet to the last position.
3367 m_pDoc
->MoveTab(0, 1);
3368 pPage
= pDrawLayer
->GetPage(0);
3369 CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage
);
3370 CPPUNIT_ASSERT_EQUAL_MESSAGE("1st sheet should have no object.", size_t(0), pPage
->GetObjCount());
3371 pPage
= pDrawLayer
->GetPage(1);
3372 CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage
);
3373 CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet should have one object.", size_t(1), pPage
->GetObjCount());
3374 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maStart
.Tab());
3375 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(1), pData
->maEnd
.Tab());
3377 // Copy the 2nd sheet, which has one drawing object to the last position.
3378 m_pDoc
->CopyTab(1, 2);
3379 pPage
= pDrawLayer
->GetPage(2);
3380 CPPUNIT_ASSERT_MESSAGE("Copied sheet should have one object.", pPage
);
3381 CPPUNIT_ASSERT_EQUAL_MESSAGE("Copied sheet should have one object.", size_t(1), pPage
->GetObjCount());
3382 pObj
= pPage
->GetObj(0);
3383 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj
);
3384 pData
= ScDrawLayer::GetObjData(pObj
.get());
3385 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData
);
3386 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(2), pData
->maStart
.Tab());
3387 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sheet ID in cell anchor data!", SCTAB(2), pData
->maEnd
.Tab());
3389 m_pDoc
->DeleteTab(2);
3390 m_pDoc
->DeleteTab(1);
3391 m_pDoc
->DeleteTab(0);
3394 CPPUNIT_TEST_FIXTURE(Test
, testToggleRefFlag
)
3397 * Test toggling relative/absolute flag of cell and cell range references.
3398 * This corresponds with hitting Shift-F4 while the cursor is on a formula
3401 // In this test, there is no need to insert formula string into a cell in
3402 // the document, as ScRefFinder does not depend on the content of the
3403 // document except for the sheet names.
3405 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3408 // Calc A1: basic 2D reference
3410 OUString
aFormula(u
"=B100"_ustr
);
3411 ScAddress
aPos(1, 5, 0);
3412 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
3415 CPPUNIT_ASSERT_EQUAL_MESSAGE("Does not equal the original text.", aFormula
, aFinder
.GetText());
3417 // column relative / row relative -> column absolute / row absolute
3418 aFinder
.ToggleRel(0, aFormula
.getLength());
3419 aFormula
= aFinder
.GetText();
3420 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", u
"=$B$100"_ustr
, aFormula
);
3422 // column absolute / row absolute -> column relative / row absolute
3423 aFinder
.ToggleRel(0, aFormula
.getLength());
3424 aFormula
= aFinder
.GetText();
3425 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", u
"=B$100"_ustr
, aFormula
);
3427 // column relative / row absolute -> column absolute / row relative
3428 aFinder
.ToggleRel(0, aFormula
.getLength());
3429 aFormula
= aFinder
.GetText();
3430 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", u
"=$B100"_ustr
, aFormula
);
3432 // column absolute / row relative -> column relative / row relative
3433 aFinder
.ToggleRel(0, aFormula
.getLength());
3434 aFormula
= aFinder
.GetText();
3435 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong conversion.", u
"=B100"_ustr
, aFormula
);
3439 // Excel R1C1: basic 2D reference
3441 OUString
aFormula(u
"=R2C1"_ustr
);
3442 ScAddress
aPos(3, 5, 0);
3443 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
3446 CPPUNIT_ASSERT_EQUAL_MESSAGE("Does not equal the original text.", aFormula
, aFinder
.GetText());
3448 // column absolute / row absolute -> column relative / row absolute
3449 aFinder
.ToggleRel(0, aFormula
.getLength());
3450 aFormula
= aFinder
.GetText();
3451 CPPUNIT_ASSERT_EQUAL(u
"=R2C[-3]"_ustr
, aFormula
);
3453 // column relative / row absolute - > column absolute / row relative
3454 aFinder
.ToggleRel(0, aFormula
.getLength());
3455 aFormula
= aFinder
.GetText();
3456 CPPUNIT_ASSERT_EQUAL(u
"=R[-4]C1"_ustr
, aFormula
);
3458 // column absolute / row relative -> column relative / row relative
3459 aFinder
.ToggleRel(0, aFormula
.getLength());
3460 aFormula
= aFinder
.GetText();
3461 CPPUNIT_ASSERT_EQUAL(u
"=R[-4]C[-3]"_ustr
, aFormula
);
3463 // column relative / row relative -> column absolute / row absolute
3464 aFinder
.ToggleRel(0, aFormula
.getLength());
3465 aFormula
= aFinder
.GetText();
3466 CPPUNIT_ASSERT_EQUAL(u
"=R2C1"_ustr
, aFormula
);
3470 // Excel R1C1: Selection at the end of the formula string and does not
3471 // overlap the formula string at all (inspired by fdo#39135).
3472 OUString
aFormula(u
"=R1C1"_ustr
);
3473 ScAddress
aPos(1, 1, 0);
3474 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_XL_R1C1
);
3477 CPPUNIT_ASSERT_EQUAL(aFormula
, aFinder
.GetText());
3479 // Make the column relative.
3480 sal_Int32 n
= aFormula
.getLength();
3481 aFinder
.ToggleRel(n
, n
);
3482 aFormula
= aFinder
.GetText();
3483 CPPUNIT_ASSERT_EQUAL(u
"=R1C[-1]"_ustr
, aFormula
);
3485 // Make the row relative.
3486 n
= aFormula
.getLength();
3487 aFinder
.ToggleRel(n
, n
);
3488 aFormula
= aFinder
.GetText();
3489 CPPUNIT_ASSERT_EQUAL(u
"=R[-1]C1"_ustr
, aFormula
);
3491 // Make both relative.
3492 n
= aFormula
.getLength();
3493 aFinder
.ToggleRel(n
, n
);
3494 aFormula
= aFinder
.GetText();
3495 CPPUNIT_ASSERT_EQUAL(u
"=R[-1]C[-1]"_ustr
, aFormula
);
3497 // Back to the original.
3498 n
= aFormula
.getLength();
3499 aFinder
.ToggleRel(n
, n
);
3500 aFormula
= aFinder
.GetText();
3501 CPPUNIT_ASSERT_EQUAL(u
"=R1C1"_ustr
, aFormula
);
3506 OUString
aFormula(u
"=A1+4"_ustr
);
3507 ScAddress
aPos(1, 1, 0);
3508 ScRefFinder
aFinder(aFormula
, aPos
, *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
3511 CPPUNIT_ASSERT_EQUAL(aFormula
, aFinder
.GetText());
3513 // Set the cursor over the 'A1' part and toggle.
3514 aFinder
.ToggleRel(2, 2);
3515 aFormula
= aFinder
.GetText();
3516 CPPUNIT_ASSERT_EQUAL(u
"=$A$1+4"_ustr
, aFormula
);
3518 aFinder
.ToggleRel(2, 2);
3519 aFormula
= aFinder
.GetText();
3520 CPPUNIT_ASSERT_EQUAL(u
"=A$1+4"_ustr
, aFormula
);
3522 aFinder
.ToggleRel(2, 2);
3523 aFormula
= aFinder
.GetText();
3524 CPPUNIT_ASSERT_EQUAL(u
"=$A1+4"_ustr
, aFormula
);
3526 aFinder
.ToggleRel(2, 2);
3527 aFormula
= aFinder
.GetText();
3528 CPPUNIT_ASSERT_EQUAL(u
"=A1+4"_ustr
, aFormula
);
3531 // TODO: Add more test cases esp. for 3D references, Excel A1 syntax, and
3532 // partial selection within formula string.
3534 m_pDoc
->DeleteTab(0);
3537 CPPUNIT_TEST_FIXTURE(Test
, testAutofilter
)
3539 m_pDoc
->InsertTab( 0, u
"Test"_ustr
);
3541 // cell contents (0 = empty cell)
3542 const char* aData
[][3] = {
3543 { "C1", "C2", "C3" },
3545 { "1", "2", nullptr },
3550 SCCOL nCols
= std::size(aData
[0]);
3551 SCROW nRows
= std::size(aData
);
3554 for (SCROW i
= 0; i
< nRows
; ++i
)
3555 for (SCCOL j
= 0; j
< nCols
; ++j
)
3557 m_pDoc
->SetString(j
, i
, 0, OUString::createFromAscii(aData
[i
][j
]));
3559 ScDBData
* pDBData
= new ScDBData(u
"NONAME"_ustr
, 0, 0, 0, nCols
-1, nRows
-1);
3560 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3562 pDBData
->SetAutoFilter(true);
3564 pDBData
->GetArea(aRange
);
3565 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3566 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3567 aRange
.aStart
.Tab(), ScMF::Auto
);
3569 //create the query param
3570 ScQueryParam aParam
;
3571 pDBData
->GetQueryParam(aParam
);
3572 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3573 rEntry
.bDoQuery
= true;
3575 rEntry
.eOp
= SC_EQUAL
;
3576 rEntry
.GetQueryItem().mfVal
= 0;
3577 // add queryParam to database range.
3578 pDBData
->SetQueryParam(aParam
);
3580 // perform the query.
3581 m_pDoc
->Query(0, aParam
, true);
3585 bool bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3586 CPPUNIT_ASSERT_MESSAGE("rows 2 & 3 should be hidden", bHidden
);
3587 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2 & 3 should be hidden", SCROW(2), nRow1
);
3588 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2 & 3 should be hidden", SCROW(3), nRow2
);
3590 // Remove filtering.
3592 m_pDoc
->Query(0, aParam
, true);
3593 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3594 CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !bHidden
);
3595 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", SCROW(0), nRow1
);
3596 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", m_pDoc
->MaxRow(), nRow2
);
3598 // Filter for non-empty cells by column C.
3599 rEntry
.bDoQuery
= true;
3601 rEntry
.SetQueryByNonEmpty();
3602 m_pDoc
->Query(0, aParam
, true);
3604 // only row 3 should be hidden. The rest should be visible.
3605 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3606 CPPUNIT_ASSERT_MESSAGE("rows 1 & 2 should be visible.", !bHidden
);
3607 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 1 & 2 should be visible.", SCROW(0), nRow1
);
3608 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 1 & 2 should be visible.", SCROW(1), nRow2
);
3609 bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3610 CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden.", bHidden
);
3611 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be hidden.", SCROW(2), nRow1
);
3612 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be hidden.", SCROW(2), nRow2
);
3613 bHidden
= m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
);
3614 CPPUNIT_ASSERT_MESSAGE("row 4 and down should be visible.", !bHidden
);
3615 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 4 and down should be visible.", SCROW(3), nRow1
);
3616 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 4 and down should be visible.", m_pDoc
->MaxRow(), nRow2
);
3618 // Now, filter for empty cells by column C.
3619 rEntry
.SetQueryByEmpty();
3620 m_pDoc
->Query(0, aParam
, true);
3622 // Now, only row 1 and 3, and 6 and down should be visible.
3623 bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
3624 CPPUNIT_ASSERT_MESSAGE("row 1 should be visible.", !bHidden
);
3625 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 1 should be visible.", SCROW(0), nRow1
);
3626 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 1 should be visible.", SCROW(0), nRow2
);
3627 bHidden
= m_pDoc
->RowHidden(1, 0, &nRow1
, &nRow2
);
3628 CPPUNIT_ASSERT_MESSAGE("row 2 should be hidden.", bHidden
);
3629 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 2 should be hidden.", SCROW(1), nRow1
);
3630 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 2 should be hidden.", SCROW(1), nRow2
);
3631 bHidden
= m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
);
3632 CPPUNIT_ASSERT_MESSAGE("row 3 should be visible.", !bHidden
);
3633 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be visible.", SCROW(2), nRow1
);
3634 CPPUNIT_ASSERT_EQUAL_MESSAGE("row 3 should be visible.", SCROW(2), nRow2
);
3635 bHidden
= m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
);
3636 CPPUNIT_ASSERT_MESSAGE("rows 4 & 5 should be hidden.", bHidden
);
3637 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 4 & 5 should be hidden.", SCROW(3), nRow1
);
3638 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 4 & 5 should be hidden.", SCROW(4), nRow2
);
3639 bHidden
= m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
);
3640 CPPUNIT_ASSERT_MESSAGE("rows 6 and down should be all visible.", !bHidden
);
3641 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 6 and down should be all visible.", SCROW(5), nRow1
);
3642 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 6 and down should be all visible.", m_pDoc
->MaxRow(), nRow2
);
3644 m_pDoc
->DeleteTab(0);
3647 CPPUNIT_TEST_FIXTURE(Test
, testAutoFilterTimeValue
)
3649 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3651 m_pDoc
->SetString(ScAddress(0,0,0), u
"Hours"_ustr
);
3652 m_pDoc
->SetValue(ScAddress(0,1,0), 72.3604166666671);
3653 m_pDoc
->SetValue(ScAddress(0,2,0), 265);
3655 ScDBData
* pDBData
= new ScDBData(STR_DB_GLOBAL_NONAME
, 0, 0, 0, 0, 2);
3656 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3658 // Apply the "hour:minute:second" format to A2:A3.
3659 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3660 sal_uInt32 nFormat
= pFormatter
->GetFormatIndex(NF_TIME_HH_MMSS
, LANGUAGE_ENGLISH_US
);
3661 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3662 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3663 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3665 m_pDoc
->ApplyPatternAreaTab(0, 1, 0, 2, 0, aNewAttrs
); // apply it to A2:A3.
3667 printRange(m_pDoc
, ScRange(0,0,0,0,2,0), "Data"); // A1:A3
3669 // Make sure the hour:minute:second format is really applied.
3670 CPPUNIT_ASSERT_EQUAL(u
"1736:39:00"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0))); // A2
3671 CPPUNIT_ASSERT_EQUAL(u
"6360:00:00"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0))); // A3
3673 // Filter by the A2 value. Only A1 and A2 should be visible.
3674 ScQueryParam aParam
;
3675 pDBData
->GetQueryParam(aParam
);
3676 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
3677 rEntry
.bDoQuery
= true;
3679 rEntry
.eOp
= SC_EQUAL
;
3680 rEntry
.GetQueryItem().maString
= m_pDoc
->GetSharedStringPool().intern(u
"1736:39:00"_ustr
);
3681 rEntry
.GetQueryItem().meType
= ScQueryEntry::ByString
;
3683 pDBData
->SetQueryParam(aParam
);
3685 // perform the query.
3686 m_pDoc
->Query(0, aParam
, true);
3688 // A1:A2 should be visible while A3 should be filtered out.
3689 CPPUNIT_ASSERT_MESSAGE("A1 should be visible.", !m_pDoc
->RowFiltered(0,0));
3690 CPPUNIT_ASSERT_MESSAGE("A2 should be visible.", !m_pDoc
->RowFiltered(1,0));
3691 CPPUNIT_ASSERT_MESSAGE("A3 should be filtered out.", m_pDoc
->RowFiltered(2,0));
3693 m_pDoc
->DeleteTab(0);
3696 CPPUNIT_TEST_FIXTURE(Test
, testAutofilterOptimizations
)
3698 m_pDoc
->InsertTab( 0, u
"Test"_ustr
);
3700 constexpr SCCOL nCols
= 4;
3701 constexpr SCROW nRows
= 200;
3702 m_pDoc
->SetString(0, 0, 0, u
"Column1"_ustr
);
3703 m_pDoc
->SetString(1, 0, 0, u
"Column2"_ustr
);
3704 m_pDoc
->SetString(2, 0, 0, u
"Column3"_ustr
);
3705 m_pDoc
->SetString(3, 0, 0, u
"Column4"_ustr
);
3707 // Fill 1st column with 0-199, 2nd with 1-200, 3rd with "1000"-"1199", 4th with "1001-1200"
3708 // (the pairs are off by one to each other to check filtering out a value filters out
3709 // only the relevant column).
3710 for(SCROW i
= 0; i
< nRows
; ++i
)
3712 m_pDoc
->SetValue(0, i
+ 1, 0, i
);
3713 m_pDoc
->SetValue(1, i
+ 1, 0, i
+1);
3714 m_pDoc
->SetString(2, i
+ 1, 0, "val" + OUString::number(i
+1000));
3715 m_pDoc
->SetString(3, i
+ 1, 0, "val" + OUString::number(i
+1000+1));
3718 ScDBData
* pDBData
= new ScDBData(u
"NONAME"_ustr
, 0, 0, 0, nCols
, nRows
);
3719 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
3721 pDBData
->SetAutoFilter(true);
3723 pDBData
->GetArea(aRange
);
3724 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
3725 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
3726 aRange
.aStart
.Tab(), ScMF::Auto
);
3728 //create the query param
3729 ScQueryParam aParam
;
3730 pDBData
->GetQueryParam(aParam
);
3731 ScQueryEntry
& rEntry0
= aParam
.GetEntry(0);
3732 rEntry0
.bDoQuery
= true;
3734 rEntry0
.eOp
= SC_EQUAL
;
3735 rEntry0
.GetQueryItems().resize(nRows
);
3736 ScQueryEntry
& rEntry1
= aParam
.GetEntry(1);
3737 rEntry1
.bDoQuery
= true;
3739 rEntry1
.eOp
= SC_EQUAL
;
3740 rEntry1
.GetQueryItems().resize(nRows
);
3741 ScQueryEntry
& rEntry2
= aParam
.GetEntry(2);
3742 rEntry2
.bDoQuery
= true;
3744 rEntry2
.eOp
= SC_EQUAL
;
3745 rEntry2
.GetQueryItems().resize(nRows
);
3746 ScQueryEntry
& rEntry3
= aParam
.GetEntry(3);
3747 rEntry3
.bDoQuery
= true;
3749 rEntry3
.eOp
= SC_EQUAL
;
3750 rEntry3
.GetQueryItems().resize(nRows
);
3751 // Set up autofilter to select all values except one in each column.
3752 // This should only filter out 2nd, 3rd, 6th and 7th rows.
3753 for( int i
= 0; i
< nRows
; ++i
)
3756 rEntry0
.GetQueryItems()[i
].mfVal
= i
;
3758 rEntry1
.GetQueryItems()[i
].mfVal
= i
+ 1;
3761 rEntry2
.GetQueryItems()[i
].maString
= m_pDoc
->GetSharedStringPool().intern("val" + OUString::number(i
+1000));
3762 rEntry2
.GetQueryItems()[i
].meType
= ScQueryEntry::ByString
;
3766 rEntry3
.GetQueryItems()[i
].maString
= m_pDoc
->GetSharedStringPool().intern("val" + OUString::number(i
+1000+1));
3767 rEntry3
.GetQueryItems()[i
].meType
= ScQueryEntry::ByString
;
3770 // add queryParam to database range.
3771 pDBData
->SetQueryParam(aParam
);
3773 // perform the query.
3774 m_pDoc
->Query(0, aParam
, true);
3776 // check that only rows with filtered out values are hidden, and not rows that share
3777 // a value in a different column
3779 CPPUNIT_ASSERT_MESSAGE("row 2 should be visible", !m_pDoc
->RowHidden(1, 0, &nRow1
, &nRow2
));
3780 CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden", m_pDoc
->RowHidden(2, 0, &nRow1
, &nRow2
));
3781 CPPUNIT_ASSERT_MESSAGE("row 4 should be hidden", m_pDoc
->RowHidden(3, 0, &nRow1
, &nRow2
));
3782 CPPUNIT_ASSERT_MESSAGE("row 5 should be visible", !m_pDoc
->RowHidden(4, 0, &nRow1
, &nRow2
));
3783 CPPUNIT_ASSERT_MESSAGE("row 6 should be visible", !m_pDoc
->RowHidden(5, 0, &nRow1
, &nRow2
));
3784 CPPUNIT_ASSERT_MESSAGE("row 7 should be hidden", m_pDoc
->RowHidden(6, 0, &nRow1
, &nRow2
));
3785 CPPUNIT_ASSERT_MESSAGE("row 8 should be hidden", m_pDoc
->RowHidden(7, 0, &nRow1
, &nRow2
));
3786 CPPUNIT_ASSERT_MESSAGE("row 9 should be visible", !m_pDoc
->RowHidden(8, 0, &nRow1
, &nRow2
));
3788 // Remove filtering.
3792 m_pDoc
->Query(0, aParam
, true);
3793 CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
));
3794 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", SCROW(0), nRow1
);
3795 CPPUNIT_ASSERT_EQUAL_MESSAGE("All rows should be shown.", m_pDoc
->MaxRow(), nRow2
);
3797 m_pDoc
->DeleteTab(0);
3800 CPPUNIT_TEST_FIXTURE(Test
, testTdf76441
)
3802 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3804 // The result will be different depending on whether the format is set before
3805 // or after inserting the string
3807 OUString aCode
= u
"MM:SS"_ustr
;
3808 sal_Int32 nCheckPos
;
3809 SvNumFormatType nType
;
3811 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3812 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3814 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3815 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3816 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3818 // First insert the string, then the format
3819 m_pDoc
->SetString(ScAddress(0,0,0), u
"01:20"_ustr
);
3821 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3823 CPPUNIT_ASSERT_EQUAL(u
"20:00"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3827 // First set the format, then insert the string
3828 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3830 m_pDoc
->SetString(ScAddress(0,1,0), u
"01:20"_ustr
);
3832 // Without the fix in place, this test would have failed with
3833 // - Expected: 01:20
3835 CPPUNIT_ASSERT_EQUAL(u
"01:20"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
3838 m_pDoc
->DeleteTab(0);
3841 CPPUNIT_TEST_FIXTURE(Test
, testTdf76836
)
3843 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3845 OUString aCode
= u
"\"192.168.0.\"@"_ustr
;
3846 sal_Int32 nCheckPos
;
3847 SvNumFormatType nType
;
3849 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3850 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3852 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3853 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3854 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3856 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3857 m_pDoc
->SetValue(0,0,0, 10.0);
3859 // Without the fix in place, this test would have failed with
3861 // - Actual : 192.168.0.10
3862 CPPUNIT_ASSERT_EQUAL(u
"10"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3864 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3865 m_pDoc
->SetString(ScAddress(0,1,0), u
"10"_ustr
);
3866 CPPUNIT_ASSERT_EQUAL(u
"192.168.0.10"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
3868 m_pDoc
->DeleteTab(0);
3871 CPPUNIT_TEST_FIXTURE(Test
, testTdf151752
)
3873 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3875 m_pDoc
->SetString(ScAddress(0,0,0), u
"66000:00"_ustr
);
3877 // Without the fix in place, this test would have failed with
3878 // - Expected: 66000:00:00
3879 // - Actual : 464:00:00
3880 CPPUNIT_ASSERT_EQUAL(u
"66000:00:00"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3882 m_pDoc
->DeleteTab(0);
3885 CPPUNIT_TEST_FIXTURE(Test
, testTdf142186
)
3887 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3889 // The result will be different depending on whether the format is set before
3890 // or after inserting the string
3892 OUString aCode
= u
"0\".\"0"_ustr
;
3893 sal_Int32 nCheckPos
;
3894 SvNumFormatType nType
;
3896 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3897 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3899 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3900 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3901 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3903 // First insert the string, then the format
3904 m_pDoc
->SetString(ScAddress(0,0,0), u
"123.45"_ustr
);
3906 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3908 CPPUNIT_ASSERT_EQUAL(u
"12.3"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3912 // First set the format, then insert the string
3913 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
3915 m_pDoc
->SetString(ScAddress(0,1,0), u
"123.45"_ustr
);
3917 // Without the fix in place, this test would have failed with
3919 // - Actual : 1234.5
3920 CPPUNIT_ASSERT_EQUAL(u
"12.3"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
3923 m_pDoc
->DeleteTab(0);
3926 CPPUNIT_TEST_FIXTURE(Test
, testTdf137063
)
3928 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3930 m_pDoc
->SetValue(0,0,0, 0.000000006);
3931 m_pDoc
->SetValue(0,1,0, 0.0000000006);
3933 // Without the fix in place, this test would have failed with
3934 // - Expected: 0.000000006
3936 CPPUNIT_ASSERT_EQUAL(u
"0.000000006"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3937 CPPUNIT_ASSERT_EQUAL(u
"6E-10"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
3939 m_pDoc
->DeleteTab(0);
3942 CPPUNIT_TEST_FIXTURE(Test
, testTdf126342
)
3944 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3946 OUString aCode
= u
"YYYY-MM-DD"_ustr
;
3947 sal_Int32 nCheckPos
;
3948 SvNumFormatType nType
;
3950 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
3951 pFormatter
->PutEntry( aCode
, nCheckPos
, nType
, nFormat
);
3953 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
3954 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3955 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
3956 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
);
3958 m_pDoc
->SetString(ScAddress(0,0,0), u
"11/7/19"_ustr
);
3960 CPPUNIT_ASSERT_EQUAL(u
"2019-11-07"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3962 // Overwrite the existing date with the exact same input
3963 m_pDoc
->SetString(ScAddress(0,0,0), u
"11/7/19"_ustr
);
3965 // Without the fix in place, this test would have failed with
3966 // - Expected: 2019-11-07
3967 // - Actual : 2011-07-19
3968 CPPUNIT_ASSERT_EQUAL(u
"2019-11-07"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
3970 m_pDoc
->DeleteTab(0);
3973 CPPUNIT_TEST_FIXTURE(Test
, testAdvancedFilter
)
3975 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
3977 // cell contents (nullptr = empty cell)
3978 std::vector
<std::vector
<const char*>> aData
= {
3979 { "Value", "Tag" }, // A1:B11
3991 { "Value", "Tag" }, // A13:B14
3996 for (size_t nRow
= 0; nRow
< aData
.size(); ++nRow
)
3998 const std::vector
<const char*>& rRowData
= aData
[nRow
];
3999 for (size_t nCol
= 0; nCol
< rRowData
.size(); ++nCol
)
4001 const char* pCell
= rRowData
[nCol
];
4003 m_pDoc
->SetString(nCol
, nRow
, 0, OUString::createFromAscii(pCell
));
4007 ScDBData
* pDBData
= new ScDBData(STR_DB_GLOBAL_NONAME
, 0, 0, 0, 1, 10);
4008 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
4010 ScRange
aDataRange(0,0,0,1,10,0);
4011 ScRange
aFilterRuleRange(0,12,0,1,13,0);
4013 printRange(m_pDoc
, aDataRange
, "Data");
4014 printRange(m_pDoc
, aFilterRuleRange
, "Filter Rule");
4016 ScQueryParam aQueryParam
;
4017 aQueryParam
.bHasHeader
= true;
4018 aQueryParam
.nCol1
= aDataRange
.aStart
.Col();
4019 aQueryParam
.nRow1
= aDataRange
.aStart
.Row();
4020 aQueryParam
.nCol2
= aDataRange
.aEnd
.Col();
4021 aQueryParam
.nRow2
= aDataRange
.aEnd
.Row();
4022 aQueryParam
.nTab
= aDataRange
.aStart
.Tab();
4024 bool bGood
= m_pDoc
->CreateQueryParam(aFilterRuleRange
, aQueryParam
);
4025 CPPUNIT_ASSERT_MESSAGE("failed to create query param.", bGood
);
4027 // First entry is for the 'Value' field, and is greater than 5.
4028 ScQueryEntry aEntry
= aQueryParam
.GetEntry(0);
4029 CPPUNIT_ASSERT(aEntry
.bDoQuery
);
4030 CPPUNIT_ASSERT_EQUAL(SCCOLROW(0), aEntry
.nField
);
4031 CPPUNIT_ASSERT_EQUAL(SC_GREATER
, aEntry
.eOp
);
4033 ScQueryEntry::QueryItemsType aItems
= aEntry
.GetQueryItems();
4034 CPPUNIT_ASSERT_EQUAL(size_t(1), aItems
.size());
4035 CPPUNIT_ASSERT_EQUAL(ScQueryEntry::ByValue
, aItems
[0].meType
);
4036 CPPUNIT_ASSERT_EQUAL(5.0, aItems
[0].mfVal
);
4038 // Second entry is for the 'Tag' field, and is == 'R'.
4039 aEntry
= aQueryParam
.GetEntry(1);
4040 CPPUNIT_ASSERT(aEntry
.bDoQuery
);
4041 CPPUNIT_ASSERT_EQUAL(SCCOLROW(1), aEntry
.nField
);
4042 CPPUNIT_ASSERT_EQUAL(SC_EQUAL
, aEntry
.eOp
);
4044 aItems
= aEntry
.GetQueryItems();
4045 CPPUNIT_ASSERT_EQUAL(size_t(1), aItems
.size());
4046 CPPUNIT_ASSERT_EQUAL(ScQueryEntry::ByString
, aItems
[0].meType
);
4047 CPPUNIT_ASSERT_EQUAL(u
"R"_ustr
, aItems
[0].maString
.getString());
4049 // perform the query.
4050 m_pDoc
->Query(0, aQueryParam
, true);
4052 // Only rows 1,8-10 should be visible.
4053 bool bFiltered
= m_pDoc
->RowFiltered(0, 0);
4054 CPPUNIT_ASSERT_MESSAGE("row 1 (header row) should be visible", !bFiltered
);
4056 SCROW nRow1
= -1, nRow2
= -1;
4057 bFiltered
= m_pDoc
->RowFiltered(1, 0, &nRow1
, &nRow2
);
4058 CPPUNIT_ASSERT_MESSAGE("rows 2-7 should be filtered out.", bFiltered
);
4059 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2-7 should be filtered out.", SCROW(1), nRow1
);
4060 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 2-7 should be filtered out.", SCROW(6), nRow2
);
4062 bFiltered
= m_pDoc
->RowFiltered(7, 0, &nRow1
, &nRow2
);
4063 CPPUNIT_ASSERT_MESSAGE("rows 8-10 should be visible.", !bFiltered
);
4064 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 8-10 should be visible.", SCROW(7), nRow1
);
4065 CPPUNIT_ASSERT_EQUAL_MESSAGE("rows 8-10 should be visible.", SCROW(9), nRow2
);
4067 m_pDoc
->DeleteTab(0);
4070 CPPUNIT_TEST_FIXTURE(Test
, testDateFilterContains
)
4072 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
4074 constexpr SCCOL nCols
= 1;
4075 constexpr SCROW nRows
= 5;
4076 m_pDoc
->SetString(0, 0, 0, u
"Date"_ustr
);
4077 m_pDoc
->SetString(0, 1, 0, u
"1/2/2021"_ustr
);
4078 m_pDoc
->SetString(0, 2, 0, u
"2/1/1999"_ustr
);
4079 m_pDoc
->SetString(0, 3, 0, u
"2/1/1997"_ustr
);
4080 m_pDoc
->SetString(0, 4, 0, u
"3/3/2001"_ustr
);
4081 m_pDoc
->SetString(0, 5, 0, u
"3/3/1996"_ustr
);
4083 // Set the fields as dates.
4084 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
4085 sal_uInt32 nFormat
= pFormatter
->GetFormatIndex(NF_DATE_DIN_YYMMDD
, LANGUAGE_ENGLISH_US
);
4086 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
4087 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
4088 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
4089 m_pDoc
->ApplyPatternAreaTab(0, 1, 0, 5, 0, aNewAttrs
); // apply it to A1:A6
4091 ScDBData
* pDBData
= new ScDBData(u
"NONAME"_ustr
, 0, 0, 0, nCols
, nRows
);
4092 m_pDoc
->SetAnonymousDBData(0, std::unique_ptr
<ScDBData
>(pDBData
));
4094 pDBData
->SetAutoFilter(true);
4096 pDBData
->GetArea(aRange
);
4097 m_pDoc
->ApplyFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
4098 aRange
.aEnd
.Col(), aRange
.aStart
.Row(),
4099 aRange
.aStart
.Tab(), ScMF::Auto
);
4101 //create the query param
4102 ScQueryParam aParam
;
4103 pDBData
->GetQueryParam(aParam
);
4104 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
4105 rEntry
.bDoQuery
= true;
4107 rEntry
.eOp
= SC_CONTAINS
;
4108 rEntry
.GetQueryItem().maString
= m_pDoc
->GetSharedStringPool().intern(u
"2"_ustr
);
4109 pDBData
->SetQueryParam(aParam
);
4111 // perform the query.
4112 m_pDoc
->Query(0, aParam
, true);
4114 // Dates in rows 2-4 contain '2', row 5 shows 2001 only as 01, and row 6 doesn't contain it at all.
4115 CPPUNIT_ASSERT_MESSAGE("row 2 should be visible", !m_pDoc
->RowHidden(1, 0));
4116 CPPUNIT_ASSERT_MESSAGE("row 3 should be visible", !m_pDoc
->RowHidden(2, 0));
4117 CPPUNIT_ASSERT_MESSAGE("row 4 should be visible", !m_pDoc
->RowHidden(3, 0));
4118 CPPUNIT_ASSERT_MESSAGE("row 5 should be hidden", m_pDoc
->RowHidden(4, 0));
4119 CPPUNIT_ASSERT_MESSAGE("row 6 should be hidden", m_pDoc
->RowHidden(5, 0));
4121 m_pDoc
->DeleteTab(0);
4124 CPPUNIT_TEST_FIXTURE(Test
, testTdf98642
)
4126 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4127 m_pDoc
->SetString(0, 0, 0, u
"test"_ustr
);
4129 ScRangeData
* pName1
= new ScRangeData( *m_pDoc
, u
"name1"_ustr
, u
"$Sheet1.$A$1"_ustr
);
4130 ScRangeData
* pName2
= new ScRangeData( *m_pDoc
, u
"name2"_ustr
, u
"$Sheet1.$A$1"_ustr
);
4132 std::unique_ptr
<ScRangeName
> pGlobalRangeName(new ScRangeName());
4133 pGlobalRangeName
->insert(pName1
);
4134 pGlobalRangeName
->insert(pName2
);
4135 m_pDoc
->SetRangeName(std::move(pGlobalRangeName
));
4137 m_pDoc
->SetString(1, 0, 0, u
"=name1"_ustr
);
4138 m_pDoc
->SetString(1, 1, 0, u
"=name2"_ustr
);
4140 CPPUNIT_ASSERT_EQUAL(u
"test"_ustr
, m_pDoc
->GetString(1, 0, 0));
4141 CPPUNIT_ASSERT_EQUAL(u
"test"_ustr
, m_pDoc
->GetString(1, 1, 0));
4143 OUString aFormula
= m_pDoc
->GetFormula(1,0,0);
4144 CPPUNIT_ASSERT_EQUAL(u
"=name1"_ustr
, aFormula
);
4145 aFormula
= m_pDoc
->GetFormula(1,1,0);
4147 // Without the fix in place, this test would have failed with
4148 // - Expected: =name2
4149 // - Actual : =name1
4150 CPPUNIT_ASSERT_EQUAL(u
"=name2"_ustr
, aFormula
);
4152 m_pDoc
->DeleteTab(0);
4155 CPPUNIT_TEST_FIXTURE(Test
, testMergedCells
)
4157 //test merge and unmerge
4158 //TODO: an undo/redo test for this would be a good idea
4159 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4160 m_pDoc
->DoMerge(1, 1, 3, 3, 0, false);
4163 m_pDoc
->ExtendMerge( 1, 1, nEndCol
, nEndRow
, 0);
4164 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not merge cells", SCCOL(3), nEndCol
);
4165 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not merge cells", SCROW(3), nEndRow
);
4166 ScRange
aRange(0,2,0,m_pDoc
->MaxCol(),2,0);
4167 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4168 aMark
.SetMarkArea(aRange
);
4169 m_xDocShell
->GetDocFunc().InsertCells(aRange
, &aMark
, INS_INSROWS_BEFORE
, true, true);
4170 m_pDoc
->ExtendMerge(1, 1, nEndCol
, nEndRow
, 0);
4171 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not increase merge area", SCCOL(3), nEndCol
);
4172 CPPUNIT_ASSERT_EQUAL_MESSAGE("did not increase merge area", SCROW(4), nEndRow
);
4173 m_pDoc
->DeleteTab(0);
4176 CPPUNIT_TEST_FIXTURE(Test
, testRenameTable
)
4178 //test set rename table
4179 //TODO: set name1 and name2 and do an undo to check if name 1 is set now
4180 //TODO: also check if new name for table is same as another table
4182 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4183 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
4185 //test case 1 , rename table2 to sheet 1, it should return error
4186 OUString nameToSet
= u
"Sheet1"_ustr
;
4187 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4188 CPPUNIT_ASSERT_MESSAGE("name same as another table is being set", !rDocFunc
.RenameTable(1,nameToSet
,false,true) );
4190 //test case 2 , simple rename to check name
4191 nameToSet
= "test1";
4192 m_xDocShell
->GetDocFunc().RenameTable(0,nameToSet
,false,true);
4193 OUString nameJustSet
;
4194 m_pDoc
->GetName(0,nameJustSet
);
4195 CPPUNIT_ASSERT_EQUAL_MESSAGE("table not renamed", nameToSet
, nameJustSet
);
4197 //test case 3 , rename again
4199 m_pDoc
->GetName(0,anOldName
);
4201 nameToSet
= "test2";
4202 rDocFunc
.RenameTable(0,nameToSet
,false,true);
4203 m_pDoc
->GetName(0,nameJustSet
);
4204 CPPUNIT_ASSERT_EQUAL_MESSAGE("table not renamed", nameToSet
, nameJustSet
);
4206 //test case 4 , check if undo works
4207 SfxUndoAction
* pUndo
= new ScUndoRenameTab(m_xDocShell
.get(),0,anOldName
,nameToSet
);
4209 m_pDoc
->GetName(0,nameJustSet
);
4210 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct name is not set after undo", nameJustSet
, anOldName
);
4213 m_pDoc
->GetName(0,nameJustSet
);
4214 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after redo", nameJustSet
, nameToSet
);
4217 m_pDoc
->DeleteTab(0);
4218 m_pDoc
->DeleteTab(1);
4221 CPPUNIT_TEST_FIXTURE(Test
, testSetBackgroundColor
)
4223 //test set background color
4224 //TODO: set color1 and set color2 and do an undo to check if color1 is set now.
4226 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4231 m_xDocShell
->GetDocFunc().SetTabBgColor(0,aColor
,false, true);
4232 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set",
4233 aColor
, m_pDoc
->GetTabBgColor(0));
4235 Color aOldTabBgColor
=m_pDoc
->GetTabBgColor(0);
4237 m_xDocShell
->GetDocFunc().SetTabBgColor(0,aColor
,false, true);
4238 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set the second time",
4239 aColor
, m_pDoc
->GetTabBgColor(0));
4241 //now check for undo
4242 SfxUndoAction
* pUndo
= new ScUndoTabColor(m_xDocShell
.get(), 0, aOldTabBgColor
, aColor
);
4244 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after undo", aOldTabBgColor
, m_pDoc
->GetTabBgColor(0));
4246 CPPUNIT_ASSERT_EQUAL_MESSAGE("the correct color is not set after undo", aColor
, m_pDoc
->GetTabBgColor(0));
4248 m_pDoc
->DeleteTab(0);
4251 CPPUNIT_TEST_FIXTURE(Test
, testUpdateReference
)
4253 //test that formulas are correctly updated during sheet delete
4254 //TODO: add tests for relative references, updating of named ranges, ...
4255 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4256 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
4257 m_pDoc
->InsertTab(2, u
"Sheet3"_ustr
);
4258 m_pDoc
->InsertTab(3, u
"Sheet4"_ustr
);
4260 m_pDoc
->SetValue(0,0,2, 1);
4261 m_pDoc
->SetValue(1,0,2, 2);
4262 m_pDoc
->SetValue(1,1,3, 4);
4263 m_pDoc
->SetString(2,0,2, u
"=A1+B1"_ustr
);
4264 m_pDoc
->SetString(2,1,2, u
"=Sheet4.B2+A1"_ustr
);
4267 aValue
= m_pDoc
->GetValue(2,0,2);
4268 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", 3, aValue
);
4269 aValue
= m_pDoc
->GetValue(2,1,2);
4270 ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", 5, aValue
);
4272 //test deleting both sheets: one is not directly before the sheet, the other one is
4273 m_pDoc
->DeleteTab(0);
4274 aValue
= m_pDoc
->GetValue(2,0,1);
4275 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", 3, aValue
);
4276 aValue
= m_pDoc
->GetValue(2,1,1);
4277 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", 5, aValue
);
4279 m_pDoc
->DeleteTab(0);
4280 aValue
= m_pDoc
->GetValue(2,0,0);
4281 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", 3, aValue
);
4282 aValue
= m_pDoc
->GetValue(2,1,0);
4283 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", 5, aValue
);
4285 //test adding two sheets
4286 m_pDoc
->InsertTab(0, u
"Sheet2"_ustr
);
4287 aValue
= m_pDoc
->GetValue(2,0,1);
4288 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", 3, aValue
);
4289 aValue
= m_pDoc
->GetValue(2,1,1);
4290 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", 5, aValue
);
4292 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4293 aValue
= m_pDoc
->GetValue(2,0,2);
4294 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", 3, aValue
);
4295 aValue
= m_pDoc
->GetValue(2,1,2);
4296 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", 5, aValue
);
4298 //test new DeleteTabs/InsertTabs methods
4299 m_pDoc
->DeleteTabs(0, 2);
4300 aValue
= m_pDoc
->GetValue(2, 0, 0);
4301 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", 3, aValue
);
4302 aValue
= m_pDoc
->GetValue(2, 1, 0);
4303 ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", 5, aValue
);
4305 std::vector
<OUString
> aSheets
;
4306 aSheets
.emplace_back("Sheet1");
4307 aSheets
.emplace_back("Sheet2");
4308 m_pDoc
->InsertTabs(0, aSheets
, true);
4309 aValue
= m_pDoc
->GetValue(2, 0, 2);
4311 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", 3, aValue
);
4312 aValue
= m_pDoc
->GetValue(2, 1, 2);
4313 ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", 5, aValue
);
4315 m_pDoc
->DeleteTab(3);
4316 m_pDoc
->DeleteTab(2);
4317 m_pDoc
->DeleteTab(1);
4318 m_pDoc
->DeleteTab(0);
4320 // Test positional update and invalidation of lookup cache for insertion
4321 // and deletion within entire column reference.
4322 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
4323 m_pDoc
->InsertTab(1, u
"Sheet2"_ustr
);
4324 m_pDoc
->SetString(0,1,0, u
"s1"_ustr
);
4325 m_pDoc
->SetString(0,0,1, u
"=MATCH(\"s1\";Sheet1.A:A;0)"_ustr
);
4326 aValue
= m_pDoc
->GetValue(0,0,1);
4327 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 2, aValue
);
4328 m_pDoc
->InsertRow(0,0,m_pDoc
->MaxCol(),0,0,1); // insert 1 row before row 1 in Sheet1
4329 aValue
= m_pDoc
->GetValue(0,0,1);
4330 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 3, aValue
);
4331 m_pDoc
->DeleteRow(0,0,m_pDoc
->MaxCol(),0,0,1); // delete row 1 in Sheet1
4332 aValue
= m_pDoc
->GetValue(0,0,1);
4333 ASSERT_DOUBLES_EQUAL_MESSAGE("unexpected MATCH result", 2, aValue
);
4334 m_pDoc
->DeleteTab(1);
4335 m_pDoc
->DeleteTab(0);
4338 CPPUNIT_TEST_FIXTURE(Test
, testSearchCells
)
4340 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
4342 m_pDoc
->SetString(ScAddress(0,0,0), u
"A"_ustr
);
4343 m_pDoc
->SetString(ScAddress(0,1,0), u
"B"_ustr
);
4344 m_pDoc
->SetString(ScAddress(0,2,0), u
"A"_ustr
);
4346 m_pDoc
->SetString(ScAddress(0,4,0), u
"A"_ustr
);
4347 m_pDoc
->SetString(ScAddress(0,5,0), u
"B"_ustr
);
4348 m_pDoc
->SetString(ScAddress(0,6,0), u
"C"_ustr
);
4350 SvxSearchItem
aItem(SID_SEARCH_ITEM
);
4351 aItem
.SetSearchString(u
"A"_ustr
);
4352 aItem
.SetCommand(SvxSearchCmd::FIND_ALL
);
4353 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4354 aMarkData
.SelectOneTable(0);
4358 ScRangeList aMatchedRanges
;
4360 bool bMatchedRangesWereClamped
= false;
4361 bool bSuccess
= m_pDoc
->SearchAndReplace(aItem
, nCol
, nRow
, nTab
, aMarkData
, aMatchedRanges
, aUndoStr
, nullptr, bMatchedRangesWereClamped
);
4363 CPPUNIT_ASSERT_MESSAGE("Search And Replace should succeed", bSuccess
);
4364 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 3 matching cells.", size_t(3), aMatchedRanges
.size());
4365 ScAddress
aHit(0,0,0);
4366 CPPUNIT_ASSERT_MESSAGE("A1 should be inside the matched range.", aMatchedRanges
.Contains(ScRange(aHit
)));
4368 CPPUNIT_ASSERT_MESSAGE("A3 should be inside the matched range.", aMatchedRanges
.Contains(ScRange(aHit
)));
4370 CPPUNIT_ASSERT_MESSAGE("A5 should be inside the matched range.", aMatchedRanges
.Contains(ScRange(aHit
)));
4372 m_pDoc
->DeleteTab(0);
4375 CPPUNIT_TEST_FIXTURE(Test
, testFormulaPosition
)
4377 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
4379 ScAddress
aPos(0,0,0); // A1
4380 m_pDoc
->SetString(aPos
, u
"=ROW()"_ustr
);
4381 aPos
.IncRow(); // A2
4382 m_pDoc
->SetString(aPos
, u
"=ROW()"_ustr
);
4383 aPos
.SetRow(3); // A4;
4384 m_pDoc
->SetString(aPos
, u
"=ROW()"_ustr
);
4387 SCROW aRows
[] = { 0, 1, 3 };
4388 bool bRes
= checkFormulaPositions(*m_pDoc
, aPos
.Tab(), aPos
.Col(), aRows
, std::size(aRows
));
4389 CPPUNIT_ASSERT(bRes
);
4392 m_pDoc
->InsertRow(0,0,0,0,1,5); // Insert 5 rows at A2.
4394 SCROW aRows
[] = { 0, 6, 8 };
4395 bool bRes
= checkFormulaPositions(*m_pDoc
, aPos
.Tab(), aPos
.Col(), aRows
, std::size(aRows
));
4396 CPPUNIT_ASSERT(bRes
);
4399 m_pDoc
->DeleteTab(0);
4404 bool hasRange(const ScDocument
* pDoc
, const std::vector
<ScTokenRef
>& rRefTokens
, const ScRange
& rRange
, const ScAddress
& rPos
)
4406 for (const ScTokenRef
& p
: rRefTokens
)
4408 if (!ScRefTokenHelper::isRef(p
) || ScRefTokenHelper::isExternalRef(p
))
4411 switch (p
->GetType())
4413 case formula::svSingleRef
:
4415 ScSingleRefData aData
= *p
->GetSingleRef();
4416 if (rRange
.aStart
!= rRange
.aEnd
)
4419 ScAddress aThis
= aData
.toAbs(*pDoc
, rPos
);
4420 if (aThis
== rRange
.aStart
)
4424 case formula::svDoubleRef
:
4426 ScComplexRefData aData
= *p
->GetDoubleRef();
4427 ScRange aThis
= aData
.toAbs(*pDoc
, rPos
);
4428 if (aThis
== rRange
)
4441 CPPUNIT_TEST_FIXTURE(Test
, testJumpToPrecedentsDependents
)
4444 * Test to make sure correct precedent / dependent cells are obtained when
4445 * preparing to jump to them.
4447 // Precedent is another cell that the cell references, while dependent is
4448 // another cell that references it.
4449 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
4451 m_pDoc
->SetString(2, 0, 0, u
"=A1+A2+B3"_ustr
); // C1
4452 m_pDoc
->SetString(2, 1, 0, u
"=A1"_ustr
); // C2
4455 std::vector
<ScTokenRef
> aRefTokens
;
4456 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
4459 // C1's precedent should be A1:A2,B3.
4460 ScAddress
aC1(2, 0, 0);
4461 ScRangeList
aRange((ScRange(aC1
)));
4462 rDocFunc
.DetectiveCollectAllPreds(aRange
, aRefTokens
);
4463 CPPUNIT_ASSERT_MESSAGE("A1:A2 should be a precedent of C1.",
4464 hasRange(m_pDoc
, aRefTokens
, ScRange(0, 0, 0, 0, 1, 0), aC1
));
4465 CPPUNIT_ASSERT_MESSAGE("B3 should be a precedent of C1.",
4466 hasRange(m_pDoc
, aRefTokens
, ScRange(1, 2, 0), aC1
));
4470 // C2's precedent should be A1 only.
4471 ScAddress
aC2(2, 1, 0);
4472 ScRangeList
aRange((ScRange(aC2
)));
4473 rDocFunc
.DetectiveCollectAllPreds(aRange
, aRefTokens
);
4474 CPPUNIT_ASSERT_EQUAL_MESSAGE("there should only be one reference token.",
4475 static_cast<size_t>(1), aRefTokens
.size());
4476 CPPUNIT_ASSERT_MESSAGE("A1 should be a precedent of C1.",
4477 hasRange(m_pDoc
, aRefTokens
, ScRange(0, 0, 0), aC2
));
4481 // A1's dependent should be C1:C2.
4482 ScAddress
aA1(0, 0, 0);
4483 ScRangeList
aRange((ScRange(aA1
)));
4484 rDocFunc
.DetectiveCollectAllSuccs(aRange
, aRefTokens
);
4485 CPPUNIT_ASSERT_EQUAL_MESSAGE("C1:C2 should be the only dependent of A1.",
4486 std::vector
<ScTokenRef
>::size_type(1), aRefTokens
.size());
4487 CPPUNIT_ASSERT_MESSAGE("C1:C2 should be the only dependent of A1.",
4488 hasRange(m_pDoc
, aRefTokens
, ScRange(2, 0, 0, 2, 1, 0), aA1
));
4491 m_pDoc
->DeleteTab(0);
4494 CPPUNIT_TEST_FIXTURE(Test
, testTdf149665
)
4496 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
4498 m_pDoc
->SetString(0, 0, 0, u
"''1"_ustr
);
4500 // Without the fix in place, this test would have failed with
4503 CPPUNIT_ASSERT_EQUAL( u
"'1"_ustr
, m_pDoc
->GetString( 0, 0, 0 ) );
4505 m_pDoc
->DeleteTab(0);
4508 CPPUNIT_TEST_FIXTURE(Test
, testTdf64001
)
4510 m_pDoc
->InsertTab(0, u
"test"_ustr
);
4512 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4513 aMarkData
.SelectTable(0, true);
4515 m_pDoc
->SetString( 0, 0, 0, u
"TRUE"_ustr
);
4516 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 9, FILL_TO_BOTTOM
, FILL_AUTO
);
4518 for (SCCOL i
= 0; i
< 10; ++i
)
4520 CPPUNIT_ASSERT_EQUAL( u
"TRUE"_ustr
, m_pDoc
->GetString( 0, i
, 0 ) );
4523 m_pDoc
->SetString( 0, 10, 0, u
"FALSE"_ustr
);
4525 m_pDoc
->SetString( 1, 0, 0, u
"=COUNTIF(A1:A11;TRUE)"_ustr
);
4527 // Without the fix in place, this test would have failed with
4530 CPPUNIT_ASSERT_EQUAL( 10.0, m_pDoc
->GetValue( 1, 0, 0 ) );
4532 m_pDoc
->DeleteTab(0);
4535 CPPUNIT_TEST_FIXTURE(Test
, testAutoFill
)
4537 m_pDoc
->InsertTab(0, u
"test"_ustr
);
4539 m_pDoc
->SetValue(0,0,0,1);
4541 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4542 aMarkData
.SelectTable(0, true);
4544 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 5);
4545 for (SCROW i
= 0; i
< 6; ++i
)
4546 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
+1.0), m_pDoc
->GetValue(0, i
, 0));
4548 // check that hidden rows are not affected by autofill
4549 // set values for hidden rows
4550 m_pDoc
->SetValue(0,1,0,10);
4551 m_pDoc
->SetValue(0,2,0,10);
4553 m_pDoc
->SetRowHidden(1, 2, 0, true);
4554 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 8);
4556 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,1,0));
4557 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,2,0));
4558 for (SCROW i
= 3; i
< 8; ++i
)
4559 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
-1.0), m_pDoc
->GetValue(0, i
, 0));
4561 m_pDoc
->Fill( 0, 0, 0, 8, nullptr, aMarkData
, 5, FILL_TO_RIGHT
);
4562 for (SCCOL i
= 0; i
< 5; ++i
)
4564 for(SCROW j
= 0; j
< 8; ++j
)
4568 ASSERT_DOUBLES_EQUAL(static_cast<double>(j
-1+i
), m_pDoc
->GetValue(i
, j
, 0));
4572 ASSERT_DOUBLES_EQUAL(static_cast<double>(i
+1), m_pDoc
->GetValue(i
, 0, 0));
4574 else // j == 1 || j == 2
4577 ASSERT_DOUBLES_EQUAL(10.0, m_pDoc
->GetValue(0,j
,0));
4579 ASSERT_DOUBLES_EQUAL(0.0, m_pDoc
->GetValue(i
,j
,0));
4584 // test auto fill user data lists
4585 m_pDoc
->SetString( 0, 100, 0, u
"January"_ustr
);
4586 m_pDoc
->Fill( 0, 100, 0, 100, nullptr, aMarkData
, 2, FILL_TO_BOTTOM
, FILL_AUTO
);
4587 OUString aTestValue
= m_pDoc
->GetString( 0, 101, 0 );
4588 CPPUNIT_ASSERT_EQUAL( u
"February"_ustr
, aTestValue
);
4589 aTestValue
= m_pDoc
->GetString( 0, 102, 0 );
4590 CPPUNIT_ASSERT_EQUAL( u
"March"_ustr
, aTestValue
);
4592 // test that two same user data list entries will not result in incremental fill
4593 m_pDoc
->SetString( 0, 101, 0, u
"January"_ustr
);
4594 m_pDoc
->Fill( 0, 100, 0, 101, nullptr, aMarkData
, 2, FILL_TO_BOTTOM
, FILL_AUTO
);
4595 for ( SCROW i
= 102; i
<= 103; ++i
)
4597 aTestValue
= m_pDoc
->GetString( 0, i
, 0 );
4598 CPPUNIT_ASSERT_EQUAL( u
"January"_ustr
, aTestValue
);
4601 // Clear column A for a new test.
4602 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4603 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4605 // Fill A1:A6 with 1,2,3,4,5,6.
4606 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
4607 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
4608 ScRange
aRange(0,0,0,0,5,0);
4609 aMarkData
.SetMarkArea(aRange
);
4610 rFunc
.FillSeries(aRange
, &aMarkData
, FILL_TO_BOTTOM
, FILL_AUTO
, FILL_DAY
, MAXDOUBLE
, 1.0, MAXDOUBLE
, true);
4611 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4612 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4613 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
4614 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
4615 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
4616 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
4618 // Undo should clear the area except for the top cell.
4619 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
4620 CPPUNIT_ASSERT(pUndoMgr
);
4623 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4624 for (SCROW i
= 1; i
<= 5; ++i
)
4625 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE
, m_pDoc
->GetCellType(ScAddress(0,i
,0)));
4627 // Redo should put the serial values back in.
4629 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
4630 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4631 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
4632 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
4633 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
4634 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
4636 // test that filling formulas vertically up does the right thing
4637 for(SCROW nRow
= 0; nRow
< 10; ++nRow
)
4638 m_pDoc
->SetValue(100, 100 + nRow
, 0, 1);
4640 m_pDoc
->SetString(100, 110, 0, u
"=A111"_ustr
);
4642 m_pDoc
->Fill(100, 110, 100, 110, nullptr, aMarkData
, 10, FILL_TO_TOP
, FILL_AUTO
);
4643 for(SCROW nRow
= 110; nRow
>= 100; --nRow
)
4645 OUString aExpected
= "=A" + OUString::number(nRow
+1);
4646 OUString aFormula
= m_pDoc
->GetFormula(100, nRow
, 0);
4647 CPPUNIT_ASSERT_EQUAL(aExpected
, aFormula
);
4650 // Clear column A for a new test.
4651 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4652 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4654 m_pDoc
->SetString( 0, 100, 0, u
"2012-10-31"_ustr
);
4655 m_pDoc
->SetString( 0, 101, 0, u
"2012-10-31"_ustr
);
4656 m_pDoc
->Fill( 0, 100, 0, 101, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4658 // tdf#89754, Without the fix in place, this test would have failed with
4659 // - Expected: 2012-10-31
4660 // - Actual : 2012-11-01
4661 CPPUNIT_ASSERT_EQUAL( u
"2012-10-31"_ustr
, m_pDoc
->GetString( 0, 102, 0 ) );
4662 CPPUNIT_ASSERT_EQUAL( u
"2012-10-31"_ustr
, m_pDoc
->GetString( 0, 103, 0 ) );
4663 CPPUNIT_ASSERT_EQUAL( u
"2012-10-31"_ustr
, m_pDoc
->GetString( 0, 104, 0 ) );
4665 // Clear column A for a new test.
4666 clearRange(m_pDoc
, ScRange(0, 0, 0, 0, m_pDoc
->MaxRow(), 0));
4667 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4669 m_pDoc
->SetString(0, 100, 0, u
"2019-10-31"_ustr
);
4670 m_pDoc
->SetString(0, 101, 0, u
"2019-11-30"_ustr
);
4671 m_pDoc
->SetString(0, 102, 0, u
"2019-12-31"_ustr
);
4672 m_pDoc
->Fill(0, 100, 0, 102, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4674 // tdf#58745, Without the fix in place, this test would have failed with
4675 // - Expected: 2020-01-31
4676 // - Actual : 2019-01-11
4677 CPPUNIT_ASSERT_EQUAL(u
"2020-01-31"_ustr
, m_pDoc
->GetString(0, 103, 0));
4678 CPPUNIT_ASSERT_EQUAL(u
"2020-02-29"_ustr
, m_pDoc
->GetString(0, 104, 0));
4679 CPPUNIT_ASSERT_EQUAL(u
"2020-03-31"_ustr
, m_pDoc
->GetString(0, 105, 0));
4681 // Clear column A for a new test.
4682 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4683 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4685 m_pDoc
->SetString( 0, 50, 0, u
"1.0"_ustr
);
4686 m_pDoc
->SetString( 0, 51, 0, u
"1.1"_ustr
);
4687 m_pDoc
->SetString( 0, 52, 0, u
"1.2"_ustr
);
4688 m_pDoc
->SetString( 0, 53, 0, u
"1.3"_ustr
);
4689 m_pDoc
->Fill( 0, 50, 0, 53, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4691 CPPUNIT_ASSERT_EQUAL( u
"1.4"_ustr
, m_pDoc
->GetString( 0, 54, 0 ) );
4692 CPPUNIT_ASSERT_EQUAL( u
"1.5"_ustr
, m_pDoc
->GetString( 0, 55, 0 ) );
4693 CPPUNIT_ASSERT_EQUAL( u
"1.6"_ustr
, m_pDoc
->GetString( 0, 56, 0 ) );
4695 m_pDoc
->SetString( 0, 60, 0, u
"4.0"_ustr
);
4696 m_pDoc
->SetString( 0, 61, 0, u
"4.1"_ustr
);
4697 m_pDoc
->SetString( 0, 62, 0, u
"4.2"_ustr
);
4698 m_pDoc
->SetString( 0, 63, 0, u
"4.3"_ustr
);
4699 m_pDoc
->Fill( 0, 60, 0, 63, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4701 // tdf#37424: Without the fix in place, this test would have failed with
4704 CPPUNIT_ASSERT_EQUAL( u
"4.4"_ustr
, m_pDoc
->GetString( 0, 64, 0 ) );
4705 CPPUNIT_ASSERT_EQUAL( u
"4.5"_ustr
, m_pDoc
->GetString( 0, 65, 0 ) );
4706 CPPUNIT_ASSERT_EQUAL( u
"4.6"_ustr
, m_pDoc
->GetString( 0, 66, 0 ) );
4708 // Clear column A for a new test.
4709 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4710 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4712 m_pDoc
->SetString( 0, 70, 0, u
"001-001-001"_ustr
);
4713 m_pDoc
->Fill( 0, 70, 0, 70, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4715 // tdf#105268: Without the fix in place, this test would have failed with
4716 // - Expected: 001-001-002
4717 // - Actual : 001-001000
4718 CPPUNIT_ASSERT_EQUAL( u
"001-001-002"_ustr
, m_pDoc
->GetString( 0, 71, 0 ) );
4719 CPPUNIT_ASSERT_EQUAL( u
"001-001-003"_ustr
, m_pDoc
->GetString( 0, 72, 0 ) );
4720 CPPUNIT_ASSERT_EQUAL( u
"001-001-004"_ustr
, m_pDoc
->GetString( 0, 73, 0 ) );
4722 // Clear column A for a new test.
4723 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4724 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4726 m_pDoc
->SetString( 0, 80, 0, u
"1%"_ustr
);
4727 m_pDoc
->Fill( 0, 80, 0, 80, nullptr, aMarkData
, 3, FILL_TO_BOTTOM
, FILL_AUTO
);
4729 // tdf#89998: Without the fix in place, this test would have failed with
4730 // - Expected: 2.00%
4731 // - Actual : 101.00%
4732 CPPUNIT_ASSERT_EQUAL( u
"2.00%"_ustr
, m_pDoc
->GetString( 0, 81, 0 ) );
4733 CPPUNIT_ASSERT_EQUAL( u
"3.00%"_ustr
, m_pDoc
->GetString( 0, 82, 0 ) );
4734 CPPUNIT_ASSERT_EQUAL( u
"4.00%"_ustr
, m_pDoc
->GetString( 0, 83, 0 ) );
4736 // Clear column A for a new test.
4737 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4738 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4740 m_pDoc
->SetString( 0, 0, 0, u
"1"_ustr
);
4741 m_pDoc
->SetString( 0, 1, 0, u
"1.1"_ustr
);
4742 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 60, FILL_TO_BOTTOM
, FILL_AUTO
);
4744 // tdf#129606: Without the fix in place, this test would have failed with
4746 // - Actual : 6.00000000000001
4747 CPPUNIT_ASSERT_EQUAL( u
"6"_ustr
, m_pDoc
->GetString( 0, 50, 0 ) );
4749 // Clear column A for a new test.
4750 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4751 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4753 m_pDoc
->SetString( 0, 0, 0, u
"2022-10-01 00:00:00.000"_ustr
);
4754 m_pDoc
->SetString( 0, 1, 0, u
"2022-10-01 01:00:00.000"_ustr
);
4755 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 25, FILL_TO_BOTTOM
, FILL_AUTO
);
4757 // tdf#151460: Without the fix in place, this test would have failed with
4758 // - Expected: 2022-10-01 20:00:00.000
4759 // - Actual : 2022-10-01 19:59:59.999
4760 CPPUNIT_ASSERT_EQUAL( u
"2022-10-01 20:00:00.000"_ustr
, m_pDoc
->GetString( 0, 20, 0 ) );
4762 // Clear column A for a new test.
4763 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4764 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4766 m_pDoc
->SetString( 0, 0, 0, u
"1st"_ustr
);
4768 m_pDoc
->Fill( 0, 0, 0, 0, nullptr, aMarkData
, 5, FILL_TO_BOTTOM
, FILL_AUTO
);
4770 CPPUNIT_ASSERT_EQUAL( u
"1st"_ustr
, m_pDoc
->GetString( 0, 0, 0 ) );
4771 CPPUNIT_ASSERT_EQUAL( u
"2nd"_ustr
, m_pDoc
->GetString( 0, 1, 0 ) );
4772 CPPUNIT_ASSERT_EQUAL( u
"3rd"_ustr
, m_pDoc
->GetString( 0, 2, 0 ) );
4774 // Clear column A for a new test.
4775 clearRange(m_pDoc
, ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
4776 m_pDoc
->SetRowHidden(0, m_pDoc
->MaxRow(), 0, false); // Show all rows.
4778 m_pDoc
->SetString( 0, 200, 0, u
"15:00"_ustr
);
4779 m_pDoc
->SetString( 0, 201, 0, u
"15:20"_ustr
);
4780 m_pDoc
->Fill( 0, 200, 0, 201, nullptr, aMarkData
, 25, FILL_TO_BOTTOM
, FILL_AUTO
);
4782 CPPUNIT_ASSERT_EQUAL( u
"03:00:00 PM"_ustr
, m_pDoc
->GetString( 0, 200, 0 ) );
4784 // tdf#153517: Without the fix in place, this test would have failed with
4785 // - Expected: 03:20:00 PM
4786 // - Actual : 03:19:59 PM
4787 CPPUNIT_ASSERT_EQUAL( u
"03:20:00 PM"_ustr
, m_pDoc
->GetString( 0, 201, 0 ) );
4788 CPPUNIT_ASSERT_EQUAL( u
"03:40:00 PM"_ustr
, m_pDoc
->GetString( 0, 202, 0 ) );
4789 CPPUNIT_ASSERT_EQUAL( u
"04:00:00 PM"_ustr
, m_pDoc
->GetString( 0, 203, 0 ) );
4791 m_pDoc
->DeleteTab(0);
4794 CPPUNIT_TEST_FIXTURE(Test
, testAutoFillSimple
)
4796 m_pDoc
->InsertTab(0, u
"test"_ustr
);
4798 m_pDoc
->SetValue(0, 0, 0, 1);
4799 m_pDoc
->SetString(0, 1, 0, u
"=10"_ustr
);
4801 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
4802 aMarkData
.SelectTable(0, true);
4804 m_pDoc
->Fill( 0, 0, 0, 1, nullptr, aMarkData
, 6, FILL_TO_BOTTOM
, FILL_AUTO
);
4806 for(SCROW nRow
= 0; nRow
< 8; ++nRow
)
4810 double nVal
= m_pDoc
->GetValue(0, nRow
, 0);
4811 CPPUNIT_ASSERT_EQUAL((nRow
+2)/2.0, nVal
);
4815 OString aMsg
= "wrong value in row: " + OString::number(nRow
);
4816 double nVal
= m_pDoc
->GetValue(0, nRow
, 0);
4817 CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg
.getStr(), 10.0, nVal
);
4821 m_pDoc
->DeleteTab(0);
4824 CPPUNIT_TEST_FIXTURE(Test
, testFindAreaPosVertical
)
4826 std::vector
<std::vector
<const char*>> aData
= {
4827 { nullptr, "1", "1" },
4828 { "1", nullptr, "1" },
4830 { nullptr, "1", "1" },
4832 { "1", nullptr, "1" },
4836 m_pDoc
->InsertTab(0, u
"Test1"_ustr
);
4837 clearRange( m_pDoc
, ScRange(0, 0, 0, 1, aData
.size(), 0));
4838 ScAddress
aPos(0,0,0);
4839 ScRange aDataRange
= insertRangeData( m_pDoc
, aPos
, aData
);
4840 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
4842 m_pDoc
->SetRowHidden(4,4,0,true);
4843 bool bHidden
= m_pDoc
->RowHidden(4,0);
4844 CPPUNIT_ASSERT(bHidden
);
4848 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4850 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4851 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4853 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4855 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), nRow
);
4856 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4858 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4860 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(5), nRow
);
4861 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4863 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4865 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), nRow
);
4866 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4868 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4870 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxRow(), nRow
);
4871 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), nCol
);
4876 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4878 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(3), nRow
);
4879 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4881 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_DOWN
);
4883 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), nRow
);
4884 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4888 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_UP
);
4889 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4890 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), nCol
);
4892 m_pDoc
->DeleteTab(0);
4895 CPPUNIT_TEST_FIXTURE(Test
, testFindAreaPosColRight
)
4897 std::vector
<std::vector
<const char*>> aData
= {
4898 { "", "1", "1", "", "1", "1", "1" },
4899 { "", "", "1", "1", "1", "", "1" },
4902 m_pDoc
->InsertTab(0, u
"test1"_ustr
);
4903 clearRange( m_pDoc
, ScRange(0, 0, 0, 7, aData
.size(), 0));
4904 ScAddress
aPos(0,0,0);
4905 ScRange aDataRange
= insertRangeData( m_pDoc
, aPos
, aData
);
4906 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
4908 m_pDoc
->SetColHidden(4,4,0,true);
4909 bool bHidden
= m_pDoc
->ColHidden(4,0);
4910 CPPUNIT_ASSERT(bHidden
);
4914 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4916 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4917 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCol
);
4919 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4921 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4922 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), nCol
);
4924 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4926 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4927 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(5), nCol
);
4929 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4931 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4932 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(6), nCol
);
4934 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4936 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), nRow
);
4937 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxCol(), nCol
);
4942 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4944 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4945 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(3), nCol
);
4947 m_pDoc
->FindAreaPos(nCol
, nRow
, 0, SC_MOVE_RIGHT
);
4949 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), nRow
);
4950 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(6), nCol
);
4952 m_pDoc
->DeleteTab(0);
4955 CPPUNIT_TEST_FIXTURE(Test
, testShiftCells
)
4957 m_pDoc
->InsertTab(0, u
"foo"_ustr
);
4959 // We need a drawing layer in order to create caption objects.
4960 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
4962 OUString
aTestVal(u
"Some Text"_ustr
);
4964 // Text into cell E5.
4965 m_pDoc
->SetString(4, 3, 0, aTestVal
);
4967 // put a Note in cell E5
4968 ScAddress
rAddr(4, 3, 0);
4969 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
4970 pNote
->SetText(rAddr
, u
"Hello"_ustr
);
4972 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(4, 3, 0));
4974 // Insert cell at D5. This should shift the string cell to right.
4975 m_pDoc
->InsertCol(3, 0, 3, 0, 3, 1);
4976 OUString aStr
= m_pDoc
->GetString(5, 3, 0);
4977 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have a string cell here.", aTestVal
, aStr
);
4978 CPPUNIT_ASSERT_MESSAGE("D5 is supposed to be blank.", m_pDoc
->IsBlockEmpty(3, 4, 3, 4, 0));
4980 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc
->HasNote(4, 3, 0));
4981 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(5, 3, 0));
4983 // Delete cell D5, to shift the text cell back into D5.
4984 m_pDoc
->DeleteCol(3, 0, 3, 0, 3, 1);
4985 aStr
= m_pDoc
->GetString(4, 3, 0);
4986 CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have a string cell here.", aTestVal
, aStr
);
4987 CPPUNIT_ASSERT_MESSAGE("E5 is supposed to be blank.", m_pDoc
->IsBlockEmpty(4, 4, 4, 4, 0));
4989 CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc
->HasNote(5, 3, 0));
4990 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(4, 3, 0));
4992 m_pDoc
->DeleteTab(0);
4995 CPPUNIT_TEST_FIXTURE(Test
, testNoteDefaultStyle
)
4997 m_pDoc
->InsertTab(0, u
"PostIts"_ustr
);
4999 // We need a drawing layer in order to create caption objects.
5000 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5002 auto pNote
= m_pDoc
->GetOrCreateNote({0, 0, 0});
5003 auto pCaption
= pNote
->GetCaption();
5005 CPPUNIT_ASSERT(pCaption
);
5006 CPPUNIT_ASSERT_EQUAL(ScResId(STR_STYLENAME_NOTE
), pCaption
->GetStyleSheet()->GetName());
5008 m_pDoc
->DeleteTab(0);
5011 CPPUNIT_TEST_FIXTURE(Test
, testNoteBasic
)
5013 m_pDoc
->InsertTab(0, u
"PostIts"_ustr
);
5015 // We need a drawing layer in order to create caption objects.
5016 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5018 CPPUNIT_ASSERT(!m_pDoc
->HasNotes());
5020 // Check for note's presence in all tables before inserting any notes.
5021 for (SCTAB i
= 0; i
<= MAXTAB
; ++i
)
5023 bool bHasNotes
= m_pDoc
->HasTabNotes(i
);
5024 CPPUNIT_ASSERT(!bHasNotes
);
5027 ScAddress
aAddr(2, 2, 0); // cell C3
5028 ScPostIt
*pNote
= m_pDoc
->GetOrCreateNote(aAddr
);
5030 pNote
->SetText(aAddr
, u
"Hello world"_ustr
);
5031 pNote
->SetAuthor(u
"Jim Bob"_ustr
);
5033 ScPostIt
*pGetNote
= m_pDoc
->GetNote(aAddr
);
5034 CPPUNIT_ASSERT_EQUAL_MESSAGE("note should be itself", pNote
, pGetNote
);
5036 // Insert one row at row 1.
5037 bool bInsertRow
= m_pDoc
->InsertRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 1);
5038 CPPUNIT_ASSERT_MESSAGE("failed to insert row", bInsertRow
);
5040 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
5041 aAddr
.IncRow(); // cell C4
5042 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
5044 // Insert column at column A.
5045 bool bInsertCol
= m_pDoc
->InsertCol(0, 0, m_pDoc
->MaxRow(), 0, 1, 1);
5046 CPPUNIT_ASSERT_MESSAGE("failed to insert column", bInsertCol
);
5048 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
5049 aAddr
.IncCol(); // cell D4
5050 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
5052 // Insert a new sheet to shift the current sheet to the right.
5053 m_pDoc
->InsertTab(0, u
"Table2"_ustr
);
5054 CPPUNIT_ASSERT_MESSAGE("note hasn't moved", !m_pDoc
->GetNote(aAddr
));
5055 aAddr
.IncTab(); // Move to the next sheet.
5056 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
5058 m_pDoc
->DeleteTab(0);
5060 CPPUNIT_ASSERT_EQUAL_MESSAGE("note not there", pNote
, m_pDoc
->GetNote(aAddr
));
5062 // Insert cell at C4. This should NOT shift the note position.
5063 bInsertRow
= m_pDoc
->InsertRow(2, 0, 2, 0, 3, 1);
5064 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell at C4.", bInsertRow
);
5065 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note shouldn't have moved but it has.", pNote
, m_pDoc
->GetNote(aAddr
));
5067 // Delete cell at C4. Again, this should NOT shift the note position.
5068 m_pDoc
->DeleteRow(2, 0, 2, 0, 3, 1);
5069 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note shouldn't have moved but it has.", pNote
, m_pDoc
->GetNote(aAddr
));
5071 // Now, with the note at D4, delete cell D3. This should shift the note one cell up.
5072 m_pDoc
->DeleteRow(3, 0, 3, 0, 2, 1);
5073 aAddr
.IncRow(-1); // cell D3
5074 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at D4 should have shifted up to D3.", pNote
, m_pDoc
->GetNote(aAddr
));
5076 // Delete column C. This should shift the note one cell left.
5077 m_pDoc
->DeleteCol(0, 0, m_pDoc
->MaxRow(), 0, 2, 1);
5078 aAddr
.IncCol(-1); // cell C3
5079 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at D3 should have shifted left to C3.", pNote
, m_pDoc
->GetNote(aAddr
));
5081 // Insert a text where the note is.
5082 m_pDoc
->SetString(aAddr
, u
"Note is here."_ustr
);
5084 // Delete row 1. This should shift the note from C3 to C2.
5085 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 0, 1);
5086 aAddr
.IncRow(-1); // C2
5087 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note at C3 should have shifted up to C2.", pNote
, m_pDoc
->GetNote(aAddr
));
5089 m_pDoc
->DeleteTab(0);
5092 CPPUNIT_TEST_FIXTURE(Test
, testNoteDeleteRow
)
5094 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
5096 // We need a drawing layer in order to create caption objects.
5097 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5099 ScAddress
aPos(1, 1, 0);
5100 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5101 pNote
->SetText(aPos
, u
"Hello"_ustr
);
5102 pNote
->SetAuthor(u
"Jim Bob"_ustr
);
5104 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(1, 1, 0));
5106 // test with IsBlockEmpty
5107 CPPUNIT_ASSERT_MESSAGE("The Block should be detected as empty (no Notes)", m_pDoc
->IsEmptyData(0, 0, 100, 100, 0));
5108 CPPUNIT_ASSERT_MESSAGE("The Block should NOT be detected as empty", !m_pDoc
->IsBlockEmpty(0, 0, 100, 100, 0));
5110 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), 0, 1, 1);
5112 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc
->HasNote(1, 1, 0));
5114 // Set values and notes into B3:B4.
5115 aPos
= ScAddress(1,2,0); // B3
5116 m_pDoc
->SetString(aPos
, u
"First"_ustr
);
5117 ScNoteUtil::CreateNoteFromString(*m_pDoc
, aPos
, u
"First Note"_ustr
, false, false);
5119 aPos
= ScAddress(1,3,0); // B4
5120 m_pDoc
->SetString(aPos
, u
"Second"_ustr
);
5121 ScNoteUtil::CreateNoteFromString(*m_pDoc
, aPos
, u
"Second Note"_ustr
, false, false);
5124 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
5125 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5126 aMark
.SelectOneTable(0);
5127 rDocFunc
.DeleteCells(ScRange(0,1,0,m_pDoc
->MaxCol(),1,0), &aMark
, DelCellCmd::CellsUp
, true);
5129 // Check to make sure the notes have shifted upward.
5130 pNote
= m_pDoc
->GetNote(ScAddress(1,1,0));
5131 CPPUNIT_ASSERT_MESSAGE("B2 should have a note.", pNote
);
5132 CPPUNIT_ASSERT_EQUAL(u
"First Note"_ustr
, pNote
->GetText());
5133 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
5134 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
5135 CPPUNIT_ASSERT_EQUAL(u
"Second Note"_ustr
, pNote
->GetText());
5136 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
5137 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote
);
5141 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5142 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr
);
5143 m_pDoc
->CreateAllNoteCaptions(); // to make sure that all notes have their corresponding caption objects...
5146 pNote
= m_pDoc
->GetNote(ScAddress(1,1,0));
5147 CPPUNIT_ASSERT_MESSAGE("B2 should NOT have a note.", !pNote
);
5148 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
5149 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
5150 CPPUNIT_ASSERT_EQUAL(u
"First Note"_ustr
, pNote
->GetText());
5151 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
5152 CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote
);
5153 CPPUNIT_ASSERT_EQUAL(u
"Second Note"_ustr
, pNote
->GetText());
5156 rDocFunc
.DeleteCells(ScRange(0,2,0,m_pDoc
->MaxCol(),2,0), &aMark
, DelCellCmd::CellsUp
, true);
5158 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
5159 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
5160 CPPUNIT_ASSERT_EQUAL(u
"Second Note"_ustr
, pNote
->GetText());
5161 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
5162 CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote
);
5164 // Undo and check the result.
5166 pNote
= m_pDoc
->GetNote(ScAddress(1,2,0));
5167 CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote
);
5168 CPPUNIT_ASSERT_EQUAL(u
"First Note"_ustr
, pNote
->GetText());
5169 pNote
= m_pDoc
->GetNote(ScAddress(1,3,0));
5170 CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote
);
5171 CPPUNIT_ASSERT_EQUAL(u
"Second Note"_ustr
, pNote
->GetText());
5173 m_pDoc
->DeleteTab(0);
5176 CPPUNIT_TEST_FIXTURE(Test
, testNoteDeleteCol
)
5178 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
5180 // We need a drawing layer in order to create caption objects.
5181 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5183 ScAddress
rAddr(1, 1, 0);
5184 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
5185 pNote
->SetText(rAddr
, u
"Hello"_ustr
);
5186 pNote
->SetAuthor(u
"Jim Bob"_ustr
);
5188 CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc
->HasNote(1, 1, 0));
5190 m_pDoc
->DeleteCol(0, 0, m_pDoc
->MaxRow(), 0, 1, 1);
5192 CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc
->HasNote(1, 1, 0));
5194 m_pDoc
->DeleteTab(0);
5197 CPPUNIT_TEST_FIXTURE(Test
, testNoteLifeCycle
)
5199 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5201 // We need a drawing layer in order to create caption objects.
5202 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5204 ScAddress
aPos(1,1,0);
5205 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5206 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new cell comment.", pNote
);
5208 pNote
->SetText(aPos
, u
"New note"_ustr
);
5209 std::unique_ptr
<ScPostIt
> pNote2
= m_pDoc
->ReleaseNote(aPos
);
5210 CPPUNIT_ASSERT_EQUAL_MESSAGE("This note instance is expected to be identical to the original.", pNote
, pNote2
.get());
5211 CPPUNIT_ASSERT_MESSAGE("The note shouldn't be here after it's been released.", !m_pDoc
->HasNote(aPos
));
5213 // Modify the internal state of the note instance to make sure it's really
5215 pNote
->SetText(aPos
, u
"New content"_ustr
);
5217 // Re-insert the note back to the same place.
5218 m_pDoc
->SetNote(aPos
, std::move(pNote2
));
5219 SdrCaptionObj
* pCaption
= pNote
->GetOrCreateCaption(aPos
);
5220 CPPUNIT_ASSERT_MESSAGE("Failed to create a caption object.", pCaption
);
5221 CPPUNIT_ASSERT_EQUAL_MESSAGE("This caption should belong to the drawing layer of the document.",
5222 m_pDoc
->GetDrawLayer(), static_cast<ScDrawLayer
*>(&pCaption
->getSdrModelFromSdrObject()));
5224 // Copy B2 with note to a clipboard.
5226 ScClipParam
aClipParam(ScRange(aPos
), false);
5227 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
5228 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
5229 aMarkData
.SelectOneTable(0);
5230 m_pDoc
->CopyToClip(aClipParam
, &aClipDoc
, &aMarkData
, false, true);
5232 ScPostIt
* pClipNote
= aClipDoc
.GetNote(aPos
);
5233 CPPUNIT_ASSERT_MESSAGE("Failed to copy note to the clipboard.", pClipNote
);
5234 CPPUNIT_ASSERT_EQUAL_MESSAGE("Note on the clipboard should share the same caption object from the original.",
5235 pCaption
, pClipNote
->GetCaption());
5238 // Move B2 to B3 with note, which creates an ScUndoDragDrop, and Undo.
5240 ScAddress
aOrigPos(aPos
);
5241 ScAddress
aMovePos(1,2,0);
5242 ScPostIt
* pOrigNote
= m_pDoc
->GetNote(aOrigPos
);
5243 const SdrCaptionObj
* pOrigCaption
= pOrigNote
->GetOrCreateCaption(aOrigPos
);
5244 bool const bCut
= true; // like Drag&Drop
5245 bool bRecord
= true; // record Undo
5246 bool const bPaint
= false; // don't care about
5247 bool bApi
= true; // API to prevent dialogs
5248 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
5249 bool bMoveDone
= rDocFunc
.MoveBlock(ScRange(aOrigPos
, aOrigPos
), aMovePos
, bCut
, bRecord
, bPaint
, bApi
);
5250 CPPUNIT_ASSERT_MESSAGE("Cells not moved", bMoveDone
);
5252 // Verify the note move.
5253 ScPostIt
* pGoneNote
= m_pDoc
->GetNote(aOrigPos
);
5254 CPPUNIT_ASSERT_MESSAGE("Failed to move the note from source.", !pGoneNote
);
5255 ScPostIt
* pMoveNote
= m_pDoc
->GetNote(aMovePos
);
5256 CPPUNIT_ASSERT_MESSAGE("Failed to move the note to destination.", pMoveNote
);
5258 // The caption object should not be identical, it was newly created upon
5259 // Drop from clipboard.
5260 // pOrigCaption is a dangling pointer.
5261 const SdrCaptionObj
* pMoveCaption
= pMoveNote
->GetOrCreateCaption(aMovePos
);
5262 CPPUNIT_ASSERT_MESSAGE("Captions identical after move.", pOrigCaption
!= pMoveCaption
);
5264 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5265 CPPUNIT_ASSERT(pUndoMgr
);
5266 pUndoMgr
->Undo(); // this should not crash ... tdf#92995
5268 // Verify the note move Undo.
5269 pMoveNote
= m_pDoc
->GetNote(aMovePos
);
5270 CPPUNIT_ASSERT_MESSAGE("Failed to undo the note move from destination.", !pMoveNote
);
5271 pOrigNote
= m_pDoc
->GetNote(aOrigPos
);
5272 CPPUNIT_ASSERT_MESSAGE("Failed to undo the note move to source.", pOrigNote
);
5274 // The caption object still should not be identical.
5275 // pMoveCaption is a dangling pointer.
5276 pOrigCaption
= pOrigNote
->GetOrCreateCaption(aOrigPos
);
5277 CPPUNIT_ASSERT_MESSAGE("Captions identical after move undo.", pOrigCaption
!= pMoveCaption
);
5280 // Create a note at B4, merge B4 and B5 with ScUndoMerge, and Undo.
5282 ScAddress
aPosB4(1,3,0);
5283 ScPostIt
* pNoteB4
= m_pDoc
->GetOrCreateNote(aPosB4
);
5284 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B4.", pNoteB4
);
5285 const SdrCaptionObj
* pCaptionB4
= pNoteB4
->GetOrCreateCaption(aPosB4
);
5286 ScCellMergeOption
aCellMergeOption(1,3,2,3);
5287 rDocFunc
.MergeCells( aCellMergeOption
, true /*bContents*/, bRecord
, bApi
, false /*bEmptyMergedCells*/ );
5289 SfxUndoManager
* pMergeUndoManager
= m_pDoc
->GetUndoManager();
5290 CPPUNIT_ASSERT(pMergeUndoManager
);
5291 pMergeUndoManager
->Undo(); // this should not crash ... tdf#105667
5293 // Undo contained the original caption object pointer which was still alive
5294 // at B4 after the merge and not cloned nor recreated during Undo.
5295 ScPostIt
* pUndoNoteB4
= m_pDoc
->GetNote(aPosB4
);
5296 CPPUNIT_ASSERT_MESSAGE("No cell comment at B4 after Undo.", pUndoNoteB4
);
5297 const SdrCaptionObj
* pUndoCaptionB4
= pUndoNoteB4
->GetCaption();
5298 CPPUNIT_ASSERT_EQUAL_MESSAGE("Captions not identical after Merge Undo.", pCaptionB4
, pUndoCaptionB4
);
5301 // In a second document copy a note from B5 to clipboard, close the
5302 // document and then paste the note into this document.
5304 ScDocShellRef xDocSh2
;
5305 getNewDocShell(xDocSh2
);
5306 ScDocument
* pDoc2
= &xDocSh2
->GetDocument();
5307 pDoc2
->InsertTab(0, u
"OtherSheet1"_ustr
);
5308 pDoc2
->InitDrawLayer(xDocSh2
.get());
5310 ScAddress
aPosB5(1,4,0);
5311 ScPostIt
* pOtherNoteB5
= pDoc2
->GetOrCreateNote(aPosB5
);
5312 CPPUNIT_ASSERT_MESSAGE("Failed to insert cell comment at B5.", pOtherNoteB5
);
5313 const SdrCaptionObj
* pOtherCaptionB5
= pOtherNoteB5
->GetOrCreateCaption(aPosB5
);
5314 CPPUNIT_ASSERT_MESSAGE("No caption at B5.", pOtherCaptionB5
);
5316 ScDocument
aClipDoc2(SCDOCMODE_CLIP
);
5317 copyToClip( pDoc2
, ScRange(aPosB5
), &aClipDoc2
);
5319 // There's no ScTransferObject involved in the "fake" clipboard copy
5320 // and ScDocument dtor asking IsClipboardSource() gets no, so emulate
5321 // the part that normally is responsible for forgetting the caption
5323 aClipDoc2
.ClosingClipboardSource();
5325 pDoc2
->DeleteTab(0);
5329 pasteFromClip( m_pDoc
, ScRange(aPosB5
), &aClipDoc2
); // should not crash... tdf#104967
5330 ScPostIt
* pNoteB5
= m_pDoc
->GetNote(aPosB5
);
5331 CPPUNIT_ASSERT_MESSAGE("Failed to paste cell comment at B5.", pNoteB5
);
5332 const SdrCaptionObj
* pCaptionB5
= pNoteB5
->GetOrCreateCaption(aPosB5
);
5333 CPPUNIT_ASSERT_MESSAGE("No caption at pasted B5.", pCaptionB5
);
5334 // Do not test if pCaptionB5 != pOtherCaptionB5 because since pDoc2
5335 // has been closed and the caption been deleted objects *may* be
5336 // allocated at the very same memory location.
5339 m_pDoc
->DeleteTab(0);
5342 CPPUNIT_TEST_FIXTURE(Test
, testNoteCopyPaste
)
5344 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5346 // We need a drawing layer in order to create caption objects.
5347 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5349 // Insert in B2 a text and cell comment.
5350 ScAddress
aPos(1,1,0);
5351 m_pDoc
->SetString(aPos
, u
"Text"_ustr
);
5352 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5353 CPPUNIT_ASSERT(pNote
);
5354 pNote
->SetText(aPos
, u
"Note1"_ustr
);
5356 // Insert in B4 a number and cell comment.
5358 m_pDoc
->SetValue(aPos
, 1.1);
5359 pNote
= m_pDoc
->GetOrCreateNote(aPos
);
5360 CPPUNIT_ASSERT(pNote
);
5361 pNote
->SetText(aPos
, u
"Note2"_ustr
);
5363 // Copy B2:B4 to clipboard.
5364 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5365 aMark
.SelectOneTable(0);
5366 ScRange
aCopyRange(1,1,0,1,3,0);
5367 ScDocument
aClipDoc(SCDOCMODE_CLIP
);
5368 aClipDoc
.ResetClip(m_pDoc
, &aMark
);
5369 ScClipParam
aClipParam(aCopyRange
, false);
5370 m_pDoc
->CopyToClip(aClipParam
, &aClipDoc
, &aMark
, false, false);
5372 // Make sure the notes are in the clipboard.
5373 pNote
= aClipDoc
.GetNote(ScAddress(1,1,0));
5374 CPPUNIT_ASSERT(pNote
);
5375 CPPUNIT_ASSERT_EQUAL(u
"Note1"_ustr
, pNote
->GetText());
5377 pNote
= aClipDoc
.GetNote(ScAddress(1,3,0));
5378 CPPUNIT_ASSERT(pNote
);
5379 CPPUNIT_ASSERT_EQUAL(u
"Note2"_ustr
, pNote
->GetText());
5381 // Paste to B6:B8 but only cell notes.
5382 ScRange
aDestRange(1,5,0,1,7,0);
5383 m_pDoc
->CopyFromClip(aDestRange
, aMark
, InsertDeleteFlags::NOTE
, nullptr, &aClipDoc
);
5385 // Make sure the notes are there.
5386 pNote
= m_pDoc
->GetNote(ScAddress(1,5,0));
5387 CPPUNIT_ASSERT(pNote
);
5388 CPPUNIT_ASSERT_EQUAL(u
"Note1"_ustr
, pNote
->GetText());
5390 pNote
= m_pDoc
->GetNote(ScAddress(1,7,0));
5391 CPPUNIT_ASSERT(pNote
);
5392 CPPUNIT_ASSERT_EQUAL(u
"Note2"_ustr
, pNote
->GetText());
5394 // Test that GetNotesInRange includes the end of its range
5395 // and so can find the note
5396 std::vector
<sc::NoteEntry
> aNotes
;
5397 m_pDoc
->GetNotesInRange(ScRange(1,7,0), aNotes
);
5398 CPPUNIT_ASSERT_EQUAL(size_t(1), aNotes
.size());
5400 m_pDoc
->DeleteTab(0);
5404 CPPUNIT_TEST_FIXTURE(Test
, testNoteContainsNotesInRange
)
5406 m_pDoc
->InsertTab(0, u
"PostIts"_ustr
);
5408 // We need a drawing layer in order to create caption objects.
5409 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5411 ScAddress
aAddr(2, 2, 0); // cell C3
5413 CPPUNIT_ASSERT_MESSAGE("Claiming there's notes in a document that doesn't have any.",
5414 !m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), aAddr
))));
5416 m_pDoc
->GetOrCreateNote(aAddr
);
5418 CPPUNIT_ASSERT_MESSAGE("Claiming there's notes in range that doesn't have any.",
5419 !m_pDoc
->ContainsNotesInRange(ScRange(ScAddress(0, 0, 0), ScAddress(0, 1, 0))));
5420 CPPUNIT_ASSERT_MESSAGE("Note not detected that lies on border of range.",
5421 m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), aAddr
))));
5422 CPPUNIT_ASSERT_MESSAGE("Note not detected that lies in inner area of range.",
5423 m_pDoc
->ContainsNotesInRange((ScRange(ScAddress(0, 0, 0), ScAddress(3, 3, 0)))));
5426 CPPUNIT_TEST_FIXTURE(Test
, testAreasWithNotes
)
5428 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
5430 // We need a drawing layer in order to create caption objects.
5431 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
5433 ScAddress
rAddr(1, 5, 0);
5434 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(rAddr
);
5435 pNote
->SetText(rAddr
, u
"Hello"_ustr
);
5436 pNote
->SetAuthor(u
"Jim Bob"_ustr
);
5437 ScAddress
rAddrMin(2, 2, 0);
5438 ScPostIt
* pNoteMin
= m_pDoc
->GetOrCreateNote(rAddrMin
);
5439 pNoteMin
->SetText(rAddrMin
, u
"Hello"_ustr
);
5445 // only cell notes (empty content)
5447 dataFound
= m_pDoc
->GetDataStart(0,col
,row
);
5449 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound
);
5450 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong col for notes", static_cast<SCCOL
>(1), col
);
5451 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong row for notes", static_cast<SCROW
>(2), row
);
5453 dataFound
= m_pDoc
->GetCellArea(0,col
,row
);
5455 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound
);
5456 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong col for notes", static_cast<SCCOL
>(2), col
);
5457 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong row for notes", static_cast<SCROW
>(5), row
);
5460 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5462 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5463 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col for notes", static_cast<SCCOL
>(2), col
);
5464 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row for notes", static_cast<SCROW
>(5), row
);
5467 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5468 CPPUNIT_ASSERT_MESSAGE("No PrintArea should be found", !dataFound
);
5471 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5472 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5473 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(5), row
);
5475 dataFound
= m_pDoc
->GetPrintAreaVer(0,2,3,row
, bNotes
); // cols 2 & 3
5476 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5477 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(2), row
);
5479 dataFound
= m_pDoc
->GetPrintAreaVer(0,20,21,row
, bNotes
); // cols 20 & 21
5480 CPPUNIT_ASSERT_MESSAGE("PrintAreaVer found", !dataFound
);
5481 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row for notes", static_cast<SCROW
>(0), row
);
5484 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // col 0 & 1
5485 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer should be found", !dataFound
);
5487 // now add cells with value, check that notes are taken into account in good cases
5489 m_pDoc
->SetString(0, 3, 0, u
"Some Text"_ustr
);
5490 m_pDoc
->SetString(3, 3, 0, u
"Some Text"_ustr
);
5492 dataFound
= m_pDoc
->GetDataStart(0,col
,row
);
5494 CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound
);
5495 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong col", static_cast<SCCOL
>(0), col
);
5496 CPPUNIT_ASSERT_EQUAL_MESSAGE("DataStart wrong row", static_cast<SCROW
>(2), row
);
5498 dataFound
= m_pDoc
->GetCellArea(0,col
,row
);
5500 CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound
);
5501 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong col", static_cast<SCCOL
>(3), col
);
5502 CPPUNIT_ASSERT_EQUAL_MESSAGE("CellArea wrong row", static_cast<SCROW
>(5), row
);
5505 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5507 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5508 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col", static_cast<SCCOL
>(3), col
);
5509 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row", static_cast<SCROW
>(5), row
);
5512 dataFound
= m_pDoc
->GetPrintArea(0,col
,row
, bNotes
);
5513 CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound
);
5514 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong col", static_cast<SCCOL
>(3), col
);
5515 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintArea wrong row", static_cast<SCROW
>(3), row
);
5518 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5519 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5520 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(5), row
);
5522 dataFound
= m_pDoc
->GetPrintAreaVer(0,2,3,row
, bNotes
); // cols 2 & 3
5523 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5524 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(3), row
);
5527 dataFound
= m_pDoc
->GetPrintAreaVer(0,0,1,row
, bNotes
); // cols 0 & 1
5528 CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound
);
5529 CPPUNIT_ASSERT_EQUAL_MESSAGE("PrintAreaVer wrong row", static_cast<SCROW
>(3), row
);
5531 m_pDoc
->DeleteTab(0);
5534 CPPUNIT_TEST_FIXTURE(Test
, testAnchoredRotatedShape
)
5536 m_pDoc
->InsertTab(0, u
"TestTab"_ustr
);
5538 bool bHidden
= m_pDoc
->RowHidden(0, 0, &nRow1
, &nRow2
);
5539 CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden
);
5540 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", SCROW(0), nRow1
);
5541 CPPUNIT_ASSERT_EQUAL_MESSAGE("new sheet should have all rows visible", m_pDoc
->MaxRow(), nRow2
);
5543 m_pDoc
->InitDrawLayer();
5544 ScDrawLayer
*pDrawLayer
= m_pDoc
->GetDrawLayer();
5545 CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer
!= nullptr);
5546 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
5547 CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage
!= nullptr);
5548 m_pDoc
->SetRowHeightRange(0, m_pDoc
->MaxRow(), 0, o3tl::toTwips(1000, o3tl::Length::mm100
));
5549 constexpr tools::Long TOLERANCE
= 30; //30 hmm
5550 for ( SCCOL nCol
= 0; nCol
< m_pDoc
->MaxCol(); ++nCol
)
5551 m_pDoc
->SetColWidth(nCol
, 0, o3tl::toTwips(1000, o3tl::Length::mm100
));
5554 tools::Rectangle
aRect( 4000, 5000, 10000, 7000 );
5556 tools::Rectangle
aRotRect( 6000, 3000, 8000, 9000 );
5557 rtl::Reference
<SdrRectObj
> pObj
= new SdrRectObj(*pDrawLayer
, aRect
);
5558 pPage
->InsertObject(pObj
.get());
5559 Point
aRef1(pObj
->GetSnapRect().Center());
5560 Degree100 nAngle
= 9000_deg100
; //90 deg.
5561 double nSin
= 1.0; // sin(90 deg)
5562 double nCos
= 0.0; // cos(90 deg)
5563 pObj
->Rotate(aRef1
,nAngle
,nSin
,nCos
);
5565 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, true);
5567 tools::Rectangle aSnap
= pObj
->GetSnapRect();
5568 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetHeight(), aSnap
.GetHeight(), TOLERANCE
);
5569 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetWidth(), aSnap
.GetWidth(), TOLERANCE
);
5570 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.Left(), aSnap
.Left(), TOLERANCE
);
5571 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.Top(), aSnap
.Top(), TOLERANCE
);
5573 ScDrawObjData aAnchor
;
5574 ScDrawObjData
* pData
= ScDrawLayer::GetObjData( pObj
.get() );
5575 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData
);
5577 aAnchor
.maStart
= pData
->maStart
;
5578 aAnchor
.maEnd
= pData
->maEnd
;
5580 m_pDoc
->SetDrawPageSize(0);
5582 // increase row 5 by 2000 hmm
5583 m_pDoc
->SetRowHeight(5, 0, o3tl::toTwips(3000, o3tl::Length::mm100
));
5584 // increase col 6 by 1000 hmm
5585 m_pDoc
->SetColWidth(6, 0, o3tl::toTwips(2000, o3tl::Length::mm100
));
5587 aRotRect
.setWidth( aRotRect
.GetWidth() + 1000 );
5588 aRotRect
.setHeight( aRotRect
.GetHeight() + 2000 );
5590 m_pDoc
->SetDrawPageSize(0);
5592 aSnap
= pObj
->GetSnapRect();
5594 // ensure that width and height have been adjusted accordingly
5595 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetHeight(), aSnap
.GetHeight(), TOLERANCE
);
5596 CPPUNIT_ASSERT_DOUBLES_EQUAL( aRotRect
.GetWidth(), aSnap
.GetWidth(), TOLERANCE
);
5598 // ensure that anchor start and end addresses haven't changed
5599 CPPUNIT_ASSERT_EQUAL( aAnchor
.maStart
.Row(), pData
->maStart
.Row() ); // start row 0
5600 CPPUNIT_ASSERT_EQUAL( aAnchor
.maStart
.Col(), pData
->maStart
.Col() ); // start column 5
5601 CPPUNIT_ASSERT_EQUAL( aAnchor
.maEnd
.Row(), pData
->maEnd
.Row() ); // end row 3
5602 CPPUNIT_ASSERT_EQUAL( aAnchor
.maEnd
.Col(), pData
->maEnd
.Col() ); // end col 7
5604 m_pDoc
->DeleteTab(0);
5607 CPPUNIT_TEST_FIXTURE(Test
, testCellTextWidth
)
5609 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5611 ScAddress
aTopCell(0, 0, 0);
5614 std::unique_ptr
<ScColumnTextWidthIterator
> pIter(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5615 CPPUNIT_ASSERT_MESSAGE("Column should have no text widths stored.", !pIter
->hasCell());
5617 // Sheet only has one cell.
5618 m_pDoc
->SetString(0, 0, 0, u
"Only one cell"_ustr
);
5619 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5620 CPPUNIT_ASSERT_MESSAGE("Column should have a cell.", pIter
->hasCell());
5621 CPPUNIT_ASSERT_EQUAL(SCROW(0), pIter
->getPos());
5623 // Setting a text width here should commit it to the column.
5624 sal_uInt16 nTestVal
= 432;
5625 pIter
->setValue(nTestVal
);
5626 CPPUNIT_ASSERT_EQUAL(nTestVal
, m_pDoc
->GetTextWidth(aTopCell
));
5628 // Set values to row 2 through 6.
5629 for (SCROW i
= 2; i
<= 6; ++i
)
5630 m_pDoc
->SetString(0, i
, 0, u
"foo"_ustr
);
5632 // Set values to row 10 through 18.
5633 for (SCROW i
= 10; i
<= 18; ++i
)
5634 m_pDoc
->SetString(0, i
, 0, u
"foo"_ustr
);
5638 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5639 SCROW aRows
[] = { 0, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
5640 for (const auto& rRow
: aRows
)
5642 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5643 CPPUNIT_ASSERT_EQUAL(rRow
, pIter
->getPos());
5646 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5650 // Specify start and end rows (6 - 16)
5651 ScAddress aStart
= aTopCell
;
5653 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aStart
, 16));
5654 SCROW aRows
[] = { 6, 10, 11, 12, 13, 14, 15, 16 };
5655 for (const auto& rRow
: aRows
)
5657 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5658 CPPUNIT_ASSERT_EQUAL(rRow
, pIter
->getPos());
5661 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5664 // Clear from row 3 to row 17. After this, we should only have cells at rows 0, 2 and 18.
5665 clearRange(m_pDoc
, ScRange(0, 3, 0, 0, 17, 0));
5668 // Full range again.
5669 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5670 SCROW aRows
[] = { 0, 2, 18 };
5671 for (const auto& rRow
: aRows
)
5673 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5674 CPPUNIT_ASSERT_EQUAL(rRow
, pIter
->getPos());
5677 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5680 // Delete row 2 which shifts all cells below row 2 upward. After this, we
5681 // should only have cells at rows 0 and 17.
5682 m_pDoc
->DeleteRow(0, 0, m_pDoc
->MaxCol(), MAXTAB
, 2, 1);
5684 // Full range again.
5685 pIter
.reset(new ScColumnTextWidthIterator(*m_pDoc
, aTopCell
, m_pDoc
->MaxRow()));
5686 SCROW aRows
[] = { 0, 17 };
5687 for (const auto& rRow
: aRows
)
5689 CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter
->hasCell());
5690 CPPUNIT_ASSERT_EQUAL(rRow
, pIter
->getPos());
5693 CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter
->hasCell());
5696 m_pDoc
->DeleteTab(0);
5699 static bool checkEditTextIterator(sc::EditTextIterator
& rIter
, const char** pChecks
)
5701 const EditTextObject
* pText
= rIter
.first();
5702 const char* p
= *pChecks
;
5704 for (int i
= 0; i
< 100; ++i
) // cap it to 100 loops.
5707 // No more edit cells. The check string array should end too.
5708 return p
== nullptr;
5711 // More edit cell, but no more check string. Bad.
5714 if (pText
->GetParagraphCount() != 1)
5715 // For this test, we don't handle multi-paragraph text.
5718 if (pText
->GetText(0) != OUString::createFromAscii(p
))
5719 // Text differs from what's expected.
5722 pText
= rIter
.next();
5730 CPPUNIT_TEST_FIXTURE(Test
, testEditTextIterator
)
5732 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5735 // First, try with an empty sheet.
5736 sc::EditTextIterator
aIter(*m_pDoc
,0);
5737 const char* pChecks
[] = { nullptr };
5738 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5741 ScFieldEditEngine
& rEditEngine
= m_pDoc
->GetEditEngine();
5744 // Only set one edit cell.
5745 rEditEngine
.SetTextCurrentDefaults(u
"A2"_ustr
);
5746 m_pDoc
->SetEditText(ScAddress(0,1,0), rEditEngine
.CreateTextObject());
5747 sc::EditTextIterator
aIter(*m_pDoc
,0);
5748 const char* pChecks
[] = { "A2", nullptr };
5749 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5753 // Add a series of edit cells.
5754 rEditEngine
.SetTextCurrentDefaults(u
"A5"_ustr
);
5755 m_pDoc
->SetEditText(ScAddress(0,4,0), rEditEngine
.CreateTextObject());
5756 rEditEngine
.SetTextCurrentDefaults(u
"A6"_ustr
);
5757 m_pDoc
->SetEditText(ScAddress(0,5,0), rEditEngine
.CreateTextObject());
5758 rEditEngine
.SetTextCurrentDefaults(u
"A7"_ustr
);
5759 m_pDoc
->SetEditText(ScAddress(0,6,0), rEditEngine
.CreateTextObject());
5760 sc::EditTextIterator
aIter(*m_pDoc
,0);
5761 const char* pChecks
[] = { "A2", "A5", "A6", "A7", nullptr };
5762 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5766 // Add more edit cells to column C. Skip column B.
5767 rEditEngine
.SetTextCurrentDefaults(u
"C1"_ustr
);
5768 m_pDoc
->SetEditText(ScAddress(2,0,0), rEditEngine
.CreateTextObject());
5769 rEditEngine
.SetTextCurrentDefaults(u
"C3"_ustr
);
5770 m_pDoc
->SetEditText(ScAddress(2,2,0), rEditEngine
.CreateTextObject());
5771 rEditEngine
.SetTextCurrentDefaults(u
"C4"_ustr
);
5772 m_pDoc
->SetEditText(ScAddress(2,3,0), rEditEngine
.CreateTextObject());
5773 sc::EditTextIterator
aIter(*m_pDoc
,0);
5774 const char* pChecks
[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", nullptr };
5775 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5779 // Add some numeric, string and formula cells. This shouldn't affect the outcome.
5780 m_pDoc
->SetString(ScAddress(0,99,0), u
"=ROW()"_ustr
);
5781 m_pDoc
->SetValue(ScAddress(1,3,0), 1.2);
5782 m_pDoc
->SetString(ScAddress(2,4,0), u
"Simple string"_ustr
);
5783 sc::EditTextIterator
aIter(*m_pDoc
,0);
5784 const char* pChecks
[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", nullptr };
5785 CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter
, pChecks
));
5788 m_pDoc
->DeleteTab(0);
5791 CPPUNIT_TEST_FIXTURE(Test
, testImportStream
)
5793 sc::AutoCalcSwitch
aAC(*m_pDoc
, true); // turn on auto calc.
5794 sc::UndoSwitch
aUndo(*m_pDoc
, true); // enable undo.
5796 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5798 m_pDoc
->SetString(ScAddress(0,1,0), u
"=SUM(A1:C1)"_ustr
); // A2
5800 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5802 // CSV import options.
5803 ScAsciiOptions aOpt
;
5804 aOpt
.SetFieldSeps(u
","_ustr
);
5806 // Import values to A1:C1.
5807 ScImportExport
aObj(*m_pDoc
, ScAddress(0,0,0));
5808 aObj
.SetImportBroadcast(true);
5809 aObj
.SetExtOptions(aOpt
);
5810 aObj
.ImportString(u
"1,2,3"_ustr
, SotClipboardFormatId::STRING
);
5812 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5813 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5814 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5816 // Formula value should have been updated.
5817 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5819 // Undo, and check the result.
5820 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5821 CPPUNIT_ASSERT_MESSAGE("Failed to get the undo manager.", pUndoMgr
);
5824 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5825 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5826 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5828 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,1,0))); // formula
5830 // Redo, and check the result.
5833 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5834 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
5835 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
5837 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0))); // formula
5841 m_pDoc
->DeleteTab(0);
5844 CPPUNIT_TEST_FIXTURE(Test
, testDeleteContents
)
5846 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
5847 sc::UndoSwitch
aUndoSwitch(*m_pDoc
, true); // enable undo.
5849 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5851 m_pDoc
->SetValue(ScAddress(3,1,0), 1.0);
5852 m_pDoc
->SetValue(ScAddress(3,2,0), 1.0);
5853 m_pDoc
->SetValue(ScAddress(3,3,0), 1.0);
5854 m_pDoc
->SetValue(ScAddress(3,4,0), 1.0);
5855 m_pDoc
->SetValue(ScAddress(3,5,0), 1.0);
5856 m_pDoc
->SetValue(ScAddress(3,6,0), 1.0);
5857 m_pDoc
->SetValue(ScAddress(3,7,0), 1.0);
5858 m_pDoc
->SetValue(ScAddress(3,8,0), 1.0);
5859 m_pDoc
->SetString(ScAddress(3,15,0), u
"=SUM(D2:D15)"_ustr
);
5861 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5864 ScRange
aRange(3,1,0,3,5,0);
5865 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5866 aMark
.SelectOneTable(0);
5867 aMark
.SetMarkArea(aRange
);
5869 ScDocumentUniquePtr
pUndoDoc(new ScDocument(SCDOCMODE_UNDO
));
5870 pUndoDoc
->InitUndo(*m_pDoc
, 0, 0);
5871 m_pDoc
->CopyToDocument(aRange
, InsertDeleteFlags::CONTENTS
, false, *pUndoDoc
, &aMark
);
5872 ScUndoDeleteContents
aUndo(m_xDocShell
.get(), aMark
, aRange
, std::move(pUndoDoc
), false, InsertDeleteFlags::CONTENTS
, true);
5874 clearRange(m_pDoc
, aRange
);
5875 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5878 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5881 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(3,15,0))); // formula
5883 m_pDoc
->DeleteTab(0);
5886 CPPUNIT_TEST_FIXTURE(Test
, testTransliterateText
)
5888 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5890 // Set texts to A1:A3.
5891 m_pDoc
->SetString(ScAddress(0,0,0), u
"Mike"_ustr
);
5892 m_pDoc
->SetString(ScAddress(0,1,0), u
"Noah"_ustr
);
5893 m_pDoc
->SetString(ScAddress(0,2,0), u
"Oscar"_ustr
);
5895 // Change them to uppercase.
5896 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5897 aMark
.SetMarkArea(ScRange(0,0,0,0,2,0));
5898 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5899 rFunc
.TransliterateText(
5900 aMark
, TransliterationFlags::LOWERCASE_UPPERCASE
, true);
5902 CPPUNIT_ASSERT_EQUAL(u
"MIKE"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
5903 CPPUNIT_ASSERT_EQUAL(u
"NOAH"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
5904 CPPUNIT_ASSERT_EQUAL(u
"OSCAR"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0)));
5906 // Test the undo and redo.
5907 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
5908 CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr
);
5911 CPPUNIT_ASSERT_EQUAL(u
"Mike"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
5912 CPPUNIT_ASSERT_EQUAL(u
"Noah"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
5913 CPPUNIT_ASSERT_EQUAL(u
"Oscar"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0)));
5916 CPPUNIT_ASSERT_EQUAL(u
"MIKE"_ustr
, m_pDoc
->GetString(ScAddress(0,0,0)));
5917 CPPUNIT_ASSERT_EQUAL(u
"NOAH"_ustr
, m_pDoc
->GetString(ScAddress(0,1,0)));
5918 CPPUNIT_ASSERT_EQUAL(u
"OSCAR"_ustr
, m_pDoc
->GetString(ScAddress(0,2,0)));
5920 m_pDoc
->DeleteTab(0);
5923 CPPUNIT_TEST_FIXTURE(Test
, testFormulaToValue
)
5925 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true);
5926 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
5928 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
5930 std::vector
<std::vector
<const char*>> aData
= {
5931 { "=1", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5932 { "=2", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5933 { "=3", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5934 { "=4", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5935 { "=5", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5936 { "=6", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
5939 ScAddress
aPos(1,2,0); // B3
5940 ScRange aDataRange
= insertRangeData(m_pDoc
, aPos
, aData
);
5941 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
5944 // Expected output table content. 0 = empty cell
5945 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5946 { "1", "2", "TRUE" },
5947 { "2", "4", "TRUE" },
5948 { "3", "6", "TRUE" },
5949 { "4", "8", "TRUE" },
5950 { "5", "10", "TRUE" },
5951 { "6", "12", "TRUE" },
5954 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
5955 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5958 // Convert B5:C6 to static values, and check the result.
5959 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
5960 ScRange
aConvRange(1,4,0,2,5,0); // B5:C6
5961 rFunc
.ConvertFormulaToValue(aConvRange
, false);
5964 // Expected output table content. 0 = empty cell
5965 std::vector
<std::vector
<const char*>> aOutputCheck
= {
5966 { "1", "2", "TRUE" },
5967 { "2", "4", "TRUE" },
5968 { "3", "6", "FALSE" },
5969 { "4", "8", "FALSE" },
5970 { "5", "10", "TRUE" },
5971 { "6", "12", "TRUE" },
5974 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Converted");
5975 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
5978 // Make sure that B3:B4 and B7:B8 are formula cells.
5979 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,2,0)));
5980 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,3,0)));
5981 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,6,0)));
5982 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,7,0)));
5984 // Make sure that B5:C6 are numeric cells.
5985 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,4,0)));
5986 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,5,0)));
5987 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,4,0)));
5988 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,5,0)));
5990 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
5991 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
5992 CPPUNIT_ASSERT(pFC
);
5993 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
5994 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
5995 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,6,0));
5996 CPPUNIT_ASSERT(pFC
);
5997 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
5998 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
6001 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
6002 CPPUNIT_ASSERT(pUndoMgr
);
6006 // Expected output table content. 0 = empty cell
6007 std::vector
<std::vector
<const char*>> aOutputCheck
= {
6008 { "1", "2", "TRUE" },
6009 { "2", "4", "TRUE" },
6010 { "3", "6", "TRUE" },
6011 { "4", "8", "TRUE" },
6012 { "5", "10", "TRUE" },
6013 { "6", "12", "TRUE" },
6016 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "After undo");
6017 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
6020 // B3:B8 should all be (ungrouped) formula cells.
6021 for (SCROW i
= 2; i
<= 7; ++i
)
6023 pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,i
,0));
6024 CPPUNIT_ASSERT(pFC
);
6025 CPPUNIT_ASSERT(!pFC
->IsShared());
6028 // C3:C8 should be shared formula cells.
6029 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
6030 CPPUNIT_ASSERT(pFC
);
6031 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
6032 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedLength());
6037 // Expected output table content. 0 = empty cell
6038 std::vector
<std::vector
<const char*>> aOutputCheck
= {
6039 { "1", "2", "TRUE" },
6040 { "2", "4", "TRUE" },
6041 { "3", "6", "FALSE" },
6042 { "4", "8", "FALSE" },
6043 { "5", "10", "TRUE" },
6044 { "6", "12", "TRUE" },
6047 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Converted");
6048 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
6051 // Make sure that B3:B4 and B7:B8 are formula cells.
6052 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,2,0)));
6053 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,3,0)));
6054 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,6,0)));
6055 CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA
, m_pDoc
->GetCellType(ScAddress(1,7,0)));
6057 // Make sure that B5:C6 are numeric cells.
6058 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,4,0)));
6059 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(1,5,0)));
6060 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,4,0)));
6061 CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE
, m_pDoc
->GetCellType(ScAddress(2,5,0)));
6063 // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
6064 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
6065 CPPUNIT_ASSERT(pFC
);
6066 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedTopRow());
6067 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
6068 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,6,0));
6069 CPPUNIT_ASSERT(pFC
);
6070 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(6), pFC
->GetSharedTopRow());
6071 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
6073 // Undo again and make sure the recovered formulas in C5:C6 still track B5:B6.
6075 m_pDoc
->SetValue(ScAddress(1,4,0), 10);
6076 m_pDoc
->SetValue(ScAddress(1,5,0), 11);
6077 CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc
->GetValue(ScAddress(2,4,0)));
6078 CPPUNIT_ASSERT_EQUAL(22.0, m_pDoc
->GetValue(ScAddress(2,5,0)));
6080 m_pDoc
->DeleteTab(0);
6083 CPPUNIT_TEST_FIXTURE(Test
, testFormulaToValue2
)
6085 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true);
6086 FormulaGrammarSwitch
aFGSwitch(m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
);
6088 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6090 std::vector
<std::vector
<const char*>> aData
= {
6091 { "=1", "=ISFORMULA(RC[-1])" },
6092 { "=2", "=ISFORMULA(RC[-1])" },
6093 { "3", "=ISFORMULA(RC[-1])" },
6094 { "=4", "=ISFORMULA(RC[-1])" },
6095 { "=5", "=ISFORMULA(RC[-1])" },
6098 // Insert data into B2:C6.
6099 ScAddress
aPos(1,1,0); // B2
6100 ScRange aDataRange
= insertRangeData(m_pDoc
, aPos
, aData
);
6101 CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos
, aDataRange
.aStart
);
6104 // Expected output table content. 0 = empty cell
6105 std::vector
<std::vector
<const char*>> aOutputCheck
= {
6113 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
6114 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
6117 // Convert B3:B5 to a value.
6118 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
6119 ScRange
aConvRange(1,2,0,1,4,0); // B3:B5
6120 rFunc
.ConvertFormulaToValue(aConvRange
, false);
6123 // Expected output table content. 0 = empty cell
6124 std::vector
<std::vector
<const char*>> aOutputCheck
= {
6132 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
6133 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
6137 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
6138 CPPUNIT_ASSERT(pUndoMgr
);
6142 // Expected output table content. 0 = empty cell
6143 std::vector
<std::vector
<const char*>> aOutputCheck
= {
6151 bool bSuccess
= checkOutput(m_pDoc
, aDataRange
, aOutputCheck
, "Initial value");
6152 CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess
);
6155 m_pDoc
->DeleteTab(0);
6158 CPPUNIT_TEST_FIXTURE(Test
, testColumnFindEditCells
)
6160 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6162 // Test the basics with real edit cells, using Column A.
6164 SCROW nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,m_pDoc
->MaxRow(),0));
6165 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
6166 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,0,0));
6167 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
6168 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(0,0,0,0,10,0));
6169 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no edit cells.", SCROW(-1), nResRow
);
6171 ScFieldEditEngine
& rEE
= m_pDoc
->GetEditEngine();
6172 rEE
.SetTextCurrentDefaults(u
"Test"_ustr
);
6173 m_pDoc
->SetEditText(ScAddress(0,0,0), rEE
.CreateTextObject());
6174 const EditTextObject
* pObj
= m_pDoc
->GetEditText(ScAddress(0,0,0));
6175 CPPUNIT_ASSERT_MESSAGE("There should be an edit cell here.", pObj
);
6177 ScRange
aRange(0,0,0,0,0,0);
6178 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6179 CPPUNIT_ASSERT_EQUAL_MESSAGE("There is an edit cell here.", SCROW(0), nResRow
);
6181 aRange
.aStart
.SetRow(1);
6182 aRange
.aEnd
.SetRow(1);
6183 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6184 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6186 aRange
.aStart
.SetRow(2);
6187 aRange
.aEnd
.SetRow(4);
6188 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6189 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6191 aRange
.aStart
.SetRow(0);
6192 aRange
.aEnd
.SetRow(m_pDoc
->MaxRow());
6193 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6194 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be an edit cell in specified range.", SCROW(0), nResRow
);
6196 m_pDoc
->SetString(ScAddress(0,0,0), u
"Test"_ustr
);
6197 m_pDoc
->SetValue(ScAddress(0,2,0), 1.0);
6198 ScRefCellValue aCell
;
6199 aCell
.assign(*m_pDoc
, ScAddress(0,0,0));
6200 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a string cell.", CELLTYPE_STRING
, aCell
.getType());
6201 aCell
.assign(*m_pDoc
, ScAddress(0,1,0));
6202 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be an empty cell.", CELLTYPE_NONE
, aCell
.getType());
6203 aCell
.assign(*m_pDoc
, ScAddress(0,2,0));
6204 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be a numeric cell.", CELLTYPE_VALUE
, aCell
.getType());
6205 aCell
.assign(*m_pDoc
, ScAddress(0,3,0));
6206 CPPUNIT_ASSERT_EQUAL_MESSAGE("This should be an empty cell.", CELLTYPE_NONE
, aCell
.getType());
6208 aRange
.aStart
.SetRow(1);
6209 aRange
.aEnd
.SetRow(1);
6210 nResRow
= m_pDoc
->GetFirstEditTextRow(aRange
);
6211 CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be an edit cell in specified range.", SCROW(-1), nResRow
);
6213 // Test with non-edit cell but with ambiguous script type.
6215 m_pDoc
->SetString(ScAddress(1,11,0), u
"Some text"_ustr
);
6216 m_pDoc
->SetString(ScAddress(1,12,0), u
"Some text"_ustr
);
6217 m_pDoc
->SetString(ScAddress(1,13,0), u
"Other text"_ustr
);
6219 m_pDoc
->SetScriptType(ScAddress(1,11,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6220 m_pDoc
->SetScriptType(ScAddress(1,12,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6221 m_pDoc
->SetScriptType(ScAddress(1,13,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6223 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(ScAddress(1,11,0)));
6224 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(11), nResRow
);
6225 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(ScAddress(1,12,0)));
6226 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(12), nResRow
);
6228 for (SCROW i
= 0; i
<= 5; ++i
)
6229 m_pDoc
->SetString(ScAddress(2,i
,0), u
"Text"_ustr
);
6231 m_pDoc
->SetScriptType(ScAddress(2,5,0), (SvtScriptType::LATIN
| SvtScriptType::ASIAN
));
6233 nResRow
= m_pDoc
->GetFirstEditTextRow(ScRange(ScAddress(2,1,0)));
6234 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(-1), nResRow
);
6236 m_pDoc
->DeleteTab(0);
6240 CPPUNIT_TEST_FIXTURE(Test
, testSetFormula
)
6242 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6244 static struct aInputs
6248 const char* aFormula1
; // Represents the formula that is input to SetFormula function.
6249 const char* aFormula2
; // Represents the formula that is actually stored in the cell.
6250 formula::FormulaGrammar::Grammar
const eGram
;
6253 { 5 , 4 , "=SUM($D$2:$F$3)" ,"=SUM($D$2:$F$3)" , formula::FormulaGrammar::Grammar::GRAM_ENGLISH
},
6254 { 5 , 5 , "=A1-$C2+B$3-$F$4" ,"=A1-$C2+B$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_NATIVE
},
6255 { 6 , 6 , "=A1-$C2+B$3-$F$4" ,"=A1-$C2+B$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_NATIVE_XL_A1
},
6256 { 7 , 8 , "=[.A1]-[.$C2]+[.G$3]-[.$F$4]","=A1-$C2+G$3-$F$4", formula::FormulaGrammar::Grammar::GRAM_ODFF
}
6259 for(const auto& rTest
: aTest
)
6261 m_pDoc
->SetFormula(ScAddress(rTest
.nCol
, rTest
.nRow
, 0), OUString::createFromAscii(rTest
.aFormula1
), rTest
.eGram
);
6262 OUString aBuffer
= m_pDoc
->GetFormula(rTest
.nCol
, rTest
.nRow
, 0);
6264 CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to set formula", OUString::createFromAscii(rTest
.aFormula2
), aBuffer
);
6267 m_pDoc
->DeleteTab(0);
6270 CPPUNIT_TEST_FIXTURE(Test
, testMultipleDataCellsInRange
)
6272 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6274 ScRange
aRange(1,2,0); // B3
6275 sc::MultiDataCellState aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6276 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::Empty
, aState
.meState
);
6278 // Set a numeric value to B3.
6279 m_pDoc
->SetValue(ScAddress(1,2,0), 1.0);
6280 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6281 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6282 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6283 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6285 // Set another numeric value to B4.
6286 m_pDoc
->SetValue(ScAddress(1,3,0), 2.0);
6287 aRange
.aEnd
.SetRow(3); // B3:B4
6288 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6289 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasMultipleCells
, aState
.meState
);
6290 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6291 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6293 // Set the query range to B4:B5. Now it should only report one cell, with
6294 // B4 being the first non-empty cell.
6295 aRange
.aStart
.SetRow(3);
6296 aRange
.aEnd
.SetRow(4);
6297 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6298 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6299 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6300 CPPUNIT_ASSERT_EQUAL(SCROW(3), aState
.mnRow1
);
6302 // Set the query range to A1:C3. The first non-empty cell should be B3.
6303 aRange
= ScRange(0,0,0,2,2,0);
6304 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6305 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasOneCell
, aState
.meState
);
6306 CPPUNIT_ASSERT_EQUAL(SCCOL(1), aState
.mnCol1
);
6307 CPPUNIT_ASSERT_EQUAL(SCROW(2), aState
.mnRow1
);
6309 // Set string cells to D4 and F5, and query D3:F5. D4 should be the first
6311 m_pDoc
->SetString(ScAddress(3,3,0), u
"foo"_ustr
);
6312 m_pDoc
->SetString(ScAddress(5,4,0), u
"bar"_ustr
);
6313 aRange
= ScRange(3,2,0,5,4,0);
6314 aState
= m_pDoc
->HasMultipleDataCells(aRange
);
6315 CPPUNIT_ASSERT_EQUAL(sc::MultiDataCellState::HasMultipleCells
, aState
.meState
);
6316 CPPUNIT_ASSERT_EQUAL(SCCOL(3), aState
.mnCol1
);
6317 CPPUNIT_ASSERT_EQUAL(SCROW(3), aState
.mnRow1
);
6319 // TODO : add more test cases as needed.
6321 m_pDoc
->DeleteTab(0);
6324 CPPUNIT_TEST_FIXTURE(Test
, testFormulaWizardSubformula
)
6326 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6328 m_pDoc
->SetString(ScAddress(1,0,0), u
"=1"_ustr
); // B1
6329 m_pDoc
->SetString(ScAddress(1,1,0), u
"=1/0"_ustr
); // B2
6330 m_pDoc
->SetString(ScAddress(1,2,0), u
"=gibberish"_ustr
); // B3
6332 ScSimpleFormulaCalculator
aFCell1( *m_pDoc
, ScAddress(0,0,0), u
"=B1:B3"_ustr
, true );
6333 FormulaError nErrCode
= aFCell1
.GetErrCode();
6334 CPPUNIT_ASSERT( nErrCode
== FormulaError::NONE
|| aFCell1
.IsMatrix() );
6335 CPPUNIT_ASSERT_EQUAL( u
"{1|#DIV/0!|#NAME?}"_ustr
, aFCell1
.GetString().getString() );
6337 m_pDoc
->SetString(ScAddress(1,0,0), u
"=NA()"_ustr
); // B1
6338 m_pDoc
->SetString(ScAddress(1,1,0), u
"2"_ustr
); // B2
6339 m_pDoc
->SetString(ScAddress(1,2,0), u
"=1+2"_ustr
); // B3
6340 ScSimpleFormulaCalculator
aFCell2( *m_pDoc
, ScAddress(0,0,0), u
"=B1:B3"_ustr
, true );
6341 nErrCode
= aFCell2
.GetErrCode();
6342 CPPUNIT_ASSERT( nErrCode
== FormulaError::NONE
|| aFCell2
.IsMatrix() );
6343 CPPUNIT_ASSERT_EQUAL( u
"{#N/A|2|3}"_ustr
, aFCell2
.GetString().getString() );
6345 m_pDoc
->DeleteTab(0);
6348 CPPUNIT_TEST_FIXTURE(Test
, testDiagonalBorders
)
6350 m_pDoc
->InsertTab(0, u
"Diagonal"_ustr
);
6353 const editeng::SvxBorderLine
* pLine
;
6354 const ScPatternAttr
* pPat
;
6356 // diagonal down border
6357 ::editeng::SvxBorderLine
dDownBorderLine(nullptr, 1);
6358 SvxLineItem
dDownLineItem(ATTR_BORDER_TLBR
);
6359 dDownLineItem
.SetLine(&dDownBorderLine
);
6361 // set diagonal down border to cell(A1)
6362 m_pDoc
->ApplyAttr(0, 0, 0, dDownLineItem
);
6365 pPat
= m_pDoc
->GetPattern(aPos
);
6366 CPPUNIT_ASSERT(pPat
);
6368 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6369 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was expected, but not found!", pLine
);
6371 // diagonal up border
6372 ::editeng::SvxBorderLine
dUpBorderLine(nullptr, 1);
6373 SvxLineItem
dUpLineItem(ATTR_BORDER_BLTR
);
6374 dUpLineItem
.SetLine(&dUpBorderLine
);
6376 // set diagonal up border to cell(A2)
6377 m_pDoc
->ApplyAttr(0, 1, 0, dUpLineItem
);
6380 pPat
= m_pDoc
->GetPattern(aPos
);
6381 CPPUNIT_ASSERT(pPat
);
6383 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6384 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was expected, but not found!", pLine
);
6386 // diagonal down and up border in the same cell (A5)
6387 m_pDoc
->ApplyAttr(0, 4, 0, dDownLineItem
);
6388 m_pDoc
->ApplyAttr(0, 4, 0, dUpLineItem
);
6390 // test if both borders are applied successfully in the same cell (A5)
6392 pPat
= m_pDoc
->GetPattern(aPos
);
6393 CPPUNIT_ASSERT(pPat
);
6395 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6396 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was expected, but not found!", pLine
);
6397 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6398 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was expected, but not found!", pLine
);
6400 // test if both borders are removed successfully
6401 dDownLineItem
.SetLine(nullptr);
6402 dUpLineItem
.SetLine(nullptr);
6404 // SetLine(nullptr) should remove the lines from (A5)
6405 m_pDoc
->ApplyAttr(0, 4, 0, dDownLineItem
);
6406 m_pDoc
->ApplyAttr(0, 4, 0, dUpLineItem
);
6408 pPat
= m_pDoc
->GetPattern(aPos
);
6409 CPPUNIT_ASSERT(pPat
);
6411 pLine
= pPat
->GetItem(ATTR_BORDER_TLBR
).GetLine();
6412 CPPUNIT_ASSERT_MESSAGE("Diagonal down border was not expected, but is found!", !pLine
);
6413 pLine
= pPat
->GetItem(ATTR_BORDER_BLTR
).GetLine();
6414 CPPUNIT_ASSERT_MESSAGE("Diagonal up border was not expected, but is found!", !pLine
);
6416 m_pDoc
->DeleteTab(0);
6419 CPPUNIT_TEST_FIXTURE(Test
, testWholeDocBorders
)
6421 m_pDoc
->InsertTab(0, u
"Borders"_ustr
);
6423 // Set outside border to be on all sides, and inside borders to be only vertical.
6424 // This should result in edge borders of the spreadsheets being set, but internal
6425 // borders between cells should be only vertical, not horizontal.
6426 ::editeng::SvxBorderLine
line(nullptr, 50, SvxBorderLineStyle::SOLID
);
6427 SvxBoxItem
borderItem(ATTR_BORDER
);
6428 borderItem
.SetLine(&line
, SvxBoxItemLine::LEFT
);
6429 borderItem
.SetLine(&line
, SvxBoxItemLine::RIGHT
);
6430 borderItem
.SetLine(&line
, SvxBoxItemLine::TOP
);
6431 borderItem
.SetLine(&line
, SvxBoxItemLine::BOTTOM
);
6432 SvxBoxInfoItem
boxInfoItem(ATTR_BORDER
);
6433 boxInfoItem
.SetLine(&line
, SvxBoxInfoItemLine::VERT
);
6435 ScMarkData
mark( m_pDoc
->GetSheetLimits(), ScRange( 0, 0, 0, m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 0 ));
6436 m_pDoc
->ApplySelectionFrame( mark
, borderItem
, &boxInfoItem
);
6438 const ScPatternAttr
* attr
;
6439 attr
= m_pDoc
->GetPattern( 0, 0, 0 );
6440 CPPUNIT_ASSERT(attr
);
6441 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6442 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6443 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6444 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6446 attr
= m_pDoc
->GetPattern( 1, 0, 0 );
6447 CPPUNIT_ASSERT(attr
);
6448 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6449 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6450 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6451 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6453 attr
= m_pDoc
->GetPattern( 0, 1, 0 );
6454 CPPUNIT_ASSERT(attr
);
6455 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6456 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6457 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6458 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6460 attr
= m_pDoc
->GetPattern( 1, 1, 0 );
6461 CPPUNIT_ASSERT(attr
);
6462 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6463 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6464 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6465 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6467 attr
= m_pDoc
->GetPattern( m_pDoc
->MaxCol(), 0, 0 );
6468 CPPUNIT_ASSERT(attr
);
6469 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetTop());
6470 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6471 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6472 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetBottom());
6474 attr
= m_pDoc
->GetPattern( 0, m_pDoc
->MaxRow(), 0 );
6475 CPPUNIT_ASSERT(attr
);
6476 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6477 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6478 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6479 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetBottom());
6481 attr
= m_pDoc
->GetPattern( m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 0 );
6482 CPPUNIT_ASSERT(attr
);
6483 CPPUNIT_ASSERT(!attr
->GetItem(ATTR_BORDER
).GetTop());
6484 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetLeft());
6485 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetRight());
6486 CPPUNIT_ASSERT(attr
->GetItem(ATTR_BORDER
).GetBottom());
6488 m_pDoc
->DeleteTab(0);
6491 CPPUNIT_TEST_FIXTURE(Test
, testSetStringAndNote
)
6493 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6495 // We need a drawing layer in order to create caption objects.
6496 m_pDoc
->InitDrawLayer(m_xDocShell
.get());
6499 ScAddress
aAdrA1 (0, 0, 0);
6500 ScPostIt
* pNote
= m_pDoc
->GetOrCreateNote(aAdrA1
);
6501 pNote
->SetText(aAdrA1
, u
"Hello world in A1"_ustr
);
6503 m_pDoc
->SetString(0, 0, 0, u
""_ustr
);
6505 pNote
= m_pDoc
->GetNote(aAdrA1
);
6506 CPPUNIT_ASSERT(pNote
);
6508 m_pDoc
->DeleteTab(0);
6511 CPPUNIT_TEST_FIXTURE(Test
, testUndoDataAnchor
)
6513 m_pDoc
->InsertTab(0, u
"Tab1"_ustr
);
6514 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only 1 sheets to begin with",
6515 static_cast<SCTAB
>(1), m_pDoc
->GetTableCount());
6517 m_pDoc
->InitDrawLayer();
6518 ScDrawLayer
* pDrawLayer
= m_pDoc
->GetDrawLayer();
6519 CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer
);
6520 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
6521 CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage
);
6523 // Insert an object.
6524 tools::Rectangle
aObjRect(2,1000,100,1100);
6525 rtl::Reference
<SdrObject
> pObj
= new SdrRectObj(*pDrawLayer
, aObjRect
);
6526 pPage
->InsertObject(pObj
.get());
6527 ScDrawLayer::SetCellAnchoredFromPosition(*pObj
, *m_pDoc
, 0, false);
6530 ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pObj
.get());
6531 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6533 ScAddress aOldStart
= pData
->maStart
;
6534 ScAddress aOldEnd
= pData
->maEnd
;
6536 // Get non rotated anchor data
6537 ScDrawObjData
* pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6538 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6540 ScAddress aNOldStart
= pNData
->maStart
;
6541 ScAddress aNOldEnd
= pNData
->maEnd
;
6542 CPPUNIT_ASSERT_EQUAL(aOldStart
, aNOldStart
);
6543 CPPUNIT_ASSERT_EQUAL(aOldEnd
, aNOldEnd
);
6545 //pDrawLayer->BeginCalcUndo(false);
6546 // Insert a new row at row 3.
6547 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
6548 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6549 aMark
.SelectOneTable(0);
6550 rFunc
.InsertCells(ScRange( 0, aOldStart
.Row() - 1, 0, m_pDoc
->MaxCol(), aOldStart
.Row(), 0 ), &aMark
, INS_INSROWS_BEFORE
, true, true);
6552 pData
= ScDrawLayer::GetObjData(pObj
.get());
6553 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6555 ScAddress aNewStart
= pData
->maStart
;
6556 ScAddress aNewEnd
= pData
->maEnd
;
6558 // Get non rotated anchor data
6559 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6560 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6562 ScAddress aNNewStart
= pNData
->maStart
;
6563 ScAddress aNNewEnd
= pNData
->maEnd
;
6564 CPPUNIT_ASSERT_EQUAL(aNewStart
, aNNewStart
);
6565 CPPUNIT_ASSERT_EQUAL(aNewEnd
, aNNewEnd
);
6566 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewStart
!= aOldStart
);
6567 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewEnd
!= aOldEnd
);
6568 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNNewStart
!= aNOldStart
);
6569 CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNNewEnd
!= aNOldEnd
);
6571 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
6572 CPPUNIT_ASSERT(pUndoMgr
);
6576 ScAnchorType oldType
= ScDrawLayer::GetAnchorType(*pObj
);
6577 CPPUNIT_ASSERT_EQUAL_MESSAGE( "Failed to check state SCA_CELL.", SCA_CELL
, oldType
);
6580 pData
= ScDrawLayer::GetObjData(pObj
.get());
6581 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6583 // Get non rotated anchor data
6584 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6585 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6587 // Check if data has moved to new rows
6588 CPPUNIT_ASSERT_EQUAL(pData
->maStart
, aOldStart
);
6589 CPPUNIT_ASSERT_EQUAL(pData
->maEnd
, aOldEnd
);
6591 CPPUNIT_ASSERT_EQUAL(pNData
->maStart
, aNOldStart
);
6592 CPPUNIT_ASSERT_EQUAL(pNData
->maEnd
, aNOldEnd
);
6597 pData
= ScDrawLayer::GetObjData(pObj
.get());
6598 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
6600 // Get non rotated anchor data
6601 pNData
= ScDrawLayer::GetNonRotatedObjData( pObj
.get() );
6602 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData
);
6604 // Check if data has moved to new rows
6605 CPPUNIT_ASSERT_EQUAL(pData
->maStart
, aNewStart
);
6606 CPPUNIT_ASSERT_EQUAL(pData
->maEnd
, aNewEnd
);
6608 CPPUNIT_ASSERT_EQUAL(pNData
->maStart
, aNNewStart
);
6609 CPPUNIT_ASSERT_EQUAL(pNData
->maEnd
, aNNewEnd
);
6611 m_pDoc
->DeleteTab(0);
6615 CPPUNIT_TEST_FIXTURE(Test
, testEmptyCalcDocDefaults
)
6617 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetCellCount() );
6618 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetFormulaGroupCount() );
6619 CPPUNIT_ASSERT_EQUAL( sal_uInt64(0), m_pDoc
->GetCodeCount() );
6620 CPPUNIT_ASSERT_EQUAL( int(CharCompressType::NONE
), static_cast<int>(m_pDoc
->GetAsianCompression()) );
6622 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasPrintRange() );
6623 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInVBAMode() );
6624 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasNotes() );
6625 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCutMode() );
6627 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedFonts() );
6628 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedUsedFontsOnly() );
6629 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptLatin() );
6630 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptAsian() );
6631 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsEmbedFontScriptComplex() );
6632 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsEmbedded() );
6634 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsDocEditable() );
6635 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDocProtected() );
6636 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDocVisible() );
6637 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsUserInteractionEnabled() );
6639 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasAnyCalcNotification() );
6640 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsAutoCalcShellDisabled() );
6641 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsForcedFormulaPending() );
6642 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCalculatingFormulaTree() );
6644 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipOrUndo() );
6645 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipboard() );
6646 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsUndo() );
6647 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsUndoEnabled() );
6648 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCutMode() );
6649 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsClipboardSource() );
6650 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInsertingFromOtherDoc() );
6651 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->PastingDrawFromOtherDoc() );
6653 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsAdjustHeightLocked() );
6654 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsExecuteLinkEnabled() );
6655 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsChangeReadOnlyEnabled() );
6657 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IdleCalcTextWidth() );
6658 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsIdleEnabled() );
6659 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsDetectiveDirty() );
6660 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasLinkFormulaNeedingCheck() );
6661 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsChartListenerCollectionNeedsUpdate() );
6663 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasRangeOverflow() );
6664 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsImportingXML() );
6665 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsCalcingAfterLoad() );
6666 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->GetNoListening() );
6668 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsValidAsianCompression() );
6669 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->GetAsianKerning() );
6670 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsValidAsianKerning() );
6672 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInInterpreter() );
6673 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInInterpreterTableOp() );
6674 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInDtorClear() );
6675 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsExpandRefs() );
6676 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsInLinkUpdate() );
6678 SCTAB tab
= m_pDoc
->GetVisibleTab();
6680 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsVisible(tab
) );
6681 CPPUNIT_ASSERT_EQUAL( true, m_pDoc
->IsDefaultTabBgColor(tab
) );
6682 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasTable(tab
) );
6684 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->IsActiveScenario(tab
) );
6685 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasCalcNotification(tab
) );
6686 CPPUNIT_ASSERT_EQUAL( false, m_pDoc
->HasManualBreaks(tab
) );
6689 void Test::checkPrecisionAsShown( OUString
& rCode
, double fValue
, double fExpectedRoundVal
)
6691 SvNumberFormatter
* pFormatter
= m_pDoc
->GetFormatTable();
6692 sal_uInt32 nFormat
= pFormatter
->GetEntryKey( rCode
);
6693 if ( nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
6695 sal_Int32 nCheckPos
= 0;
6696 SvNumFormatType nType
;
6697 pFormatter
->PutEntry( rCode
, nCheckPos
, nType
, nFormat
);
6698 CPPUNIT_ASSERT_EQUAL( sal_Int32(0), nCheckPos
);
6700 double fRoundValue
= m_pDoc
->RoundValueAsShown( fValue
, nFormat
);
6701 OString aMessage
= "Format \"" +
6702 OUStringToOString( rCode
, RTL_TEXTENCODING_ASCII_US
) +
6703 "\" is not correctly rounded";
6704 CPPUNIT_ASSERT_EQUAL_MESSAGE( aMessage
.getStr(), fExpectedRoundVal
, fRoundValue
);
6707 CPPUNIT_TEST_FIXTURE(Test
, testPrecisionAsShown
)
6709 m_pDoc
->InsertTab(0, u
"Test"_ustr
);
6711 // Turn on "precision as shown" option.
6712 setCalcAsShown( m_pDoc
, true);
6715 double fValue
, fExpectedRoundVal
;
6716 { // decimal rounding
6719 fExpectedRoundVal
= 0.33;
6720 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6721 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6723 fExpectedRoundVal
= 10.0;
6724 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6725 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6727 { // thousand rounding tdf#106253
6729 fValue
= 4.0e9
/ 7.0;
6730 fExpectedRoundVal
= 571e6
;
6731 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6732 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6733 aCode
= "\"k\"[$$-409]* #,;[RED]-\"k\"[$$-409]* #,";
6734 fValue
= 4.0e8
/ 7.0;
6735 fExpectedRoundVal
= 57.143e6
;
6736 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6737 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6739 { // percent rounding
6742 fExpectedRoundVal
= 0.5714;
6743 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6744 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6745 fValue
= 40.0 / 7.0;
6746 fExpectedRoundVal
= 5.7143;
6747 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6748 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6750 { // scientific rounding
6752 fValue
= 400000.0 / 7.0;
6753 fExpectedRoundVal
= 57100.0;
6754 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6755 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6756 fValue
= 4.0 / 70000.0;
6757 fExpectedRoundVal
= 5.71e-5;
6758 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6759 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6760 // engineering rounding tdf#106252
6761 aCode
= "##0.000E0";
6762 fValue
= 400000.0 / 7.0;
6763 fExpectedRoundVal
= 57.143e3
;
6764 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6765 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6766 fValue
= 4000000.0 / 7.0;
6767 fExpectedRoundVal
= 571.429e3
;
6768 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6769 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6770 fValue
= 40000000.0 / 7.0;
6771 fExpectedRoundVal
= 5.714e6
;
6772 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6773 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6774 fValue
= 4.0 / 70000.0;
6775 fExpectedRoundVal
= 57.143e-6;
6776 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6777 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6778 fValue
= 4.0 / 7000.0;
6779 fExpectedRoundVal
= 571.429e-6;
6780 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6781 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6782 fValue
= 4.0 / 700.0;
6783 fExpectedRoundVal
= 5.714e-3;
6784 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6785 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6786 aCode
= "##?0.0#E0";
6787 fValue
= 400000.0 / 7.0;
6788 fExpectedRoundVal
= 5.71e4
;
6789 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6790 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6791 fValue
= 4000000.0 / 7.0;
6792 fExpectedRoundVal
= 57.14e4
;
6793 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6794 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6795 fValue
= 40000000.0 / 7.0;
6796 fExpectedRoundVal
= 571.43e4
;
6797 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6798 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6799 fValue
= 400000000.0 / 7.0;
6800 fExpectedRoundVal
= 5714.29e4
;
6801 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6802 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6803 fValue
= 4.0 / 70000.0;
6804 fExpectedRoundVal
= 5714.29e-8;
6805 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6806 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6807 fValue
= 4.0 / 7000.0;
6808 fExpectedRoundVal
= 5.71e-4;
6809 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6810 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6811 fValue
= 4.0 / 700.0;
6812 fExpectedRoundVal
= 57.14e-4;
6813 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6814 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6815 fValue
= 4.0 / 70.0;
6816 fExpectedRoundVal
= 571.43e-4;
6817 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6818 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6820 { // fraction rounding tdf#105657
6823 fExpectedRoundVal
= 1.0/3.0;
6824 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6825 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6830 fExpectedRoundVal
= 0.35;
6831 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6832 checkPrecisionAsShown( aCode
, -fValue
, -fExpectedRoundVal
);
6834 { // several sub-formats tdf#106052
6835 aCode
= "0.00;-0.000";
6837 fExpectedRoundVal
= 0.33;
6838 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6840 fExpectedRoundVal
= -0.333;
6841 checkPrecisionAsShown( aCode
, fValue
, fExpectedRoundVal
);
6844 setCalcAsShown( m_pDoc
, false);
6845 m_pDoc
->DeleteTab(0);
6848 CPPUNIT_TEST_FIXTURE(Test
, testProtectedSheetEditByRow
)
6850 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
6851 m_pDoc
->InsertTab(0, u
"Protected"_ustr
);
6854 // Remove protected flags from rows 2-5.
6855 ScPatternAttr
aAttr(m_pDoc
->getCellAttributeHelper());
6856 aAttr
.GetItemSet().Put(ScProtectionAttr(false));
6857 m_pDoc
->ApplyPatternAreaTab(0, 1, m_pDoc
->MaxCol(), 4, 0, aAttr
);
6859 // Protect the sheet without any options.
6860 ScTableProtection aProtect
;
6861 aProtect
.setProtected(true);
6862 m_pDoc
->SetTabProtection(0, &aProtect
);
6864 // Try to delete row 3. It should fail.
6865 ScRange
aRow3(0,2,0,m_pDoc
->MaxCol(),2,0);
6866 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6867 aMark
.SelectOneTable(0);
6868 bool bDeleted
= rDocFunc
.DeleteCells(aRow3
, &aMark
, DelCellCmd::Rows
, true);
6869 CPPUNIT_ASSERT_MESSAGE("deletion of row 3 should fail.", !bDeleted
);
6871 // Protect the sheet but allow row deletion.
6872 aProtect
.setOption(ScTableProtection::DELETE_ROWS
, true);
6873 m_pDoc
->SetTabProtection(0, &aProtect
);
6875 // Now we should be able to delete row 3.
6876 bDeleted
= rDocFunc
.DeleteCells(aRow3
, &aMark
, DelCellCmd::Rows
, true);
6877 CPPUNIT_ASSERT_MESSAGE("deletion of row 3 should succeed.", bDeleted
);
6879 // But, row deletion should still fail on a protected row.
6880 ScRange
aRow10(0,9,0,m_pDoc
->MaxCol(),9,0);
6881 bDeleted
= rDocFunc
.DeleteCells(aRow10
, &aMark
, DelCellCmd::Rows
, true);
6882 CPPUNIT_ASSERT_MESSAGE("deletion of row 10 should not be allowed.", !bDeleted
);
6884 // Try inserting a new row. It should fail.
6885 bool bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_AFTER
, true, true);
6886 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should fail.", !bInserted
);
6888 // Allow row insertions.
6889 aProtect
.setOption(ScTableProtection::INSERT_ROWS
, true);
6890 m_pDoc
->SetTabProtection(0, &aProtect
);
6892 bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_AFTER
, true, true);
6893 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should succeed.", bInserted
);
6895 // Row insertion is allowed even when the rows above and below have protected flags set.
6896 bInserted
= rDocFunc
.InsertCells(aRow10
, &aMark
, INS_INSROWS_AFTER
, true, true);
6897 CPPUNIT_ASSERT_MESSAGE("row insertion at row 10 should succeed.", bInserted
);
6900 m_pDoc
->InsertTab(1, u
"Matrix"_ustr
); // This sheet is unprotected.
6903 // Insert matrix into B2:C3.
6904 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6905 aMark
.SelectOneTable(1);
6906 m_pDoc
->InsertMatrixFormula(1, 1, 2, 2, aMark
, u
"={1;2|3;4}"_ustr
);
6908 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,1)));
6909 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,1)));
6910 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,1)));
6911 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(2,2,1)));
6913 // Try to insert a row at row 3. It should fail because of matrix's presence.
6915 ScRange
aRow3(0,2,1,m_pDoc
->MaxCol(),2,1);
6916 bool bInserted
= rDocFunc
.InsertCells(aRow3
, &aMark
, INS_INSROWS_BEFORE
, true, true);
6917 CPPUNIT_ASSERT_MESSAGE("row insertion at row 3 should fail.", !bInserted
);
6920 m_pDoc
->DeleteTab(1);
6921 m_pDoc
->DeleteTab(0);
6924 CPPUNIT_TEST_FIXTURE(Test
, testProtectedSheetEditByColumn
)
6926 ScDocFunc
& rDocFunc
= m_xDocShell
->GetDocFunc();
6927 m_pDoc
->InsertTab(0, u
"Protected"_ustr
);
6930 // Remove protected flags from columns B to E.
6931 ScPatternAttr
aAttr(m_pDoc
->getCellAttributeHelper());
6932 aAttr
.GetItemSet().Put(ScProtectionAttr(false));
6933 m_pDoc
->ApplyPatternAreaTab(1, 0, 4, m_pDoc
->MaxRow(), 0, aAttr
);
6935 // Protect the sheet without any options.
6936 ScTableProtection aProtect
;
6937 aProtect
.setProtected(true);
6938 m_pDoc
->SetTabProtection(0, &aProtect
);
6940 // Try to delete column C. It should fail.
6941 ScRange
aCol3(2,0,0,2,m_pDoc
->MaxRow(),0);
6942 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6943 aMark
.SelectOneTable(0);
6944 bool bDeleted
= rDocFunc
.DeleteCells(aCol3
, &aMark
, DelCellCmd::Cols
, true);
6945 CPPUNIT_ASSERT_MESSAGE("deletion of column 3 should fail.", !bDeleted
);
6947 // Protect the sheet but allow column deletion.
6948 aProtect
.setOption(ScTableProtection::DELETE_COLUMNS
, true);
6949 m_pDoc
->SetTabProtection(0, &aProtect
);
6951 // Now we should be able to delete column C.
6952 bDeleted
= rDocFunc
.DeleteCells(aCol3
, &aMark
, DelCellCmd::Cols
, true);
6953 CPPUNIT_ASSERT_MESSAGE("deletion of column 3 should succeed.", bDeleted
);
6955 // But, column deletion should still fail on a protected column.
6956 ScRange
aCol10(9,0,0,9,m_pDoc
->MaxRow(),0);
6957 bDeleted
= rDocFunc
.DeleteCells(aCol10
, &aMark
, DelCellCmd::Cols
, true);
6958 CPPUNIT_ASSERT_MESSAGE("deletion of column 10 should not be allowed.", !bDeleted
);
6960 // Try inserting a new column. It should fail.
6961 bool bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6962 CPPUNIT_ASSERT_MESSAGE("column insertion at column 3 should fail.", !bInserted
);
6964 // Allow column insertions.
6965 aProtect
.setOption(ScTableProtection::INSERT_COLUMNS
, true);
6966 m_pDoc
->SetTabProtection(0, &aProtect
);
6968 bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6969 CPPUNIT_ASSERT_MESSAGE("column insertion at column 3 should succeed.", bInserted
);
6971 // Column insertion is allowed even when the columns above and below have protected flags set.
6972 bInserted
= rDocFunc
.InsertCells(aCol10
, &aMark
, INS_INSCOLS_AFTER
, true, true);
6973 CPPUNIT_ASSERT_MESSAGE("column insertion at column 10 should succeed.", bInserted
);
6976 m_pDoc
->InsertTab(1, u
"Matrix"_ustr
); // This sheet is unprotected.
6979 // Insert matrix into B2:C3.
6980 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
6981 aMark
.SelectOneTable(1);
6982 m_pDoc
->InsertMatrixFormula(1, 1, 2, 2, aMark
, u
"={1;2|3;4}"_ustr
);
6984 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,1,1)));
6985 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,1)));
6986 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,2,1)));
6987 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(2,2,1)));
6989 // Try to insert a column at column C. It should fail because of matrix's presence.
6991 ScRange
aCol3(2,0,1,2,m_pDoc
->MaxRow(),1);
6992 bool bInserted
= rDocFunc
.InsertCells(aCol3
, &aMark
, INS_INSCOLS_BEFORE
, true, true);
6993 CPPUNIT_ASSERT_MESSAGE("column insertion at column C should fail.", !bInserted
);
6996 m_pDoc
->DeleteTab(1);
6997 m_pDoc
->DeleteTab(0);
7000 CPPUNIT_TEST_FIXTURE(Test
, testInsertColumnsWithFormulaCells
)
7002 m_pDoc
->InsertTab(0, u
"Tab1"_ustr
);
7004 std::set
<SCCOL
> aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
7005 CPPUNIT_ASSERT_MESSAGE("empty sheet should contain no formula cells.", aCols
.empty());
7007 auto equals
= [](const std::set
<SCCOL
>& left
, const std::set
<SCCOL
>& right
)
7009 return left
== right
;
7012 // insert formula cells in columns 2, 4 and 6.
7013 m_pDoc
->SetFormula(ScAddress(2, 2, 0), u
"=1"_ustr
, m_pDoc
->GetGrammar());
7014 m_pDoc
->SetFormula(ScAddress(4, 2, 0), u
"=1"_ustr
, m_pDoc
->GetGrammar());
7015 m_pDoc
->SetFormula(ScAddress(6, 2, 0), u
"=1"_ustr
, m_pDoc
->GetGrammar());
7017 aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
7019 std::set
<SCCOL
> aExpected
= { 2, 4, 6 };
7020 CPPUNIT_ASSERT_MESSAGE("Columns 2, 4 and 6 should contain formula cells.", equals(aExpected
, aCols
));
7022 // Insert 2 columns at column A to shift everything to right by 2.
7023 m_pDoc
->InsertCol(0, 0, m_pDoc
->MaxRow(), 0, 0, 2);
7025 aExpected
= { 4, 6, 8 };
7026 aCols
= m_pDoc
->QueryColumnsWithFormulaCells(0);
7027 CPPUNIT_ASSERT_MESSAGE("Columns 4, 6 and 8 should contain formula cells.", equals(aExpected
, aCols
));
7031 m_pDoc
->CheckIntegrity(0);
7033 catch (const std::exception
& e
)
7035 std::ostringstream os
;
7036 os
<< "document integrity check failed: " << e
.what();
7037 CPPUNIT_FAIL(os
.str());
7040 m_pDoc
->DeleteTab(0);
7043 CPPUNIT_TEST_FIXTURE(Test
, testDocumentModelAccessor_getDocumentCurrencies
)
7045 m_pDoc
->InsertTab(0, u
"Sheet1"_ustr
);
7047 // Check document currencies - expect 0
7048 auto pAccessor
= m_xDocShell
->GetDocumentModelAccessor();
7049 CPPUNIT_ASSERT(pAccessor
);
7050 CPPUNIT_ASSERT_EQUAL(size_t(0), pAccessor
->getDocumentCurrencies().size());
7052 // Set a currency to a cell
7054 m_pDoc
->SetValue(ScAddress(0, 0, 0), 2.0);
7056 OUString aCode
= u
"#.##0,00[$€-424]"_ustr
;
7058 sal_Int32 nCheckPos
;
7059 SvNumFormatType eType
;
7062 m_pDoc
->GetFormatTable()->PutEntry(aCode
, nCheckPos
, eType
, nFormat
, LANGUAGE_SLOVENIAN
);
7063 CPPUNIT_ASSERT_EQUAL(SvNumFormatType::CURRENCY
, eType
);
7065 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
7066 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
7067 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
7068 m_pDoc
->ApplyPattern(0, 0, 0, aNewAttrs
); // A1.
7070 CPPUNIT_ASSERT_EQUAL(u
"2,00€"_ustr
, m_pDoc
->GetString(ScAddress(0, 0, 0)));
7073 // Check document currencies again
7074 auto aCurrencyIDs
= pAccessor
->getDocumentCurrencies();
7075 CPPUNIT_ASSERT_EQUAL(size_t(1), aCurrencyIDs
.size());
7077 CPPUNIT_ASSERT_EQUAL(LANGUAGE_SLOVENIAN
, aCurrencyIDs
[0].eLanguage
);
7078 CPPUNIT_ASSERT_EQUAL(u
"-424"_ustr
, aCurrencyIDs
[0].aExtension
);
7079 CPPUNIT_ASSERT_EQUAL(u
"€"_ustr
, aCurrencyIDs
[0].aSymbol
);
7081 // Set the same currency to 2 more cells
7083 m_pDoc
->SetValue(ScAddress(1, 1, 0), 5.0);
7084 m_pDoc
->SetValue(ScAddress(2, 2, 0), 7.0);
7086 OUString aCode
= u
"#.##0,00[$€-424]"_ustr
;
7088 sal_Int32 nCheckPos
;
7089 SvNumFormatType eType
;
7092 m_pDoc
->GetFormatTable()->PutEntry(aCode
, nCheckPos
, eType
, nFormat
, LANGUAGE_SLOVENIAN
);
7093 CPPUNIT_ASSERT_EQUAL(SvNumFormatType::CURRENCY
, eType
);
7095 ScPatternAttr
aNewAttrs(m_pDoc
->getCellAttributeHelper());
7096 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
7097 rSet
.Put(SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
7098 m_pDoc
->ApplyPattern(1, 1, 0, aNewAttrs
); // B2.
7099 m_pDoc
->ApplyPattern(2, 2, 0, aNewAttrs
); // C3.
7101 CPPUNIT_ASSERT_EQUAL(u
"5,00€"_ustr
, m_pDoc
->GetString(ScAddress(1, 1, 0)));
7102 CPPUNIT_ASSERT_EQUAL(u
"7,00€"_ustr
, m_pDoc
->GetString(ScAddress(2, 2, 0)));
7105 // Check document currencies again - should be 1 entry only
7106 aCurrencyIDs
= pAccessor
->getDocumentCurrencies();
7107 CPPUNIT_ASSERT_EQUAL(size_t(1), aCurrencyIDs
.size());
7109 CPPUNIT_ASSERT_EQUAL(LANGUAGE_SLOVENIAN
, aCurrencyIDs
[0].eLanguage
);
7110 CPPUNIT_ASSERT_EQUAL(u
"-424"_ustr
, aCurrencyIDs
[0].aExtension
);
7111 CPPUNIT_ASSERT_EQUAL(u
"€"_ustr
, aCurrencyIDs
[0].aSymbol
);
7115 CPPUNIT_PLUGIN_IMPLEMENT();
7117 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */