1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 #include <sal/config.h>
4 #include <test/bootstrapfixture.hxx>
5 #include <rtl/strbuf.hxx>
6 #include <osl/file.hxx>
9 #include <sfx2/app.hxx>
10 #include <sfx2/docfilt.hxx>
11 #include <sfx2/docfile.hxx>
12 #include <sfx2/sfxmodelfactory.hxx>
13 #include <svl/stritem.hxx>
15 #include "helper/qahelper.hxx"
17 #include <calcconfig.hxx>
18 #include <interpre.hxx>
22 #include <patattr.hxx>
23 #include <scitems.hxx>
24 #include <document.hxx>
25 #include <cellform.hxx>
26 #include <drwlayer.hxx>
27 #include <userdat.hxx>
28 #include <formulacell.hxx>
29 #include <formulagroup.hxx>
30 #include <scopetools.hxx>
32 #include <svx/svdpage.hxx>
34 #include <officecfg/Office/Calc.hxx>
37 using namespace css::uno
;
39 class ScParallelismTest
: public ScBootstrapFixture
44 virtual void setUp() override
;
45 virtual void tearDown() override
;
47 void getNewDocShell(ScDocShellRef
& rDocShellRef
);
52 void testVLOOKUPSUM();
54 void testSUMIFImplicitRange();
56 CPPUNIT_TEST_SUITE(ScParallelismTest
);
57 CPPUNIT_TEST(testSUMIFS
);
58 CPPUNIT_TEST(testDivision
);
59 CPPUNIT_TEST(testVLOOKUP
);
60 CPPUNIT_TEST(testVLOOKUPSUM
);
61 CPPUNIT_TEST(testSingleRef
);
62 CPPUNIT_TEST(testSUMIFImplicitRange
);
63 CPPUNIT_TEST_SUITE_END();
67 bool getThreadingFlag();
68 void setThreadingFlag(bool bSet
);
72 ScDocShellRef m_xDocShell
;
73 bool m_bThreadingFlagCfg
;
76 ScParallelismTest::ScParallelismTest()
77 : ScBootstrapFixture( "sc/qa/unit/data" )
81 bool ScParallelismTest::getThreadingFlag()
83 return officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get();
86 void ScParallelismTest::setThreadingFlag( bool bSet
)
88 std::shared_ptr
<comphelper::ConfigurationChanges
> xBatch(comphelper::ConfigurationChanges::create());
89 officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::set(bSet
, xBatch
);
93 void ScParallelismTest::setUp()
95 test::BootstrapFixture::setUp();
99 getNewDocShell(m_xDocShell
);
100 m_pDoc
= &m_xDocShell
->GetDocument();
102 sc::FormulaGroupInterpreter::disableOpenCL_UnitTestsOnly();
104 m_bThreadingFlagCfg
= getThreadingFlag();
105 if (!m_bThreadingFlagCfg
)
106 setThreadingFlag(true);
109 void ScParallelismTest::tearDown()
111 // Restore threading flag
112 if (!m_bThreadingFlagCfg
)
113 setThreadingFlag(false);
115 test::BootstrapFixture::tearDown();
118 void ScParallelismTest::getNewDocShell( ScDocShellRef
& rDocShellRef
)
120 rDocShellRef
= new ScDocShell(
121 SfxModelFlags::EMBEDDED_OBJECT
|
122 SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS
|
123 SfxModelFlags::DISABLE_DOCUMENT_RECOVERY
);
126 void ScParallelismTest::testSUMIFS()
128 m_pDoc
->InsertTab(0, "1");
130 m_pDoc
->SetValue(0, 0, 0, 1001);
132 for (auto i
= 1; i
< 1000; i
++)
136 m_pDoc
->SetValue(0, i
, 0, i
/10 + 1000);
138 m_pDoc
->SetValue(0, i
, 0, 123456);
139 /*B*/ m_pDoc
->SetValue(1, i
, 0, i
%10);
140 /*C*/ m_pDoc
->SetValue(2, i
, 0, i
%5);
142 /*F*/ m_pDoc
->SetValue(5, i
, 0, i
%17 + i
%13);
144 /*L*/ m_pDoc
->SetValue(11, i
, 0, i
%10);
145 /*M*/ m_pDoc
->SetValue(12, i
, 0, i
%5);
148 for (auto i
= 1; i
< 1000; i
++)
150 // For instance P389 will contain the formula:
151 // =SUMIFS($F$2:$F$1000; $A$2:$A$1000; A$1; $B$2:$B$1000; $L389; $C$2:$C$1000; $M389)
153 // In other words, it will sum those values in F2:1000 where the A value matches A1 (1001),
154 // the B value matches L389 and the C value matches M389. (There should be just one such
155 // value, so the formula is actually simply used to pick out that single value from the F
156 // column where A,B,C match. Silly, but that is how SUMIFS is used in some corners of the
157 // real world, apparently.)
159 /*P*/ m_pDoc
->SetFormula(ScAddress(15, i
, 0),
160 "=SUMIFS($F$2:$F$1000; "
161 "$A$2:$A$1000; A$1; "
162 "$B$2:$B$1000; $L" + OUString::number(i
+1) + "; "
163 "$C$2:$C$1000; $M" + OUString::number(i
+1) +
165 formula::FormulaGrammar::GRAM_NATIVE_UI
);
168 m_xDocShell
->DoHardRecalc();
173 std::cerr
<< "A1=" << m_pDoc
->GetValue(0, 0, 0) << std::endl
;
175 std::cerr
<< " A,B,C F L,M" << std::endl
;
176 for (auto i
= 1; i
< 30; i
++)
180 m_pDoc
->GetValue(0, i
, 0) << "," <<
181 m_pDoc
->GetValue(1, i
, 0) << "," <<
182 m_pDoc
->GetValue(2, i
, 0) << " " <<
183 m_pDoc
->GetValue(5, i
, 0) << " " <<
184 m_pDoc
->GetValue(11, i
, 0) << "," <<
185 m_pDoc
->GetValue(12, i
, 0) << " \"";
186 m_pDoc
->GetFormula(15, i
, 0, sFormula
);
187 std::cerr
<< sFormula
<< "\": \"" <<
188 m_pDoc
->GetString(15, i
, 0) << "\": " <<
189 m_pDoc
->GetValue(15, i
, 0) << std::endl
;
193 for (auto i
= 1; i
< 1000; i
++)
195 OString sMessage
= "At row " + OString::number(i
+1);
197 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(sMessage
.getStr(), m_pDoc
->GetValue(5, 10+i
%10, 0), m_pDoc
->GetValue(15, i
, 0), 1e-10);
199 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(sMessage
.getStr(), 0, m_pDoc
->GetValue(15, i
, 0), 1e-10);
202 m_pDoc
->DeleteTab(0);
205 void ScParallelismTest::testDivision()
207 m_pDoc
->InsertTab(0, "1");
209 for (auto i
= 1; i
< 1000; i
++)
211 /*A*/ m_pDoc
->SetValue(0, i
, 0, i
);
212 /*B*/ m_pDoc
->SetValue(1, i
, 0, i
%10);
213 /*C*/ m_pDoc
->SetFormula(ScAddress(2, i
, 0),
214 "=A" + OUString::number(i
+1) + "/B" + OUString::number(i
+1),
215 formula::FormulaGrammar::GRAM_NATIVE_UI
);
218 m_xDocShell
->DoHardRecalc();
220 for (auto i
= 1; i
< 1000; i
++)
222 OString sMessage
= "At row " + OString::number(i
+1);
224 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(sMessage
.getStr(), static_cast<double>(i
)/(i
%10), m_pDoc
->GetValue(2, i
, 0), 1e-10);
226 CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage
.getStr(), OUString("#DIV/0!"), m_pDoc
->GetString(2, i
, 0));
229 m_pDoc
->DeleteTab(0);
232 void ScParallelismTest::testVLOOKUP()
234 m_pDoc
->InsertTab(0, "1");
236 for (auto i
= 1; i
< 2000; i
++)
239 m_pDoc
->SetValue(0, i
, 0, 1042.42);
241 m_pDoc
->SetValue(0, i
, 0, i
);
243 m_pDoc
->SetValue(0, i
, 0, i
+0.1);
246 m_pDoc
->SetValue(1, i
, 0, i
*10);
248 m_pDoc
->SetString(1, i
, 0, "N" + OUString::number(i
*10));
252 m_pDoc
->SetFormula(ScAddress(2, i
, 0),
253 "=VLOOKUP(" + OUString::number(i
) + "; "
255 formula::FormulaGrammar::GRAM_NATIVE_UI
);
261 m_pDoc
->SetFormula(ScAddress(2, i
, 0),
264 formula::FormulaGrammar::GRAM_NATIVE_UI
);
266 m_pDoc
->SetFormula(ScAddress(2, i
, 0),
269 formula::FormulaGrammar::GRAM_NATIVE_UI
);
273 m_xDocShell
->DoHardRecalc();
275 for (auto i
= 1; i
< 2000; i
++)
277 OString sMessage
= "At row " + OString::number(i
+1);
283 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(sMessage
.getStr(), static_cast<double>(i
*10), m_pDoc
->GetValue(2, i
, 0), 1e-10);
285 CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage
.getStr(), OUString("N" + OUString::number(i
*10)), m_pDoc
->GetString(2, i
, 0));
289 // The corresponding value in A is i+0.1
290 CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage
.getStr(), OUString("#N/A"), m_pDoc
->GetString(2, i
, 0));
296 CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage
.getStr(), OUString("N" + OUString::number(i
*10)), m_pDoc
->GetString(2, i
, 0));
298 CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage
.getStr(), OUString("#N/A"), m_pDoc
->GetString(2, i
, 0));
302 m_pDoc
->DeleteTab(0);
305 void ScParallelismTest::testVLOOKUPSUM()
307 m_pDoc
->InsertTab(0, "1");
309 const size_t nNumRows
= 4096*4;
310 OUString aTableRef
= "$A$1:$B$" + OUString::number(nNumRows
);
311 for (size_t i
= 0; i
< nNumRows
; ++i
)
313 m_pDoc
->SetValue(0, i
, 0, static_cast<double>(i
));
314 m_pDoc
->SetValue(1, i
, 0, static_cast<double>(5*i
+ 100));
315 m_pDoc
->SetValue(2, i
, 0, static_cast<double>(nNumRows
- i
- 1));
317 for (size_t i
= 0; i
< nNumRows
; ++i
)
319 OUString aArgNum
= "C" + OUString::number(i
+1);
320 m_pDoc
->SetFormula(ScAddress(3, i
, 0),
321 "=SUM(" + aArgNum
+ ";VLOOKUP(" + aArgNum
+ ";" + aTableRef
+ "; 2; 0)) + SUM($A1:$A2)",
322 formula::FormulaGrammar::GRAM_NATIVE_UI
);
325 m_xDocShell
->DoHardRecalc();
327 for (size_t i
= 0; i
< nNumRows
; ++i
)
329 OString aMsg
= "At row " + OString::number(i
);
330 CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg
.getStr(), 6 * (nNumRows
- i
- 1) + 101, static_cast<size_t>(m_pDoc
->GetValue(3, i
, 0)));
332 m_pDoc
->DeleteTab(0);
335 void ScParallelismTest::testSingleRef()
337 m_pDoc
->InsertTab(0, "1");
339 const size_t nNumRows
= 200;
340 for (size_t i
= 0; i
< nNumRows
; ++i
)
342 m_pDoc
->SetValue(0, i
, 0, static_cast<double>(i
));
343 m_pDoc
->SetFormula(ScAddress(1, i
, 0), "=A" + OUString::number(i
+1), formula::FormulaGrammar::GRAM_NATIVE_UI
);
346 m_xDocShell
->DoHardRecalc();
348 for (size_t i
= 0; i
< nNumRows
; ++i
)
350 OString aMsg
= "At row " + OString::number(i
);
351 CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg
.getStr(), i
, static_cast<size_t>(m_pDoc
->GetValue(1, i
, 0)));
353 m_pDoc
->DeleteTab(0);
356 // Common test setup steps for testSUMIFImplicitRange*()
357 void lcl_setupCommon(ScDocument
* pDoc
, size_t nNumRows
, size_t nConstCellValue
)
359 pDoc
->SetValue(3, 0, 0, static_cast<double>(nConstCellValue
)); // D1
360 for (size_t i
= 0; i
<= (nNumRows
*2); ++i
)
362 pDoc
->SetValue(0, i
, 0, static_cast<double>(i
));
363 pDoc
->SetFormula(ScAddress(1, i
, 0),
364 "=A" + OUString::number(i
+1),
365 formula::FormulaGrammar::GRAM_NATIVE_UI
);
369 void ScParallelismTest::testSUMIFImplicitRange()
371 sc::AutoCalcSwitch
aACSwitch(*m_pDoc
, false);
372 m_pDoc
->InsertTab(0, "1");
374 const size_t nNumRows
= 1048;
375 const size_t nConstCellValue
= 20;
376 lcl_setupCommon(m_pDoc
, nNumRows
, nConstCellValue
);
377 OUString aSrcRange
= "$A$1:$A$" + OUString::number(nNumRows
);
379 for (size_t i
= 0; i
< nNumRows
; ++i
)
381 aFormula
= "=SUMIF(" + aSrcRange
+ ";$D$1;$B$1)";
382 m_pDoc
->SetFormula(ScAddress(2, i
, 0),
384 formula::FormulaGrammar::GRAM_NATIVE_UI
);
387 ScFormulaCell
* pCell
= m_pDoc
->GetFormulaCell(ScAddress(2, 0, 0));
388 sc::AutoCalcSwitch
aACSwitch2(*m_pDoc
, true);
389 pCell
->InterpretFormulaGroup(); // Start calculation on the F.G at C1
391 for (size_t i
= 0; i
< nNumRows
; ++i
)
393 OString aMsg
= "At row " + OString::number(i
);
394 CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg
.getStr(), nConstCellValue
, static_cast<size_t>(m_pDoc
->GetValue(2, i
, 0)));
396 m_pDoc
->DeleteTab(0);
399 CPPUNIT_TEST_SUITE_REGISTRATION(ScParallelismTest
);
401 CPPUNIT_PLUGIN_IMPLEMENT();
403 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */