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 <test/unoapi_test.hxx>
11 #include <comphelper/propertyvalue.hxx>
13 #include <com/sun/star/sheet/SolverObjectiveType.hpp>
14 #include <com/sun/star/sheet/XSolverSettings.hpp>
15 #include <com/sun/star/sheet/XSpreadsheet.hpp>
16 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
17 #include <com/sun/star/table/CellAddress.hpp>
18 #include <com/sun/star/uno/Reference.hxx>
19 #include <com/sun/star/sheet/ModelConstraint.hpp>
20 #include <com/sun/star/sheet/SolverConstraintOperator.hpp>
21 #include <com/sun/star/table/CellRangeAddress.hpp>
22 #include <com/sun/star/beans/PropertyValue.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/uno/Sequence.hxx>
25 #include <com/sun/star/uno/Any.hxx>
31 class ScSolverSettingsObj
: public UnoApiTest
34 ScSolverSettingsObj();
36 virtual void setUp() override
;
37 void testXSolverSettings();
38 void testCellAddress(const table::CellAddress
& rExpected
, const uno::Any
& rActual
);
39 void testCellRangeAddress(const uno::Any
& rExpected
, const uno::Any
& rActual
);
41 CPPUNIT_TEST_SUITE(ScSolverSettingsObj
);
42 CPPUNIT_TEST(testXSolverSettings
);
43 CPPUNIT_TEST_SUITE_END();
46 ScSolverSettingsObj::ScSolverSettingsObj()
47 : UnoApiTest(u
"/sc/qa/extras/testdocuments"_ustr
)
51 void ScSolverSettingsObj::testCellAddress(const table::CellAddress
& rExpected
,
52 const uno::Any
& rActual
)
54 table::CellAddress aActualAddress
;
55 rActual
>>= aActualAddress
;
56 CPPUNIT_ASSERT_EQUAL(rExpected
.Column
, aActualAddress
.Column
);
57 CPPUNIT_ASSERT_EQUAL(rExpected
.Row
, aActualAddress
.Row
);
58 CPPUNIT_ASSERT_EQUAL(rExpected
.Sheet
, aActualAddress
.Sheet
);
61 void ScSolverSettingsObj::testCellRangeAddress(const uno::Any
& rExpected
, const uno::Any
& rActual
)
63 table::CellRangeAddress aActualAddress
;
64 table::CellRangeAddress aExpectedAddress
;
65 rActual
>>= aActualAddress
;
66 rExpected
>>= aExpectedAddress
;
67 CPPUNIT_ASSERT_EQUAL(aExpectedAddress
.Sheet
, aActualAddress
.Sheet
);
68 CPPUNIT_ASSERT_EQUAL(aExpectedAddress
.StartRow
, aActualAddress
.StartRow
);
69 CPPUNIT_ASSERT_EQUAL(aExpectedAddress
.StartColumn
, aActualAddress
.StartColumn
);
70 CPPUNIT_ASSERT_EQUAL(aExpectedAddress
.EndRow
, aActualAddress
.EndRow
);
71 CPPUNIT_ASSERT_EQUAL(aExpectedAddress
.EndColumn
, aActualAddress
.EndColumn
);
74 // Creates a model using the XSolverSettings API checks if it is accessible via the API
75 void ScSolverSettingsObj::testXSolverSettings()
77 uno::Reference
<sheet::XSpreadsheetDocument
> xDoc(mxComponent
, uno::UNO_QUERY_THROW
);
78 uno::Reference
<container::XIndexAccess
> xIndex(xDoc
->getSheets(), uno::UNO_QUERY_THROW
);
79 uno::Reference
<sheet::XSpreadsheet
> xSheet(xIndex
->getByIndex(0), uno::UNO_QUERY_THROW
);
80 uno::Reference
<beans::XPropertySet
> xPropSet(xSheet
, uno::UNO_QUERY_THROW
);
81 uno::Reference
<sheet::XSolverSettings
> xSolverModel(
82 xPropSet
->getPropertyValue("SolverSettings"), uno::UNO_QUERY_THROW
);
84 // Objective cell is in G7
85 table::CellAddress
aObjCell(0, 6, 6);
86 xSolverModel
->setObjectiveCell(uno::Any(aObjCell
));
87 xSolverModel
->setObjectiveType(sheet::SolverObjectiveType::MAXIMIZE
);
89 // Variable cells (E3:E17)
90 uno::Sequence
<uno::Any
> aVarCells(1);
91 auto pVarCells
= aVarCells
.getArray();
92 pVarCells
[0] <<= table::CellRangeAddress(0, 4, 2, 4, 16);
93 xSolverModel
->setVariableCells(aVarCells
);
96 uno::Sequence
<sheet::ModelConstraint
> aConstraints(2);
97 auto pConstraints
= aConstraints
.getArray();
98 pConstraints
[0].Left
<<= OUString("$E$3:$E$17");
99 pConstraints
[0].Operator
= sheet::SolverConstraintOperator_BINARY
;
100 pConstraints
[1].Left
<<= OUString("$G$5");
101 pConstraints
[1].Operator
= sheet::SolverConstraintOperator_LESS_EQUAL
;
102 pConstraints
[1].Right
<<= OUString("$G$3");
103 xSolverModel
->setConstraints(aConstraints
);
105 // Set solver engine options
106 xSolverModel
->setEngine(u
"com.sun.star.comp.Calc.LpsolveSolver"_ustr
);
107 uno::Sequence
<beans::PropertyValue
> aEngineOptions
{
108 comphelper::makePropertyValue(u
"Timeout"_ustr
, uno::Any(static_cast<sal_Int32
>(10))),
109 comphelper::makePropertyValue(u
"NonNegative"_ustr
, true),
111 xSolverModel
->setEngineOptions(aEngineOptions
);
113 // Run the model and check the results
114 xSolverModel
->saveToFile();
115 xSolverModel
->setSuppressDialog(true);
116 xSolverModel
->solve();
118 // The correct solution value is 6981 (using LpsolveSolver)
119 CPPUNIT_ASSERT_EQUAL(static_cast<double>(6981), xSheet
->getCellByPosition(6, 6)->getValue());
121 // Check objective function and variable cells
122 testCellAddress(aObjCell
, xSolverModel
->getObjectiveCell());
123 CPPUNIT_ASSERT_EQUAL(sheet::SolverObjectiveType::MAXIMIZE
, xSolverModel
->getObjectiveType());
124 uno::Sequence
<uno::Any
> aSeq
= xSolverModel
->getVariableCells();
125 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aSeq
.getLength());
126 testCellRangeAddress(aVarCells
[0], aSeq
[0]);
128 // Check if constraints were set
129 uno::Sequence
<sheet::ModelConstraint
> aSeqConstr
= xSolverModel
->getConstraints();
130 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(2), aSeqConstr
.getLength());
131 CPPUNIT_ASSERT_EQUAL(sheet::SolverConstraintOperator::SolverConstraintOperator_BINARY
,
132 aSeqConstr
[0].Operator
);
133 table::CellRangeAddress
aLeft1(0, 4, 2, 4, 16);
134 table::CellRangeAddress
aRight1(0, 0, 0, 0, 0);
135 testCellRangeAddress(uno::Any(aLeft1
), aSeqConstr
[0].Left
);
136 testCellRangeAddress(uno::Any(aRight1
), aSeqConstr
[0].Right
);
137 CPPUNIT_ASSERT_EQUAL(sheet::SolverConstraintOperator::SolverConstraintOperator_LESS_EQUAL
,
138 aSeqConstr
[1].Operator
);
139 table::CellRangeAddress
aLeft2(0, 6, 4, 6, 4);
140 table::CellRangeAddress
aRight2(0, 6, 2, 6, 2);
141 testCellRangeAddress(uno::Any(aLeft2
), aSeqConstr
[1].Left
);
142 testCellRangeAddress(uno::Any(aRight2
), aSeqConstr
[1].Right
);
144 // Check solver engine options
145 CPPUNIT_ASSERT_EQUAL(u
"com.sun.star.comp.Calc.LpsolveSolver"_ustr
, xSolverModel
->getEngine());
147 // Check solver engine options
148 uno::Sequence
<beans::PropertyValue
> aEngProps
= xSolverModel
->getEngineOptions();
149 CPPUNIT_ASSERT_EQUAL(OUString("EpsilonLevel"), aEngProps
[0].Name
);
150 CPPUNIT_ASSERT_EQUAL(uno::Any(static_cast<sal_Int32
>(0)), aEngProps
[0].Value
);
151 CPPUNIT_ASSERT_EQUAL(u
"GenSensitivityReport"_ustr
, aEngProps
[1].Name
);
152 CPPUNIT_ASSERT_EQUAL(uno::Any(false), aEngProps
[1].Value
);
153 CPPUNIT_ASSERT_EQUAL(u
"Integer"_ustr
, aEngProps
[2].Name
);
154 CPPUNIT_ASSERT_EQUAL(uno::Any(false), aEngProps
[2].Value
);
155 CPPUNIT_ASSERT_EQUAL(u
"LimitBBDepth"_ustr
, aEngProps
[3].Name
);
156 CPPUNIT_ASSERT_EQUAL(uno::Any(true), aEngProps
[3].Value
);
157 CPPUNIT_ASSERT_EQUAL(u
"NonNegative"_ustr
, aEngProps
[4].Name
);
158 CPPUNIT_ASSERT_EQUAL(uno::Any(true), aEngProps
[4].Value
);
159 CPPUNIT_ASSERT_EQUAL(u
"Timeout"_ustr
, aEngProps
[5].Name
);
160 CPPUNIT_ASSERT_EQUAL(uno::Any(static_cast<sal_Int32
>(10)), aEngProps
[5].Value
);
162 // Save file and reload to check if solver settings are still there
163 saveAndReload(u
"calc8"_ustr
);
164 uno::Reference
<sheet::XSpreadsheetDocument
> xDoc2(mxComponent
, uno::UNO_QUERY_THROW
);
165 uno::Reference
<container::XIndexAccess
> xIndex2(xDoc2
->getSheets(), uno::UNO_QUERY_THROW
);
166 uno::Reference
<sheet::XSpreadsheet
> xSheet2(xIndex2
->getByIndex(0), uno::UNO_QUERY_THROW
);
167 uno::Reference
<beans::XPropertySet
> xPropSet2(xSheet2
, uno::UNO_QUERY_THROW
);
168 uno::Reference
<sheet::XSolverSettings
> xSolverModel2(
169 xPropSet2
->getPropertyValue("SolverSettings"), uno::UNO_QUERY_THROW
);
171 // // Check objective function
172 testCellAddress(aObjCell
, xSolverModel2
->getObjectiveCell());
173 CPPUNIT_ASSERT_EQUAL(sheet::SolverObjectiveType::MAXIMIZE
, xSolverModel2
->getObjectiveType());
175 // Check variable cells
176 uno::Sequence
<uno::Any
> aVarCells2
= xSolverModel2
->getVariableCells();
177 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aVarCells2
.getLength());
178 testCellRangeAddress(aVarCells
[0], aVarCells2
[0]);
181 uno::Sequence
<sheet::ModelConstraint
> aSeqConstr2
= xSolverModel2
->getConstraints();
182 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(2), aSeqConstr2
.getLength());
183 CPPUNIT_ASSERT_EQUAL(sheet::SolverConstraintOperator::SolverConstraintOperator_BINARY
,
184 aSeqConstr2
[0].Operator
);
185 testCellRangeAddress(uno::Any(aLeft1
), aSeqConstr2
[0].Left
);
186 testCellRangeAddress(uno::Any(aRight1
), aSeqConstr2
[0].Right
);
187 CPPUNIT_ASSERT_EQUAL(sheet::SolverConstraintOperator::SolverConstraintOperator_LESS_EQUAL
,
188 aSeqConstr2
[1].Operator
);
189 testCellRangeAddress(uno::Any(aLeft2
), aSeqConstr2
[1].Left
);
190 testCellRangeAddress(uno::Any(aRight2
), aSeqConstr2
[1].Right
);
192 // Check solver engine options
193 uno::Sequence
<beans::PropertyValue
> aEngProps2
= xSolverModel2
->getEngineOptions();
194 CPPUNIT_ASSERT_EQUAL(OUString("EpsilonLevel"), aEngProps2
[0].Name
);
195 CPPUNIT_ASSERT_EQUAL(uno::Any(static_cast<sal_Int32
>(0)), aEngProps2
[0].Value
);
196 CPPUNIT_ASSERT_EQUAL(u
"GenSensitivityReport"_ustr
, aEngProps2
[1].Name
);
197 CPPUNIT_ASSERT_EQUAL(uno::Any(false), aEngProps2
[1].Value
);
198 CPPUNIT_ASSERT_EQUAL(u
"Integer"_ustr
, aEngProps2
[2].Name
);
199 CPPUNIT_ASSERT_EQUAL(uno::Any(false), aEngProps2
[2].Value
);
200 CPPUNIT_ASSERT_EQUAL(u
"LimitBBDepth"_ustr
, aEngProps2
[3].Name
);
201 CPPUNIT_ASSERT_EQUAL(uno::Any(true), aEngProps2
[3].Value
);
202 CPPUNIT_ASSERT_EQUAL(u
"NonNegative"_ustr
, aEngProps2
[4].Name
);
203 CPPUNIT_ASSERT_EQUAL(uno::Any(true), aEngProps2
[4].Value
);
204 CPPUNIT_ASSERT_EQUAL(u
"Timeout"_ustr
, aEngProps2
[5].Name
);
205 CPPUNIT_ASSERT_EQUAL(uno::Any(static_cast<sal_Int32
>(10)), aEngProps2
[5].Value
);
208 void ScSolverSettingsObj::setUp()
211 loadFromFile(u
"knapsack.ods");
214 CPPUNIT_TEST_SUITE_REGISTRATION(ScSolverSettingsObj
);
216 } // namespace sc_apitest
218 CPPUNIT_PLUGIN_IMPLEMENT();
220 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */