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"
12 #include <scopetools.hxx>
13 #include <formulacell.hxx>
14 #include <docfunc.hxx>
15 #include <inputopt.hxx>
16 #include <tokenstringcontext.hxx>
17 #include <refupdatecontext.hxx>
19 #include <validat.hxx>
20 #include <scitems.hxx>
21 #include <docpool.hxx>
23 #include <undomanager.hxx>
25 #include <formula/vectortoken.hxx>
26 #include <svl/intitem.hxx>
32 using namespace formula
;
37 void setExpandRefs(bool bExpand
)
39 ScModule
* pMod
= SC_MOD();
40 ScInputOptions aOpt
= pMod
->GetInputOptions();
41 aOpt
.SetExpandRefs(bExpand
);
42 pMod
->SetInputOptions(aOpt
);
45 void testFormulaRefUpdateNameCopySheetCheckTab( const ScDocument
* pDoc
, SCTAB nTab
, bool bCheckNames
)
49 const ScRangeData
* pName
;
50 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("GLOBAL");
51 CPPUNIT_ASSERT_MESSAGE("Sheet-local name GLOBAL should exist", pName
);
52 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("LOCAL");
53 CPPUNIT_ASSERT_MESSAGE("Sheet-local name LOCAL should exist", pName
);
54 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("GLOBAL_GLOBAL");
55 CPPUNIT_ASSERT_MESSAGE("Sheet-local name GLOBAL_GLOBAL should exist", pName
);
56 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("GLOBAL_LOCAL");
57 CPPUNIT_ASSERT_MESSAGE("Sheet-local name GLOBAL_LOCAL should exist", pName
);
58 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("GLOBAL_UNUSED");
59 CPPUNIT_ASSERT_MESSAGE("Sheet-local name GLOBAL_UNUSED should exist", pName
);
60 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("GLOBAL_UNUSED_NOREF");
61 CPPUNIT_ASSERT_MESSAGE("Sheet-local name GLOBAL_UNUSED_NOREF should not exist", !pName
);
62 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("LOCAL_GLOBAL");
63 CPPUNIT_ASSERT_MESSAGE("Sheet-local name LOCAL_GLOBAL should exist", pName
);
64 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("LOCAL_LOCAL");
65 CPPUNIT_ASSERT_MESSAGE("Sheet-local name LOCAL_LOCAL should exist", pName
);
66 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("LOCAL_UNUSED");
67 CPPUNIT_ASSERT_MESSAGE("Sheet-local name LOCAL_UNUSED should exist", pName
);
68 pName
= pDoc
->GetRangeName(nTab
)->findByUpperName("LOCAL_UNUSED_NOREF");
69 CPPUNIT_ASSERT_MESSAGE("Sheet-local name LOCAL_UNUSED_NOREF should exist", pName
);
72 ScAddress
aPos(0,0,0);
75 int nSheet
= nTab
+ 1;
76 CPPUNIT_ASSERT_EQUAL( 1.0 * nSheet
, pDoc
->GetValue(aPos
));
78 CPPUNIT_ASSERT_EQUAL( 11.0 * nSheet
, pDoc
->GetValue(aPos
));
80 CPPUNIT_ASSERT_EQUAL( 100.0 * nSheet
, pDoc
->GetValue(aPos
));
82 CPPUNIT_ASSERT_EQUAL( 11000.0 * nSheet
, pDoc
->GetValue(aPos
));
84 CPPUNIT_ASSERT_EQUAL( 10000.0 * nSheet
, pDoc
->GetValue(aPos
));
86 CPPUNIT_ASSERT_EQUAL( 1100000.0 * nSheet
, pDoc
->GetValue(aPos
));
92 class TestFormula
: public ScUcalcTestBase
96 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaCreateStringFromTokens
)
99 m_pDoc
->InsertTab(0, "Test");
100 m_pDoc
->InsertTab(1, "Kevin's Data");
101 m_pDoc
->InsertTab(2, "Past Data");
102 m_pDoc
->InsertTab(3, "2013");
104 // Insert named ranges.
105 static const struct {
110 { true, "x", "Test.H1" },
111 { true, "y", "Test.H2" },
112 { true, "z", "Test.H3" },
114 { false, "sheetx", "Test.J1" }
117 ScRangeName
* pGlobalNames
= m_pDoc
->GetRangeName();
118 ScRangeName
* pSheetNames
= m_pDoc
->GetRangeName(0);
119 CPPUNIT_ASSERT_MESSAGE("Failed to obtain global named expression object.", pGlobalNames
);
120 CPPUNIT_ASSERT_MESSAGE("Failed to obtain sheet-local named expression object.", pSheetNames
);
122 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aNames
); ++i
)
124 ScRangeData
* pName
= new ScRangeData(
125 *m_pDoc
, OUString::createFromAscii(aNames
[i
].pName
), OUString::createFromAscii(aNames
[i
].pExpr
),
126 ScAddress(0,0,0), ScRangeData::Type::Name
, formula::FormulaGrammar::GRAM_NATIVE
);
128 if (aNames
[i
].bGlobal
)
130 bool bInserted
= pGlobalNames
->insert(pName
);
131 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bInserted
);
135 bool bInserted
= pSheetNames
->insert(pName
);
136 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bInserted
);
141 static const struct {
149 { "Table1", 0, 0, 0, 10, 10 },
150 { "Table2", 1, 0, 0, 10, 10 },
151 { "Table3", 2, 0, 0, 10, 10 }
154 ScDBCollection
* pDBs
= m_pDoc
->GetDBCollection();
155 CPPUNIT_ASSERT_MESSAGE("Failed to fetch DB collection object.", pDBs
);
157 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aDBs
); ++i
)
159 std::unique_ptr
<ScDBData
> pData( new ScDBData(
160 OUString::createFromAscii(
161 aDBs
[i
].pName
), aDBs
[i
].nTab
, aDBs
[i
].nCol1
, aDBs
[i
].nRow1
, aDBs
[i
].nCol2
,aDBs
[i
].nRow2
) );
162 bool bInserted
= pDBs
->getNamedDBs().insert(std::move(pData
));
163 CPPUNIT_ASSERT_MESSAGE(
165 OString::Concat("Failed to insert \"") + aDBs
[i
].pName
+ "\"").getStr(),
169 const char* aTests
[] = {
171 "SUM(A1:A10;B1:B10;C5;D6)",
172 "IF(Test.B10<>10;\"Good\";\"Bad\")",
173 "AVERAGE('2013'.B10:C20)",
174 "'Kevin''s Data'.B10",
175 "'Past Data'.B1+'2013'.B2*(1+'Kevin''s Data'.C10)",
176 "x+y*z", // named ranges
177 "SUM(sheetx;x;y;z)", // sheet local and global named ranges mixed
178 "MAX(Table1)+MIN(Table2)*SUM(Table3)", // database ranges
179 "{1;TRUE;3|FALSE;5;\"Text\"|;;}", // inline matrix
180 "SUM('file:///path/to/fake.file'#$Sheet.A1:B10)",
184 sc::TokenStringContext
aCxt(*m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH
);
186 // Artificially add external reference data after the context object is
188 aCxt
.maExternalFileNames
.emplace_back("file:///path/to/fake.file");
189 std::vector
<OUString
> aExtTabNames
;
190 aExtTabNames
.emplace_back("Sheet");
191 aCxt
.maExternalCachedTabNames
.emplace(0, aExtTabNames
);
193 ScAddress
aPos(0,0,0);
195 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aTests
); ++i
)
198 OUString aFormula
= OUString::createFromAscii(aTests
[i
]);
200 ScCompiler
aComp(*m_pDoc
, aPos
, FormulaGrammar::GRAM_ENGLISH
);
201 #if 0 // TODO: This call to CompileString() causes the cppunittester to somehow fail on Windows.
202 pArray
.reset(aComp
.CompileString(aFormula
));
203 CPPUNIT_ASSERT_MESSAGE("Failed to compile formula string.", pArray
.get());
205 OUString aCheck
= pArray
->CreateString(aCxt
, aPos
);
206 CPPUNIT_ASSERT_EQUAL(aFormula
, aCheck
);
210 m_pDoc
->DeleteTab(3);
211 m_pDoc
->DeleteTab(2);
212 m_pDoc
->DeleteTab(1);
213 m_pDoc
->DeleteTab(0);
218 bool isEmpty( const formula::VectorRefArray
& rArray
, size_t nPos
)
220 if (rArray
.mpStringArray
)
222 if (rArray
.mpStringArray
[nPos
])
226 if (rArray
.mpNumericArray
)
227 return std::isnan(rArray
.mpNumericArray
[nPos
]);
232 bool equals( const formula::VectorRefArray
& rArray
, size_t nPos
, double fVal
)
234 if (rArray
.mpStringArray
&& rArray
.mpStringArray
[nPos
])
235 // This is a string cell.
238 return rArray
.mpNumericArray
&& rArray
.mpNumericArray
[nPos
] == fVal
;
241 bool equals( const formula::VectorRefArray
& rArray
, size_t nPos
, const OUString
& rVal
)
243 if (!rArray
.mpStringArray
)
246 bool bEquals
= OUString(rArray
.mpStringArray
[nPos
]).equalsIgnoreAsciiCase(rVal
);
249 cerr
<< "Expected: " << rVal
.toAsciiUpperCase() << " (upcased)" << endl
;
250 cerr
<< "Actual: " << OUString(rArray
.mpStringArray
[nPos
]) << " (upcased)" << endl
;
257 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaParseReference
)
259 OUString
aTab1("90's Music"), aTab2("90's and 70's"), aTab3("All Others"), aTab4("NoQuote");
260 m_pDoc
->InsertTab(0, "Dummy"); // just to shift the sheet indices...
261 m_pDoc
->InsertTab(1, aTab1
); // name with a single quote.
262 m_pDoc
->InsertTab(2, aTab2
); // name with 2 single quotes.
263 m_pDoc
->InsertTab(3, aTab3
); // name without single quotes.
264 m_pDoc
->InsertTab(4, aTab4
); // name that doesn't require to be quoted.
267 m_pDoc
->GetName(1, aTabName
);
268 CPPUNIT_ASSERT_EQUAL(aTab1
, aTabName
);
269 m_pDoc
->GetName(2, aTabName
);
270 CPPUNIT_ASSERT_EQUAL(aTab2
, aTabName
);
271 m_pDoc
->GetName(3, aTabName
);
272 CPPUNIT_ASSERT_EQUAL(aTab3
, aTabName
);
273 m_pDoc
->GetName(4, aTabName
);
274 CPPUNIT_ASSERT_EQUAL(aTab4
, aTabName
);
276 // Make sure the formula input and output match.
278 const char* aChecks
[] = {
279 "='90''s Music'.B12",
280 "='90''s and 70''s'.$AB$100",
281 "='All Others'.Z$100",
285 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aChecks
); ++i
)
287 // Use the 'Dummy' sheet for this.
288 m_pDoc
->SetString(ScAddress(0,0,0), OUString::createFromAscii(aChecks
[i
]));
289 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString::createFromAscii(aChecks
[i
]), m_pDoc
->GetFormula(0,0,0));
294 ScAddress::ExternalInfo aExtInfo
;
295 ScRefFlags nRes
= aPos
.Parse("'90''s Music'.D10", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
, &aExtInfo
);
296 CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes
& ScRefFlags::VALID
));
297 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(1), aPos
.Tab());
298 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(3), aPos
.Col());
299 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(9), aPos
.Row());
300 CPPUNIT_ASSERT_MESSAGE("This is not an external address.", !aExtInfo
.mbExternal
);
302 nRes
= aPos
.Parse("'90''s and 70''s'.C100", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
, &aExtInfo
);
303 CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes
& ScRefFlags::VALID
));
304 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(2), aPos
.Tab());
305 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), aPos
.Col());
306 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(99), aPos
.Row());
307 CPPUNIT_ASSERT_MESSAGE("This is not an external address.", !aExtInfo
.mbExternal
);
309 nRes
= aPos
.Parse("'All Others'.B3", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
, &aExtInfo
);
310 CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes
& ScRefFlags::VALID
));
311 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(3), aPos
.Tab());
312 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), aPos
.Col());
313 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), aPos
.Row());
314 CPPUNIT_ASSERT_MESSAGE("This is not an external address.", !aExtInfo
.mbExternal
);
316 nRes
= aPos
.Parse("NoQuote.E13", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
, &aExtInfo
);
317 CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes
& ScRefFlags::VALID
));
318 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(4), aPos
.Tab());
319 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(4), aPos
.Col());
320 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(12), aPos
.Row());
321 CPPUNIT_ASSERT_MESSAGE("This is not an external address.", !aExtInfo
.mbExternal
);
325 aRange
.aStart
.SetTab(0);
326 nRes
= aRange
.Parse(":B", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
327 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
329 aRange
.aStart
.SetTab(0);
330 nRes
= aRange
.Parse("B:", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
331 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
333 aRange
.aStart
.SetTab(0);
334 nRes
= aRange
.Parse(":B2", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
335 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
337 aRange
.aStart
.SetTab(0);
338 nRes
= aRange
.Parse("B2:", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
339 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
341 aRange
.aStart
.SetTab(0);
342 nRes
= aRange
.Parse(":2", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
343 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
345 aRange
.aStart
.SetTab(0);
346 nRes
= aRange
.Parse("2:", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
347 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
349 aRange
.aStart
.SetTab(0);
350 nRes
= aRange
.Parse(":2B", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
351 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
353 aRange
.aStart
.SetTab(0);
354 nRes
= aRange
.Parse("2B:", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
355 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
357 aRange
.aStart
.SetTab(0);
358 nRes
= aRange
.Parse("abc_foo:abc_bar", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
359 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
361 aRange
.aStart
.SetTab(0);
362 nRes
= aRange
.Parse("B1:B2~C1", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
363 CPPUNIT_ASSERT_MESSAGE("Should fail to parse.", !(nRes
& ScRefFlags::VALID
));
365 aRange
.aStart
.SetTab(0);
366 nRes
= aRange
.Parse("B:B", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
367 CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes
& ScRefFlags::VALID
));
368 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(0), aRange
.aStart
.Tab());
369 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), aRange
.aStart
.Col());
370 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), aRange
.aStart
.Row());
371 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(0), aRange
.aEnd
.Tab());
372 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), aRange
.aEnd
.Col());
373 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxRow(), aRange
.aEnd
.Row());
374 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
375 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
),
376 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
377 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
)));
378 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::ZERO
),
379 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_ABS
| ScRefFlags::COL2_ABS
)));
380 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::ROW_ABS
| ScRefFlags::ROW2_ABS
),
381 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::ROW_ABS
| ScRefFlags::ROW2_ABS
)));
383 aRange
.aStart
.SetTab(0);
384 nRes
= aRange
.Parse("2:2", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
385 CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes
& ScRefFlags::VALID
));
386 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(0), aRange
.aStart
.Tab());
387 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), aRange
.aStart
.Col());
388 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), aRange
.aStart
.Row());
389 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(0), aRange
.aEnd
.Tab());
390 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxCol(), aRange
.aEnd
.Col());
391 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), aRange
.aEnd
.Row());
392 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
393 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
),
394 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
395 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
)));
396 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::ZERO
),
397 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::ROW_ABS
| ScRefFlags::ROW2_ABS
)));
398 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::COL_ABS
| ScRefFlags::COL2_ABS
),
399 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_ABS
| ScRefFlags::COL2_ABS
)));
401 nRes
= aRange
.Parse("NoQuote.B:C", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
402 CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes
& ScRefFlags::VALID
));
403 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(4), aRange
.aStart
.Tab());
404 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), aRange
.aStart
.Col());
405 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), aRange
.aStart
.Row());
406 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(4), aRange
.aEnd
.Tab());
407 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(2), aRange
.aEnd
.Col());
408 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxRow(), aRange
.aEnd
.Row());
409 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
410 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
),
411 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
412 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
)));
413 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::ZERO
),
414 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_ABS
| ScRefFlags::COL2_ABS
)));
415 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::ROW_ABS
| ScRefFlags::ROW2_ABS
),
416 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::ROW_ABS
| ScRefFlags::ROW2_ABS
)));
418 // Both rows at sheet bounds and relative => convert to absolute => entire column reference.
419 aRange
.aStart
.SetTab(0);
420 nRes
= aRange
.Parse(m_pDoc
->MaxRow() == MAXROW
? OUString("B1:B1048576")
421 : OUString("B1:B16777216"),
422 *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
423 CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes
& ScRefFlags::VALID
));
424 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(0), aRange
.aStart
.Tab());
425 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), aRange
.aStart
.Col());
426 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), aRange
.aStart
.Row());
427 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(0), aRange
.aEnd
.Tab());
428 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), aRange
.aEnd
.Col());
429 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxRow(), aRange
.aEnd
.Row());
430 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
431 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
),
432 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
433 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
)));
434 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::ZERO
),
435 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_ABS
| ScRefFlags::COL2_ABS
)));
436 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::ROW_ABS
| ScRefFlags::ROW2_ABS
),
437 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::ROW_ABS
| ScRefFlags::ROW2_ABS
)));
439 // Both columns at sheet bounds and relative => convert to absolute => entire row reference.
440 aRange
.aStart
.SetTab(0);
441 nRes
= aRange
.Parse("A2:" + m_pDoc
->MaxColAsString() + "2", *m_pDoc
, formula::FormulaGrammar::CONV_OOO
);
442 CPPUNIT_ASSERT_MESSAGE("Failed to parse.", (nRes
& ScRefFlags::VALID
));
443 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(0), aRange
.aStart
.Tab());
444 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(0), aRange
.aStart
.Col());
445 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), aRange
.aStart
.Row());
446 CPPUNIT_ASSERT_EQUAL(static_cast<SCTAB
>(0), aRange
.aEnd
.Tab());
447 CPPUNIT_ASSERT_EQUAL(m_pDoc
->MaxCol(), aRange
.aEnd
.Col());
448 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), aRange
.aEnd
.Row());
449 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
450 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
),
451 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_VALID
| ScRefFlags::ROW_VALID
| ScRefFlags::TAB_VALID
|
452 ScRefFlags::COL2_VALID
| ScRefFlags::ROW2_VALID
| ScRefFlags::TAB2_VALID
)));
453 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::ZERO
),
454 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::ROW_ABS
| ScRefFlags::ROW2_ABS
)));
455 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(ScRefFlags::COL_ABS
| ScRefFlags::COL2_ABS
),
456 static_cast<sal_uInt16
>(nRes
& (ScRefFlags::COL_ABS
| ScRefFlags::COL2_ABS
)));
458 // Check for reference input conversion to and display string of entire column/row.
460 const char* row1048576Checks
[][2] = {
462 { "=B1:B1048576", "=B:B" },
463 { "=B1:B$1048576", "=B1:B$1048576" },
464 { "=B$1:B1048576", "=B$1:B1048576" },
465 { "=B$1:B$1048576", "=B:B" }
467 const char* row16777216Checks
[][2] = {
469 { "=B1:B16777216", "=B:B" },
470 { "=B1:B$16777216", "=B1:B$16777216" },
471 { "=B$1:B16777216", "=B$1:B16777216" },
472 { "=B$1:B$16777216", "=B:B" }
474 const char* col1024Checks
[][2] = {
476 { "=A2:AMJ2", "=2:2" },
477 { "=A2:$AMJ2", "=A2:$AMJ2" },
478 { "=$A2:AMJ2", "=$A2:AMJ2" },
479 { "=$A2:$AMJ2", "=2:2" }
481 const char* col16384Checks
[][2] = {
483 { "=A2:XFD2", "=2:2" },
484 { "=A2:$XFD2", "=A2:$XFD2" },
485 { "=$A2:XFD2", "=$A2:XFD2" },
486 { "=$A2:$XFD2", "=2:2" }
489 if (m_pDoc
->MaxRow() == 1048575)
491 for (const auto& check
: row1048576Checks
)
493 // Use the 'Dummy' sheet for this.
494 m_pDoc
->SetString(ScAddress(0,0,0), OUString::createFromAscii(check
[0]));
495 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString::createFromAscii(check
[1]), m_pDoc
->GetFormula(0,0,0));
500 CPPUNIT_ASSERT_EQUAL(SCROW(16777215), m_pDoc
->MaxRow());
501 for (const auto& check
: row16777216Checks
)
503 m_pDoc
->SetString(ScAddress(0,0,0), OUString::createFromAscii(check
[0]));
504 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString::createFromAscii(check
[1]), m_pDoc
->GetFormula(0,0,0));
507 if (m_pDoc
->MaxCol() == 1023)
509 for (const auto& check
: col1024Checks
)
511 m_pDoc
->SetString(ScAddress(0,0,0), OUString::createFromAscii(check
[0]));
512 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString::createFromAscii(check
[1]), m_pDoc
->GetFormula(0,0,0));
517 CPPUNIT_ASSERT_EQUAL(SCCOL(16383), m_pDoc
->MaxCol());
518 for (const auto& check
: col16384Checks
)
520 m_pDoc
->SetString(ScAddress(0,0,0), OUString::createFromAscii(check
[0]));
521 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString::createFromAscii(check
[1]), m_pDoc
->GetFormula(0,0,0));
526 m_pDoc
->DeleteTab(4);
527 m_pDoc
->DeleteTab(3);
528 m_pDoc
->DeleteTab(2);
529 m_pDoc
->DeleteTab(1);
530 m_pDoc
->DeleteTab(0);
533 CPPUNIT_TEST_FIXTURE(TestFormula
, testFetchVectorRefArray
)
535 m_pDoc
->InsertTab(0, "Test");
537 // All numeric cells in Column A.
538 m_pDoc
->SetValue(ScAddress(0,0,0), 1);
539 m_pDoc
->SetValue(ScAddress(0,1,0), 2);
540 m_pDoc
->SetValue(ScAddress(0,2,0), 3);
541 m_pDoc
->SetValue(ScAddress(0,3,0), 4);
543 formula::VectorRefArray aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(0,0,0), 4);
544 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
545 CPPUNIT_ASSERT_MESSAGE("Array is expected to be numeric cells only.", !aArray
.mpStringArray
);
546 CPPUNIT_ASSERT_EQUAL(1.0, aArray
.mpNumericArray
[0]);
547 CPPUNIT_ASSERT_EQUAL(2.0, aArray
.mpNumericArray
[1]);
548 CPPUNIT_ASSERT_EQUAL(3.0, aArray
.mpNumericArray
[2]);
549 CPPUNIT_ASSERT_EQUAL(4.0, aArray
.mpNumericArray
[3]);
551 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(0,0,0), 5);
552 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
553 CPPUNIT_ASSERT_MESSAGE("Array is expected to be numeric cells only.", !aArray
.mpStringArray
);
554 CPPUNIT_ASSERT_EQUAL(1.0, aArray
.mpNumericArray
[0]);
555 CPPUNIT_ASSERT_EQUAL(2.0, aArray
.mpNumericArray
[1]);
556 CPPUNIT_ASSERT_EQUAL(3.0, aArray
.mpNumericArray
[2]);
557 CPPUNIT_ASSERT_EQUAL(4.0, aArray
.mpNumericArray
[3]);
558 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 4));
560 // All string cells in Column B. Note that the fetched string arrays are
561 // only to be compared case-insensitively. Right now, we use upper cased
562 // strings to achieve case-insensitive-ness, but that may change. So,
563 // don't count on that.
564 m_pDoc
->SetString(ScAddress(1,0,0), "Andy");
565 m_pDoc
->SetString(ScAddress(1,1,0), "Bruce");
566 m_pDoc
->SetString(ScAddress(1,2,0), "Charlie");
567 m_pDoc
->SetString(ScAddress(1,3,0), "David");
568 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(1,0,0), 5);
569 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
570 CPPUNIT_ASSERT_MESSAGE("Array is expected to be string cells only.", !aArray
.mpNumericArray
);
571 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 0, "Andy"));
572 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 1, "Bruce"));
573 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 2, "Charlie"));
574 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 3, "David"));
575 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 4));
577 // Mixture of numeric, string, and empty cells in Column C.
578 m_pDoc
->SetString(ScAddress(2,0,0), "Header");
579 m_pDoc
->SetValue(ScAddress(2,1,0), 11);
580 m_pDoc
->SetValue(ScAddress(2,2,0), 12);
581 m_pDoc
->SetValue(ScAddress(2,3,0), 13);
582 m_pDoc
->SetString(ScAddress(2,5,0), "=SUM(C2:C4)");
585 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(2,0,0), 7);
586 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
587 CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray
.mpNumericArray
);
588 CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray
.mpStringArray
);
589 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 0, "Header"));
590 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 1, 11));
591 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 2, 12));
592 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 3, 13));
593 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 4));
594 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 5, 36));
595 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 6));
597 // Mixed type again in Column D, but it starts with a numeric cell.
598 m_pDoc
->SetValue(ScAddress(3,0,0), 10);
599 m_pDoc
->SetString(ScAddress(3,1,0), "Below 10");
600 // Leave 2 empty cells.
601 m_pDoc
->SetValue(ScAddress(3,4,0), 11);
602 m_pDoc
->SetString(ScAddress(3,5,0), "=12");
603 m_pDoc
->SetString(ScAddress(3,6,0), "=13");
604 m_pDoc
->SetString(ScAddress(3,7,0), "=CONCATENATE(\"A\";\"B\";\"C\")");
607 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(3,0,0), 8);
608 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
609 CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray
.mpNumericArray
);
610 CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray
.mpStringArray
);
611 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 0, 10));
612 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 1, "Below 10"));
613 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 2));
614 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 3));
615 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 4, 11));
616 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 5, 12));
617 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 6, 13));
618 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 7, "ABC"));
620 // Column E consists of formula cells whose results are all numeric.
621 for (SCROW i
= 0; i
<= 6; ++i
)
622 m_pDoc
->SetString(ScAddress(4,i
,0), "=ROW()");
625 // Leave row 7 empty.
626 m_pDoc
->SetString(ScAddress(4,8,0), "Andy");
627 m_pDoc
->SetValue(ScAddress(4,9,0), 123);
629 // This array fits within a single formula block.
630 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(4,0,0), 5);
631 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
632 CPPUNIT_ASSERT_MESSAGE("Array should be purely numeric.", aArray
.mpNumericArray
);
633 CPPUNIT_ASSERT_MESSAGE("Array should be purely numeric.", !aArray
.mpStringArray
);
634 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 0, 1));
635 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 1, 2));
636 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 2, 3));
637 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 3, 4));
638 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 4, 5));
640 // This array spans over multiple blocks.
641 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(4,0,0), 11);
642 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
643 CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray
.mpNumericArray
);
644 CPPUNIT_ASSERT_MESSAGE("Array should have both numeric and string arrays.", aArray
.mpStringArray
);
645 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 0, 1));
646 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 1, 2));
647 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 2, 3));
648 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 3, 4));
649 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 4, 5));
650 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 5, 6));
651 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 6, 7));
652 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 7));
653 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 8, "Andy"));
654 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 9, 123));
655 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 10));
657 // Hit the cache but at a different start row.
658 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(4,2,0), 3);
659 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
660 CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray
.mpNumericArray
);
661 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 0, 3));
662 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 1, 4));
663 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 2, 5));
665 // Column F begins with empty rows at the top.
666 m_pDoc
->SetValue(ScAddress(5,2,0), 1.1);
667 m_pDoc
->SetValue(ScAddress(5,3,0), 1.2);
668 m_pDoc
->SetString(ScAddress(5,4,0), "=2*8");
671 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(5,2,0), 4);
672 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
673 CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray
.mpNumericArray
);
674 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 0, 1.1));
675 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 1, 1.2));
676 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 2, 16));
677 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 3));
679 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(5,0,0), 3);
680 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
681 CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray
.mpNumericArray
);
682 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 0));
683 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 1));
684 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 2, 1.1));
686 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(5,0,0), 10);
687 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
688 CPPUNIT_ASSERT_MESSAGE("Array should at least have a numeric array.", aArray
.mpNumericArray
);
689 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 0));
690 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 1));
691 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 2, 1.1));
692 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 3, 1.2));
693 CPPUNIT_ASSERT_MESSAGE("Unexpected numeric cell.", equals(aArray
, 4, 16));
694 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 5));
695 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 6));
696 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 7));
697 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 8));
698 CPPUNIT_ASSERT_MESSAGE("This should be empty.", isEmpty(aArray
, 9));
700 // Get the array for F3:F4. This array should only consist of numeric array.
701 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(5,2,0), 3);
702 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
703 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
704 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
706 // Column G consists only of strings.
707 m_pDoc
->SetString(ScAddress(6,0,0), "Title");
708 m_pDoc
->SetString(ScAddress(6,1,0), "foo");
709 m_pDoc
->SetString(ScAddress(6,2,0), "bar");
710 m_pDoc
->SetString(ScAddress(6,3,0), "foo");
711 m_pDoc
->SetString(ScAddress(6,4,0), "baz");
712 m_pDoc
->SetString(ScAddress(6,5,0), "quack");
713 m_pDoc
->SetString(ScAddress(6,6,0), "beep");
714 m_pDoc
->SetString(ScAddress(6,7,0), "kerker");
716 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(6,1,0), 4); // G2:G5
717 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
718 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a numeric array.", !aArray
.mpNumericArray
);
719 CPPUNIT_ASSERT_MESSAGE("Array should have a string array.", aArray
.mpStringArray
);
720 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 0, "foo"));
721 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 1, "bar"));
722 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 2, "foo"));
723 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 3, "baz"));
725 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(6,2,0), 4); // G3:G6
726 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
727 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a numeric array.", !aArray
.mpNumericArray
);
728 CPPUNIT_ASSERT_MESSAGE("Array should have a string array.", aArray
.mpStringArray
);
729 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 0, "bar"));
730 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 1, "foo"));
731 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 2, "baz"));
732 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 3, "quack"));
734 // Column H starts with formula cells.
735 for (SCROW i
= 0; i
< 10; ++i
)
736 m_pDoc
->SetString(ScAddress(7,i
,0), "=ROW()");
739 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(7,3,0), 3); // H4:H6
740 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
741 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
742 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
743 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 0, 4.0));
744 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 1, 5.0));
745 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 2, 6.0));
747 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(7,4,0), 10); // H5:H15
748 CPPUNIT_ASSERT_MESSAGE("Failed to fetch vector ref array.", aArray
.isValid());
749 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
750 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
751 CPPUNIT_ASSERT_MESSAGE("Unexpected string cell.", equals(aArray
, 0, 5.0));
753 // Clear everything and start over.
754 clearRange(m_pDoc
, ScRange(0,0,0,m_pDoc
->MaxCol(),m_pDoc
->MaxRow(),0));
755 m_pDoc
->PrepareFormulaCalc();
757 // Totally empty range in a totally empty column (Column A).
758 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(0,0,0), 3); // A1:A3
759 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
760 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
761 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[0]));
762 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[1]));
763 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[2]));
765 // Totally empty range in a non-empty column (Column B).
766 m_pDoc
->SetString(ScAddress(1,10,0), "Some text"); // B11
767 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(1,0,0), 3); // B1:B3
768 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
769 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
770 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[0]));
771 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[1]));
772 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[2]));
774 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(1,12,0), 3); // B13:B15
775 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
776 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
777 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[0]));
778 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[1]));
779 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[2]));
781 // These values come from a cache because of the call above.
782 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(1,1,0), 3); // B2:B4
783 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
784 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
785 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[0]));
786 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[1]));
787 CPPUNIT_ASSERT(std::isnan(aArray
.mpNumericArray
[2]));
789 // The column begins with a string header at row 1 (Column C).
790 m_pDoc
->SetString(ScAddress(2,0,0), "MyHeader");
791 for (SCROW i
= 1; i
<= 9; ++i
) // rows 2-10 are numeric.
792 m_pDoc
->SetValue(ScAddress(2,i
,0), i
);
794 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(2,1,0), 9); // C2:C10
795 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
796 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
797 for (size_t i
= 0; i
< 9; ++i
)
798 CPPUNIT_ASSERT_EQUAL(double(i
+1), aArray
.mpNumericArray
[i
]);
800 // The column begins with a number, followed by a string then followed by
801 // a block of numbers (Column D).
802 m_pDoc
->SetValue(ScAddress(3,0,0), 0.0);
803 m_pDoc
->SetString(ScAddress(3,1,0), "Some string");
804 for (SCROW i
= 2; i
<= 9; ++i
) // rows 3-10 are numeric.
805 m_pDoc
->SetValue(ScAddress(3,i
,0), i
);
807 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(3,2,0), 8); // D3:D10
808 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
809 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
810 for (size_t i
= 0; i
< 8; ++i
)
811 CPPUNIT_ASSERT_EQUAL(double(i
+2), aArray
.mpNumericArray
[i
]);
813 // The column begins with a formula, followed by a string then followed by
814 // a block of numbers (Column E).
815 m_pDoc
->SetString(ScAddress(4,0,0), "=1*2");
816 m_pDoc
->SetString(ScAddress(4,1,0), "Some string");
817 for (SCROW i
= 2; i
<= 9; ++i
) // rows 3-10 are numeric.
818 m_pDoc
->SetValue(ScAddress(4,i
,0), i
*2);
820 aArray
= m_pDoc
->FetchVectorRefArray(ScAddress(4,2,0), 8); // E3:E10
821 CPPUNIT_ASSERT_MESSAGE("Array should have a numeric array.", aArray
.mpNumericArray
);
822 CPPUNIT_ASSERT_MESSAGE("Array should NOT have a string array.", !aArray
.mpStringArray
);
823 for (size_t i
= 0; i
< 8; ++i
)
824 CPPUNIT_ASSERT_EQUAL(double((i
+2)*2), aArray
.mpNumericArray
[i
]);
826 m_pDoc
->DeleteTab(0);
829 CPPUNIT_TEST_FIXTURE(TestFormula
, testGroupConverter3D
)
831 m_pDoc
->InsertTab(0, "Test");
832 m_pDoc
->InsertTab(1, "Test2");
834 m_pDoc
->SetValue(1, 0, 0, 1.0);
835 m_pDoc
->SetValue(1, 0, 1, 2.0);
837 for (SCROW nRow
= 0; nRow
< 200; ++nRow
)
839 OUString aFormula
= "=SUM(Test.B" + OUString::number(nRow
+1) + ":Test2.B" + OUString::number(nRow
+1) + ")";
840 m_pDoc
->SetString(0, nRow
, 0, aFormula
);
843 double nVal
= m_pDoc
->GetValue(0, 0, 0);
844 CPPUNIT_ASSERT_EQUAL(3.0, nVal
);
846 m_pDoc
->DeleteTab(1);
847 m_pDoc
->DeleteTab(0);
850 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaTokenEquality
)
852 struct FormulaTokenEqualityTest
854 const char* mpFormula1
;
855 const char* mpFormula2
;
859 static const FormulaTokenEqualityTest aTests
[] = {
860 { "R1C2", "R1C2", true },
861 { "R1C2", "R1C3", false },
862 { "R1C2", "R2C2", false },
863 { "RC2", "RC[1]", false },
864 { "R1C2:R10C2", "R1C2:R10C2", true },
865 { "R1C2:R10C2", "R1C2:R11C2", false },
867 { "RC[1]+1.2", "RC[1]+1.2", true },
868 { "RC[1]*0.2", "RC[1]*0.5", false },
869 { "\"Test1\"", "\"Test2\"", false },
870 { "\"Test\"", "\"Test\"", true },
871 { "CONCATENATE(\"Test1\")", "CONCATENATE(\"Test1\")", true },
872 { "CONCATENATE(\"Test1\")", "CONCATENATE(\"Test2\")", false },
875 formula::FormulaGrammar::Grammar eGram
= formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1
;
876 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aTests
); ++i
)
878 ScFormulaCell
aCell1(*m_pDoc
, ScAddress(), OUString::createFromAscii(aTests
[i
].mpFormula1
), eGram
);
879 ScFormulaCell
aCell2(*m_pDoc
, ScAddress(), OUString::createFromAscii(aTests
[i
].mpFormula2
), eGram
);
881 ScFormulaCell::CompareState eComp
= aCell1
.CompareByTokenArray(aCell2
);
882 if (aTests
[i
].mbEqual
)
884 if (eComp
== ScFormulaCell::NotEqual
)
886 std::ostringstream os
;
887 os
<< "These two formulas should be evaluated equal: '"
888 << aTests
[i
].mpFormula1
<< "' vs '" << aTests
[i
].mpFormula2
<< "'" << endl
;
889 CPPUNIT_FAIL(os
.str());
894 if (eComp
!= ScFormulaCell::NotEqual
)
896 std::ostringstream os
;
897 os
<< "These two formulas should be evaluated non-equal: '"
898 << aTests
[i
].mpFormula1
<< "' vs '" << aTests
[i
].mpFormula2
<< "'" << endl
;
899 CPPUNIT_FAIL(os
.str());
905 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefData
)
907 std::unique_ptr
<ScDocument
> pDoc
= std::make_unique
<ScDocument
>();
909 ScAddress
aAddr(4,5,3), aPos(2,2,2);
910 ScSingleRefData aRef
;
911 aRef
.InitAddress(aAddr
);
912 CPPUNIT_ASSERT_MESSAGE("Wrong ref data state.", !aRef
.IsRowRel());
913 CPPUNIT_ASSERT_MESSAGE("Wrong ref data state.", !aRef
.IsColRel());
914 CPPUNIT_ASSERT_MESSAGE("Wrong ref data state.", !aRef
.IsTabRel());
915 CPPUNIT_ASSERT_EQUAL(SCCOL(4), aRef
.Col());
916 CPPUNIT_ASSERT_EQUAL(SCROW(5), aRef
.Row());
917 CPPUNIT_ASSERT_EQUAL(SCTAB(3), aRef
.Tab());
919 aRef
.SetRowRel(true);
920 aRef
.SetColRel(true);
921 aRef
.SetTabRel(true);
922 aRef
.SetAddress(pDoc
->GetSheetLimits(), aAddr
, aPos
);
923 CPPUNIT_ASSERT_EQUAL(SCCOL(2), aRef
.Col());
924 CPPUNIT_ASSERT_EQUAL(SCROW(3), aRef
.Row());
925 CPPUNIT_ASSERT_EQUAL(SCTAB(1), aRef
.Tab());
927 // Test extension of range reference.
929 ScComplexRefData aDoubleRef
;
930 aDoubleRef
.InitRange(ScRange(2,2,0,4,4,0));
932 aRef
.InitAddress(ScAddress(6,5,0));
934 aDoubleRef
.Extend(pDoc
->GetSheetLimits(), aRef
, ScAddress());
935 ScRange aTest
= aDoubleRef
.toAbs(*pDoc
, ScAddress());
936 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong start position of extended range.", ScAddress(2,2,0), aTest
.aStart
);
937 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong end position of extended range.", ScAddress(6,5,0), aTest
.aEnd
);
939 ScComplexRefData aDoubleRef2
;
940 aDoubleRef2
.InitRangeRel(*pDoc
, ScRange(1,2,0,8,6,0), ScAddress(5,5,0));
941 aDoubleRef
.Extend(pDoc
->GetSheetLimits(), aDoubleRef2
, ScAddress(5,5,0));
942 aTest
= aDoubleRef
.toAbs(*pDoc
, ScAddress(5,5,0));
944 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong start position of extended range.", ScAddress(1,2,0), aTest
.aStart
);
945 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong end position of extended range.", ScAddress(8,6,0), aTest
.aEnd
);
948 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaCompiler
)
950 static const struct {
951 const char* pInput
; FormulaGrammar::Grammar eInputGram
;
952 const char* pOutput
; FormulaGrammar::Grammar eOutputGram
;
954 { "=B1-$C2+D$3-$E$4", FormulaGrammar::GRAM_NATIVE
, "[.B1]-[.$C2]+[.D$3]-[.$E$4]", FormulaGrammar::GRAM_ODFF
},
955 { "=B1-$C2+D$3-$E$4", FormulaGrammar::GRAM_NATIVE
, "B1-$C2+D$3-$E$4", FormulaGrammar::GRAM_NATIVE
},
956 { "=B1-$C2+D$3-$E$4", FormulaGrammar::GRAM_NATIVE
, "B1-$C2+D$3-$E$4", FormulaGrammar::GRAM_NATIVE_XL_A1
},
957 { "=B1-$C2+D$3-$E$4", FormulaGrammar::GRAM_NATIVE
, "RC[1]-R[1]C3+R3C[3]-R4C5", FormulaGrammar::GRAM_NATIVE_XL_R1C1
},
960 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aTests
); ++i
)
962 std::unique_ptr
<ScTokenArray
> pArray
= compileFormula(m_pDoc
, OUString::createFromAscii(aTests
[i
].pInput
), aTests
[i
].eInputGram
);
963 CPPUNIT_ASSERT_MESSAGE("Token array shouldn't be NULL!", pArray
);
965 ScCompiler
aComp(*m_pDoc
, ScAddress(), *pArray
, aTests
[i
].eOutputGram
);
967 aComp
.CreateStringFromTokenArray(aBuf
);
968 OUString aFormula
= aBuf
.makeStringAndClear();
970 CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(aTests
[i
].pOutput
), aFormula
);
974 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaCompilerJumpReordering
)
983 // Compile formula string first.
984 std::unique_ptr
<ScTokenArray
> pCode(compileFormula(m_pDoc
, "=IF(B1;12;\"text\")"));
985 CPPUNIT_ASSERT(pCode
);
987 // Then generate RPN tokens.
988 ScCompiler
aCompRPN(*m_pDoc
, ScAddress(), *pCode
, FormulaGrammar::GRAM_NATIVE
);
989 aCompRPN
.CompileTokenArray();
991 // RPN tokens should be ordered: B1, ocIf, C1, ocSep, D1, ocClose.
992 static const TokenCheck aCheckRPN
[] =
994 { ocPush
, svSingleRef
},
995 { ocIf
, svUnknown
}, // type is context dependent, don't test it
996 { ocPush
, svDouble
},
998 { ocPush
, svString
},
1002 sal_uInt16 nLen
= pCode
->GetCodeLen();
1003 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong RPN token count.", static_cast<sal_uInt16
>(SAL_N_ELEMENTS(aCheckRPN
)), nLen
);
1005 FormulaToken
** ppTokens
= pCode
->GetCode();
1006 for (sal_uInt16 i
= 0; i
< nLen
; ++i
)
1008 const FormulaToken
* p
= ppTokens
[i
];
1009 CPPUNIT_ASSERT_EQUAL(aCheckRPN
[i
].meOp
, p
->GetOpCode());
1010 if (aCheckRPN
[i
].meOp
!= ocIf
)
1011 CPPUNIT_ASSERT_EQUAL(static_cast<int>(aCheckRPN
[i
].meType
), static_cast<int>(p
->GetType()));
1014 // Generate RPN tokens again, but this time no jump command reordering.
1016 ScCompiler
aCompRPN2(*m_pDoc
, ScAddress(), *pCode
, FormulaGrammar::GRAM_NATIVE
);
1017 aCompRPN2
.EnableJumpCommandReorder(false);
1018 aCompRPN2
.CompileTokenArray();
1020 static const TokenCheck aCheckRPN2
[] =
1022 { ocPush
, svSingleRef
},
1023 { ocPush
, svDouble
},
1024 { ocPush
, svString
},
1025 { ocIf
, svUnknown
}, // type is context dependent, don't test it
1028 nLen
= pCode
->GetCodeLen();
1029 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong RPN token count.", static_cast<sal_uInt16
>(SAL_N_ELEMENTS(aCheckRPN2
)), nLen
);
1030 ppTokens
= pCode
->GetCode();
1031 for (sal_uInt16 i
= 0; i
< nLen
; ++i
)
1033 const FormulaToken
* p
= ppTokens
[i
];
1034 CPPUNIT_ASSERT_EQUAL(aCheckRPN2
[i
].meOp
, p
->GetOpCode());
1035 if (aCheckRPN
[i
].meOp
== ocPush
)
1036 CPPUNIT_ASSERT_EQUAL(static_cast<int>(aCheckRPN2
[i
].meType
), static_cast<int>(p
->GetType()));
1041 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaCompilerImplicitIntersection2Param
)
1043 struct TestCaseFormula
1046 ScAddress aCellAddress
;
1048 bool bStartColRel
; // SumRange-StartCol
1049 bool bEndColRel
; // SumRange-EndCol
1052 m_pDoc
->InsertTab(0, "Formula");
1053 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
1056 TestCaseFormula aTestCases
[] =
1058 // Formula, FormulaCellAddress, SumRange with Implicit Intersection
1060 // Sumrange is single cell, address is abs
1062 OUString("=SUMIF($B$2:$B$10;F2;$D$5)"),
1064 ScRange( ScAddress(3, 4, 0), ScAddress(3, 12, 0) ),
1069 // Sumrange is single cell, address is relative
1071 OUString("=SUMIF($B$2:$B$10;F2;D5)"),
1073 ScRange( ScAddress(3, 4, 0), ScAddress(3, 12, 0) ),
1078 // Baserange(abs,abs), Sumrange(abs,abs)
1080 OUString("=SUMIF($B$2:$B$10;F2;$D$5:$D$10)"),
1082 ScRange( ScAddress(3, 4, 0), ScAddress(3, 12, 0) ),
1087 // Baserange(abs,rel), Sumrange(abs,abs)
1089 OUString("=SUMIF($B$2:B10;F2;$D$5:$D$10)"),
1091 ScRange( ScAddress(3, 4, 0), ScAddress(3, 12, 0) ),
1096 // Baserange(rel,abs), Sumrange(abs,abs)
1098 OUString("=SUMIF(B2:$B$10;F2;$D$5:$D$10)"),
1100 ScRange( ScAddress(3, 4, 0), ScAddress(3, 12, 0) ),
1105 // Baserange(rel,rel), Sumrange(abs,abs)
1107 OUString("=SUMIF(B2:B10;F2;$D$5:$D$10)"),
1109 ScRange( ScAddress(3, 4, 0), ScAddress(3, 12, 0) ),
1114 // Baserange(abs,abs), Sumrange(abs,rel)
1116 OUString("=SUMIF($B$2:$B$10;F2;$D$5:D10)"),
1118 ScRange( ScAddress(3, 4, 0), ScAddress(3, 12, 0) ),
1123 // Baserange(abs,abs), Sumrange(rel,abs)
1125 OUString("=SUMIF($B$2:$B$10;F2;D5:$D$10)"),
1127 ScRange( ScAddress(3, 4, 0), ScAddress(3, 12, 0) ),
1132 // Baserange(abs,abs), Sumrange(rel,rel)
1134 OUString("=SUMIF($B$2:$B$10;F2;D5:D10)"),
1136 ScRange( ScAddress(3, 4, 0), ScAddress(3, 12, 0) ),
1142 for (const auto& rCase
: aTestCases
)
1144 m_pDoc
->SetString(rCase
.aCellAddress
, rCase
.aFormula
);
1145 const ScFormulaCell
* pCell
= m_pDoc
->GetFormulaCell(rCase
.aCellAddress
);
1146 const ScTokenArray
* pCode
= pCell
->GetCode();
1147 CPPUNIT_ASSERT(pCode
);
1149 sal_uInt16 nLen
= pCode
->GetCodeLen();
1150 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong RPN token count.", static_cast<sal_uInt16
>(4), nLen
);
1152 FormulaToken
** ppTokens
= pCode
->GetCode();
1154 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong type of token(first argument to SUMIF)", svDoubleRef
, ppTokens
[0]->GetType());
1155 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong type of token(third argument to SUMIF)", svDoubleRef
, ppTokens
[2]->GetType());
1157 ScComplexRefData aSumRangeData
= *ppTokens
[2]->GetDoubleRef();
1158 ScRange aSumRange
= aSumRangeData
.toAbs(*m_pDoc
, rCase
.aCellAddress
);
1159 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong sum-range in RPN array", rCase
.aSumRange
, aSumRange
);
1161 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong IsRel type for start column address in sum-range", rCase
.bStartColRel
, aSumRangeData
.Ref1
.IsColRel());
1162 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong IsRel type for end column address in sum-range", rCase
.bEndColRel
, aSumRangeData
.Ref2
.IsColRel());
1167 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaCompilerImplicitIntersection1ParamNoChange
)
1169 struct TestCaseFormulaNoChange
1172 ScAddress aCellAddress
;
1173 bool bMatrixFormula
;
1177 m_pDoc
->InsertTab(0, "Formula");
1178 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
1181 ScAddress
aStartAddr(4, 5, 0);
1182 TestCaseFormulaNoChange aCasesNoChange
[] =
1185 OUString("=COS(A$2:A$100)"), // No change because of abs col ref.
1191 OUString("=COS($A7:$A100)"), // No intersection
1197 OUString("=COS($A5:$C7)"), // No intersection 2-D range
1203 OUString("=SUMPRODUCT(COS(A6:A10))"), // COS() in forced array mode
1209 OUString("=COS(A6:A10)"), // Matrix formula
1216 for (const auto& rCase
: aCasesNoChange
)
1218 if (rCase
.bMatrixFormula
)
1220 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
1221 aMark
.SelectOneTable(0);
1222 SCCOL nColStart
= rCase
.aCellAddress
.Col();
1223 SCROW nRowStart
= rCase
.aCellAddress
.Row();
1224 m_pDoc
->InsertMatrixFormula(nColStart
, nRowStart
, nColStart
, nRowStart
+ 4,
1225 aMark
, rCase
.aFormula
);
1228 m_pDoc
->SetString(rCase
.aCellAddress
, rCase
.aFormula
);
1230 const ScFormulaCell
* pCell
= m_pDoc
->GetFormulaCell(rCase
.aCellAddress
);
1231 const ScTokenArray
* pCode
= pCell
->GetCode();
1232 CPPUNIT_ASSERT(pCode
);
1234 sal_uInt16 nRPNLen
= pCode
->GetCodeLen();
1235 sal_uInt16 nRawLen
= pCode
->GetLen();
1236 sal_uInt16 nRawArgPos
;
1237 if (rCase
.bForcedArray
)
1240 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong raw token count.", static_cast<sal_uInt16
>(7), nRawLen
);
1241 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong RPN token count.", static_cast<sal_uInt16
>(3), nRPNLen
);
1246 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong raw token count.", static_cast<sal_uInt16
>(4), nRawLen
);
1247 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong RPN token count.", static_cast<sal_uInt16
>(2), nRPNLen
);
1250 FormulaToken
** ppRawTokens
= pCode
->GetArray();
1251 FormulaToken
** ppRPNTokens
= pCode
->GetCode();
1253 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong type of raw token(argument to COS)", svDoubleRef
, ppRawTokens
[nRawArgPos
]->GetType());
1254 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong type of RPN token(argument to COS)", svDoubleRef
, ppRPNTokens
[0]->GetType());
1256 ScComplexRefData aArgRangeRaw
= *ppRawTokens
[nRawArgPos
]->GetDoubleRef();
1257 ScComplexRefData aArgRangeRPN
= *ppRPNTokens
[0]->GetDoubleRef();
1258 bool bRawMatchRPNToken(aArgRangeRaw
== aArgRangeRPN
);
1259 CPPUNIT_ASSERT_MESSAGE("raw arg token and RPN arg token contents do not match", bRawMatchRPNToken
);
1264 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaCompilerImplicitIntersection1ParamWithChange
)
1266 struct TestCaseFormula
1269 ScAddress aCellAddress
;
1273 m_pDoc
->InsertTab(0, "Formula");
1274 m_pDoc
->InsertTab(1, "Formula1");
1275 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
1278 ScAddress
aStartAddr(10, 5, 0);
1279 TestCaseFormula aCasesWithChange
[] =
1282 OUString("=COS($A6:$A100)"), // Corner case with intersection
1287 OUString("=COS($A2:$A6)"), // Corner case with intersection
1292 OUString("=COS($A2:$A100)"), // Typical 1D case
1297 OUString("=COS($Formula.$A1:$C3)"), // 2D corner case
1298 ScAddress(0, 0, 1), // Formula in sheet 1
1302 OUString("=COS($Formula.$A1:$C3)"), // 2D corner case
1303 ScAddress(0, 2, 1), // Formula in sheet 1
1307 OUString("=COS($Formula.$A1:$C3)"), // 2D corner case
1308 ScAddress(2, 0, 1), // Formula in sheet 1
1312 OUString("=COS($Formula.$A1:$C3)"), // 2D corner case
1313 ScAddress(2, 2, 1), // Formula in sheet 1
1317 OUString("=COS($Formula.$A1:$C3)"), // Typical 2D case
1318 ScAddress(1, 1, 1), // Formula in sheet 1
1323 for (const auto& rCase
: aCasesWithChange
)
1325 m_pDoc
->SetString(rCase
.aCellAddress
, rCase
.aFormula
);
1327 const ScFormulaCell
* pCell
= m_pDoc
->GetFormulaCell(rCase
.aCellAddress
);
1328 const ScTokenArray
* pCode
= pCell
->GetCode();
1329 CPPUNIT_ASSERT(pCode
);
1331 sal_uInt16 nRPNLen
= pCode
->GetCodeLen();
1332 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong RPN token count.", static_cast<sal_uInt16
>(2), nRPNLen
);
1334 FormulaToken
** ppRPNTokens
= pCode
->GetCode();
1336 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong type of RPN token(argument to COS)", svSingleRef
, ppRPNTokens
[0]->GetType());
1338 ScSingleRefData aArgAddrRPN
= *ppRPNTokens
[0]->GetSingleRef();
1339 ScAddress aArgAddrActual
= aArgAddrRPN
.toAbs(*m_pDoc
, rCase
.aCellAddress
);
1340 CPPUNIT_ASSERT_EQUAL_MESSAGE("Computed implicit intersection singleref is wrong", rCase
.aArgAddr
, aArgAddrActual
);
1345 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaCompilerImplicitIntersection1NoGroup
)
1347 m_pDoc
->InsertTab(0, "Formula");
1348 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
1350 m_pDoc
->SetString(ScAddress(1,2,0), "=COS(A1:A5)"); // B3
1351 m_pDoc
->SetString(ScAddress(1,3,0), "=COS(A1:A5)"); // B4
1353 // Implicit intersection optimization in ScCompiler::HandleIIOpCode() internally changes
1354 // these to "=COS(A3)" and "=COS(A4)", but these shouldn't be merged into a formula group,
1355 // otherwise B4's formula would then be "=COS(A2:A6)".
1356 CPPUNIT_ASSERT_EQUAL_MESSAGE("Formula in B3 has changed.", OUString("=COS(A1:A5)"), m_pDoc
->GetFormula(1,2,0));
1357 CPPUNIT_ASSERT_EQUAL_MESSAGE("Formula in B4 has changed.", OUString("=COS(A1:A5)"), m_pDoc
->GetFormula(1,3,0));
1359 m_pDoc
->DeleteTab(0);
1362 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaCompilerImplicitIntersectionOperators
)
1366 OUString formula
[3];
1370 m_pDoc
->InsertTab(0, "Test");
1371 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
1373 m_pDoc
->SetValue(2, 0, 0, 5); // C1
1374 m_pDoc
->SetValue(2, 1, 0, 4); // C2
1375 m_pDoc
->SetValue(2, 2, 0, 3); // C3
1376 m_pDoc
->SetValue(3, 0, 0, 1); // D1
1377 m_pDoc
->SetValue(3, 1, 0, 2); // D2
1378 m_pDoc
->SetValue(3, 2, 0, 3); // D3
1382 { OUString("=C:C/D:D"), OUString("=C:C/D:D"), OUString("=C:C/D:D"), 5, 2, 1 },
1383 { OUString("=C1:C2/D1:D2"), OUString("=C2:C3/D2:D3"), OUString("=C3:C4/D3:D4"), 5, 2, 1 }
1386 for (const TestCase
& test
: tests
)
1388 for(int i
= 0; i
< 2; ++i
)
1389 m_pDoc
->SetString(ScAddress(4,i
,0), test
.formula
[i
]); // E1-3
1390 for(int i
= 0; i
< 2; ++i
)
1391 CPPUNIT_ASSERT_EQUAL_MESSAGE(OUString( test
.formula
[i
] + " result incorrect in row " + OUString::number(i
+1)).toUtf8().getStr(),
1392 test
.result
[i
], m_pDoc
->GetValue(ScAddress(4,i
,0)));
1395 m_pDoc
->DeleteTab(0);
1398 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaAnnotateTrimOnDoubleRefs
)
1400 m_pDoc
->InsertTab(0, "Test");
1401 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
1403 constexpr sal_Int32 nCols
= 2;
1404 constexpr sal_Int32 nRows
= 5;
1407 constexpr sal_Int32 aMat
[nRows
][nCols
] = {
1415 for (sal_Int32 nCol
= 0; nCol
< nCols
; ++nCol
)
1417 for (sal_Int32 nRow
= 0; nRow
< nRows
; ++nRow
)
1418 m_pDoc
->SetValue(nCol
, nRow
, 0, aMat
[nRow
][nCol
]);
1421 m_pDoc
->SetValue(2, 0, 0, 4); // C1 = 4
1422 m_pDoc
->SetValue(3, 0, 0, 5); // D1 = 5
1424 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
1425 aMark
.SelectOneTable(0);
1430 ScRange aTrimmableRange
;
1432 bool bMatrixFormula
;
1435 constexpr sal_Int32 nTestCases
= 5;
1436 TestCase aTestCases
[nTestCases
] = {
1438 "=SUM(IF($C$1=A:A;B:B)/10*D1)",
1439 ScRange(0, 0, 0, 0, 1048575, 0),
1445 "=SUM(IF(A:A=5;B:B)/10*D1)",
1446 ScRange(0, 0, 0, 0, 1048575, 0),
1452 "=SUM(IF($C$1=A:A;B:B;B:B)/10*D1)", // IF has else clause
1453 ScRange(-1, -1, -1, -1, -1, -1), // Has no trimmable double-ref.
1459 "=SUM(IF($C$1=A:A;B:B)/10*D1)",
1460 ScRange(-1, -1, -1, -1, -1, -1), // Has no trimmable double-ref.
1462 false // Not in matrix mode.
1466 "=SUMPRODUCT(A:A=$C$1; 1-(A:A=$C$1))",
1467 ScRange(0, 0, 0, 0, 1048575, 0),
1469 false // Not in matrix mode.
1473 for (sal_Int32 nTestIdx
= 0; nTestIdx
< nTestCases
; ++nTestIdx
)
1475 TestCase
& rTestCase
= aTestCases
[nTestIdx
];
1476 if (rTestCase
.bMatrixFormula
)
1477 m_pDoc
->InsertMatrixFormula(4, 0, 4, 0, aMark
, rTestCase
.aFormula
); // Formula in E1
1479 m_pDoc
->SetString(ScAddress(4, 0, 0), rTestCase
.aFormula
); // Formula in E1
1481 std::string aMsgStart
= "TestCase#" + std::to_string(nTestIdx
+ 1) + " : ";
1482 CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsgStart
+ "Incorrect formula result", rTestCase
.fResult
, m_pDoc
->GetValue(ScAddress(4, 0, 0)));
1484 ScFormulaCell
* pCell
= m_pDoc
->GetFormulaCell(ScAddress(4, 0, 0));
1485 ScTokenArray
* pCode
= pCell
->GetCode();
1486 sal_Int32 nLen
= pCode
->GetCodeLen();
1487 FormulaToken
** pRPNArray
= pCode
->GetCode();
1489 for (sal_Int32 nIdx
= 0; nIdx
< nLen
; ++nIdx
)
1491 FormulaToken
* pTok
= pRPNArray
[nIdx
];
1492 if (pTok
&& pTok
->GetType() == svDoubleRef
)
1494 ScRange aRange
= pTok
->GetDoubleRef()->toAbs(*m_pDoc
, ScAddress(4, 0, 0));
1495 if (aRange
== rTestCase
.aTrimmableRange
)
1496 CPPUNIT_ASSERT_MESSAGE(aMsgStart
+ "Double ref is incorrectly flagged as not trimmable to data",
1497 pTok
->GetDoubleRef()->IsTrimToData());
1499 CPPUNIT_ASSERT_MESSAGE(aMsgStart
+ "Double ref is incorrectly flagged as trimmable to data",
1500 !pTok
->GetDoubleRef()->IsTrimToData());
1505 m_pDoc
->DeleteTab(0);
1508 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdate
)
1510 m_pDoc
->InsertTab(0, "Formula");
1512 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
1514 m_pDoc
->SetValue(ScAddress(0,0,0), 2.0); // A1
1515 m_pDoc
->SetString(ScAddress(2,2,0), "=A1"); // C3
1516 m_pDoc
->SetString(ScAddress(2,3,0), "=$A$1"); // C4
1518 ScAddress
aPos(2,2,0);
1519 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C3.", OUString("=A1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1521 aPos
= ScAddress(2,3,0);
1522 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C4.", OUString("=$A$1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1524 // Delete row 2 to push formula cells up (to C2:C3).
1525 m_pDoc
->DeleteRow(ScRange(0,1,0,m_pDoc
->MaxCol(),1,0));
1527 aPos
= ScAddress(2,1,0);
1528 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C2.", OUString("=A1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1530 aPos
= ScAddress(2,2,0);
1531 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C3.", OUString("=$A$1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1533 // Insert one row at row 2 to move them back.
1534 m_pDoc
->InsertRow(ScRange(0,1,0,m_pDoc
->MaxCol(),1,0));
1536 aPos
= ScAddress(2,2,0);
1537 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C3.", OUString("=A1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1539 aPos
= ScAddress(2,3,0);
1540 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C4.", OUString("=$A$1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1542 // Insert 2 rows at row 1 to shift all of A1 and C3:C4 down.
1543 m_pDoc
->InsertRow(ScRange(0,0,0,m_pDoc
->MaxCol(),1,0));
1545 aPos
= ScAddress(2,4,0);
1546 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C5.", OUString("=A3"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1548 aPos
= ScAddress(2,5,0);
1549 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C6.", OUString("=$A$3"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1551 // Delete 2 rows at row 1 to shift them back.
1552 m_pDoc
->DeleteRow(ScRange(0,0,0,m_pDoc
->MaxCol(),1,0));
1554 aPos
= ScAddress(2,2,0);
1555 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C3.", OUString("=A1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1557 aPos
= ScAddress(2,3,0);
1558 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C4.", OUString("=$A$1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1560 // Insert 3 columns at column B. to shift C3:C4 to F3:F4.
1561 m_pDoc
->InsertCol(ScRange(1,0,0,3,m_pDoc
->MaxRow(),0));
1563 aPos
= ScAddress(5,2,0);
1564 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in F3.", OUString("=A1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1566 aPos
= ScAddress(5,3,0);
1567 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in F4.", OUString("=$A$1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1569 // Delete columns B:D to shift them back.
1570 m_pDoc
->DeleteCol(ScRange(1,0,0,3,m_pDoc
->MaxRow(),0));
1572 aPos
= ScAddress(2,2,0);
1573 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C3.", OUString("=A1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1575 aPos
= ScAddress(2,3,0);
1576 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C4.", OUString("=$A$1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1578 // Insert cells over A1:A3 to only shift A1 down to A4.
1579 m_pDoc
->InsertRow(ScRange(0,0,0,0,2,0));
1581 aPos
= ScAddress(2,2,0);
1582 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C3.", OUString("=A4"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1584 aPos
= ScAddress(2,3,0);
1585 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C4.", OUString("=$A$4"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1588 m_pDoc
->DeleteRow(ScRange(0,0,0,0,2,0));
1590 aPos
= ScAddress(2,2,0);
1591 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C3.", OUString("=A1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1593 aPos
= ScAddress(2,3,0);
1594 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in C4.", OUString("=$A$1"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1596 // Delete row 1 which will delete the value cell (A1).
1597 m_pDoc
->DeleteRow(ScRange(0,0,0,m_pDoc
->MaxCol(),0,0));
1599 aPos
= ScAddress(2,1,0);
1600 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(aPos
);
1601 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC
);
1602 CPPUNIT_ASSERT_EQUAL(int(FormulaError::NoRef
), static_cast<int>(pFC
->GetErrCode()));
1603 aPos
= ScAddress(2,2,0);
1604 pFC
= m_pDoc
->GetFormulaCell(aPos
);
1605 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC
);
1606 CPPUNIT_ASSERT_EQUAL(int(FormulaError::NoRef
), static_cast<int>(pFC
->GetErrCode()));
1608 // Clear all and start over.
1609 clearRange(m_pDoc
, ScRange(0,0,0,10,10,0));
1611 // Test range updates
1613 // Fill B2:C3 with values.
1614 m_pDoc
->SetValue(ScAddress(1,1,0), 1);
1615 m_pDoc
->SetValue(ScAddress(1,2,0), 2);
1616 m_pDoc
->SetValue(ScAddress(2,1,0), 3);
1617 m_pDoc
->SetValue(ScAddress(2,2,0), 4);
1619 m_pDoc
->SetString(ScAddress(0,5,0), "=SUM(B2:C3)");
1620 m_pDoc
->SetString(ScAddress(0,6,0), "=SUM($B$2:$C$3)");
1622 aPos
= ScAddress(0,5,0);
1623 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM(B2:C3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1625 aPos
= ScAddress(0,6,0);
1626 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM($B$2:$C$3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1628 // Insert a row at row 1.
1629 m_pDoc
->InsertRow(ScRange(0,0,0,m_pDoc
->MaxCol(),0,0));
1631 aPos
= ScAddress(0,6,0);
1632 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM(B3:C4)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1634 aPos
= ScAddress(0,7,0);
1635 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A8.", OUString("=SUM($B$3:$C$4)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1638 m_pDoc
->DeleteRow(ScRange(0,0,0,m_pDoc
->MaxCol(),0,0));
1640 aPos
= ScAddress(0,5,0);
1641 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM(B2:C3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1643 aPos
= ScAddress(0,6,0);
1644 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM($B$2:$C$3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1646 // Insert columns B:C to shift only the value range.
1647 m_pDoc
->InsertCol(ScRange(1,0,0,2,m_pDoc
->MaxRow(),0));
1649 aPos
= ScAddress(0,5,0);
1650 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM(D2:E3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1652 aPos
= ScAddress(0,6,0);
1653 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM($D$2:$E$3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1656 m_pDoc
->DeleteCol(ScRange(1,0,0,2,m_pDoc
->MaxRow(),0));
1658 aPos
= ScAddress(0,5,0);
1659 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM(B2:C3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1661 aPos
= ScAddress(0,6,0);
1662 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM($B$2:$C$3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1664 // Insert rows 5:6 to shift the formula cells only.
1665 m_pDoc
->InsertRow(ScRange(0,4,0,m_pDoc
->MaxCol(),5,0));
1667 aPos
= ScAddress(0,7,0);
1668 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A8.", OUString("=SUM(B2:C3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1670 aPos
= ScAddress(0,8,0);
1671 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A9.", OUString("=SUM($B$2:$C$3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1674 m_pDoc
->DeleteRow(ScRange(0,4,0,m_pDoc
->MaxCol(),5,0));
1676 aPos
= ScAddress(0,5,0);
1677 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM(B2:C3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1679 aPos
= ScAddress(0,6,0);
1680 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM($B$2:$C$3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1682 // Check the values of the formula cells in A6:A7.
1683 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
1684 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
1686 // Insert cells over B1:B2 to partially shift value range.
1687 m_pDoc
->InsertRow(ScRange(1,0,0,1,1,0));
1689 // Check the values of the formula cells in A6:A7 again.
1690 CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
1691 CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
1693 // ... and shift them back.
1694 m_pDoc
->DeleteRow(ScRange(1,0,0,1,1,0));
1696 // The formula cell results should be back too.
1697 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
1698 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
1700 // Delete rows 2:3 to completely remove the referenced range.
1701 m_pDoc
->DeleteRow(ScRange(0,1,0,m_pDoc
->MaxCol(),2,0));
1703 // Both A4 and A5 should show #REF! errors.
1704 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,3,0));
1705 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC
);
1706 CPPUNIT_ASSERT_EQUAL(int(FormulaError::NoRef
), static_cast<int>(pFC
->GetErrCode()));
1708 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,4,0));
1709 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC
);
1710 CPPUNIT_ASSERT_EQUAL(int(FormulaError::NoRef
), static_cast<int>(pFC
->GetErrCode()));
1712 m_pDoc
->DeleteTab(0);
1715 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateRange
)
1717 m_pDoc
->InsertTab(0, "Formula");
1719 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
1721 setExpandRefs(false);
1723 // Set values to B2:C5.
1724 m_pDoc
->SetValue(ScAddress(1,1,0), 1);
1725 m_pDoc
->SetValue(ScAddress(1,2,0), 2);
1726 m_pDoc
->SetValue(ScAddress(1,3,0), 3);
1727 m_pDoc
->SetValue(ScAddress(1,4,0), 4);
1728 m_pDoc
->SetValue(ScAddress(2,1,0), 5);
1729 m_pDoc
->SetValue(ScAddress(2,2,0), 6);
1730 m_pDoc
->SetValue(ScAddress(2,3,0), 7);
1731 m_pDoc
->SetValue(ScAddress(2,4,0), 8);
1733 // Set formula cells to A7 and A8.
1734 m_pDoc
->SetString(ScAddress(0,6,0), "=SUM(B2:C5)");
1735 m_pDoc
->SetString(ScAddress(0,7,0), "=SUM($B$2:$C$5)");
1737 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM(B2:C5)"), m_pDoc
->GetFormula(0,6,0));
1739 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A8.", OUString("=SUM($B$2:$C$5)"), m_pDoc
->GetFormula(0,7,0));
1741 CPPUNIT_ASSERT_EQUAL(36.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
1742 CPPUNIT_ASSERT_EQUAL(36.0, m_pDoc
->GetValue(ScAddress(0,7,0)));
1744 // Delete row 3. This should shrink the range references by one row.
1745 m_pDoc
->DeleteRow(ScRange(0,2,0,m_pDoc
->MaxCol(),2,0));
1747 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM(B2:C4)"), m_pDoc
->GetFormula(0,5,0));
1749 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM($B$2:$C$4)"), m_pDoc
->GetFormula(0,6,0));
1751 CPPUNIT_ASSERT_EQUAL(28.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
1752 CPPUNIT_ASSERT_EQUAL(28.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
1754 // Delete row 4 - bottom of range
1755 m_pDoc
->DeleteRow(ScRange(0,3,0,m_pDoc
->MaxCol(),3,0));
1757 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A5.", OUString("=SUM(B2:C3)"), m_pDoc
->GetFormula(0,4,0));
1759 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM($B$2:$C$3)"), m_pDoc
->GetFormula(0,5,0));
1761 CPPUNIT_ASSERT_EQUAL(16.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
1762 CPPUNIT_ASSERT_EQUAL(16.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
1764 // Delete row 2 - top of range
1765 m_pDoc
->DeleteRow(ScRange(0,1,0,m_pDoc
->MaxCol(),1,0));
1767 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A4.", OUString("=SUM(B2:C2)"), m_pDoc
->GetFormula(0,3,0));
1769 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A5.", OUString("=SUM($B$2:$C$2)"), m_pDoc
->GetFormula(0,4,0));
1771 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
1772 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
1774 // Clear the range and start over.
1775 clearRange(m_pDoc
, ScRange(0,0,0,20,20,0));
1777 // Fill C2:F3 with values.
1778 m_pDoc
->SetValue(ScAddress(2,1,0), 1);
1779 m_pDoc
->SetValue(ScAddress(3,1,0), 2);
1780 m_pDoc
->SetValue(ScAddress(4,1,0), 3);
1781 m_pDoc
->SetValue(ScAddress(5,1,0), 4);
1782 m_pDoc
->SetValue(ScAddress(2,2,0), 5);
1783 m_pDoc
->SetValue(ScAddress(3,2,0), 6);
1784 m_pDoc
->SetValue(ScAddress(4,2,0), 7);
1785 m_pDoc
->SetValue(ScAddress(5,2,0), 8);
1787 // Set formulas to A2 and A3.
1788 m_pDoc
->SetString(ScAddress(0,1,0), "=SUM(C2:F3)");
1789 m_pDoc
->SetString(ScAddress(0,2,0), "=SUM($C$2:$F$3)");
1791 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A2.", OUString("=SUM(C2:F3)"), m_pDoc
->GetFormula(0,1,0));
1793 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A3.", OUString("=SUM($C$2:$F$3)"), m_pDoc
->GetFormula(0,2,0));
1795 CPPUNIT_ASSERT_EQUAL(36.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
1796 CPPUNIT_ASSERT_EQUAL(36.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
1799 m_pDoc
->DeleteCol(ScRange(3,0,0,3,m_pDoc
->MaxRow(),0));
1801 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A2.", OUString("=SUM(C2:E3)"), m_pDoc
->GetFormula(0,1,0));
1803 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A3.", OUString("=SUM($C$2:$E$3)"), m_pDoc
->GetFormula(0,2,0));
1805 CPPUNIT_ASSERT_EQUAL(28.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
1806 CPPUNIT_ASSERT_EQUAL(28.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
1808 // Delete column E - the right edge of reference range.
1809 m_pDoc
->DeleteCol(ScRange(4,0,0,4,m_pDoc
->MaxRow(),0));
1811 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A2.", OUString("=SUM(C2:D3)"), m_pDoc
->GetFormula(0,1,0));
1813 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A3.", OUString("=SUM($C$2:$D$3)"), m_pDoc
->GetFormula(0,2,0));
1815 CPPUNIT_ASSERT_EQUAL(16.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
1816 CPPUNIT_ASSERT_EQUAL(16.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
1818 // Delete column C - the left edge of reference range.
1819 m_pDoc
->DeleteCol(ScRange(2,0,0,2,m_pDoc
->MaxRow(),0));
1821 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A2.", OUString("=SUM(C2:C3)"), m_pDoc
->GetFormula(0,1,0));
1823 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A3.", OUString("=SUM($C$2:$C$3)"), m_pDoc
->GetFormula(0,2,0));
1825 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
1826 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
1828 // Clear the range and start over.
1829 clearRange(m_pDoc
, ScRange(0,0,0,20,20,0));
1831 // Disable expansion of range reference on insertion in adjacent areas.
1832 setExpandRefs(false);
1834 // Fill C2:D3 with values.
1835 m_pDoc
->SetValue(ScAddress(2,1,0), 1);
1836 m_pDoc
->SetValue(ScAddress(3,1,0), 2);
1837 m_pDoc
->SetValue(ScAddress(2,2,0), 3);
1838 m_pDoc
->SetValue(ScAddress(3,2,0), 4);
1840 // Set formulas at A5 and A6.
1841 m_pDoc
->SetString(ScAddress(0,4,0), "=SUM(C2:D3)");
1842 m_pDoc
->SetString(ScAddress(0,5,0), "=SUM($C$2:$D$3)");
1844 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A5.", OUString("=SUM(C2:D3)"), m_pDoc
->GetFormula(0,4,0));
1846 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM($C$2:$D$3)"), m_pDoc
->GetFormula(0,5,0));
1848 // Insert a column at column C. This should simply shift the reference without expansion.
1849 m_pDoc
->InsertCol(ScRange(2,0,0,2,m_pDoc
->MaxRow(),0));
1851 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A5.", OUString("=SUM(D2:E3)"), m_pDoc
->GetFormula(0,4,0));
1853 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM($D$2:$E$3)"), m_pDoc
->GetFormula(0,5,0));
1856 m_pDoc
->DeleteCol(ScRange(2,0,0,2,m_pDoc
->MaxRow(),0));
1858 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A5.", OUString("=SUM(C2:D3)"), m_pDoc
->GetFormula(0,4,0));
1860 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM($C$2:$D$3)"), m_pDoc
->GetFormula(0,5,0));
1862 // Insert at column D. This should expand the reference by one column length.
1863 m_pDoc
->InsertCol(ScRange(3,0,0,3,m_pDoc
->MaxRow(),0));
1865 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A5.", OUString("=SUM(C2:E3)"), m_pDoc
->GetFormula(0,4,0));
1867 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM($C$2:$E$3)"), m_pDoc
->GetFormula(0,5,0));
1869 // Insert at column F. No expansion should occur since the edge expansion is turned off.
1870 m_pDoc
->InsertCol(ScRange(5,0,0,5,m_pDoc
->MaxRow(),0));
1872 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A5.", OUString("=SUM(C2:E3)"), m_pDoc
->GetFormula(0,4,0));
1874 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM($C$2:$E$3)"), m_pDoc
->GetFormula(0,5,0));
1876 // Insert at row 2. No expansion should occur with edge expansion turned off.
1877 m_pDoc
->InsertRow(ScRange(0,1,0,m_pDoc
->MaxCol(),1,0));
1879 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A6.", OUString("=SUM(C3:E4)"), m_pDoc
->GetFormula(0,5,0));
1881 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM($C$3:$E$4)"), m_pDoc
->GetFormula(0,6,0));
1883 // Insert at row 4 to expand the reference range.
1884 m_pDoc
->InsertRow(ScRange(0,3,0,m_pDoc
->MaxCol(),3,0));
1886 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A7.", OUString("=SUM(C3:E5)"), m_pDoc
->GetFormula(0,6,0));
1888 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A8.", OUString("=SUM($C$3:$E$5)"), m_pDoc
->GetFormula(0,7,0));
1890 // Insert at row 6. No expansion with edge expansion turned off.
1891 m_pDoc
->InsertRow(ScRange(0,5,0,m_pDoc
->MaxCol(),5,0));
1893 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A8.", OUString("=SUM(C3:E5)"), m_pDoc
->GetFormula(0,7,0));
1895 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A9.", OUString("=SUM($C$3:$E$5)"), m_pDoc
->GetFormula(0,8,0));
1897 // Clear the range and start over.
1898 clearRange(m_pDoc
, ScRange(0,0,0,20,20,0));
1900 // Turn edge expansion on.
1901 setExpandRefs(true);
1903 // Fill C6:D7 with values.
1904 m_pDoc
->SetValue(ScAddress(2,5,0), 1);
1905 m_pDoc
->SetValue(ScAddress(2,6,0), 2);
1906 m_pDoc
->SetValue(ScAddress(3,5,0), 3);
1907 m_pDoc
->SetValue(ScAddress(3,6,0), 4);
1909 // Set formulas at A2 and A3.
1910 m_pDoc
->SetString(ScAddress(0,1,0), "=SUM(C6:D7)");
1911 m_pDoc
->SetString(ScAddress(0,2,0), "=SUM($C$6:$D$7)");
1913 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A2.", OUString("=SUM(C6:D7)"), m_pDoc
->GetFormula(0,1,0));
1915 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A3.", OUString("=SUM($C$6:$D$7)"), m_pDoc
->GetFormula(0,2,0));
1917 // Insert at column E. This should expand the reference range by one column.
1918 m_pDoc
->InsertCol(ScRange(4,0,0,4,m_pDoc
->MaxRow(),0));
1920 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A2.", OUString("=SUM(C6:E7)"), m_pDoc
->GetFormula(0,1,0));
1922 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A3.", OUString("=SUM($C$6:$E$7)"), m_pDoc
->GetFormula(0,2,0));
1924 // Insert at column C to edge-expand the reference range.
1925 m_pDoc
->InsertCol(ScRange(2,0,0,2,m_pDoc
->MaxRow(),0));
1927 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A2.", OUString("=SUM(C6:F7)"), m_pDoc
->GetFormula(0,1,0));
1929 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A3.", OUString("=SUM($C$6:$F$7)"), m_pDoc
->GetFormula(0,2,0));
1931 // Insert at row 8 to edge-expand.
1932 m_pDoc
->InsertRow(ScRange(0,7,0,m_pDoc
->MaxCol(),7,0));
1934 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A2.", OUString("=SUM(C6:F8)"), m_pDoc
->GetFormula(0,1,0));
1936 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A3.", OUString("=SUM($C$6:$F$8)"), m_pDoc
->GetFormula(0,2,0));
1938 // Insert at row 6 to edge-expand.
1939 m_pDoc
->InsertRow(ScRange(0,5,0,m_pDoc
->MaxCol(),5,0));
1941 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A2.", OUString("=SUM(C6:F9)"), m_pDoc
->GetFormula(0,1,0));
1943 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in A3.", OUString("=SUM($C$6:$F$9)"), m_pDoc
->GetFormula(0,2,0));
1945 m_pDoc
->InsertTab(1, "StickyRange");
1947 // A3:A18 all possible combinations of relative and absolute addressing,
1948 // leaving one row above and below unreferenced.
1949 ScAddress
aPos(0,2,1);
1950 m_pDoc
->SetString( aPos
, "=B2:B1048575");
1952 m_pDoc
->SetString( aPos
, "=B2:B$1048575");
1954 m_pDoc
->SetString( aPos
, "=B2:$B1048575");
1956 m_pDoc
->SetString( aPos
, "=B2:$B$1048575");
1958 m_pDoc
->SetString( aPos
, "=B$2:B1048575");
1960 m_pDoc
->SetString( aPos
, "=B$2:B$1048575");
1962 m_pDoc
->SetString( aPos
, "=B$2:$B1048575");
1964 m_pDoc
->SetString( aPos
, "=B$2:$B$1048575");
1966 m_pDoc
->SetString( aPos
, "=$B2:B1048575");
1968 m_pDoc
->SetString( aPos
, "=$B2:B$1048575");
1970 m_pDoc
->SetString( aPos
, "=$B2:$B1048575");
1972 m_pDoc
->SetString( aPos
, "=$B2:$B$1048575");
1974 m_pDoc
->SetString( aPos
, "=$B$2:B1048575");
1976 m_pDoc
->SetString( aPos
, "=$B$2:B$1048575");
1978 m_pDoc
->SetString( aPos
, "=$B$2:$B1048575");
1980 m_pDoc
->SetString( aPos
, "=$B$2:$B$1048575");
1982 // A19 reference to two cells on one row.
1983 m_pDoc
->SetString( aPos
, "=B1048575:C1048575");
1986 // Insert 2 rows in the middle to shift bottom reference down and make it
1988 m_pDoc
->InsertRow( ScRange( 0, aPos
.Row(), 1, m_pDoc
->MaxCol(), aPos
.Row()+1, 1));
1990 // A3:A18 must not result in #REF! anywhere.
1992 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A3 after insertion.", OUString("=B2:B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1994 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A4 after insertion.", OUString("=B2:B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1996 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A5 after insertion.", OUString("=B2:$B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
1998 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A6 after insertion.", OUString("=B2:$B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2000 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A7 after insertion.", OUString("=B$2:B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2002 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A8 after insertion.", OUString("=B$2:B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2004 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A9 after insertion.", OUString("=B$2:$B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2006 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A10 after insertion.", OUString("=B$2:$B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2008 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A11 after insertion.", OUString("=$B2:B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2010 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A12 after insertion.", OUString("=$B2:B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2012 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A13 after insertion.", OUString("=$B2:$B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2014 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A14 after insertion.", OUString("=$B2:$B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2016 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A15 after insertion.", OUString("=$B$2:B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2018 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A16 after insertion.", OUString("=$B$2:B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2020 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A17 after insertion.", OUString("=$B$2:$B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2022 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A18 after insertion.", OUString("=$B$2:$B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2025 // A19 reference to one row shifted out should be #REF!
2026 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A19 after insertion.", OUString("=B#REF!:C#REF!"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2027 // A19 enter reference to last row.
2028 m_pDoc
->SetString( aPos
, "=B1048576:C1048576");
2031 // Delete row 1 to shift top reference up, bottom reference stays sticky.
2032 m_pDoc
->DeleteRow(ScRange(0,0,1,m_pDoc
->MaxCol(),0,1));
2034 // Check sticky bottom references and display of entire column references,
2037 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A2 after deletion.", OUString("=B:B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2039 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A3 after deletion.", OUString("=B1:B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2041 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A4 after deletion.", OUString("=B:$B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2043 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A5 after deletion.", OUString("=B1:$B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2045 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A6 after deletion.", OUString("=B$1:B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2047 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A7 after deletion.", OUString("=B:B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2049 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A8 after deletion.", OUString("=B$1:$B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2051 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A9 after deletion.", OUString("=B:$B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2053 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A10 after deletion.", OUString("=$B:B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2055 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A11 after deletion.", OUString("=$B1:B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2057 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A12 after deletion.", OUString("=$B:$B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2059 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A13 after deletion.", OUString("=$B1:$B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2061 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A14 after deletion.", OUString("=$B$1:B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2063 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A15 after deletion.", OUString("=$B:B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2065 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A16 after deletion.", OUString("=$B$1:$B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2067 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A17 after deletion.", OUString("=$B:$B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2070 // A18 reference to one last row should be shifted up.
2071 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A18 after deletion.", OUString("=B1048575:C1048575"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2074 // Insert 4 rows in the middle.
2075 m_pDoc
->InsertRow( ScRange( 0, aPos
.Row(), 1, m_pDoc
->MaxCol(), aPos
.Row()+3, 1));
2076 // Delete 2 rows in the middle.
2077 m_pDoc
->DeleteRow( ScRange( 0, aPos
.Row(), 1, m_pDoc
->MaxCol(), aPos
.Row()+1, 1));
2079 // References in A2:A17 must still be the same.
2081 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A2 after deletion.", OUString("=B:B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2083 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A3 after deletion.", OUString("=B1:B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2085 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A4 after deletion.", OUString("=B:$B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2087 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A5 after deletion.", OUString("=B1:$B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2089 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A6 after deletion.", OUString("=B$1:B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2091 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A7 after deletion.", OUString("=B:B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2093 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A8 after deletion.", OUString("=B$1:$B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2095 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A9 after deletion.", OUString("=B:$B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2097 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A10 after deletion.", OUString("=$B:B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2099 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A11 after deletion.", OUString("=$B1:B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2101 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A12 after deletion.", OUString("=$B:$B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2103 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A13 after deletion.", OUString("=$B1:$B$1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2105 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A14 after deletion.", OUString("=$B$1:B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2107 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A15 after deletion.", OUString("=$B:B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2109 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A16 after deletion.", OUString("=$B$1:$B1048576"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2111 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong reference in A17 after deletion.", OUString("=$B:$B"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
2114 // Enter values in B1 and B1048576/B16777216 (last row).
2115 m_pDoc
->SetValue( 1,0,1, 1.0);
2116 m_pDoc
->SetValue( 1,m_pDoc
->MaxRow(),1, 2.0);
2117 // Sticky reference including last row.
2118 m_pDoc
->SetString( 2,0,1, "=SUM(B:B)");
2119 // Reference to last row.
2120 CPPUNIT_ASSERT_MESSAGE("m_pDoc->MaxRow() changed, adapt unit test.",
2121 m_pDoc
->MaxRow() == 1048575 || m_pDoc
->MaxRow() == 16777215);
2122 m_pDoc
->SetString( 2,1,1, m_pDoc
->MaxRow() == 1048575 ? OUString("=SUM(B1048576:C1048576)")
2123 : OUString("=SUM(B16777216:C16777216)"));
2124 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong result in C1.", 3.0, m_pDoc
->GetValue(2,0,1));
2125 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong result in C2.", 2.0, m_pDoc
->GetValue(2,1,1));
2127 m_pDoc
->DeleteRow( ScRange( 0, m_pDoc
->MaxRow(), 1, m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 1));
2128 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong result in C1.", 1.0, m_pDoc
->GetValue(2,0,1));
2129 CPPUNIT_ASSERT_EQUAL_MESSAGE("Reference in C2 not invalidated.", OUString("#REF!"), m_pDoc
->GetString(2,1,1));
2131 // Enter values in A23 and AMJ23/XFD23 (last column).
2132 m_pDoc
->SetValue( 0,22,1, 1.0);
2133 m_pDoc
->SetValue( m_pDoc
->MaxCol(),22,1, 2.0);
2134 // C3 with sticky reference including last column.
2135 m_pDoc
->SetString( 2,2,1, "=SUM(23:23)");
2136 // C4 with reference to last column.
2137 m_pDoc
->SetString( 2,3,1, "=SUM(" + m_pDoc
->MaxColAsString() + "22:" + m_pDoc
->MaxColAsString() + "23)");
2138 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong result in C3.", 3.0, m_pDoc
->GetValue(2,2,1));
2139 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong result in C4.", 2.0, m_pDoc
->GetValue(2,3,1));
2140 // Delete last column.
2141 m_pDoc
->DeleteCol( ScRange( m_pDoc
->MaxCol(), 0, 1, m_pDoc
->MaxCol(), m_pDoc
->MaxRow(), 1));
2142 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong result in C3.", 1.0, m_pDoc
->GetValue(2,2,1));
2143 CPPUNIT_ASSERT_EQUAL_MESSAGE("Reference in C4 not invalidated.", OUString("#REF!"), m_pDoc
->GetString(2,3,1));
2145 m_pDoc
->DeleteTab(1);
2147 m_pDoc
->DeleteTab(0);
2150 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateSheets
)
2152 m_pDoc
->InsertTab(0, "Sheet1");
2153 m_pDoc
->InsertTab(1, "Sheet2");
2156 m_pDoc
->GetName(0, aName
);
2157 CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aName
);
2158 m_pDoc
->GetName(1, aName
);
2159 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aName
);
2161 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2163 // Set values to B2:C3 on sheet Sheet1.
2164 m_pDoc
->SetValue(ScAddress(1,1,0), 1);
2165 m_pDoc
->SetValue(ScAddress(1,2,0), 2);
2166 m_pDoc
->SetValue(ScAddress(2,1,0), 3);
2167 m_pDoc
->SetValue(ScAddress(2,2,0), 4);
2169 // Set formulas to B2 and B3 on sheet Sheet2.
2170 m_pDoc
->SetString(ScAddress(1,1,1), "=SUM(Sheet1.B2:C3)");
2171 m_pDoc
->SetString(ScAddress(1,2,1), "=SUM($Sheet1.$B$2:$C$3)");
2173 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,1));
2175 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,1));
2178 m_pDoc
->MoveTab(0, 1);
2179 m_pDoc
->GetName(0, aName
);
2180 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aName
);
2181 m_pDoc
->GetName(1, aName
);
2182 CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aName
);
2184 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,0));
2186 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,0));
2189 m_pDoc
->MoveTab(0, 1);
2190 m_pDoc
->GetName(0, aName
);
2191 CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aName
);
2192 m_pDoc
->GetName(1, aName
);
2193 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aName
);
2195 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,1));
2197 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,1));
2199 // Insert a new sheet between the two.
2200 m_pDoc
->InsertTab(1, "Temp");
2202 m_pDoc
->GetName(1, aName
);
2203 CPPUNIT_ASSERT_EQUAL(OUString("Temp"), aName
);
2204 m_pDoc
->GetName(2, aName
);
2205 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aName
);
2207 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,2));
2209 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,2));
2211 // Move the last sheet (Sheet2) to the first position.
2212 m_pDoc
->MoveTab(2, 0);
2214 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,0));
2216 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,0));
2219 m_pDoc
->MoveTab(0, 2);
2221 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,2));
2223 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,2));
2225 // Move the "Temp" sheet to the last position.
2226 m_pDoc
->MoveTab(1, 2);
2228 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,1));
2230 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,1));
2233 m_pDoc
->MoveTab(2, 1);
2235 // Delete the temporary sheet.
2236 m_pDoc
->DeleteTab(1);
2238 m_pDoc
->GetName(1, aName
);
2239 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aName
);
2241 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,1));
2243 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,1));
2245 // Insert a new sheet before the first one.
2246 m_pDoc
->InsertTab(0, "Temp");
2248 m_pDoc
->GetName(1, aName
);
2249 CPPUNIT_ASSERT_EQUAL(OUString("Sheet1"), aName
);
2250 m_pDoc
->GetName(2, aName
);
2251 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aName
);
2253 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,2));
2255 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,2));
2257 // Delete the temporary sheet.
2258 m_pDoc
->DeleteTab(0);
2260 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,1));
2262 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,1));
2264 // Append a bunch of sheets.
2265 m_pDoc
->InsertTab(2, "Temp1");
2266 m_pDoc
->InsertTab(3, "Temp2");
2267 m_pDoc
->InsertTab(4, "Temp3");
2269 // Move these tabs around. This shouldn't affects the first 2 sheets.
2270 m_pDoc
->MoveTab(2, 4);
2271 m_pDoc
->MoveTab(3, 2);
2273 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(Sheet1.B2:C3)"), m_pDoc
->GetFormula(1,1,1));
2275 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($Sheet1.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,1));
2277 // Delete the temp sheets.
2278 m_pDoc
->DeleteTab(4);
2279 m_pDoc
->DeleteTab(3);
2280 m_pDoc
->DeleteTab(2);
2283 m_pDoc
->DeleteTab(0);
2284 m_pDoc
->GetName(0, aName
);
2285 CPPUNIT_ASSERT_EQUAL(OUString("Sheet2"), aName
);
2287 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B2.", OUString("=SUM(#REF!.B2:C3)"), m_pDoc
->GetFormula(1,1,0));
2289 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in Sheet2.B3.", OUString("=SUM($#REF!.$B$2:$C$3)"), m_pDoc
->GetFormula(1,2,0));
2291 m_pDoc
->DeleteTab(0);
2294 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateInsertRows
)
2296 setExpandRefs(false);
2298 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2299 m_pDoc
->InsertTab(0, "Formula");
2301 // Insert raw values in B2:B4.
2302 m_pDoc
->SetValue(ScAddress(1,1,0), 1.0);
2303 m_pDoc
->SetValue(ScAddress(1,2,0), 2.0);
2304 m_pDoc
->SetValue(ScAddress(1,3,0), 3.0);
2306 // Insert a formula in B5 to sum up B2:B4.
2307 m_pDoc
->SetString(ScAddress(1,4,0), "=SUM(B2:B4)");
2309 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,4,0)));
2311 // Insert rows over rows 1:2.
2312 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2313 aMark
.SelectOneTable(0);
2314 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
2315 rFunc
.InsertCells(ScRange(0,0,0,m_pDoc
->MaxCol(),1,0), &aMark
, INS_INSROWS_BEFORE
, false, true);
2317 // The raw data should have shifted to B4:B6.
2318 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,3,0)));
2319 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,4,0)));
2320 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(1,5,0)));
2322 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(B4:B6)"), m_pDoc
->GetFormula(1,6,0));
2324 // Clear and start over.
2325 clearSheet(m_pDoc
, 0);
2327 // Set raw values in A4:A6.
2328 m_pDoc
->SetValue(ScAddress(0,3,0), 1.0);
2329 m_pDoc
->SetValue(ScAddress(0,4,0), 2.0);
2330 m_pDoc
->SetValue(ScAddress(0,5,0), 3.0);
2332 // Set formula in A3 to reference A4:A6.
2333 m_pDoc
->SetString(ScAddress(0,2,0), "=MAX(A4:A6)");
2335 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
2337 // Insert 3 rows over 2:4. This should push A3:A6 to A6:A9.
2338 rFunc
.InsertCells(ScRange(0,1,0,m_pDoc
->MaxCol(),3,0), &aMark
, INS_INSROWS_BEFORE
, false, true);
2339 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,5,0));
2340 CPPUNIT_ASSERT(pFC
);
2341 CPPUNIT_ASSERT_EQUAL_MESSAGE("This formula cell should not be an error.", 0, static_cast<int>(pFC
->GetErrCode()));
2342 ASSERT_DOUBLES_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
2344 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=MAX(A7:A9)"), m_pDoc
->GetFormula(0,5,0));
2346 m_pDoc
->DeleteTab(0);
2349 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateSheetsDelete
)
2351 m_pDoc
->InsertTab(0, "Sheet1");
2352 m_pDoc
->InsertTab(1, "Sheet2");
2353 m_pDoc
->InsertTab(2, "Sheet3");
2354 m_pDoc
->InsertTab(3, "Sheet4");
2356 m_pDoc
->SetString(ScAddress(4,1,0), "=SUM(Sheet2.A4:Sheet4.A4)");
2357 m_pDoc
->SetString(ScAddress(4,2,0), "=SUM($Sheet2.A4:$Sheet4.A4)");
2358 m_pDoc
->DeleteTab(1);
2360 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM(Sheet3.A4:Sheet4.A4)"), m_pDoc
->GetFormula(4,1,0));
2361 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM($Sheet3.A4:$Sheet4.A4)"), m_pDoc
->GetFormula(4,2,0));
2363 m_pDoc
->InsertTab(1, "Sheet2");
2365 m_pDoc
->SetString(ScAddress(5,1,3), "=SUM(Sheet1.A5:Sheet3.A5)");
2366 m_pDoc
->SetString(ScAddress(5,2,3), "=SUM($Sheet1.A5:$Sheet3.A5)");
2367 m_pDoc
->DeleteTab(2);
2369 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM(Sheet1.A5:Sheet2.A5)"), m_pDoc
->GetFormula(5,1,2));
2370 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM($Sheet1.A5:$Sheet2.A5)"), m_pDoc
->GetFormula(5,2,2));
2372 m_pDoc
->InsertTab(2, "Sheet3");
2374 m_pDoc
->SetString(ScAddress(6,1,3), "=SUM(Sheet1.A6:Sheet3.A6)");
2375 m_pDoc
->SetString(ScAddress(6,2,3), "=SUM($Sheet1.A6:$Sheet3.A6)");
2376 m_pDoc
->DeleteTabs(0,3);
2378 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM(#REF!.A6:#REF!.A6)"), m_pDoc
->GetFormula(6,1,0));
2379 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM($#REF!.A6:$#REF!.A6)"), m_pDoc
->GetFormula(6,2,0));
2381 m_pDoc
->InsertTab(0, "Sheet1");
2382 m_pDoc
->InsertTab(1, "Sheet2");
2383 m_pDoc
->InsertTab(2, "Sheet3");
2385 m_pDoc
->SetString(ScAddress(1,1,1), "=SUM(Sheet1.A2:Sheet3.A2");
2386 m_pDoc
->SetString(ScAddress(2,1,1), "=SUM(Sheet1.A1:Sheet2.A1");
2387 m_pDoc
->SetString(ScAddress(3,1,1), "=SUM(Sheet2.A3:Sheet4.A3");
2389 m_pDoc
->SetString(ScAddress(1,2,1), "=SUM($Sheet1.A2:$Sheet3.A2");
2390 m_pDoc
->SetString(ScAddress(2,2,1), "=SUM($Sheet1.A1:$Sheet2.A1");
2391 m_pDoc
->SetString(ScAddress(3,2,1), "=SUM($Sheet2.A3:$Sheet4.A3");
2393 m_pDoc
->DeleteTab(2);
2395 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM(Sheet1.A2:Sheet2.A2)"), m_pDoc
->GetFormula(1,1,1));
2397 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM(Sheet1.A1:Sheet2.A1)"), m_pDoc
->GetFormula(2,1,1));
2399 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM(Sheet2.A3:Sheet4.A3)"), m_pDoc
->GetFormula(3,1,1));
2401 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM($Sheet1.A2:$Sheet2.A2)"), m_pDoc
->GetFormula(1,2,1));
2403 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM($Sheet1.A1:$Sheet2.A1)"), m_pDoc
->GetFormula(2,2,1));
2405 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM($Sheet2.A3:$Sheet4.A3)"), m_pDoc
->GetFormula(3,2,1));
2407 m_pDoc
->DeleteTab(0);
2409 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM(Sheet2.A2:Sheet2.A2)"), m_pDoc
->GetFormula(1,1,0));
2411 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM(Sheet2.A1:Sheet2.A1)"), m_pDoc
->GetFormula(2,1,0));
2413 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM(Sheet2.A3:Sheet4.A3)"), m_pDoc
->GetFormula(3,1,0));
2415 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM($Sheet2.A2:$Sheet2.A2)"), m_pDoc
->GetFormula(1,2,0));
2417 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM($Sheet2.A1:$Sheet2.A1)"), m_pDoc
->GetFormula(2,2,0));
2419 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong Formula", OUString("=SUM($Sheet2.A3:$Sheet4.A3)"), m_pDoc
->GetFormula(3,2,0));
2421 m_pDoc
->DeleteTab(0);
2422 m_pDoc
->DeleteTab(0);
2425 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateInsertColumns
)
2427 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2428 setExpandRefs(false);
2430 m_pDoc
->InsertTab(0, "Formula");
2432 // Set named range for B2 with absolute column and relative same row.
2433 const ScAddress
aNamePos(0,1,0);
2434 bool bInserted
= m_pDoc
->InsertNewRangeName("RowRelativeRange", aNamePos
, "$Formula.$B2");
2435 CPPUNIT_ASSERT(bInserted
);
2437 // Set named range for entire absolute column B.
2438 bInserted
= m_pDoc
->InsertNewRangeName("EntireColumn", aNamePos
, "$B:$B");
2439 CPPUNIT_ASSERT(bInserted
);
2441 // Set named range for entire absolute row 2.
2442 bInserted
= m_pDoc
->InsertNewRangeName("EntireRow", aNamePos
, "$2:$2");
2443 CPPUNIT_ASSERT(bInserted
);
2445 // Set values in B1:B3.
2446 m_pDoc
->SetValue(ScAddress(1,0,0), 1.0);
2447 m_pDoc
->SetValue(ScAddress(1,1,0), 2.0);
2448 m_pDoc
->SetValue(ScAddress(1,2,0), 3.0);
2450 // Reference them in B4.
2451 m_pDoc
->SetString(ScAddress(1,3,0), "=SUM(B1:B3)");
2452 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,3,0)));
2454 // Use named range in C2 to reference B2.
2455 m_pDoc
->SetString(ScAddress(2,1,0), "=RowRelativeRange");
2456 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
2458 // Use named range in C3 to reference column B, values in B1,B2,B3,B4
2459 m_pDoc
->SetString(ScAddress(2,2,0), "=SUM(EntireColumn)");
2460 CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
2462 // Use named range in C4 to reference row 2, values in B2 and C2.
2463 m_pDoc
->SetString(ScAddress(2,3,0), "=SUM(EntireRow)");
2464 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
2466 // Insert columns over A:B.
2467 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
2468 aMark
.SelectOneTable(0);
2469 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
2470 rFunc
.InsertCells(ScRange(0,0,0,1,m_pDoc
->MaxRow(),0), &aMark
, INS_INSCOLS_BEFORE
, false, true);
2472 // Now, the original column B has moved to column D.
2473 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D4 after column insertion.", OUString("=SUM(D1:D3)"), m_pDoc
->GetFormula(3,3,0));
2475 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(3,3,0)));
2477 // Check that the named reference points to the moved cell, now D2.
2478 ScRangeData
* pName
= m_pDoc
->GetRangeName()->findByUpperName("ROWRELATIVERANGE");
2479 CPPUNIT_ASSERT(pName
);
2480 OUString aSymbol
= pName
->GetSymbol(aNamePos
, formula::FormulaGrammar::GRAM_ENGLISH
);
2481 CPPUNIT_ASSERT_EQUAL(OUString("$Formula.$D2"), aSymbol
);
2483 // Check that the formula using the name, now in E2, still has the same result.
2484 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in E2 after column insertion.", OUString("=RowRelativeRange"), m_pDoc
->GetFormula(4,1,0));
2486 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(4,1,0)));
2488 // Check that the named column reference points to the moved column, now D.
2489 pName
= m_pDoc
->GetRangeName()->findByUpperName("ENTIRECOLUMN");
2490 CPPUNIT_ASSERT(pName
);
2491 aSymbol
= pName
->GetSymbol(aNamePos
, formula::FormulaGrammar::GRAM_ENGLISH
);
2492 CPPUNIT_ASSERT_EQUAL(OUString("$D:$D"), aSymbol
);
2494 // Check that the formula using the name, now in E3, still has the same result.
2495 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in E3 after column insertion.", OUString("=SUM(EntireColumn)"), m_pDoc
->GetFormula(4,2,0));
2497 CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc
->GetValue(ScAddress(4,2,0)));
2499 // Check that the named row reference still points to the same entire row
2500 // and does not have a #REF! error due to inserted columns.
2501 pName
= m_pDoc
->GetRangeName()->findByUpperName("ENTIREROW");
2502 CPPUNIT_ASSERT(pName
);
2503 aSymbol
= pName
->GetSymbol(aNamePos
, formula::FormulaGrammar::GRAM_ENGLISH
);
2504 CPPUNIT_ASSERT_EQUAL(OUString("$2:$2"), aSymbol
);
2506 // Check that the formula using the name, now in E4, still has the same result.
2507 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in E4 after column insertion.", OUString("=SUM(EntireRow)"), m_pDoc
->GetFormula(4,3,0));
2509 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(4,3,0)));
2511 m_pDoc
->DeleteTab(0);
2514 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateMove
)
2516 m_pDoc
->InsertTab(0, "Sheet1");
2518 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2520 // Set value to B4:B6.
2521 m_pDoc
->SetValue(ScAddress(1,3,0), 1);
2522 m_pDoc
->SetValue(ScAddress(1,4,0), 2);
2523 m_pDoc
->SetValue(ScAddress(1,5,0), 3);
2525 // Set formulas to A9:A12 that references B4:B6.
2526 m_pDoc
->SetString(ScAddress(0,8,0), "=SUM(B4:B6)");
2527 m_pDoc
->SetString(ScAddress(0,9,0), "=SUM($B$4:$B$6)");
2528 m_pDoc
->SetString(ScAddress(0,10,0), "=B5");
2529 m_pDoc
->SetString(ScAddress(0,11,0), "=$B$6");
2531 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(0,8,0));
2532 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(0,9,0));
2533 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(0,10,0));
2534 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(0,11,0));
2536 // Move B4:B6 to D4 (two columns to the right).
2537 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
2538 bool bMoved
= rFunc
.MoveBlock(ScRange(1,3,0,1,5,0), ScAddress(3,3,0), true, false, false, false);
2539 CPPUNIT_ASSERT_MESSAGE("Failed to move B4:B6.", bMoved
);
2541 // The results of the formula cells that reference the moved range should remain the same.
2542 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(0,8,0));
2543 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(0,9,0));
2544 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(0,10,0));
2545 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(0,11,0));
2547 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(D4:D6)"), m_pDoc
->GetFormula(0,8,0));
2548 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM($D$4:$D$6)"), m_pDoc
->GetFormula(0,9,0));
2549 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=D5"), m_pDoc
->GetFormula(0,10,0));
2550 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=$D$6"), m_pDoc
->GetFormula(0,11,0));
2552 // Move A9:A12 to B10:B13.
2553 bMoved
= rFunc
.MoveBlock(ScRange(0,8,0,0,11,0), ScAddress(1,9,0), true, false, false, false);
2554 CPPUNIT_ASSERT_MESSAGE("Failed to move A9:A12 to B10:B13", bMoved
);
2556 // The results of these formula cells should still stay the same.
2557 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(1,9,0));
2558 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(1,10,0));
2559 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(1,11,0));
2560 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(1,12,0));
2562 // Displayed formulas should stay the same since the referenced range hasn't moved.
2563 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(D4:D6)"), m_pDoc
->GetFormula(1,9,0));
2564 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM($D$4:$D$6)"), m_pDoc
->GetFormula(1,10,0));
2565 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=D5"), m_pDoc
->GetFormula(1,11,0));
2566 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=$D$6"), m_pDoc
->GetFormula(1,12,0));
2568 // The value cells are in D4:D6. Move D4:D5 to the right but leave D6
2570 bMoved
= rFunc
.MoveBlock(ScRange(3,3,0,3,4,0), ScAddress(4,3,0), true, false, false, false);
2571 CPPUNIT_ASSERT_MESSAGE("Failed to move D4:D5 to E4:E5", bMoved
);
2573 // Only the values of B10 and B11 should be updated.
2574 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(1,9,0));
2575 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(1,10,0));
2576 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(1,11,0));
2577 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(1,12,0));
2579 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(D4:D6)"), m_pDoc
->GetFormula(1,9,0));
2580 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM($D$4:$D$6)"), m_pDoc
->GetFormula(1,10,0));
2581 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=E5"), m_pDoc
->GetFormula(1,11,0));
2582 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=$D$6"), m_pDoc
->GetFormula(1,12,0));
2584 m_pDoc
->DeleteTab(0);
2587 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateMoveUndo
)
2589 m_pDoc
->InsertTab(0, "Test");
2591 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2593 // Set values in A1:A4.
2594 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
2595 m_pDoc
->SetValue(ScAddress(0,1,0), 2.0);
2596 m_pDoc
->SetValue(ScAddress(0,2,0), 3.0);
2597 m_pDoc
->SetValue(ScAddress(0,3,0), 4.0);
2599 // Set formulas with single cell references in A6:A8.
2600 m_pDoc
->SetString(ScAddress(0,5,0), "=A1");
2601 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
2602 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=A1"), m_pDoc
->GetFormula(0,5,0));
2604 m_pDoc
->SetString(ScAddress(0,6,0), "=A1+A2+A3");
2605 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
2606 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=A1+A2+A3"), m_pDoc
->GetFormula(0,6,0));
2608 m_pDoc
->SetString(ScAddress(0,7,0), "=A1+A3+A4");
2609 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(0,7,0)));
2610 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=A1+A3+A4"), m_pDoc
->GetFormula(0,7,0));
2612 // Set formulas with range references in A10:A12.
2613 m_pDoc
->SetString(ScAddress(0,9,0), "=SUM(A1:A2)");
2614 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
2615 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(A1:A2)"), m_pDoc
->GetFormula(0,9,0));
2617 m_pDoc
->SetString(ScAddress(0,10,0), "=SUM(A1:A3)");
2618 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,10,0)));
2619 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(A1:A3)"), m_pDoc
->GetFormula(0,10,0));
2621 m_pDoc
->SetString(ScAddress(0,11,0), "=SUM(A1:A4)");
2622 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,11,0)));
2623 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(A1:A4)"), m_pDoc
->GetFormula(0,11,0));
2625 // Move A1:A3 to C1:C3. Note that A4 remains.
2626 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
2627 bool bMoved
= rFunc
.MoveBlock(ScRange(0,0,0,0,2,0), ScAddress(2,0,0), true, true, false, true);
2628 CPPUNIT_ASSERT(bMoved
);
2630 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
2631 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=C1"), m_pDoc
->GetFormula(0,5,0));
2633 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
2634 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=C1+C2+C3"), m_pDoc
->GetFormula(0,6,0));
2636 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(0,7,0)));
2637 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=C1+C3+A4"), m_pDoc
->GetFormula(0,7,0));
2639 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
2640 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(C1:C2)"), m_pDoc
->GetFormula(0,9,0));
2642 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,10,0)));
2643 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(C1:C3)"), m_pDoc
->GetFormula(0,10,0));
2645 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,11,0)));
2646 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(A1:A4)"), m_pDoc
->GetFormula(0,11,0));
2649 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
2650 CPPUNIT_ASSERT(pUndoMgr
);
2653 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
2654 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=A1"), m_pDoc
->GetFormula(0,5,0));
2656 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
2657 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=A1+A2+A3"), m_pDoc
->GetFormula(0,6,0));
2659 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(0,7,0)));
2660 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=A1+A3+A4"), m_pDoc
->GetFormula(0,7,0));
2662 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
2663 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(A1:A2)"), m_pDoc
->GetFormula(0,9,0));
2665 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,10,0)));
2666 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(A1:A3)"), m_pDoc
->GetFormula(0,10,0));
2668 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,11,0)));
2669 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula.", OUString("=SUM(A1:A4)"), m_pDoc
->GetFormula(0,11,0));
2671 // Make sure the broadcasters are still valid by changing the value of A1.
2672 m_pDoc
->SetValue(ScAddress(0,0,0), 20);
2674 CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
2675 CPPUNIT_ASSERT_EQUAL(25.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
2676 CPPUNIT_ASSERT_EQUAL(27.0, m_pDoc
->GetValue(ScAddress(0,7,0)));
2678 CPPUNIT_ASSERT_EQUAL(22.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
2679 CPPUNIT_ASSERT_EQUAL(25.0, m_pDoc
->GetValue(ScAddress(0,10,0)));
2680 CPPUNIT_ASSERT_EQUAL(29.0, m_pDoc
->GetValue(ScAddress(0,11,0)));
2682 m_pDoc
->DeleteTab(0);
2685 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateMoveUndo2
)
2687 m_pDoc
->InsertTab(0, "Test");
2689 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2691 std::vector
<std::vector
<const char*>> aData
= {
2692 { "1", "2", "=A2*10", "=SUM(A1:B1)" },
2693 { "3", "4", "=SUM(A2:B2)", "=SUM(A2:B2)" },
2697 ScRange aOutRange
= insertRangeData(m_pDoc
, ScAddress(0,0,0), aData
);
2699 std::vector
<std::vector
<const char*>> aCheckInitial
= {
2700 { "1", "2", "30", "3" },
2701 { "3", "4", "7", "7" },
2702 { "3", nullptr, nullptr, nullptr },
2705 bool bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "initial data");
2706 CPPUNIT_ASSERT(bGood
);
2708 // D1:D2 should be grouped.
2709 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(3,0,0));
2710 CPPUNIT_ASSERT(pFC
);
2711 CPPUNIT_ASSERT_EQUAL(SCROW(2), pFC
->GetSharedLength());
2713 // Drag A1:B1 into A2:B2 thereby overwriting the old A2:B2 content.
2714 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
2715 bool bMoved
= rFunc
.MoveBlock(ScRange(0,0,0,1,0,0), ScAddress(0,1,0), true, true, false, true);
2716 CPPUNIT_ASSERT(bMoved
);
2718 std::vector
<std::vector
<const char*>> aCheckAfter
= {
2719 { nullptr, nullptr, "10", "3" },
2720 { "1", "2", "3", "3" },
2721 { "3", nullptr, nullptr, nullptr },
2724 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "A1:B1 moved to A2:B2");
2725 CPPUNIT_ASSERT(bGood
);
2728 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
2729 CPPUNIT_ASSERT(pUndoMgr
);
2732 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "after undo");
2733 CPPUNIT_ASSERT(bGood
);
2735 // D1:D2 should be grouped.
2736 pFC
= m_pDoc
->GetFormulaCell(ScAddress(3,0,0));
2737 CPPUNIT_ASSERT(pFC
);
2738 CPPUNIT_ASSERT_EQUAL(SCROW(2), pFC
->GetSharedLength());
2743 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "after redo");
2744 CPPUNIT_ASSERT(bGood
);
2746 m_pDoc
->DeleteTab(0);
2749 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateMoveUndo3NonShared
)
2751 m_pDoc
->InsertTab(0, "Test");
2753 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2755 std::vector
<std::vector
<const char*>> aData
= {
2756 { "10", nullptr, nullptr },
2757 { "=A1", nullptr, nullptr },
2758 { "=A2+A1", nullptr, nullptr },
2761 ScRange aOutRange
= insertRangeData(m_pDoc
, ScAddress(0,0,0), aData
);
2763 std::vector
<std::vector
<const char*>> aCheckInitial
= {
2764 { "10", nullptr, nullptr },
2765 { "10", nullptr, nullptr },
2766 { "20", nullptr, nullptr },
2769 bool bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "initial data");
2770 CPPUNIT_ASSERT(bGood
);
2772 // Drag A2:A3 into C2:C3.
2773 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
2774 bool bMoved
= rFunc
.MoveBlock(ScRange(0,1,0,0,2,0), ScAddress(2,1,0), true, true, false, true);
2775 CPPUNIT_ASSERT(bMoved
);
2777 std::vector
<std::vector
<const char*>> aCheckAfter
= {
2778 { "10", nullptr, nullptr},
2779 { nullptr, nullptr, "10" },
2780 { nullptr, nullptr, "20" },
2783 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "A2:A3 moved to C2:C3");
2784 CPPUNIT_ASSERT(bGood
);
2787 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
2788 CPPUNIT_ASSERT(pUndoMgr
);
2791 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "after undo");
2792 CPPUNIT_ASSERT(bGood
);
2797 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "after redo");
2798 CPPUNIT_ASSERT(bGood
);
2800 m_pDoc
->DeleteTab(0);
2803 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateMoveUndo3Shared
)
2805 m_pDoc
->InsertTab(0, "Test");
2807 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2809 std::vector
<std::vector
<const char*>> aData
= {
2810 { "10", nullptr, nullptr },
2811 { "=A1", nullptr, nullptr },
2812 { "=A2+$A$1", nullptr, nullptr },
2813 { "=A3+$A$1", nullptr, nullptr },
2816 ScRange aOutRange
= insertRangeData(m_pDoc
, ScAddress(0,0,0), aData
);
2818 std::vector
<std::vector
<const char*>> aCheckInitial
= {
2819 { "10", nullptr, nullptr },
2820 { "10", nullptr, nullptr },
2821 { "20", nullptr, nullptr },
2822 { "30", nullptr, nullptr },
2825 bool bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "initial data");
2826 CPPUNIT_ASSERT(bGood
);
2828 // A3:A4 should be grouped.
2829 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,2,0));
2830 CPPUNIT_ASSERT(pFC
);
2831 CPPUNIT_ASSERT_EQUAL(SCROW(2), pFC
->GetSharedLength());
2833 // Drag A2:A4 into C2:C4.
2834 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
2835 bool bMoved
= rFunc
.MoveBlock(ScRange(0,1,0,0,3,0), ScAddress(2,1,0), true, true, false, true);
2836 CPPUNIT_ASSERT(bMoved
);
2838 std::vector
<std::vector
<const char*>> aCheckAfter
= {
2839 { "10", nullptr, nullptr},
2840 { nullptr, nullptr, "10" },
2841 { nullptr, nullptr, "20" },
2842 { nullptr, nullptr, "30" },
2845 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "A2:A4 moved to C2:C4");
2846 CPPUNIT_ASSERT(bGood
);
2848 // C3:C4 should be grouped.
2849 pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,2,0));
2850 CPPUNIT_ASSERT(pFC
);
2851 CPPUNIT_ASSERT_EQUAL(SCROW(2), pFC
->GetSharedLength());
2854 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
2855 CPPUNIT_ASSERT(pUndoMgr
);
2858 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "after undo");
2859 CPPUNIT_ASSERT(bGood
);
2861 // A3:A4 should be grouped.
2862 pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,2,0));
2863 CPPUNIT_ASSERT(pFC
);
2864 CPPUNIT_ASSERT_EQUAL(SCROW(2), pFC
->GetSharedLength());
2869 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "after redo");
2870 CPPUNIT_ASSERT(bGood
);
2872 m_pDoc
->DeleteTab(0);
2875 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateMoveUndoDependents
)
2877 m_pDoc
->InsertTab(0, "Test");
2879 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2880 std::vector
<std::vector
<const char*>> aData
= {
2890 ScRange aOutRange
= insertRangeData(m_pDoc
, ScAddress(2,0,0), aData
);
2892 std::vector
<std::vector
<const char*>> aCheckInitial
= {
2902 bool bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "initial data");
2903 CPPUNIT_ASSERT(bGood
);
2906 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
2907 bool bMoved
= rFunc
.MoveBlock(ScRange(2, 1, 0, 2, 1, 0), ScAddress(3, 1, 0), true, true, false, true);
2908 CPPUNIT_ASSERT(bMoved
);
2910 std::vector
<std::vector
<const char*>> aCheckAfter
= {
2920 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "C2 moved to D2");
2921 CPPUNIT_ASSERT(bGood
);
2924 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
2925 CPPUNIT_ASSERT(pUndoMgr
);
2928 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "after undo");
2929 CPPUNIT_ASSERT(bGood
);
2934 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "after redo");
2935 CPPUNIT_ASSERT(bGood
);
2937 m_pDoc
->DeleteTab(0);
2940 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateMoveUndo4
)
2942 m_pDoc
->InsertTab(0, "Test");
2944 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
2945 std::vector
<std::vector
<const char*>> aData
= {
2946 { "1", nullptr, "=B1", "=A1" },
2947 { "2", nullptr, "=B2", "=A2" },
2950 ScRange aOutRange
= insertRangeData(m_pDoc
, ScAddress(0,0,0), aData
);
2952 std::vector
<std::vector
<const char*>> aCheckInitial
= {
2953 { "1", nullptr, "0", "1" },
2954 { "2", nullptr, "0", "2" },
2957 bool bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "initial data");
2958 CPPUNIT_ASSERT(bGood
);
2960 // Drag A1:A2 into B1:B2.
2961 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
2962 bool bMoved
= rFunc
.MoveBlock(ScRange(0, 0, 0, 0, 1, 0), ScAddress(1, 0, 0), true, true, false, true);
2963 CPPUNIT_ASSERT(bMoved
);
2965 std::vector
<std::vector
<const char*>> aCheckAfter
= {
2966 { nullptr, "1", "1", "1" },
2967 { nullptr, "2", "2", "2" },
2970 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "A1:A2 moved to B1:B2");
2971 CPPUNIT_ASSERT(bGood
);
2973 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B1"), m_pDoc
->GetFormula(2,0,0)); // C1
2974 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B2"), m_pDoc
->GetFormula(2,1,0)); // C2
2975 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B1"), m_pDoc
->GetFormula(3,0,0)); // D1
2976 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B2"), m_pDoc
->GetFormula(3,1,0)); // D2
2979 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
2980 CPPUNIT_ASSERT(pUndoMgr
);
2983 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckInitial
, "after undo");
2984 CPPUNIT_ASSERT(bGood
);
2986 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B1"), m_pDoc
->GetFormula(2,0,0)); // C1
2987 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B2"), m_pDoc
->GetFormula(2,1,0)); // C2
2988 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=A1"), m_pDoc
->GetFormula(3,0,0)); // D1
2989 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=A2"), m_pDoc
->GetFormula(3,1,0)); // D2
2994 bGood
= checkOutput(m_pDoc
, aOutRange
, aCheckAfter
, "after redo");
2995 CPPUNIT_ASSERT(bGood
);
2997 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B1"), m_pDoc
->GetFormula(2,0,0)); // C1
2998 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B2"), m_pDoc
->GetFormula(2,1,0)); // C2
2999 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B1"), m_pDoc
->GetFormula(3,0,0)); // D1
3000 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=B2"), m_pDoc
->GetFormula(3,1,0)); // D2
3002 m_pDoc
->DeleteTab(0);
3005 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateMoveToSheet
)
3007 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
3009 m_pDoc
->InsertTab(0, "Sheet1");
3010 m_pDoc
->InsertTab(1, "Sheet2");
3012 // Set values to A1:A2 on Sheet1, and B1:B2 to reference them.
3013 m_pDoc
->SetValue(ScAddress(0,0,0), 11);
3014 m_pDoc
->SetValue(ScAddress(0,1,0), 12);
3015 m_pDoc
->SetString(ScAddress(1,0,0), "=A1");
3016 m_pDoc
->SetString(ScAddress(1,1,0), "=A2");
3018 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=A1"), m_pDoc
->GetFormula(1,0,0));
3019 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=A2"), m_pDoc
->GetFormula(1,1,0));
3021 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
3022 CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
3024 // Move A1:A2 on Sheet1 to B3:B4 on Sheet2.
3025 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
3026 bool bMoved
= rFunc
.MoveBlock(ScRange(0,0,0,0,1,0), ScAddress(1,2,1), true, true, false, true);
3027 CPPUNIT_ASSERT(bMoved
);
3029 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=Sheet2.B3"), m_pDoc
->GetFormula(1,0,0));
3030 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=Sheet2.B4"), m_pDoc
->GetFormula(1,1,0));
3032 // Undo and check again.
3033 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
3036 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=A1"), m_pDoc
->GetFormula(1,0,0));
3037 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=A2"), m_pDoc
->GetFormula(1,1,0));
3042 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=Sheet2.B3"), m_pDoc
->GetFormula(1,0,0));
3043 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("=Sheet2.B4"), m_pDoc
->GetFormula(1,1,0));
3045 m_pDoc
->DeleteTab(1);
3046 m_pDoc
->DeleteTab(0);
3049 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateDeleteContent
)
3051 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
3053 m_pDoc
->InsertTab(0, "Test");
3056 m_pDoc
->SetValue(ScAddress(1,1,0), 2.0);
3057 // Set formula in C2 to reference B2.
3058 m_pDoc
->SetString(ScAddress(2,1,0), "=B2");
3060 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
3063 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
3064 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
3065 aMark
.SetMarkArea(ScAddress(1,1,0));
3066 rFunc
.DeleteContents(aMark
, InsertDeleteFlags::CONTENTS
, true, true);
3068 CPPUNIT_ASSERT_EQUAL_MESSAGE("B2 should be empty.", CELLTYPE_NONE
, m_pDoc
->GetCellType(ScAddress(1,1,0)));
3069 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
3071 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
3072 CPPUNIT_ASSERT(pUndoMgr
);
3074 // Undo and check the result of C2.
3076 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(1,1,0))); // B2
3077 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,1,0))); // C2
3081 CPPUNIT_ASSERT_EQUAL_MESSAGE("B2 should be empty.", CELLTYPE_NONE
, m_pDoc
->GetCellType(ScAddress(1,1,0)));
3082 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
3084 m_pDoc
->DeleteTab(0);
3087 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateDeleteAndShiftLeft
)
3089 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
3091 m_pDoc
->InsertTab(0, "Test");
3093 // Insert 1,2,3,4,5 in C1:G1.
3094 for (SCCOL i
= 0; i
<= 4; ++i
)
3095 m_pDoc
->SetValue(ScAddress(i
+2,0,0), i
+1);
3097 // Insert formula in H1.
3098 ScAddress
aPos(7,0,0);
3099 m_pDoc
->SetString(aPos
, "=SUM(C1:G1)");
3101 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(aPos
));
3103 // Delete columns D:E (middle of the reference).
3104 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
3105 aMark
.SelectOneTable(0);
3106 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
3107 bool bDeleted
= rFunc
.DeleteCells(ScRange(3,0,0,4,m_pDoc
->MaxRow(),0), &aMark
, DelCellCmd::CellsLeft
, true);
3108 CPPUNIT_ASSERT(bDeleted
);
3111 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(aPos
));
3112 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(C1:E1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3115 SfxUndoManager
* pUndo
= m_pDoc
->GetUndoManager();
3116 CPPUNIT_ASSERT(pUndo
);
3120 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(aPos
));
3121 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(C1:G1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3123 // Delete columns C:D (left end of the reference).
3124 bDeleted
= rFunc
.DeleteCells(ScRange(2,0,0,3,m_pDoc
->MaxRow(),0), &aMark
, DelCellCmd::CellsLeft
, true);
3125 CPPUNIT_ASSERT(bDeleted
);
3128 CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc
->GetValue(aPos
));
3129 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(C1:E1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3131 // Undo and check again.
3134 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(aPos
));
3135 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(C1:G1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3137 // Delete columns B:E (overlaps on the left).
3138 bDeleted
= rFunc
.DeleteCells(ScRange(1,0,0,4,m_pDoc
->MaxRow(),0), &aMark
, DelCellCmd::CellsLeft
, true);
3139 CPPUNIT_ASSERT(bDeleted
);
3142 CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc
->GetValue(aPos
));
3143 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(B1:C1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3145 // Undo and check again.
3148 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(aPos
));
3149 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(C1:G1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3151 // Start over with a new scenario.
3152 clearSheet(m_pDoc
, 0);
3154 // Insert 1,2,3,4,5,6 into C1:H1.
3155 for (SCCOL i
= 0; i
<= 5; ++i
)
3156 m_pDoc
->SetValue(ScAddress(i
+2,0,0), i
+1);
3158 // Set formula in B1.
3159 aPos
= ScAddress(1,0,0);
3160 m_pDoc
->SetString(aPos
, "=SUM(C1:H1)");
3161 CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc
->GetValue(aPos
));
3163 // Delete columns F:H (right end of the reference).
3164 bDeleted
= rFunc
.DeleteCells(ScRange(5,0,0,7,m_pDoc
->MaxRow(),0), &aMark
, DelCellCmd::CellsLeft
, true);
3165 CPPUNIT_ASSERT(bDeleted
);
3167 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(aPos
));
3168 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(C1:E1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3172 CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc
->GetValue(aPos
));
3173 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(C1:H1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3175 // Delete columns G:I (overlaps on the right).
3176 bDeleted
= rFunc
.DeleteCells(ScRange(6,0,0,8,m_pDoc
->MaxRow(),0), &aMark
, DelCellCmd::CellsLeft
, true);
3177 CPPUNIT_ASSERT(bDeleted
);
3179 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(aPos
));
3180 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(C1:F1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3182 // Undo and check again.
3184 CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc
->GetValue(aPos
));
3185 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(C1:H1)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3187 m_pDoc
->DeleteTab(0);
3190 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateDeleteAndShiftLeft2
)
3192 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
3194 m_pDoc
->InsertTab(0, "Test");
3196 std::vector
<std::vector
<const char*>> aData
= {
3197 { "1", "=COUNT($A$1:$A$4)", "=COUNT(A1)" },
3198 { "2", "=COUNT($A$1:$A$4)", "=COUNT(A2)" },
3199 { "3", "=COUNT($A$1:$A$4)", "=COUNT(A3)" },
3200 { "4", "=COUNT($A$1:$A$4)", "=COUNT(A4)" },
3203 insertRangeData(m_pDoc
, ScAddress(), aData
);
3205 auto funcCheckOriginal
= [&]()
3207 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,0,0))); // A1
3208 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,1,0))); // A2
3209 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(0,2,0))); // A3
3210 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,3,0))); // A4
3212 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,0,0))); // B1
3213 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,1,0))); // B2
3214 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,2,0))); // B3
3215 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,3,0))); // B4
3217 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,0,0))); // C1
3218 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,1,0))); // C2
3219 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,2,0))); // C3
3220 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,3,0))); // C4
3223 auto funcCheckDeleted
= [&]()
3225 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(ScAddress(0,0,0))); // A1
3226 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(ScAddress(0,1,0))); // A2
3227 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(ScAddress(0,2,0))); // A3
3228 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(ScAddress(0,3,0))); // A4
3230 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(ScAddress(1,0,0))); // B1
3231 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(ScAddress(1,1,0))); // B2
3232 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(ScAddress(1,2,0))); // B3
3233 CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc
->GetString(ScAddress(1,3,0))); // B4
3236 funcCheckOriginal();
3239 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
3240 aMark
.SelectOneTable(0);
3241 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
3242 bool bDeleted
= rFunc
.DeleteCells(ScRange(0,0,0,0,m_pDoc
->MaxRow(),0), &aMark
, DelCellCmd::CellsLeft
, true);
3243 CPPUNIT_ASSERT(bDeleted
);
3248 SfxUndoManager
* pUndo
= m_pDoc
->GetUndoManager();
3249 CPPUNIT_ASSERT(pUndo
);
3252 funcCheckOriginal();
3258 m_pDoc
->DeleteTab(0);
3261 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateDeleteAndShiftUp
)
3263 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
3265 m_pDoc
->InsertTab(0, "Test");
3267 // Insert 1,2,3,4,5 in A3:A7.
3268 for (SCROW i
= 0; i
<= 4; ++i
)
3269 m_pDoc
->SetValue(ScAddress(0,i
+2,0), i
+1);
3271 // Insert formula in A8.
3272 ScAddress
aPos(0,7,0);
3273 m_pDoc
->SetString(aPos
, "=SUM(A3:A7)");
3275 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(aPos
));
3277 // Delete rows 4:5 (middle of the reference).
3278 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
3279 aMark
.SelectOneTable(0);
3280 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
3281 bool bDeleted
= rFunc
.DeleteCells(ScRange(0,3,0,m_pDoc
->MaxCol(),4,0), &aMark
, DelCellCmd::CellsUp
, true);
3282 CPPUNIT_ASSERT(bDeleted
);
3285 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(aPos
));
3286 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A3:A5)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3289 SfxUndoManager
* pUndo
= m_pDoc
->GetUndoManager();
3290 CPPUNIT_ASSERT(pUndo
);
3294 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(aPos
));
3295 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A3:A7)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3297 // Delete rows 3:4 (top end of the reference).
3298 bDeleted
= rFunc
.DeleteCells(ScRange(0,2,0,m_pDoc
->MaxCol(),3,0), &aMark
, DelCellCmd::CellsUp
, true);
3299 CPPUNIT_ASSERT(bDeleted
);
3302 CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc
->GetValue(aPos
));
3303 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A3:A5)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3305 // Undo and check again.
3308 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(aPos
));
3309 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A3:A7)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3311 // Delete rows 2:5 (overlaps on the top).
3312 bDeleted
= rFunc
.DeleteCells(ScRange(0,1,0,m_pDoc
->MaxCol(),4,0), &aMark
, DelCellCmd::CellsUp
, true);
3313 CPPUNIT_ASSERT(bDeleted
);
3316 CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc
->GetValue(aPos
));
3317 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A2:A3)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3319 // Undo and check again.
3322 CPPUNIT_ASSERT_EQUAL(15.0, m_pDoc
->GetValue(aPos
));
3323 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A3:A7)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3325 // Start over with a new scenario.
3326 clearSheet(m_pDoc
, 0);
3328 // Insert 1,2,3,4,5,6 into A3:A8.
3329 for (SCROW i
= 0; i
<= 5; ++i
)
3330 m_pDoc
->SetValue(ScAddress(0,i
+2,0), i
+1);
3332 // Set formula in B1.
3333 aPos
= ScAddress(0,1,0);
3334 m_pDoc
->SetString(aPos
, "=SUM(A3:A8)");
3335 CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc
->GetValue(aPos
));
3337 // Delete rows 6:8 (bottom end of the reference).
3338 bDeleted
= rFunc
.DeleteCells(ScRange(0,5,0,m_pDoc
->MaxCol(),7,0), &aMark
, DelCellCmd::CellsUp
, true);
3339 CPPUNIT_ASSERT(bDeleted
);
3341 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(aPos
));
3342 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A3:A5)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3346 CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc
->GetValue(aPos
));
3347 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A3:A8)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3349 // Delete rows 7:9 (overlaps on the bottom).
3350 bDeleted
= rFunc
.DeleteCells(ScRange(0,6,0,m_pDoc
->MaxCol(),8,0), &aMark
, DelCellCmd::CellsUp
, true);
3351 CPPUNIT_ASSERT(bDeleted
);
3353 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(aPos
));
3354 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A3:A6)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3356 // Undo and check again.
3358 CPPUNIT_ASSERT_EQUAL(21.0, m_pDoc
->GetValue(aPos
));
3359 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=SUM(A3:A8)"), m_pDoc
->GetFormula(aPos
.Col(), aPos
.Row(), aPos
.Tab()));
3361 m_pDoc
->DeleteTab(0);
3364 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateName
)
3366 m_pDoc
->InsertTab(0, "Formula");
3368 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
3370 // Fill C2:C5 with values.
3371 m_pDoc
->SetValue(ScAddress(2,1,0), 1);
3372 m_pDoc
->SetValue(ScAddress(2,2,0), 2);
3373 m_pDoc
->SetValue(ScAddress(2,3,0), 3);
3374 m_pDoc
->SetValue(ScAddress(2,4,0), 4);
3376 // Add a named expression that references the immediate left cell.
3377 ScRangeName
* pGlobalNames
= m_pDoc
->GetRangeName();
3378 CPPUNIT_ASSERT_MESSAGE("Failed to obtain global named expression object.", pGlobalNames
);
3379 ScRangeData
* pName
= new ScRangeData(
3380 *m_pDoc
, "ToLeft", "RC[-1]", ScAddress(2,1,0),
3381 ScRangeData::Type::Name
, formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1
);
3383 bool bInserted
= pGlobalNames
->insert(pName
);
3384 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bInserted
);
3386 // Insert formulas in D2:D5 using the named expression.
3387 m_pDoc
->SetString(ScAddress(3,1,0), "=ToLeft");
3388 m_pDoc
->SetString(ScAddress(3,2,0), "=ToLeft");
3389 m_pDoc
->SetString(ScAddress(3,3,0), "=ToLeft");
3390 m_pDoc
->SetString(ScAddress(3,4,0), "=ToLeft");
3392 // Make sure the results are correct.
3393 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(3,1,0));
3394 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(3,2,0));
3395 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(3,3,0));
3396 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(3,4,0));
3398 // Push cells in column C down by one cell.
3399 m_pDoc
->InsertRow(ScRange(2,0,0,2,0,0));
3401 // Make sure the results change accordingly.
3402 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(3,1,0));
3403 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(3,2,0));
3404 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(3,3,0));
3405 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(3,4,0));
3408 m_pDoc
->DeleteRow(ScRange(2,0,0,2,0,0));
3410 // Make sure the results are back as well.
3411 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(3,1,0));
3412 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(3,2,0));
3413 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(3,3,0));
3414 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(3,4,0));
3416 // Fill B10:B12 with values.
3417 m_pDoc
->SetValue(ScAddress(1,9,0), 10);
3418 m_pDoc
->SetValue(ScAddress(1,10,0), 11);
3419 m_pDoc
->SetValue(ScAddress(1,11,0), 12);
3421 // Insert a new named expression that references these values as absolute range.
3422 pName
= new ScRangeData(
3423 *m_pDoc
, "MyRange", "$B$10:$B$12", ScAddress(0,0,0), ScRangeData::Type::Name
, formula::FormulaGrammar::GRAM_NATIVE
);
3424 bInserted
= pGlobalNames
->insert(pName
);
3425 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bInserted
);
3427 // Set formula at C8 that references this named expression.
3428 m_pDoc
->SetString(ScAddress(2,7,0), "=SUM(MyRange)");
3429 CPPUNIT_ASSERT_EQUAL(33.0, m_pDoc
->GetValue(ScAddress(2,7,0)));
3431 // Shift B10:B12 to right by 2 columns.
3432 m_pDoc
->InsertCol(ScRange(1,9,0,2,11,0));
3434 // This should shift the absolute range B10:B12 that MyRange references.
3435 pName
= pGlobalNames
->findByUpperName("MYRANGE");
3436 CPPUNIT_ASSERT_MESSAGE("Failed to find named expression 'MyRange' in the global scope.", pName
);
3437 OUString aExpr
= pName
->GetSymbol();
3438 CPPUNIT_ASSERT_EQUAL(OUString("$D$10:$D$12"), aExpr
);
3440 // This move shouldn't affect the value of C8.
3441 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,7,0));
3442 CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC
);
3443 CPPUNIT_ASSERT_EQUAL(33.0, m_pDoc
->GetValue(ScAddress(2,7,0)));
3445 // Update the value of D10 and make sure C8 gets updated.
3446 m_pDoc
->SetValue(ScAddress(3,9,0), 20);
3447 CPPUNIT_ASSERT_EQUAL(43.0, m_pDoc
->GetValue(ScAddress(2,7,0)));
3449 // Insert a new sheet before the current.
3450 m_pDoc
->InsertTab(0, "New");
3452 m_pDoc
->GetName(1, aName
);
3453 CPPUNIT_ASSERT_EQUAL(OUString("Formula"), aName
);
3455 pName
= pGlobalNames
->findByUpperName("MYRANGE");
3456 CPPUNIT_ASSERT_MESSAGE("Failed to find named expression 'MyRange' in the global scope.", pName
);
3458 m_pDoc
->SetValue(ScAddress(3,9,1), 10);
3459 CPPUNIT_ASSERT_EQUAL(33.0, m_pDoc
->GetValue(ScAddress(2,7,1)));
3461 // Delete the inserted sheet, which will shift the 'Formula' sheet to the left.
3462 m_pDoc
->DeleteTab(0);
3465 m_pDoc
->GetName(0, aName
);
3466 CPPUNIT_ASSERT_EQUAL(OUString("Formula"), aName
);
3468 pName
= pGlobalNames
->findByUpperName("MYRANGE");
3469 CPPUNIT_ASSERT_MESSAGE("Failed to find named expression 'MyRange' in the global scope.", pName
);
3471 m_pDoc
->SetValue(ScAddress(3,9,0), 11);
3472 CPPUNIT_ASSERT_EQUAL(34.0, m_pDoc
->GetValue(ScAddress(2,7,0)));
3474 // Clear all and start over.
3475 clearRange(m_pDoc
, ScRange(0,0,0,100,100,0));
3476 pGlobalNames
->clear();
3478 pName
= new ScRangeData(
3479 *m_pDoc
, "MyRange", "$B$1:$C$6", ScAddress(0,0,0), ScRangeData::Type::Name
, formula::FormulaGrammar::GRAM_NATIVE
);
3480 bInserted
= pGlobalNames
->insert(pName
);
3481 CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bInserted
);
3482 aExpr
= pName
->GetSymbol();
3483 CPPUNIT_ASSERT_EQUAL(OUString("$B$1:$C$6"), aExpr
);
3485 // Insert range of cells to shift right. The range partially overlaps the named range.
3486 m_pDoc
->InsertCol(ScRange(2,4,0,3,8,0));
3488 // This should not alter the range.
3489 aExpr
= pName
->GetSymbol();
3490 CPPUNIT_ASSERT_EQUAL(OUString("$B$1:$C$6"), aExpr
);
3492 m_pDoc
->DeleteTab(0);
3495 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateNameMove
)
3497 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
3499 m_pDoc
->InsertTab(0, "Test");
3501 // Set values to B2:B4.
3502 m_pDoc
->SetValue(ScAddress(1,1,0), 1.0);
3503 m_pDoc
->SetValue(ScAddress(1,2,0), 2.0);
3504 m_pDoc
->SetValue(ScAddress(1,3,0), 3.0);
3506 // Set named range for B2:B4.
3507 bool bInserted
= m_pDoc
->InsertNewRangeName("MyRange", ScAddress(0,0,0), "$Test.$B$2:$B$4");
3508 CPPUNIT_ASSERT(bInserted
);
3510 // Set formula in A10.
3511 m_pDoc
->SetString(ScAddress(0,9,0), "=SUM(MyRange)");
3512 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
3514 ScRangeData
* pData
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3515 CPPUNIT_ASSERT(pData
);
3516 OUString aSymbol
= pData
->GetSymbol(m_pDoc
->GetGrammar());
3517 CPPUNIT_ASSERT_EQUAL(OUString("$Test.$B$2:$B$4"), aSymbol
);
3519 // Move B2:B4 to D3.
3520 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
3521 bool bMoved
= rFunc
.MoveBlock(ScRange(1,1,0,1,3,0), ScAddress(3,2,0), true, true, false, true);
3522 CPPUNIT_ASSERT(bMoved
);
3524 // The named range should have moved as well.
3525 aSymbol
= pData
->GetSymbol(m_pDoc
->GetGrammar());
3526 CPPUNIT_ASSERT_EQUAL(OUString("$Test.$D$3:$D$5"), aSymbol
);
3528 // The value of A10 should remain unchanged.
3529 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
3531 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
3532 CPPUNIT_ASSERT(pUndoMgr
);
3537 pData
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3538 CPPUNIT_ASSERT(pData
);
3539 aSymbol
= pData
->GetSymbol(m_pDoc
->GetGrammar());
3540 CPPUNIT_ASSERT_EQUAL(OUString("$Test.$B$2:$B$4"), aSymbol
);
3541 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
3546 pData
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3547 CPPUNIT_ASSERT(pData
);
3548 aSymbol
= pData
->GetSymbol(m_pDoc
->GetGrammar());
3549 CPPUNIT_ASSERT_EQUAL(OUString("$Test.$D$3:$D$5"), aSymbol
);
3550 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
3552 // Undo again to bring it back to the initial condition, and clear the undo buffer.
3556 // Add an identical formula to A11 and make a formula group over A10:A11.
3557 m_pDoc
->SetString(ScAddress(0,10,0), "=SUM(MyRange)");
3558 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(0,9,0));
3559 CPPUNIT_ASSERT(pFC
);
3560 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(9), pFC
->GetSharedTopRow());
3561 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
3563 // Move B2:B4 to D3 again.
3564 bMoved
= rFunc
.MoveBlock(ScRange(1,1,0,1,3,0), ScAddress(3,2,0), true, true, false, true);
3565 CPPUNIT_ASSERT(bMoved
);
3567 // Values of A10 and A11 should remain the same.
3568 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,9,0)));
3569 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,10,0)));
3571 // Clear and start over.
3572 clearSheet(m_pDoc
, 0);
3573 m_pDoc
->GetRangeName()->clear();
3576 m_pDoc
->SetValue(ScAddress(1,1,0), 2.0);
3578 // Define B2 as 'MyCell'.
3579 bInserted
= m_pDoc
->InsertNewRangeName("MyCell", ScAddress(0,0,0), "$Test.$B$2");
3580 CPPUNIT_ASSERT(bInserted
);
3582 // Set formula to B3 that references B2 via MyCell.
3583 m_pDoc
->SetString(ScAddress(1,2,0), "=MyCell*2");
3584 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
3587 bMoved
= rFunc
.MoveBlock(ScRange(1,1,0,1,1,0), ScAddress(3,1,0), true, true, false, true);
3588 CPPUNIT_ASSERT(bMoved
);
3590 // Value in B3 should remain unchanged.
3591 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
3593 m_pDoc
->DeleteTab(0);
3596 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateNameExpandRef
)
3598 setExpandRefs(true);
3600 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
3602 m_pDoc
->InsertTab(0, "Test");
3604 bool bInserted
= m_pDoc
->InsertNewRangeName("MyRange", ScAddress(0,0,0), "$A$1:$A$3");
3605 CPPUNIT_ASSERT(bInserted
);
3607 // Set values to A1:A3.
3608 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
3609 m_pDoc
->SetValue(ScAddress(0,1,0), 2.0);
3610 m_pDoc
->SetValue(ScAddress(0,2,0), 3.0);
3612 m_pDoc
->SetString(ScAddress(0,5,0), "=SUM(MyRange)");
3613 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
3615 // Insert a new row at row 4, which should expand the named range to A1:A4.
3616 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
3617 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
3618 aMark
.SelectOneTable(0);
3619 rFunc
.InsertCells(ScRange(0,3,0,m_pDoc
->MaxCol(),3,0), &aMark
, INS_INSROWS_BEFORE
, false, true);
3620 ScRangeData
* pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3621 CPPUNIT_ASSERT(pName
);
3622 OUString aSymbol
= pName
->GetSymbol(m_pDoc
->GetGrammar());
3623 CPPUNIT_ASSERT_EQUAL(OUString("$A$1:$A$4"), aSymbol
);
3625 // Make sure the listening area has been expanded as well. Note the
3626 // formula cell has been pushed downward by one cell.
3627 m_pDoc
->SetValue(ScAddress(0,3,0), 4.0);
3628 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
3630 // Insert a new column at column 2, which should not expand the named
3631 // range as it is only one column wide.
3632 rFunc
.InsertCells(ScRange(1,0,0,1,m_pDoc
->MaxRow(),0), &aMark
, INS_INSCOLS_BEFORE
, false, true);
3633 pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3634 CPPUNIT_ASSERT(pName
);
3635 aSymbol
= pName
->GetSymbol(m_pDoc
->GetGrammar());
3636 CPPUNIT_ASSERT_EQUAL(OUString("$A$1:$A$4"), aSymbol
);
3638 // Make sure the referenced area has not changed.
3639 m_pDoc
->SetValue(ScAddress(0,3,0), 2.0);
3640 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
3641 m_pDoc
->SetValue(ScAddress(1,3,0), 2.0);
3642 CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc
->GetValue(ScAddress(0,6,0)));
3644 // Clear the document and start over.
3645 m_pDoc
->GetRangeName()->clear();
3646 clearSheet(m_pDoc
, 0);
3648 // Set values to B4:B6.
3649 m_pDoc
->SetValue(ScAddress(1,3,0), 1.0);
3650 m_pDoc
->SetValue(ScAddress(1,4,0), 2.0);
3651 m_pDoc
->SetValue(ScAddress(1,5,0), 3.0);
3653 bInserted
= m_pDoc
->InsertNewRangeName("MyRange", ScAddress(0,0,0), "$B$4:$B$6");
3654 CPPUNIT_ASSERT(bInserted
);
3656 // Set formula to A1.
3657 m_pDoc
->SetString(ScAddress(0,0,0), "=SUM(MyRange)");
3658 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(0,0,0));
3660 // Insert rows over 3:5 which should expand the range by 3 rows.
3661 rFunc
.InsertCells(ScRange(0,2,0,m_pDoc
->MaxCol(),4,0), &aMark
, INS_INSROWS_BEFORE
, false, true);
3663 pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3664 CPPUNIT_ASSERT(pName
);
3666 aSymbol
= pName
->GetSymbol(m_pDoc
->GetGrammar());
3667 CPPUNIT_ASSERT_EQUAL(OUString("$B$4:$B$9"), aSymbol
);
3669 // Clear the document and start over.
3670 m_pDoc
->GetRangeName()->clear();
3671 clearSheet(m_pDoc
, 0);
3673 // Set values to A1:A3.
3674 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
3675 m_pDoc
->SetValue(ScAddress(0,1,0), 2.0);
3676 m_pDoc
->SetValue(ScAddress(0,2,0), 3.0);
3678 // Name A1:A3 'MyData'.
3679 bInserted
= m_pDoc
->InsertNewRangeName("MyData", ScAddress(0,0,0), "$A$1:$A$3");
3680 CPPUNIT_ASSERT(bInserted
);
3682 // Set formulas to C1:C2 and E1.
3683 m_pDoc
->SetString(ScAddress(2,0,0), "=SUM(MyData)");
3684 m_pDoc
->SetString(ScAddress(2,1,0), "=SUM(MyData)");
3685 m_pDoc
->SetString(ScAddress(4,0,0), "=SUM(MyData)");
3687 // C1:C2 should be shared.
3688 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,0,0));
3689 CPPUNIT_ASSERT(pFC
);
3690 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(0), pFC
->GetSharedTopRow());
3691 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
3693 // E1 should not be shared.
3694 pFC
= m_pDoc
->GetFormulaCell(ScAddress(4,0,0));
3695 CPPUNIT_ASSERT(pFC
);
3696 CPPUNIT_ASSERT(!pFC
->IsShared());
3698 // Check the results.
3699 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
3700 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
3701 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(4,0,0)));
3703 // Insert a new row at row 3. This should expand MyData to A1:A4.
3704 rFunc
.InsertCells(ScRange(0,2,0,m_pDoc
->MaxCol(),2,0), &aMark
, INS_INSROWS_BEFORE
, false, true);
3706 // Set new value to A3.
3707 m_pDoc
->SetValue(ScAddress(0,2,0), 4.0);
3709 // Check the results again.
3710 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
3711 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
3712 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(4,0,0)));
3714 m_pDoc
->DeleteTab(0);
3717 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateNameExpandRef2
)
3719 setExpandRefs(true);
3721 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
3723 m_pDoc
->InsertTab(0, "Test");
3725 bool bInserted
= m_pDoc
->InsertNewRangeName("MyRange", ScAddress(0,0,0), "$A$1:$B$3");
3726 CPPUNIT_ASSERT(bInserted
);
3728 // Insert a new row at row 4, which should expand the named range to A1:A4.
3729 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
3730 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
3731 aMark
.SelectOneTable(0);
3733 // Insert a new column at column 3, which should expand the named
3734 rFunc
.InsertCells(ScRange(1,0,0,1,m_pDoc
->MaxRow(),0), &aMark
, INS_INSCOLS_BEFORE
, false, true);
3735 ScRangeData
* pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3736 CPPUNIT_ASSERT(pName
);
3737 OUString aSymbol
= pName
->GetSymbol(m_pDoc
->GetGrammar());
3738 CPPUNIT_ASSERT_EQUAL(OUString("$A$1:$C$3"), aSymbol
);
3740 m_pDoc
->DeleteTab(0);
3743 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateNameDeleteRow
)
3745 m_pDoc
->InsertTab(0, "Test");
3747 // Insert a new name 'MyRange' to reference B2:B4.
3748 bool bInserted
= m_pDoc
->InsertNewRangeName("MyRange", ScAddress(0,0,0), "$B$2:$B$4");
3749 CPPUNIT_ASSERT(bInserted
);
3751 const ScRangeData
* pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3752 CPPUNIT_ASSERT(pName
);
3754 sc::TokenStringContext
aCxt(*m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH
);
3755 const ScTokenArray
* pCode
= pName
->GetCode();
3756 OUString aExpr
= pCode
->CreateString(aCxt
, ScAddress(0,0,0));
3757 CPPUNIT_ASSERT_EQUAL(OUString("$B$2:$B$4"), aExpr
);
3759 // Insert a new name 'MyAddress' to reference $B$3. Note absolute row.
3760 bInserted
= m_pDoc
->InsertNewRangeName("MyAddress", ScAddress(0,0,0), "$B$3");
3761 CPPUNIT_ASSERT(bInserted
);
3763 const ScRangeData
* pName2
= m_pDoc
->GetRangeName()->findByUpperName("MYADDRESS");
3764 CPPUNIT_ASSERT(pName2
);
3766 sc::TokenStringContext
aCxt2(*m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH
);
3767 const ScTokenArray
* pCode2
= pName2
->GetCode();
3768 OUString aExpr2
= pCode2
->CreateString(aCxt2
, ScAddress(0,0,0));
3769 CPPUNIT_ASSERT_EQUAL(OUString("$B$3"), aExpr2
);
3771 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
3774 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
3775 aMark
.SelectOneTable(0);
3776 rFunc
.DeleteCells(ScRange(0,2,0,m_pDoc
->MaxCol(),2,0), &aMark
, DelCellCmd::CellsUp
, true);
3778 // The reference in the 'MyRange' name should get updated to B2:B3.
3779 aExpr
= pCode
->CreateString(aCxt
, ScAddress(0,0,0));
3780 CPPUNIT_ASSERT_EQUAL(OUString("$B$2:$B$3"), aExpr
);
3782 // The reference in the 'MyAddress' name should get updated to $B$#REF!.
3783 aExpr2
= pCode2
->CreateString(aCxt2
, ScAddress(0,0,0));
3784 CPPUNIT_ASSERT_EQUAL(OUString("$B$#REF!"), aExpr2
);
3786 // Delete row 3 again.
3787 rFunc
.DeleteCells(ScRange(0,2,0,m_pDoc
->MaxCol(),2,0), &aMark
, DelCellCmd::CellsUp
, true);
3788 aExpr
= pCode
->CreateString(aCxt
, ScAddress(0,0,0));
3789 CPPUNIT_ASSERT_EQUAL(OUString("$B$2:$B$2"), aExpr
);
3792 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
3793 CPPUNIT_ASSERT(pUndoMgr
);
3797 pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3798 CPPUNIT_ASSERT(pName
);
3799 pCode
= pName
->GetCode();
3801 aExpr
= pCode
->CreateString(aCxt
, ScAddress(0,0,0));
3802 CPPUNIT_ASSERT_EQUAL(OUString("$B$2:$B$3"), aExpr
);
3804 // Undo again and check.
3807 pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3808 CPPUNIT_ASSERT(pName
);
3809 pCode
= pName
->GetCode();
3811 aExpr
= pCode
->CreateString(aCxt
, ScAddress(0,0,0));
3812 CPPUNIT_ASSERT_EQUAL(OUString("$B$2:$B$4"), aExpr
);
3815 rFunc
.DeleteCells(ScRange(0,1,0,m_pDoc
->MaxCol(),2,0), &aMark
, DelCellCmd::CellsUp
, true);
3817 aExpr
= pCode
->CreateString(aCxt
, ScAddress(0,0,0));
3818 CPPUNIT_ASSERT_EQUAL(OUString("$B$2:$B$2"), aExpr
);
3823 pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3824 CPPUNIT_ASSERT(pName
);
3825 pCode
= pName
->GetCode();
3827 aExpr
= pCode
->CreateString(aCxt
, ScAddress(0,0,0));
3828 CPPUNIT_ASSERT_EQUAL(OUString("$B$2:$B$4"), aExpr
);
3830 pName2
= m_pDoc
->GetRangeName()->findByUpperName("MYADDRESS");
3831 CPPUNIT_ASSERT(pName2
);
3832 pCode2
= pName2
->GetCode();
3834 aExpr2
= pCode2
->CreateString(aCxt2
, ScAddress(0,0,0));
3835 CPPUNIT_ASSERT_EQUAL(OUString("$B$3"), aExpr2
);
3837 m_pDoc
->InsertTab(1, "test2");
3839 ScMarkData
aMark2(m_pDoc
->GetSheetLimits());
3840 aMark2
.SelectOneTable(1);
3841 rFunc
.DeleteCells(ScRange(0,2,1,m_pDoc
->MaxCol(),2,1), &aMark2
, DelCellCmd::CellsUp
, true);
3843 pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
3844 CPPUNIT_ASSERT(pName
);
3845 pCode
= pName
->GetCode();
3847 aExpr
= pCode
->CreateString(aCxt
, ScAddress(0,0,0));
3848 CPPUNIT_ASSERT_EQUAL(OUString("$B$2:$B$4"), aExpr
);
3850 pName2
= m_pDoc
->GetRangeName()->findByUpperName("MYADDRESS");
3851 CPPUNIT_ASSERT(pName2
);
3852 pCode2
= pName2
->GetCode();
3854 // Deleting a range the 'MyAddress' name points into due to its implicit
3855 // relative sheet reference to the sheet where used does not invalidate
3856 // the named expression because when updating the sheet reference is
3857 // relative to its base position on sheet 0 (same for the 'MyRange' range,
3858 // which is the reason why it is not updated either).
3859 // This is a tad confusing...
3860 aExpr2
= pCode2
->CreateString(aCxt2
, ScAddress(0,0,0));
3861 CPPUNIT_ASSERT_EQUAL(OUString("$B$3"), aExpr2
);
3863 m_pDoc
->DeleteTab(1);
3864 m_pDoc
->DeleteTab(0);
3867 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateNameCopySheet
)
3869 m_pDoc
->InsertTab(0, "Test");
3870 m_pDoc
->InsertTab(1, "Test2");
3872 bool bInserted
= m_pDoc
->InsertNewRangeName("RED", ScAddress(0,0,0), "$Test.$B$2");
3873 CPPUNIT_ASSERT(bInserted
);
3874 bInserted
= m_pDoc
->InsertNewRangeName("BLUE", ScAddress(0,0,0), "$Test.$B$3");
3875 CPPUNIT_ASSERT(bInserted
);
3876 m_pDoc
->SetValue(1, 1, 0, 1);
3877 m_pDoc
->SetValue(1, 2, 0, 2);
3879 // insert formula into Test2 that is =RED+BLUE
3880 m_pDoc
->SetString(ScAddress(2,2,1), "=RED+BLUE");
3882 double nVal
= m_pDoc
->GetValue(2, 2, 1);
3883 CPPUNIT_ASSERT_EQUAL(3.0, nVal
);
3884 m_pDoc
->CopyTab(1, 0);
3886 nVal
= m_pDoc
->GetValue(2, 2, 2);
3887 CPPUNIT_ASSERT_EQUAL(3.0, nVal
);
3889 nVal
= m_pDoc
->GetValue(2, 2, 0);
3890 CPPUNIT_ASSERT_EQUAL(3.0, nVal
);
3892 m_pDoc
->SetValue(1, 1, 1, 3);
3894 nVal
= m_pDoc
->GetValue(2, 2, 2);
3895 CPPUNIT_ASSERT_EQUAL(5.0, nVal
);
3897 nVal
= m_pDoc
->GetValue(2, 2, 0);
3898 CPPUNIT_ASSERT_EQUAL(5.0, nVal
);
3900 m_pDoc
->DeleteTab(2);
3901 m_pDoc
->DeleteTab(1);
3902 m_pDoc
->DeleteTab(0);
3904 m_pDoc
->InsertTab(0, "Test1");
3905 // Global name referencing sheet Test1.
3906 bInserted
= m_pDoc
->InsertNewRangeName("sheetnumber", ScAddress(0,0,0), "$Test1.$A$1");
3907 CPPUNIT_ASSERT(bInserted
);
3908 m_pDoc
->SetString(ScAddress(0,0,0), "=SHEET()");
3909 m_pDoc
->SetString(ScAddress(1,0,0), "=sheetnumber");
3910 nVal
= m_pDoc
->GetValue(1,0,0);
3911 CPPUNIT_ASSERT_EQUAL_MESSAGE("Sheet number should be 1", 1.0, nVal
);
3913 // Copy sheet after.
3914 m_pDoc
->CopyTab(0, 1);
3915 nVal
= m_pDoc
->GetValue(1,0,1);
3916 CPPUNIT_ASSERT_EQUAL_MESSAGE("New sheet number should be 2", 2.0, nVal
);
3917 nVal
= m_pDoc
->GetValue(1,0,0);
3918 CPPUNIT_ASSERT_EQUAL_MESSAGE("Org sheet number should be 1", 1.0, nVal
);
3919 const ScRangeData
* pName
= m_pDoc
->GetRangeName(1)->findByUpperName("SHEETNUMBER");
3920 CPPUNIT_ASSERT_MESSAGE("New sheet-local name should exist", pName
);
3922 // Copy sheet before, shifting following now two sheets.
3923 m_pDoc
->CopyTab(0, 0);
3924 nVal
= m_pDoc
->GetValue(1,0,0);
3925 CPPUNIT_ASSERT_EQUAL_MESSAGE("New sheet number should be 1", 1.0, nVal
);
3926 pName
= m_pDoc
->GetRangeName(0)->findByUpperName("SHEETNUMBER");
3927 CPPUNIT_ASSERT_MESSAGE("New sheet-local name should exist", pName
);
3928 nVal
= m_pDoc
->GetValue(1,0,1);
3929 CPPUNIT_ASSERT_EQUAL_MESSAGE("Org sheet number should be 2", 2.0, nVal
);
3930 pName
= m_pDoc
->GetRangeName(1)->findByUpperName("SHEETNUMBER");
3931 CPPUNIT_ASSERT_MESSAGE("Org sheet-local name should not exist", !pName
);
3932 nVal
= m_pDoc
->GetValue(1,0,2);
3933 CPPUNIT_ASSERT_EQUAL_MESSAGE("Old sheet number should be 3", 3.0, nVal
);
3934 pName
= m_pDoc
->GetRangeName(2)->findByUpperName("SHEETNUMBER");
3935 CPPUNIT_ASSERT_MESSAGE("Old sheet-local name should exist", pName
);
3937 m_pDoc
->DeleteTab(2);
3938 m_pDoc
->DeleteTab(1);
3939 m_pDoc
->DeleteTab(0);
3941 m_pDoc
->InsertTab(0, "Test2");
3942 // Local name referencing sheet Test2.
3943 bInserted
= m_pDoc
->GetRangeName(0)->insert( new ScRangeData( *m_pDoc
, "localname", "$Test2.$A$1"));
3944 CPPUNIT_ASSERT(bInserted
);
3945 m_pDoc
->SetString(ScAddress(0,0,0), "=SHEET()");
3946 m_pDoc
->SetString(ScAddress(1,0,0), "=localname");
3947 nVal
= m_pDoc
->GetValue(1,0,0);
3948 CPPUNIT_ASSERT_EQUAL_MESSAGE("Localname sheet number should be 1", 1.0, nVal
);
3950 // Insert sheet before and shift sheet with local name.
3951 m_pDoc
->InsertTab(0, "Test1");
3952 pName
= m_pDoc
->GetRangeName(1)->findByUpperName("LOCALNAME");
3953 CPPUNIT_ASSERT_MESSAGE("Org sheet-local name should exist", pName
);
3954 nVal
= m_pDoc
->GetValue(1,0,1);
3955 CPPUNIT_ASSERT_EQUAL_MESSAGE("Localname sheet number should be 2", 2.0, nVal
);
3957 // Copy sheet before, shifting following now two sheets.
3958 m_pDoc
->CopyTab(1, 0);
3959 pName
= m_pDoc
->GetRangeName(0)->findByUpperName("LOCALNAME");
3960 CPPUNIT_ASSERT_MESSAGE("New sheet-local name should exist", pName
);
3961 nVal
= m_pDoc
->GetValue(1,0,0);
3962 CPPUNIT_ASSERT_EQUAL_MESSAGE("New sheet number should be 1", 1.0, nVal
);
3963 pName
= m_pDoc
->GetRangeName(1)->findByUpperName("LOCALNAME");
3964 CPPUNIT_ASSERT_MESSAGE("Old sheet-local name should not exist", !pName
);
3965 pName
= m_pDoc
->GetRangeName(2)->findByUpperName("LOCALNAME");
3966 CPPUNIT_ASSERT_MESSAGE("Org sheet-local name should exist", pName
);
3967 nVal
= m_pDoc
->GetValue(1,0,2);
3968 CPPUNIT_ASSERT_EQUAL_MESSAGE("New sheet number should be 3", 3.0, nVal
);
3970 m_pDoc
->DeleteTab(2);
3971 m_pDoc
->DeleteTab(1);
3972 m_pDoc
->DeleteTab(0);
3973 m_pDoc
->SetRangeName(nullptr);
3975 // Test nested names during copying sheet.
3977 m_pDoc
->InsertTab(0, "Test2");
3978 ScAddress
aPos(0,0,0);
3979 bInserted
= m_pDoc
->InsertNewRangeName( "global", aPos
, "$Test2.$A$1");
3980 CPPUNIT_ASSERT(bInserted
);
3981 bInserted
= m_pDoc
->InsertNewRangeName( aPos
.Tab(), "local", aPos
, "$Test2.$A$2");
3982 CPPUNIT_ASSERT(bInserted
);
3983 bInserted
= m_pDoc
->InsertNewRangeName( "global_global", aPos
, "global*100");
3984 CPPUNIT_ASSERT(bInserted
);
3985 bInserted
= m_pDoc
->InsertNewRangeName( "global_local", aPos
, "local*1000");
3986 CPPUNIT_ASSERT(bInserted
);
3987 bInserted
= m_pDoc
->InsertNewRangeName( "global_unused", aPos
, "$Test2.$A$1");
3988 CPPUNIT_ASSERT(bInserted
);
3989 bInserted
= m_pDoc
->InsertNewRangeName( "global_unused_noref", aPos
, "42");
3990 CPPUNIT_ASSERT(bInserted
);
3991 bInserted
= m_pDoc
->InsertNewRangeName( aPos
.Tab(), "local_global", aPos
, "global*10000");
3992 CPPUNIT_ASSERT(bInserted
);
3993 bInserted
= m_pDoc
->InsertNewRangeName( aPos
.Tab(), "local_local", aPos
, "local*100000");
3994 CPPUNIT_ASSERT(bInserted
);
3995 bInserted
= m_pDoc
->InsertNewRangeName( aPos
.Tab(), "local_unused", aPos
, "$Test2.$A$2");
3996 CPPUNIT_ASSERT(bInserted
);
3997 bInserted
= m_pDoc
->InsertNewRangeName( aPos
.Tab(), "local_unused_noref", aPos
, "23");
3998 CPPUNIT_ASSERT(bInserted
);
4000 m_pDoc
->SetString(aPos
, "=SHEET()");
4002 m_pDoc
->SetString(aPos
, "=A1*10+SHEET()");
4004 m_pDoc
->SetString(aPos
, "=global_global");
4006 m_pDoc
->SetString(aPos
, "=global_local");
4008 m_pDoc
->SetString(aPos
, "=local_global");
4010 m_pDoc
->SetString(aPos
, "=local_local");
4012 testFormulaRefUpdateNameCopySheetCheckTab( m_pDoc
, 0, false);
4014 // Copy sheet after.
4015 m_pDoc
->CopyTab(0, 1);
4016 testFormulaRefUpdateNameCopySheetCheckTab( m_pDoc
, 0, false);
4017 testFormulaRefUpdateNameCopySheetCheckTab( m_pDoc
, 1, true);
4019 // Copy sheet before, shifting following now two sheets.
4020 m_pDoc
->CopyTab(1, 0);
4021 testFormulaRefUpdateNameCopySheetCheckTab( m_pDoc
, 0, true);
4022 testFormulaRefUpdateNameCopySheetCheckTab( m_pDoc
, 1, false);
4023 testFormulaRefUpdateNameCopySheetCheckTab( m_pDoc
, 2, true);
4025 m_pDoc
->DeleteTab(2);
4026 m_pDoc
->DeleteTab(1);
4027 m_pDoc
->DeleteTab(0);
4030 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateSheetLocalMove
)
4034 m_pDoc
->InsertTab( nSheet1
, "Sheet1");
4035 m_pDoc
->InsertTab( nSheet2
, "Sheet2");
4037 ScAddress
aPos(0,0,nSheet1
);
4039 bOk
= m_pDoc
->InsertNewRangeName( 0, "MyCell", aPos
, "$Sheet1.$B$2");
4040 CPPUNIT_ASSERT(bOk
);
4041 aPos
.SetTab(nSheet2
);
4042 bOk
= m_pDoc
->InsertNewRangeName( 1, "MyCell", aPos
, "$Sheet2.$B$2");
4043 CPPUNIT_ASSERT(bOk
);
4045 aPos
.SetTab(nSheet1
);
4047 m_pDoc
->SetString( aPos
, "x");
4049 m_pDoc
->SetString( aPos
, "1.0");
4051 m_pDoc
->SetString( aPos
, "=MyCell");
4052 CPPUNIT_ASSERT_EQUAL_MESSAGE("Sheet1.B3", 1.0, m_pDoc
->GetValue(aPos
));
4054 aPos
.SetTab(nSheet2
);
4056 m_pDoc
->SetString( aPos
, "2.0");
4058 m_pDoc
->SetString( aPos
, "=MyCell");
4059 CPPUNIT_ASSERT_EQUAL_MESSAGE("Sheet2.B3", 2.0, m_pDoc
->GetValue(aPos
));
4061 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
4064 // Move Sheet1.B1 ("x") to Sheet2.B1
4065 bOk
= rFunc
.MoveBlock( ScRange(1,0,nSheet1
,1,0,nSheet1
), ScAddress(1,0,nSheet2
), true, false, false, false);
4066 CPPUNIT_ASSERT(bOk
);
4067 // Results not changed.
4068 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move x: Sheet1.B3", 1.0, m_pDoc
->GetValue(ScAddress(1,2,nSheet1
)));
4069 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move x: Sheet2.B3", 2.0, m_pDoc
->GetValue(ScAddress(1,2,nSheet2
)));
4070 // Formulas not changed.
4071 aFormula
= m_pDoc
->GetFormula( 1,2,nSheet1
);
4072 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move x: Sheet1.B3", OUString("=MyCell"), aFormula
);
4073 aFormula
= m_pDoc
->GetFormula( 1,2,nSheet2
);
4074 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move x: Sheet2.B3", OUString("=MyCell"), aFormula
);
4076 // Move Sheet2.B2 ("2.0") to Sheet1.C2
4077 bOk
= rFunc
.MoveBlock( ScRange(1,1,nSheet2
,1,1,nSheet2
), ScAddress(2,1,nSheet1
), true, false, false, false);
4078 CPPUNIT_ASSERT(bOk
);
4079 // Results not changed.
4080 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move 2.0: Sheet1.B3", 1.0, m_pDoc
->GetValue(ScAddress(1,2,nSheet1
)));
4081 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move 2.0: Sheet2.B3", 2.0, m_pDoc
->GetValue(ScAddress(1,2,nSheet2
)));
4082 // Formulas not changed.
4083 aFormula
= m_pDoc
->GetFormula( 1,2,nSheet1
);
4084 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move 2.0: Sheet1.B3", OUString("=MyCell"), aFormula
);
4085 aFormula
= m_pDoc
->GetFormula( 1,2,nSheet2
);
4086 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move 2.0: Sheet2.B3", OUString("=MyCell"), aFormula
);
4090 // Check that the sheet-local named reference points to the moved cell, now
4092 pName
= m_pDoc
->GetRangeName(nSheet2
)->findByUpperName("MYCELL");
4093 CPPUNIT_ASSERT(pName
);
4094 aFormula
= pName
->GetSymbol( ScAddress(), formula::FormulaGrammar::GRAM_ENGLISH
);
4095 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move 2.0: Sheet2 sheet-local name", OUString("$Sheet1.$C$2"), aFormula
);
4097 // Move Sheet2.B3 ("=MyCell") to Sheet1.C3
4098 bOk
= rFunc
.MoveBlock( ScRange(1,2,nSheet2
,1,2,nSheet2
), ScAddress(2,2,nSheet1
), true, false, false, false);
4099 CPPUNIT_ASSERT(bOk
);
4101 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move =MyCell: Sheet1.B3", 1.0, m_pDoc
->GetValue(ScAddress(1,2,nSheet1
)));
4102 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move =MyCell: Sheet2.B3", 0.0, m_pDoc
->GetValue(ScAddress(1,2,nSheet2
)));
4103 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move =MyCell: Sheet1.C3", 2.0, m_pDoc
->GetValue(ScAddress(2,2,nSheet1
)));
4104 // One formula identical, one adjusted.
4105 aFormula
= m_pDoc
->GetFormula( 1,2,nSheet1
);
4106 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move =MyCell: Sheet1.B3", OUString("=MyCell"), aFormula
);
4107 aFormula
= m_pDoc
->GetFormula( 2,2,nSheet1
);
4108 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move =MyCell: Sheet1.C3", OUString("=Sheet2.MyCell"), aFormula
);
4110 // Check that the sheet-local named reference in Sheet1 still points to the
4111 // original cell Sheet1.B2
4112 pName
= m_pDoc
->GetRangeName(nSheet1
)->findByUpperName("MYCELL");
4113 CPPUNIT_ASSERT(pName
);
4114 aFormula
= pName
->GetSymbol( ScAddress(), formula::FormulaGrammar::GRAM_ENGLISH
);
4115 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move =MyCell: Sheet1 sheet-local name", OUString("$Sheet1.$B$2"), aFormula
);
4117 // Check that the sheet-local named reference in Sheet2 still points to the
4118 // moved cell, now Sheet1.C2
4119 pName
= m_pDoc
->GetRangeName(nSheet2
)->findByUpperName("MYCELL");
4120 CPPUNIT_ASSERT(pName
);
4121 aFormula
= pName
->GetSymbol( ScAddress(), formula::FormulaGrammar::GRAM_ENGLISH
);
4122 CPPUNIT_ASSERT_EQUAL_MESSAGE("Move =MyCell: Sheet2 sheet-local name", OUString("$Sheet1.$C$2"), aFormula
);
4124 // Insert sheet before the others.
4125 m_pDoc
->InsertTab(0, "Sheet0");
4130 CPPUNIT_ASSERT_EQUAL_MESSAGE("Insert Sheet0: Sheet1.B3", 1.0, m_pDoc
->GetValue(ScAddress(1,2,nSheet1
)));
4131 CPPUNIT_ASSERT_EQUAL_MESSAGE("Insert Sheet0: Sheet1.C3", 2.0, m_pDoc
->GetValue(ScAddress(2,2,nSheet1
)));
4132 aFormula
= m_pDoc
->GetFormula( 1,2,nSheet1
);
4133 CPPUNIT_ASSERT_EQUAL_MESSAGE("Insert Sheet0: Sheet1.B3", OUString("=MyCell"), aFormula
);
4134 aFormula
= m_pDoc
->GetFormula( 2,2,nSheet1
);
4135 CPPUNIT_ASSERT_EQUAL_MESSAGE("Insert Sheet0: Sheet1.C3", OUString("=Sheet2.MyCell"), aFormula
);
4136 pName
= m_pDoc
->GetRangeName(nSheet1
)->findByUpperName("MYCELL");
4137 CPPUNIT_ASSERT(pName
);
4138 aFormula
= pName
->GetSymbol( ScAddress(), formula::FormulaGrammar::GRAM_ENGLISH
);
4139 CPPUNIT_ASSERT_EQUAL_MESSAGE("Insert Sheet0: Sheet1 sheet-local name", OUString("$Sheet1.$B$2"), aFormula
);
4140 pName
= m_pDoc
->GetRangeName(nSheet2
)->findByUpperName("MYCELL");
4141 CPPUNIT_ASSERT(pName
);
4142 aFormula
= pName
->GetSymbol( ScAddress(), formula::FormulaGrammar::GRAM_ENGLISH
);
4143 CPPUNIT_ASSERT_EQUAL_MESSAGE("Insert Sheet0: Sheet2 sheet-local name", OUString("$Sheet1.$C$2"), aFormula
);
4145 // Delete sheet before the others.
4146 m_pDoc
->DeleteTab(0);
4151 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet0: Sheet1.B3", 1.0, m_pDoc
->GetValue(ScAddress(1,2,nSheet1
)));
4152 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet0: Sheet1.C3", 2.0, m_pDoc
->GetValue(ScAddress(2,2,nSheet1
)));
4153 aFormula
= m_pDoc
->GetFormula( 1,2,nSheet1
);
4154 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet0: Sheet1.B3", OUString("=MyCell"), aFormula
);
4155 aFormula
= m_pDoc
->GetFormula( 2,2,nSheet1
);
4156 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet0: Sheet1.C3", OUString("=Sheet2.MyCell"), aFormula
);
4157 pName
= m_pDoc
->GetRangeName(nSheet1
)->findByUpperName("MYCELL");
4158 CPPUNIT_ASSERT(pName
);
4159 aFormula
= pName
->GetSymbol( ScAddress(), formula::FormulaGrammar::GRAM_ENGLISH
);
4160 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet0: Sheet1 sheet-local name", OUString("$Sheet1.$B$2"), aFormula
);
4161 pName
= m_pDoc
->GetRangeName(nSheet2
)->findByUpperName("MYCELL");
4162 CPPUNIT_ASSERT(pName
);
4163 aFormula
= pName
->GetSymbol( ScAddress(), formula::FormulaGrammar::GRAM_ENGLISH
);
4164 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet0: Sheet2 sheet-local name", OUString("$Sheet1.$C$2"), aFormula
);
4166 // Delete last sheet with sheet-local name.
4167 m_pDoc
->DeleteTab(nSheet2
);
4169 // XXX we *could* analyze whether the expression points to a different
4170 // sheet and then move the name to a remaining sheet. If so, adapt this
4172 // Nothing changed except the sheet-local name and its use.
4173 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet2: Sheet1.B3", 1.0, m_pDoc
->GetValue(ScAddress(1,2,nSheet1
)));
4174 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet2: Sheet1.C3", 0.0, m_pDoc
->GetValue(ScAddress(2,2,nSheet1
)));
4175 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet2: Sheet1.C3", OUString("#NAME?"), m_pDoc
->GetString(ScAddress(2,2,nSheet1
)));
4176 aFormula
= m_pDoc
->GetFormula( 1,2,nSheet1
);
4177 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet2: Sheet1.B3", OUString("=MyCell"), aFormula
);
4178 aFormula
= m_pDoc
->GetFormula( 2,2,nSheet1
);
4179 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet2: Sheet1.C3", OUString("=#NAME?"), aFormula
);
4180 pName
= m_pDoc
->GetRangeName(nSheet1
)->findByUpperName("MYCELL");
4181 CPPUNIT_ASSERT(pName
);
4182 aFormula
= pName
->GetSymbol( ScAddress(), formula::FormulaGrammar::GRAM_ENGLISH
);
4183 CPPUNIT_ASSERT_EQUAL_MESSAGE("Delete Sheet2: Sheet1 sheet-local name", OUString("$Sheet1.$B$2"), aFormula
);
4184 CPPUNIT_ASSERT(!m_pDoc
->GetRangeName(nSheet2
));
4187 m_pDoc
->DeleteTab(0);
4190 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateNameDelete
)
4192 m_pDoc
->InsertTab(0, "Test");
4194 // Insert a new name 'MyRange' to reference B1
4195 bool bInserted
= m_pDoc
->InsertNewRangeName("MyRange", ScAddress(0,0,0), "$Test.$B$1");
4196 CPPUNIT_ASSERT(bInserted
);
4198 const ScRangeData
* pName
= m_pDoc
->GetRangeName()->findByUpperName("MYRANGE");
4199 CPPUNIT_ASSERT(pName
);
4201 m_pDoc
->DeleteCol(1, 0, 3, 0, 0, 1);
4202 const ScTokenArray
* pCode
= pName
->GetCode();
4203 sc::TokenStringContext
aCxt(*m_pDoc
, formula::FormulaGrammar::GRAM_ENGLISH
);
4204 OUString aExpr
= pCode
->CreateString(aCxt
, ScAddress(0,0,0));
4205 CPPUNIT_ASSERT_EQUAL(OUString("$Test.$B$1"), aExpr
);
4207 m_pDoc
->DeleteTab(0);
4210 CPPUNIT_TEST_FIXTURE(TestFormula
, testFormulaRefUpdateValidity
)
4214 bool checkList( std::vector
<ScTypedStrData
>& rList
)
4216 double aExpected
[] = { 1.0, 2.0, 3.0 }; // must be sorted.
4217 size_t nCheckSize
= SAL_N_ELEMENTS(aExpected
);
4219 if (rList
.size() != nCheckSize
)
4221 cerr
<< "List size is not what is expected." << endl
;
4225 std::sort(rList
.begin(), rList
.end(), ScTypedStrData::LessCaseSensitive());
4227 for (size_t i
= 0; i
< nCheckSize
; ++i
)
4229 if (aExpected
[i
] != rList
[i
].GetValue())
4231 cerr
<< "Incorrect value at position " << i
4232 << ": expected=" << aExpected
[i
] << ", actual=" << rList
[i
].GetValue() << endl
;
4242 setExpandRefs(false);
4243 setCalcAsShown(m_pDoc
, true);
4245 m_pDoc
->InsertTab(0, "Formula");
4247 // Set values in C2:C4.
4248 m_pDoc
->SetValue(ScAddress(2,1,0), 1.0);
4249 m_pDoc
->SetValue(ScAddress(2,2,0), 2.0);
4250 m_pDoc
->SetValue(ScAddress(2,3,0), 3.0);
4252 // Set validity in A2.
4253 ScValidationData
aData(
4254 SC_VALID_LIST
, ScConditionMode::Equal
, "C2:C4", "", *m_pDoc
, ScAddress(0,1,0), "", "",
4255 m_pDoc
->GetGrammar(), m_pDoc
->GetGrammar());
4257 sal_uInt32 nIndex
= m_pDoc
->AddValidationEntry(aData
);
4258 SfxUInt32Item
aItem(ATTR_VALIDDATA
, nIndex
);
4260 ScPatternAttr
aNewAttrs(
4261 SfxItemSet(*m_pDoc
->GetPool(), svl::Items
<ATTR_PATTERN_START
, ATTR_PATTERN_END
>));
4262 aNewAttrs
.GetItemSet().Put(aItem
);
4264 m_pDoc
->ApplyPattern(0, 1, 0, aNewAttrs
);
4266 const ScValidationData
* pData
= m_pDoc
->GetValidationEntry(nIndex
);
4267 CPPUNIT_ASSERT(pData
);
4269 // Make sure the list is correct.
4270 std::vector
<ScTypedStrData
> aList
;
4271 pData
->FillSelectionList(aList
, ScAddress(0,1,0));
4272 bool bGood
= aCheck
.checkList(aList
);
4273 CPPUNIT_ASSERT_MESSAGE("Initial list is incorrect.", bGood
);
4275 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
4276 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4277 aMark
.SelectOneTable(0);
4279 // Insert a new column at Column B, to move the list from C2:C4 to D2:D4.
4280 bool bInserted
= rFunc
.InsertCells(ScRange(1,0,0,1,m_pDoc
->MaxRow(),0), &aMark
, INS_INSCOLS_BEFORE
, true, true);
4281 CPPUNIT_ASSERT_MESSAGE("Column insertion failed.", bInserted
);
4282 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(3,1,0)));
4283 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(3,2,0)));
4284 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(3,3,0)));
4286 // Check the list values again.
4288 pData
->FillSelectionList(aList
, ScAddress(0,1,0));
4289 bGood
= aCheck
.checkList(aList
);
4290 CPPUNIT_ASSERT_MESSAGE("List content is incorrect after column insertion.", bGood
);
4292 SfxUndoManager
* pUndoMgr
= m_pDoc
->GetUndoManager();
4293 CPPUNIT_ASSERT(pUndoMgr
);
4295 // Undo and check the list content again. The list moves back to C2:C4 after the undo.
4297 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
4298 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
4299 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
4302 pData
->FillSelectionList(aList
, ScAddress(0,1,0));
4303 bGood
= aCheck
.checkList(aList
);
4304 CPPUNIT_ASSERT_MESSAGE("List content is incorrect after undo of column insertion.", bGood
);
4306 // Move C2:C4 to E5:E7.
4307 bool bMoved
= rFunc
.MoveBlock(ScRange(2,1,0,2,3,0), ScAddress(4,4,0), false, true, false, true);
4308 CPPUNIT_ASSERT(bMoved
);
4309 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(4,4,0)));
4310 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(4,5,0)));
4311 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(4,6,0)));
4313 // Check the list again after the move.
4315 pData
->FillSelectionList(aList
, ScAddress(0,1,0));
4316 bGood
= aCheck
.checkList(aList
);
4317 CPPUNIT_ASSERT_MESSAGE("List content is incorrect after moving C2:C4 to E5:E7.", bGood
);
4319 // Undo the move and check. The list should be back to C2:C4.
4321 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
4322 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
4323 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,3,0)));
4326 pData
->FillSelectionList(aList
, ScAddress(0,1,0));
4327 bGood
= aCheck
.checkList(aList
);
4328 CPPUNIT_ASSERT_MESSAGE("List content is incorrect after undo of the move.", bGood
);
4330 m_pDoc
->DeleteTab(0);
4333 CPPUNIT_TEST_FIXTURE(TestFormula
, testTokenArrayRefUpdateMove
)
4335 m_pDoc
->InsertTab(0, "Sheet1");
4336 m_pDoc
->InsertTab(1, "Sheet2");
4338 ScAddress
aPos(0,0,0); // A1
4340 sc::TokenStringContext
aCxt(*m_pDoc
, m_pDoc
->GetGrammar());
4342 // Emulate cell movement from Sheet1.C3 to Sheet2.C3.
4343 sc::RefUpdateContext
aRefCxt(*m_pDoc
);
4344 aRefCxt
.meMode
= URM_MOVE
;
4345 aRefCxt
.maRange
= ScAddress(2,2,1); // C3 on Sheet2.
4346 aRefCxt
.mnTabDelta
= -1;
4348 std::vector
<OUString
> aTests
= {
4352 "SUM(Sheet1.B1:Sheet2.B1)"
4355 // Since C3 is not referenced in any of the above formulas, moving C3 from
4356 // Sheet1 to Sheet2 should NOT change the displayed formula string at all.
4358 for (const OUString
& aTest
: aTests
)
4360 ScCompiler
aComp(*m_pDoc
, aPos
, m_pDoc
->GetGrammar());
4361 std::unique_ptr
<ScTokenArray
> pArray(aComp
.CompileString(aTest
));
4363 OUString aStr
= pArray
->CreateString(aCxt
, aPos
);
4365 CPPUNIT_ASSERT_EQUAL(aTest
, aStr
);
4367 // This formula cell isn't moving its position. The displayed formula
4368 // string should not change.
4369 pArray
->AdjustReferenceOnMove(aRefCxt
, aPos
, aPos
);
4371 aStr
= pArray
->CreateString(aCxt
, aPos
);
4372 CPPUNIT_ASSERT_EQUAL(aTest
, aStr
);
4375 m_pDoc
->DeleteTab(1);
4376 m_pDoc
->DeleteTab(0);
4379 CPPUNIT_TEST_FIXTURE(TestFormula
, testMultipleOperations
)
4381 m_pDoc
->InsertTab(0, "MultiOp");
4383 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
4385 // Insert the reference formula at top row.
4386 m_pDoc
->SetValue(ScAddress(0,0,0), 1);
4387 m_pDoc
->SetString(ScAddress(1,0,0), "=A1*10");
4388 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
4390 // Insert variable inputs in A3:A5.
4391 m_pDoc
->SetValue(ScAddress(0,2,0), 2);
4392 m_pDoc
->SetValue(ScAddress(0,3,0), 3);
4393 m_pDoc
->SetValue(ScAddress(0,4,0), 4);
4395 // Set multiple operations range.
4396 ScTabOpParam aParam
;
4397 aParam
.aRefFormulaCell
= ScRefAddress(1,0,0);
4398 aParam
.aRefFormulaEnd
= aParam
.aRefFormulaCell
;
4399 aParam
.aRefColCell
= ScRefAddress(0,0,0);
4400 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4401 aMark
.SetMarkArea(ScRange(0,2,0,1,4,0)); // Select A3:B5.
4402 m_pDoc
->InsertTableOp(aParam
, 0, 2, 1, 4, aMark
);
4403 CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc
->GetValue(1,2,0));
4404 CPPUNIT_ASSERT_EQUAL(30.0, m_pDoc
->GetValue(1,3,0));
4405 CPPUNIT_ASSERT_EQUAL(40.0, m_pDoc
->GetValue(1,4,0));
4408 clearRange(m_pDoc
, ScRange(0,2,0,1,4,0));
4410 // This time, use indirect reference formula cell.
4411 m_pDoc
->SetString(ScAddress(2,0,0), "=B1"); // C1 simply references B1.
4412 CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
4414 // Insert variable inputs in A3:A5.
4415 m_pDoc
->SetValue(ScAddress(0,2,0), 3);
4416 m_pDoc
->SetValue(ScAddress(0,3,0), 4);
4417 m_pDoc
->SetValue(ScAddress(0,4,0), 5);
4419 // Set multiple operations range again, but this time, we'll use C1 as the reference formula.
4420 aParam
.aRefFormulaCell
.Set(2,0,0,false,false,false);
4421 aParam
.aRefFormulaEnd
= aParam
.aRefFormulaCell
;
4422 m_pDoc
->InsertTableOp(aParam
, 0, 2, 1, 4, aMark
);
4423 CPPUNIT_ASSERT_EQUAL(30.0, m_pDoc
->GetValue(1,2,0));
4424 CPPUNIT_ASSERT_EQUAL(40.0, m_pDoc
->GetValue(1,3,0));
4425 CPPUNIT_ASSERT_EQUAL(50.0, m_pDoc
->GetValue(1,4,0));
4427 m_pDoc
->DeleteTab(0);
4430 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncCOLUMN
)
4432 m_pDoc
->InsertTab(0, "Formula");
4433 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
4435 m_pDoc
->SetString(ScAddress(5,10,0), "=COLUMN()");
4436 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(5,10,0)));
4438 m_pDoc
->SetString(ScAddress(0,1,0), "=F11");
4439 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4441 // Move the formula cell with COLUMN() function to change its value.
4442 m_pDoc
->InsertCol(ScRange(5,0,0,5,m_pDoc
->MaxRow(),0));
4443 CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc
->GetValue(ScAddress(6,10,0)));
4445 // The cell that references the moved cell should update its value as well.
4446 CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4448 // Move the column in the other direction.
4449 m_pDoc
->DeleteCol(ScRange(5,0,0,5,m_pDoc
->MaxRow(),0));
4451 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(5,10,0)));
4453 // The cell that references the moved cell should update its value as well.
4454 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4456 m_pDoc
->DeleteTab(0);
4459 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncCOUNT
)
4461 m_pDoc
->InsertTab(0, "Formula");
4462 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
4464 m_pDoc
->SetValue(ScAddress(0,0,0), 2); // A1
4465 m_pDoc
->SetValue(ScAddress(0,1,0), 4); // A2
4466 m_pDoc
->SetValue(ScAddress(0,2,0), 6); // A3
4468 ScAddress
aPos(1,0,0);
4469 m_pDoc
->SetString(aPos
, "=COUNT(A1:A3)");
4470 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(aPos
));
4473 m_pDoc
->SetString(aPos
, "=COUNT(A1:A3;2)");
4474 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(aPos
));
4477 m_pDoc
->SetString(aPos
, "=COUNT(A1:A3;2;4)");
4478 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(aPos
));
4481 m_pDoc
->SetString(aPos
, "=COUNT(A1:A3;2;4;6)");
4482 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(aPos
));
4485 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4486 aMark
.SelectOneTable(0);
4487 m_pDoc
->InsertMatrixFormula(2, 0, 2, 0, aMark
, "=COUNT(SEARCH(\"a\";{\"a\";\"b\";\"a\"}))");
4488 // Check that the #VALUE! error of "a" not found in "b" is not counted.
4489 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
4492 m_pDoc
->InsertMatrixFormula(2, 2, 2, 2, aMark
, "=COUNTA(SEARCH(\"a\";{\"a\";\"b\";\"a\"}))");
4493 // Check that the #VALUE! error of "a" not found in "b" is counted.
4494 CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc
->GetValue(ScAddress(2,2,0)));
4496 m_pDoc
->DeleteTab(0);
4499 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncCOUNTBLANK
)
4501 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
4502 m_pDoc
->InsertTab(0, "Formula");
4504 std::vector
<std::vector
<const char*>> aData
= {
4505 { "1", nullptr, "=B1", "=\"\"" },
4506 { "2", nullptr, "=B2", "=\"\"" },
4507 { "A", nullptr, "=B3", "=\"\"" },
4508 { "B", nullptr, "=B4", "=D3" },
4509 { nullptr, nullptr, "=B5", "=D4" },
4510 { "=COUNTBLANK(A1:A5)", "=COUNTBLANK(B1:B5)", "=COUNTBLANK(C1:C5)", "=COUNTBLANK(D1:D5)" }
4513 ScAddress
aPos(0,0,0);
4514 ScRange aRange
= insertRangeData(m_pDoc
, aPos
, aData
);
4515 CPPUNIT_ASSERT_EQUAL(aPos
, aRange
.aStart
);
4517 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(0,5,0)));
4518 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,5,0)));
4519 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(2,5,0)));
4520 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(3,5,0)));
4522 // Test single cell reference cases.
4524 clearSheet(m_pDoc
, 0);
4526 std::vector
<std::vector
<const char*>> aData2
= {
4527 { "1", "=COUNTBLANK(A1)" },
4528 { "A", "=COUNTBLANK(A2)" },
4529 { nullptr, "=COUNTBLANK(A3)" },
4530 { "=\"\"", "=COUNTBLANK(A4)" },
4531 { "=A4" , "=COUNTBLANK(A5)" },
4534 aRange
= insertRangeData(m_pDoc
, aPos
, aData2
);
4535 CPPUNIT_ASSERT_EQUAL(aPos
, aRange
.aStart
);
4537 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
4538 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
4539 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
4540 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,3,0)));
4541 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(ScAddress(1,4,0)));
4543 m_pDoc
->DeleteTab(0);
4546 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncROW
)
4548 m_pDoc
->InsertTab(0, "Formula");
4549 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
4551 m_pDoc
->SetString(ScAddress(5,10,0), "=ROW()");
4552 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc
->GetValue(ScAddress(5,10,0)));
4554 m_pDoc
->SetString(ScAddress(0,1,0), "=F11");
4555 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4557 // Insert 2 new rows at row 4.
4558 m_pDoc
->InsertRow(ScRange(0,3,0,m_pDoc
->MaxCol(),4,0));
4559 CPPUNIT_ASSERT_EQUAL(13.0, m_pDoc
->GetValue(ScAddress(5,12,0)));
4561 // The cell that references the moved cell should update its value as well.
4562 CPPUNIT_ASSERT_EQUAL(13.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4564 // Delete 2 rows to move it back.
4565 m_pDoc
->DeleteRow(ScRange(0,3,0,m_pDoc
->MaxCol(),4,0));
4567 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc
->GetValue(ScAddress(5,10,0)));
4569 // The cell that references the moved cell should update its value as well.
4570 CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4572 // Clear sheet and start over.
4573 clearSheet(m_pDoc
, 0);
4575 m_pDoc
->SetString(ScAddress(0,1,0), "=ROW(A5)");
4576 m_pDoc
->SetString(ScAddress(1,1,0), "=ROW(B5)");
4577 m_pDoc
->SetString(ScAddress(1,2,0), "=ROW(B6)");
4578 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4579 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
4580 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
4582 // B2:B3 should be shared.
4583 const ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(1,1,0));
4584 CPPUNIT_ASSERT(pFC
);
4585 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(1), pFC
->GetSharedTopRow());
4586 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), pFC
->GetSharedLength());
4588 // Insert a new row at row 4.
4589 ScDocFunc
& rFunc
= m_xDocShell
->GetDocFunc();
4590 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4591 aMark
.SelectOneTable(0);
4592 rFunc
.InsertCells(ScRange(0,3,0,m_pDoc
->MaxCol(),3,0), &aMark
, INS_INSROWS_BEFORE
, false, true);
4593 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=ROW(A6)"), m_pDoc
->GetFormula(0,1,0));
4594 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=ROW(B6)"), m_pDoc
->GetFormula(1,1,0));
4595 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula!", OUString("=ROW(B7)"), m_pDoc
->GetFormula(1,2,0));
4597 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
4598 CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
4599 CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc
->GetValue(ScAddress(1,2,0)));
4601 m_pDoc
->DeleteTab(0);
4604 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncSUM
)
4606 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
4607 m_pDoc
->InsertTab (0, "foo"));
4609 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto calc.
4611 // Single argument case.
4612 m_pDoc
->SetValue(ScAddress(0,0,0), 1);
4613 m_pDoc
->SetValue(ScAddress(0,1,0), 1);
4614 m_pDoc
->SetString(ScAddress(0,2,0), "=SUM(A1:A2)");
4616 CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc
->GetValue(ScAddress(0,2,0)));
4618 // Multiple argument case.
4619 m_pDoc
->SetValue(ScAddress(0,0,0), 1);
4620 m_pDoc
->SetValue(ScAddress(0,1,0), 22);
4621 m_pDoc
->SetValue(ScAddress(0,2,0), 4);
4622 m_pDoc
->SetValue(ScAddress(0,3,0), 5);
4623 m_pDoc
->SetValue(ScAddress(0,4,0), 6);
4625 m_pDoc
->SetValue(ScAddress(1,0,0), 3);
4626 m_pDoc
->SetValue(ScAddress(1,1,0), 4);
4627 m_pDoc
->SetValue(ScAddress(1,2,0), 5);
4628 m_pDoc
->SetValue(ScAddress(1,3,0), 6);
4629 m_pDoc
->SetValue(ScAddress(1,4,0), 7);
4631 m_pDoc
->SetString(ScAddress(3,0,0), "=SUM(A1:A2;B1:B2)");
4632 m_pDoc
->SetString(ScAddress(3,1,0), "=SUM(A2:A3;B2:B3)");
4633 m_pDoc
->SetString(ScAddress(3,2,0), "=SUM(A3:A4;B3:B4)");
4634 CPPUNIT_ASSERT_EQUAL(30.0, m_pDoc
->GetValue(ScAddress(3,0,0)));
4635 CPPUNIT_ASSERT_EQUAL(35.0, m_pDoc
->GetValue(ScAddress(3,1,0)));
4636 CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc
->GetValue(ScAddress(3,2,0)));
4638 // Clear and start over.
4639 clearRange(m_pDoc
, ScRange(0,0,0,3,m_pDoc
->MaxRow(),0));
4641 // SUM needs to take the first error in case the range contains an error.
4642 m_pDoc
->SetValue(ScAddress(0,0,0), 1.0);
4643 m_pDoc
->SetValue(ScAddress(0,1,0), 10.0);
4644 m_pDoc
->SetValue(ScAddress(0,2,0), 100.0);
4645 m_pDoc
->SetString(ScAddress(0,3,0), "=SUM(A1:A3)");
4646 CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
4648 // Set #DIV/0! error to A3. A4 should also inherit this error.
4649 m_pDoc
->SetString(ScAddress(0,2,0), "=1/0");
4650 FormulaError nErr
= m_pDoc
->GetErrCode(ScAddress(0,2,0));
4651 CPPUNIT_ASSERT_EQUAL_MESSAGE("Cell should have a division by zero error.",
4652 int(FormulaError::DivisionByZero
), static_cast<int>(nErr
));
4653 nErr
= m_pDoc
->GetErrCode(ScAddress(0,3,0));
4654 CPPUNIT_ASSERT_EQUAL_MESSAGE("SUM should have also inherited a div-by-zero error.",
4655 int(FormulaError::DivisionByZero
), static_cast<int>(nErr
));
4657 // Set #NA! to A2. A4 should now inherit this error.
4658 m_pDoc
->SetString(ScAddress(0,1,0), "=NA()");
4659 nErr
= m_pDoc
->GetErrCode(ScAddress(0,1,0));
4660 CPPUNIT_ASSERT_MESSAGE("A2 should be an error.", nErr
!= FormulaError::NONE
);
4661 CPPUNIT_ASSERT_EQUAL_MESSAGE("A4 should have inherited the same error as A2.",
4662 static_cast<int>(nErr
), static_cast<int>(m_pDoc
->GetErrCode(ScAddress(0,3,0))));
4664 // Test the dreaded 0.1 + 0.2 - 0.3 != 0.0
4665 m_pDoc
->SetString(ScAddress(1,0,0), "=SUM(0.1;0.2;-0.3)");
4666 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(1,0,0)));
4667 // Also for +/- operators
4668 m_pDoc
->SetString(ScAddress(1,1,0), "=0.1+0.2-0.3");
4669 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(1,1,0)));
4671 m_pDoc
->DeleteTab(0);
4674 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncPRODUCT
)
4676 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto recalc.
4678 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc
->InsertTab(0, "foo"));
4680 ScAddress
aPos(3, 0, 0);
4681 m_pDoc
->SetValue(0, 0, 0, 3.0); // A1
4682 m_pDoc
->SetString(aPos
, "=PRODUCT(A1)");
4683 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT failed", 3.0, m_pDoc
->GetValue(aPos
));
4684 m_pDoc
->SetValue(0, 0, 0, -3.0); // A1
4685 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT failed", -3.0, m_pDoc
->GetValue(aPos
));
4686 m_pDoc
->SetString(aPos
, "=PRODUCT(B1)");
4687 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT failed", 0.0, m_pDoc
->GetValue(aPos
));
4688 m_pDoc
->SetValue(1, 0, 0, 10.0); // B1
4689 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT failed", 10.0, m_pDoc
->GetValue(aPos
));
4691 m_pDoc
->SetString(aPos
, "=PRODUCT(A1:C3)");
4692 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT failed", -30.0, m_pDoc
->GetValue(aPos
));
4693 m_pDoc
->SetValue(1, 1, 0, -1.0); // B2
4694 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT failed", 30.0, m_pDoc
->GetValue(aPos
));
4695 m_pDoc
->SetValue(2, 0, 0, 4.0); // C1
4696 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT failed", 120.0, m_pDoc
->GetValue(aPos
));
4697 m_pDoc
->SetValue(0, 1, 0, -2.0); // A2
4698 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT failed", -240.0, m_pDoc
->GetValue(aPos
));
4699 m_pDoc
->SetValue(2, 1, 0, 8.0); // C2
4700 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT failed", -1920.0, m_pDoc
->GetValue(aPos
));
4701 m_pDoc
->SetValue(0, 2, 0, 0.2); // A3
4702 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Calculation of PRODUCT failed", -384.0, m_pDoc
->GetValue(aPos
), 10e-4);
4703 m_pDoc
->SetValue(1, 2, 0, -0.25); // B3
4704 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Calculation of PRODUCT failed", 96.0, m_pDoc
->GetValue(aPos
), 10e-4);
4705 m_pDoc
->SetValue(2, 2, 0, -0.125); // C3
4706 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Calculation of PRODUCT failed", -12.0, m_pDoc
->GetValue(aPos
), 10e-4);
4707 m_pDoc
->SetValue(2, 2, 0, 0.0); // C3
4708 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Calculation of PRODUCT failed", 0.0, m_pDoc
->GetValue(aPos
), 10e-4);
4710 m_pDoc
->SetString(aPos
, "=PRODUCT({2;3;4})");
4711 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT with inline array failed", 24.0, m_pDoc
->GetValue(aPos
));
4712 m_pDoc
->SetString(aPos
, "=PRODUCT({2;-2;2})");
4713 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT with inline array failed", -8.0, m_pDoc
->GetValue(aPos
));
4714 m_pDoc
->SetString(aPos
, "=PRODUCT({8;0.125;-1})");
4715 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT with inline array failed", -1.0, m_pDoc
->GetValue(aPos
));
4717 m_pDoc
->SetString(aPos
, "=PRODUCT({2;3};{4;5})");
4718 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT with inline array failed", 120.0, m_pDoc
->GetValue(aPos
));
4719 m_pDoc
->SetString(aPos
, "=PRODUCT({10;-8};{3;-1};{15;30};{7})");
4720 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT with inline array failed", 756000.0, m_pDoc
->GetValue(aPos
));
4721 m_pDoc
->SetString(aPos
, "=PRODUCT({10;-0.1;8};{0.125;4;0.25;2};{0.5};{1};{-1})");
4722 CPPUNIT_ASSERT_EQUAL_MESSAGE("Calculation of PRODUCT with inline array failed", 1.0, m_pDoc
->GetValue(aPos
));
4724 m_pDoc
->DeleteTab(0);
4727 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncSUMPRODUCT
)
4729 m_pDoc
->InsertTab(0, "Test");
4731 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto recalc.
4733 ScAddress
aPos(0,0,0);
4734 m_pDoc
->SetString(aPos
, "=SUMPRODUCT(B1:B3;C1:C3)");
4735 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(aPos
));
4736 m_pDoc
->SetValue(ScAddress(2,0,0), 1.0); // C1
4737 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(aPos
));
4738 m_pDoc
->SetValue(ScAddress(1,0,0), 1.0); // B1
4739 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(aPos
));
4740 m_pDoc
->SetValue(ScAddress(1,1,0), 2.0); // B2
4741 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(aPos
));
4742 m_pDoc
->SetValue(ScAddress(2,1,0), 3.0); // C2
4743 CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc
->GetValue(aPos
));
4744 m_pDoc
->SetValue(ScAddress(2,2,0), -2.0); // C3
4745 CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc
->GetValue(aPos
));
4746 m_pDoc
->SetValue(ScAddress(1,2,0), 5.0); // B3
4747 CPPUNIT_ASSERT_EQUAL(-3.0, m_pDoc
->GetValue(aPos
));
4749 // Force an error in C2 and test ForcedArray matrix error propagation.
4750 m_pDoc
->SetString( 2, 1, 0, "=1/0");
4751 FormulaError nError
= m_pDoc
->GetErrCode(aPos
);
4752 CPPUNIT_ASSERT_MESSAGE("Formula result should be a propagated error", nError
!= FormulaError::NONE
);
4754 // Test ForceArray propagation of SUMPRODUCT parameters to ABS and + operator.
4755 // => ABS({-3,4})*({-3,4}+{-3,4}) => {3,4}*{-6,8} => {-18,32} => 14
4756 m_pDoc
->SetValue(ScAddress(4,0,0), -3.0); // E1
4757 m_pDoc
->SetValue(ScAddress(4,1,0), 4.0); // E2
4758 // Non-intersecting formula in F3.
4759 m_pDoc
->SetString(ScAddress(5,2,0), "=SUMPRODUCT(ABS(E1:E2);E1:E2+E1:E2)");
4760 CPPUNIT_ASSERT_EQUAL(14.0, m_pDoc
->GetValue(ScAddress(5,2,0)));
4762 m_pDoc
->DeleteTab(0);
4765 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncSUMXMY2
)
4767 m_pDoc
->InsertTab(0, "Test SumXMY2");
4769 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto recalc.
4771 ScAddress
aPos(0,0,0);
4772 m_pDoc
->SetString(aPos
, "=SUMXMY2(B1:B3;C1:C3)");
4773 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(aPos
));
4774 m_pDoc
->SetValue(ScAddress(1,0,0), 1.0); // B1
4775 CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc
->GetValue(aPos
));
4776 m_pDoc
->SetValue(ScAddress(1,1,0), 2.0); // B2
4777 CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc
->GetValue(aPos
));
4778 m_pDoc
->SetValue(ScAddress(1,2,0), 3.0); // B3
4779 CPPUNIT_ASSERT_EQUAL(14.0, m_pDoc
->GetValue(aPos
));
4780 m_pDoc
->SetValue(ScAddress(2,0,0), -1.0); // C1
4781 CPPUNIT_ASSERT_EQUAL(17.0, m_pDoc
->GetValue(aPos
));
4782 m_pDoc
->SetValue(ScAddress(2,1,0), 3.0); // C2
4783 CPPUNIT_ASSERT_EQUAL(14.0, m_pDoc
->GetValue(aPos
));
4784 m_pDoc
->SetValue(ScAddress(2,2,0), 1.0); // C3
4785 CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc
->GetValue(aPos
));
4787 m_pDoc
->SetString(0, 4, 0, "=SUMXMY2({2;3;4};{4;3;2})");
4788 double result
= m_pDoc
->GetValue(0, 4, 0);
4789 ASSERT_DOUBLES_EQUAL_MESSAGE("Calculation of SUMXMY2 with inline arrays failed", 8.0, result
);
4791 m_pDoc
->DeleteTab(0);
4794 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncMIN
)
4796 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn on auto recalc.
4797 m_pDoc
->InsertTab(0, "Formula");
4800 m_pDoc
->SetString(ScAddress(0,0,0), "a");
4801 m_pDoc
->SetString(ScAddress(0,1,0), "b");
4804 m_pDoc
->SetValue(ScAddress(1,0,0), 1.0);
4805 m_pDoc
->SetValue(ScAddress(1,1,0), 2.0);
4808 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
4809 aMark
.SelectOneTable(0);
4810 m_pDoc
->InsertMatrixFormula(2, 0, 2, 1, aMark
, "=MIN(IF(A1:A2=\"c\";B1:B2))");
4812 // Formula cell in C1:C2 should be a 1x2 matrix array.
4813 ScFormulaCell
* pFC
= m_pDoc
->GetFormulaCell(ScAddress(2,0,0));
4814 CPPUNIT_ASSERT(pFC
);
4815 CPPUNIT_ASSERT_EQUAL_MESSAGE("This formula should be an array.", ScMatrixMode::Formula
, pFC
->GetMatrixFlag());
4819 pFC
->GetMatColsRows(nCols
, nRows
);
4820 CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL
>(1), nCols
);
4821 CPPUNIT_ASSERT_EQUAL(static_cast<SCROW
>(2), nRows
);
4823 CPPUNIT_ASSERT_EQUAL_MESSAGE("Formula in C1 is invalid.", 0, static_cast<int>(m_pDoc
->GetErrCode(ScAddress(2,0,0))));
4824 CPPUNIT_ASSERT_EQUAL_MESSAGE("Formula in C2 is invalid.", 0, static_cast<int>(m_pDoc
->GetErrCode(ScAddress(2,1,0))));
4826 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(2,0,0)));
4827 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(2,1,0)));
4829 // Inline array input (A4).
4830 m_pDoc
->SetString(ScAddress(0,3,0), "=MIN({-2;4;3})");
4831 CPPUNIT_ASSERT_EQUAL(-2.0, m_pDoc
->GetValue(ScAddress(0,3,0)));
4833 // Add more values to B3:B4.
4834 m_pDoc
->SetValue(ScAddress(1,2,0), 20.0);
4835 m_pDoc
->SetValue(ScAddress(1,3,0), -20.0);
4837 // Get the MIN of B1:B4.
4838 m_pDoc
->SetString(ScAddress(2,4,0), "=MIN(B1:B4)");
4839 CPPUNIT_ASSERT_EQUAL(-20.0, m_pDoc
->GetValue(ScAddress(2,4,0)));
4841 m_pDoc
->DeleteTab(0);
4844 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncN
)
4846 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
4847 m_pDoc
->InsertTab (0, "foo"));
4851 // Clear the area first.
4852 clearRange(m_pDoc
, ScRange(0, 0, 0, 1, 20, 0));
4854 // Put values to reference.
4856 m_pDoc
->SetValue(0, 0, 0, val
);
4857 m_pDoc
->SetString(0, 2, 0, "Text");
4859 m_pDoc
->SetValue(0, 3, 0, val
);
4861 m_pDoc
->SetValue(0, 4, 0, val
);
4863 m_pDoc
->SetValue(0, 5, 0, val
);
4864 m_pDoc
->SetString(0, 6, 0, "'12.3");
4867 m_pDoc
->SetString(1, 0, 0, "=N(A1)");
4868 m_pDoc
->SetString(1, 1, 0, "=N(A2)");
4869 m_pDoc
->SetString(1, 2, 0, "=N(A3)");
4870 m_pDoc
->SetString(1, 3, 0, "=N(A4)");
4871 m_pDoc
->SetString(1, 4, 0, "=N(A5)");
4872 m_pDoc
->SetString(1, 5, 0, "=N(A6)");
4873 m_pDoc
->SetString(1, 6, 0, "=N(A9)");
4876 m_pDoc
->SetString(1, 7, 0, "=N(0)");
4877 m_pDoc
->SetString(1, 8, 0, "=N(1)");
4878 m_pDoc
->SetString(1, 9, 0, "=N(-1)");
4879 m_pDoc
->SetString(1, 10, 0, "=N(123)");
4880 m_pDoc
->SetString(1, 11, 0, "=N(\"\")");
4881 m_pDoc
->SetString(1, 12, 0, "=N(\"12\")");
4882 m_pDoc
->SetString(1, 13, 0, "=N(\"foo\")");
4885 m_pDoc
->SetString(2, 2, 0, "=N(A1:A8)");
4886 m_pDoc
->SetString(2, 3, 0, "=N(A1:A8)");
4887 m_pDoc
->SetString(2, 4, 0, "=N(A1:A8)");
4888 m_pDoc
->SetString(2, 5, 0, "=N(A1:A8)");
4890 // Calculate and check the results.
4892 double checks1
[] = {
4893 0, 0, 0, 1, -1, 12.3, 0, // cell reference
4894 0, 1, -1, 123, 0, 0, 0 // in-line values
4896 for (size_t i
= 0; i
< SAL_N_ELEMENTS(checks1
); ++i
)
4898 result
= m_pDoc
->GetValue(1, i
, 0);
4899 bool bGood
= result
== checks1
[i
];
4902 cerr
<< "row " << (i
+1) << ": expected=" << checks1
[i
] << " actual=" << result
<< endl
;
4903 CPPUNIT_ASSERT_MESSAGE("Unexpected result for N", false);
4906 double checks2
[] = {
4907 0, 1, -1, 12.3 // range references
4909 for (size_t i
= 0; i
< SAL_N_ELEMENTS(checks2
); ++i
)
4911 result
= m_pDoc
->GetValue(1, i
+2, 0);
4912 bool bGood
= result
== checks2
[i
];
4915 cerr
<< "row " << (i
+2+1) << ": expected=" << checks2
[i
] << " actual=" << result
<< endl
;
4916 CPPUNIT_ASSERT_MESSAGE("Unexpected result for N", false);
4920 m_pDoc
->DeleteTab(0);
4923 CPPUNIT_TEST_FIXTURE(TestFormula
, testFuncCOUNTIF
)
4925 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, true); // turn auto calc on.
4927 // COUNTIF (test case adopted from OOo i#36381)
4929 CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
4930 m_pDoc
->InsertTab (0, "foo"));
4932 // Empty A1:A39 first.
4933 clearRange(m_pDoc
, ScRange(0, 0, 0, 0, 40, 0));
4935 // Raw data (rows 1 through 9)
4936 const char* aData
[] = {
4948 SCROW nRows
= SAL_N_ELEMENTS(aData
);
4949 for (SCROW i
= 0; i
< nRows
; ++i
)
4950 m_pDoc
->SetString(0, i
, 0, OUString::createFromAscii(aData
[i
]));
4952 printRange(m_pDoc
, ScRange(0, 0, 0, 0, 8, 0), "data range for COUNTIF");
4954 // formulas and results
4955 static const struct {
4956 const char* pFormula
; double fResult
;
4958 { "=COUNTIF(A1:A12;1999)", 1 },
4959 { "=COUNTIF(A1:A12;2002)", 2 },
4960 { "=COUNTIF(A1:A12;1998)", 0 },
4961 { "=COUNTIF(A1:A12;\">=1999\")", 5 },
4962 { "=COUNTIF(A1:A12;\">1999\")", 4 },
4963 { "=COUNTIF(A1:A12;\"<2001\")", 5 },
4964 { "=COUNTIF(A1:A12;\">0\")", 5 },
4965 { "=COUNTIF(A1:A12;\">=0\")", 8 },
4966 { "=COUNTIF(A1:A12;0)", 3 },
4967 { "=COUNTIF(A1:A12;\"X\")", 1 },
4968 { "=COUNTIF(A1:A12;)", 3 }
4971 nRows
= SAL_N_ELEMENTS(aChecks
);
4972 for (SCROW i
= 0; i
< nRows
; ++i
)
4974 SCROW nRow
= 20 + i
;
4975 m_pDoc
->SetString(0, nRow
, 0, OUString::createFromAscii(aChecks
[i
].pFormula
));
4978 for (SCROW i
= 0; i
< nRows
; ++i
)
4980 SCROW nRow
= 20 + i
;
4981 double result
= m_pDoc
->GetValue(0, nRow
, 0);
4982 bool bGood
= result
== aChecks
[i
].fResult
;
4985 cerr
<< "row " << (nRow
+1) << ": formula" << aChecks
[i
].pFormula
4986 << " expected=" << aChecks
[i
].fResult
<< " actual=" << result
<< endl
;
4987 CPPUNIT_ASSERT_MESSAGE("Unexpected result for COUNTIF", false);
4991 // Don't count empty strings when searching for a number.
4994 clearRange(m_pDoc
, ScRange(0, 0, 0, 0, 1, 0));
4996 m_pDoc
->SetString(0, 0, 0, "=\"\"");
4997 m_pDoc
->SetString(0, 1, 0, "=COUNTIF(A1;1)");
4999 double result
= m_pDoc
->GetValue(0, 1, 0);
5000 ASSERT_DOUBLES_EQUAL_MESSAGE("We shouldn't count empty string as valid number.", 0.0, result
);
5002 // Another test case adopted from fdo#77039.
5003 clearSheet(m_pDoc
, 0);
5005 // Set formula cells with blank results in A1:A4.
5006 for (SCROW i
= 0; i
<=3; ++i
)
5007 m_pDoc
->SetString(ScAddress(0,i
,0), "=\"\"");
5009 // Insert formula into A5 to count all cells with empty strings.
5010 m_pDoc
->SetString(ScAddress(0,4,0), "=COUNTIF(A1:A4;\"\"");
5012 // We should correctly count with empty string key.
5013 CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc
->GetValue(ScAddress(0,4,0)));
5015 // Another test case adopted from tdf#99291, empty array elements should
5016 // not match empty cells, but cells with 0.
5017 clearSheet(m_pDoc
, 0);
5018 ScMarkData
aMark(m_pDoc
->GetSheetLimits());
5019 aMark
.SelectOneTable(0);
5020 m_pDoc
->InsertMatrixFormula(0,0, 0,1, aMark
, "=COUNTIF(B1:B5;C1:C2)");
5021 // As we will be testing for 0.0 values, check that formulas are actually present.
5022 OUString aFormula
= m_pDoc
->GetFormula(0,0,0);
5023 CPPUNIT_ASSERT_EQUAL(OUString("{=COUNTIF(B1:B5;C1:C2)}"), aFormula
);
5024 aFormula
= m_pDoc
->GetFormula(0,1,0);
5025 CPPUNIT_ASSERT_EQUAL(OUString("{=COUNTIF(B1:B5;C1:C2)}"), aFormula
);
5026 // The 0.0 results expected.
5027 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5028 CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5029 // 0.0 in B2, 1.0 in B3 and B4
5030 m_pDoc
->SetValue( ScAddress(1,1,0), 0.0);
5031 m_pDoc
->SetValue( ScAddress(1,2,0), 1.0);
5032 m_pDoc
->SetValue( ScAddress(1,3,0), 1.0);
5033 // Matched by 0.0 produced by empty cell in array, and 1.0 in C2.
5034 m_pDoc
->SetValue( ScAddress(2,1,0), 1.0);
5035 CPPUNIT_ASSERT_EQUAL_MESSAGE("One cell with 0.0", 1.0, m_pDoc
->GetValue(ScAddress(0,0,0)));
5036 CPPUNIT_ASSERT_EQUAL_MESSAGE("Two cells with 1.0", 2.0, m_pDoc
->GetValue(ScAddress(0,1,0)));
5038 m_pDoc
->DeleteTab(0);
5041 CPPUNIT_PLUGIN_IMPLEMENT();
5043 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */