2
#include "dpresulttester.hxx"
4
#include <com/sun/star/beans/Property.hpp>
5
#include <com/sun/star/beans/XPropertySet.hpp>
6
#include <com/sun/star/beans/XPropertySetInfo.hpp>
7
#include <com/sun/star/container/XEnumeration.hpp>
8
#include <com/sun/star/container/XEnumerationAccess.hpp>
9
#include <com/sun/star/container/XIndexAccess.hpp>
10
#include <com/sun/star/container/XNamed.hpp>
11
#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
12
#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
13
#include <com/sun/star/sheet/DataPilotFieldReference.hpp>
14
#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
15
#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
16
#include <com/sun/star/sheet/DataPilotTableRegion.hpp>
17
#include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
18
#include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
19
#include <com/sun/star/sheet/DataPilotTableResultData.hpp>
20
#include <com/sun/star/sheet/DataResultFlags.hpp>
21
#include <com/sun/star/sheet/GeneralFunction.hpp>
22
#include <com/sun/star/sheet/DataResult.hpp>
23
#include <com/sun/star/sheet/XDataPilotDescriptor.hpp>
24
#include <com/sun/star/sheet/XDataPilotField.hpp>
25
#include <com/sun/star/sheet/XDataPilotFieldGrouping.hpp>
26
#include <com/sun/star/sheet/XDataPilotTable2.hpp>
27
#include <com/sun/star/sheet/XDataPilotTable.hpp>
28
#include <com/sun/star/sheet/XDataPilotTables.hpp>
29
#include <com/sun/star/sheet/XDataPilotTablesSupplier.hpp>
30
#include <com/sun/star/sheet/XSheetFilterDescriptor.hpp>
31
#include <com/sun/star/sheet/XSpreadsheet.hpp>
32
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
33
#include <com/sun/star/sheet/XSpreadsheets.hpp>
34
#include <com/sun/star/table/CellAddress.hpp>
35
#include <com/sun/star/table/CellRangeAddress.hpp>
36
#include <com/sun/star/table/XCell.hpp>
37
#include <com/sun/star/table/CellContentType.hpp>
42
#include <boost/shared_ptr.hpp>
43
#include <rtl/ustrbuf.hxx>
45
using namespace ::com::sun::star;
46
using namespace ::com::sun::star::uno;
47
using namespace ::com::sun::star::sheet;
49
using ::com::sun::star::container::XIndexAccess;
50
using ::com::sun::star::beans::Property;
51
using ::com::sun::star::beans::XPropertySet;
52
using ::com::sun::star::beans::XPropertySetInfo;
53
using ::com::sun::star::table::CellAddress;
54
using ::com::sun::star::table::CellRangeAddress;
55
using ::com::sun::star::table::XCell;
56
using ::com::sun::star::table::CellContentType;
57
using ::rtl::OUString;
58
using ::rtl::OUStringBuffer;
60
using ::boost::shared_ptr;
64
ResultTester::DataFieldSetting::DataFieldSetting() :
65
FieldRef(static_cast<DataPilotFieldReference*>(NULL))
69
// ============================================================================
72
ResultTester::ResultTester(const RuntimeData& data, const Reference<XDataPilotTable2>& xDPTab) :
73
maData(data), mxDPTab(xDPTab), mnFailureCount(0)
78
ResultTester::ResultTester(const ResultTester& other) :
79
maData(other.maData), mxDPTab(other.mxDPTab),
80
maDataFieldSettings(other.maDataFieldSettings),
81
mnFailureCount(other.mnFailureCount)
86
void ResultTester::init()
88
Reference<XDataPilotDescriptor> xDPDesc(mxDPTab, UNO_QUERY_THROW);
90
// Go though each data field
91
Reference<container::XIndexAccess> xDataFields = xDPDesc->getDataFields();
92
sal_Int32 fieldCount = xDataFields->getCount();
93
maDataFieldSettings.reserve(fieldCount);
94
for (sal_Int32 i = 0; i < fieldCount; ++i)
96
Reference<XDataPilotField> xField(xDataFields->getByIndex(i), UNO_QUERY_THROW);
97
DataFieldSetting setting;
99
// Get the field ID of a given data field.
100
Reference<container::XNamed> xNamed(xField, UNO_QUERY_THROW);
101
OUString name = xNamed->getName();
102
setting.FieldId = maData.CacheTable.getFieldIndex(name);
104
// Get the function used for aggregation.
105
Reference<XPropertySet> xPS(xField, UNO_QUERY_THROW);
106
getPropertyValue(xPS, ascii("Function"), setting.Function);
108
// Get the referenced item information (if any).
109
bool hasReference = false;
110
getPropertyValue(xPS, ascii("HasReference"), hasReference);
113
setting.FieldRef.reset(new DataPilotFieldReference);
114
getPropertyValue(xPS, ascii("Reference"), *setting.FieldRef);
116
maDataFieldSettings.push_back(setting);
120
void ResultTester::operator()(const CellAddress& cell)
122
DataPilotTablePositionData posData = mxDPTab->getPositionData(cell);
124
if (posData.PositionType != DataPilotTablePositionType::RESULT)
125
// This cell doesn't belong to the result area. Bail out.
128
DataPilotTableResultData resData;
129
if (!(posData.PositionData >>= resData))
130
// For whatever reason unpacking of the result data failed. Bail out.
133
vector<DataTable::Filter> filters;
134
sal_Int32 filterSize = resData.FieldFilters.getLength();
135
filters.reserve(filterSize);
136
for (sal_Int32 i = 0; i < filterSize; ++i)
138
sal_Int32 nFieldId = maData.CacheTable.getFieldIndex(resData.FieldFilters[i].FieldName);
142
DataTable::Filter filter;
143
filter.FieldIndex = nFieldId;
144
filter.MatchStrId = DataTable::getStringId(resData.FieldFilters[i].MatchValue);
145
filters.push_back(filter);
149
// ID only for the data field set, not the actual column ID.
150
sal_Int32 nId = resData.DataFieldIndex;
151
const DataFieldSetting& setting = maDataFieldSettings.at(nId);
153
if (setting.FieldRef.get())
155
// referenced item exists.
156
switch (setting.FieldRef->ReferenceType)
158
case DataPilotFieldReferenceType::ITEM_DIFFERENCE:
159
case DataPilotFieldReferenceType::ITEM_PERCENTAGE:
160
case DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
161
case DataPilotFieldReferenceType::RUNNING_TOTAL:
162
verifyRefValue(cell, setting, filters, resData.Result);
165
case DataPilotFieldReferenceType::ROW_PERCENTAGE:
166
case DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
167
case DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
168
verifyPercentValue(cell, setting, filters, resData.Result);
170
case DataPilotFieldReferenceType::INDEX:
176
// normal display mode with no reference
178
Reference<XCell> xCell = maData.OutputSheetRef->getCellByPosition(cell.Column, cell.Row);
179
if (xCell->getType() != table::CellContentType_VALUE)
181
fprintf(stdout, "Error: cell not value (%ld, %ld)\n", cell.Row, cell.Column);
186
// This ID is the actual column ID of the data field.
187
const sal_Int32 nFieldId = setting.FieldId;
188
const sheet::GeneralFunction func = setting.Function;
189
double val1 = xCell->getValue();
190
double val2 = maData.CacheTable.aggregateValue(filters, nFieldId, func);
193
fprintf(stdout, "Error: values differ (%ld, %ld) : real value = %g check value = %g (%s)\n",
194
cell.Row, cell.Column,
195
val1, val2, getFunctionName(func).c_str());
202
sal_Int16 ResultTester::getFailureCount() const
204
return mnFailureCount;
207
void ResultTester::verifyRefValue(const CellAddress& cell,
208
const DataFieldSetting& setting,
209
const vector<DataTable::Filter>& filters,
210
const DataResult& result)
212
Reference<XCell> xCell = maData.OutputSheetRef->getCellByPosition(cell.Column, cell.Row);
213
table::CellContentType cellType = xCell->getType();
214
double valCell = xCell->getValue();
216
CellRangeAddress resRange = mxDPTab->getOutputRangeByType(DataPilotTableRegion::RESULT);
217
bool isRowSubtotal = (result.Flags & DataResultFlags::SUBTOTAL) && (resRange.EndColumn == cell.Column);
218
bool isColSubtotal = (result.Flags & DataResultFlags::SUBTOTAL) && (resRange.EndRow == cell.Row);
220
const DataPilotFieldReference& ref = *setting.FieldRef;
221
sal_Int32 refFieldId = maData.CacheTable.getFieldIndex(ref.ReferenceField);
222
DataPilotFieldOrientation refOrient = maData.FieldOrientations.at(refFieldId);
224
if (refOrient == DataPilotFieldOrientation_COLUMN && isRowSubtotal &&
225
cellType == table::CellContentType_EMPTY)
229
if (refOrient == DataPilotFieldOrientation_ROW && isColSubtotal &&
230
cellType == table::CellContentType_EMPTY)
231
// This is also expected.
234
const sal_Int32 nFieldId = setting.FieldId;
235
const sheet::GeneralFunction func = setting.Function;
237
// Obtain the aggregate value with the original filter set.
238
double valOrig = maData.CacheTable.aggregateValue(filters, nFieldId, func);
240
// Go through the filters and find the field that matches the referenced field, then
241
// replace the match value with the referenced item name.
242
vector<DataTable::Filter> filters2;
243
vector<DataTable::Filter>::const_iterator itr = filters.begin(), itrEnd = filters.end();
244
bool isRefItem = false;
245
for (; itr != itrEnd; ++itr)
247
if (itr->FieldIndex == refFieldId)
249
// This is the referenced field. Replace the match value with
250
// the referenced item name.
251
DataTable::Filter filter(*itr);
252
sal_Int32 newStrId = DataTable::getStringId(ref.ReferenceItemName);
253
if (filter.MatchStrId == newStrId)
256
filter.MatchStrId = newStrId;
257
filters2.push_back(filter);
260
filters2.push_back(*itr);
263
double valRef = maData.CacheTable.aggregateValue(filters2, nFieldId, func);
265
switch (ref.ReferenceType)
267
case DataPilotFieldReferenceType::NONE:
268
/* no reference mode. */
269
fprintf(stdout, "Error: reference type is set to NONE\n");
273
case DataPilotFieldReferenceType::ITEM_DIFFERENCE:
275
/* subtract the reference value and display the difference. */
277
if (isRefItem && cellType == table::CellContentType_EMPTY)
278
// the referenced item should be empty.
281
if (valCell != valOrig - valRef)
283
fprintf(stdout, "Error: values differ (%ld, %ld) : real value = %g check value %g - %g = %g (%s)\n",
284
cell.Row, cell.Column,
285
valCell, valOrig, valRef, valOrig - valRef,
286
getFunctionName(func).c_str());
291
case DataPilotFieldReferenceType::ITEM_PERCENTAGE:
293
/* each result is dividied by its reference value. */
297
// This is division by zero. The cell result should also be an error.
298
if ((result.Flags & DataResultFlags::ERROR))
300
fprintf(stdout, "Info: division by zero for referenced item (%s)\n",
301
getReferenceTypeName(ref.ReferenceType).c_str());
308
double res = valOrig/valRef;
309
if (!compare(valCell, res))
311
fprintf(stdout, "Error: values differ (%ld, %ld) : real value = %.10f check value %g/%g = %.10f (%s)\n",
312
cell.Row, cell.Column,
313
valCell, valOrig, valRef, res,
314
getFunctionName(func).c_str());
319
case DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
321
/* from each result, its reference value is subtracted, and the
322
* difference is further divided by the reference value.
325
if (isRefItem && cellType == table::CellContentType_EMPTY)
326
// the referenced item should be empty.
329
double res = (valOrig-valRef)/valRef;
330
if (!compare(valCell, res))
332
fprintf(stdout, "Error: values differ (%ld, %ld) : real value = %.10f check value (%g-%g)/%g = %.10f (delta = %.10f) (%s)\n",
333
cell.Row, cell.Column,
334
valCell, valOrig, valRef, valRef, res, valCell-res,
335
getFunctionName(func).c_str());
340
case DataPilotFieldReferenceType::RUNNING_TOTAL:
342
/* Each result is added to the sum of the results for preceding
343
* items in the base field, in the base field's sort order, and
344
* the total sum is shown.
347
fprintf(stdout, "* TEST CODE NOT IMPLEMENTED (%ld, %ld)\n", cell.Row, cell.Column);
352
fprintf(stdout, "* UNKNOWN REFERENCE TYPE (%ld, %ld)\n",
353
cell.Row, cell.Column);
358
void ResultTester::verifyPercentValue(const ::com::sun::star::table::CellAddress& cell,
359
const DataFieldSetting& setting,
360
const vector<DataTable::Filter>& filters,
361
const DataResult& result)
363
const sal_Int32 nFieldId = setting.FieldId;
364
const sheet::GeneralFunction func = setting.Function;
365
const DataPilotFieldReference& ref = *setting.FieldRef;
366
sal_Int32 refFieldId = maData.CacheTable.getFieldIndex(ref.ReferenceField);
367
DataPilotFieldOrientation refOrient = maData.FieldOrientations.at(refFieldId);
369
// Obtain the aggregate value with the original filter set.
370
double valOrig = maData.CacheTable.aggregateValue(filters, nFieldId, func);
372
// Go through the filters and find the field that matches the referenced field, then
373
// replace the match value with the referenced item name.
374
vector<DataTable::Filter> filters2;
375
vector<DataTable::Filter>::const_iterator itr = filters.begin(), itrEnd = filters.end();
376
bool isRefItem = false;
377
for (; itr != itrEnd; ++itr)
379
if (itr->FieldIndex == refFieldId)
381
// This is the referenced field. Replace the match value with
382
// the referenced item name.
383
DataTable::Filter filter(*itr);
384
sal_Int32 newStrId = DataTable::getStringId(ref.ReferenceItemName);
385
if (filter.MatchStrId == newStrId)
388
filter.MatchStrId = newStrId;
389
filters2.push_back(filter);
392
filters2.push_back(*itr);
395
Reference<XCell> xCell = maData.OutputSheetRef->getCellByPosition(cell.Column, cell.Row);
396
table::CellContentType cellType = xCell->getType();
397
double valCell = xCell->getValue();
399
CellRangeAddress resRange = mxDPTab->getOutputRangeByType(DataPilotTableRegion::RESULT);
400
bool isRowSubtotal = (result.Flags & DataResultFlags::SUBTOTAL) && (resRange.EndColumn == cell.Column);
401
bool isColSubtotal = (result.Flags & DataResultFlags::SUBTOTAL) && (resRange.EndRow == cell.Row);
402
double valRef = maData.CacheTable.aggregateValue(filters2, nFieldId, func);
404
switch (ref.ReferenceType)
406
case DataPilotFieldReferenceType::ROW_PERCENTAGE:
408
// Each result is divided by the total result for its row in
409
// the DataPilot table.
410
fprintf(stdout, "* TEST CODE NOT IMPLEMENTED (%ld, %ld)\n", cell.Row, cell.Column);
414
case DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
416
// Same as DataPilotFieldReferenceType::ROW_PERCENTAGE , but the total
417
// for the result's column is used.
418
fprintf(stdout, "* TEST CODE NOT IMPLEMENTED (%ld, %ld)\n", cell.Row, cell.Column);
422
case DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
424
// Same as DataPilotFieldReferenceType::ROW_PERCENTAGE , but the grand
425
// total for the result's data field is used.
426
fprintf(stdout, "* TEST CODE NOT IMPLEMENTED (%ld, %ld)\n", cell.Row, cell.Column);
430
case DataPilotFieldReferenceType::INDEX:
432
// The row and column totals and the grand total, following the same
433
// rules as above, are used to calculate the following expression.
434
fprintf(stdout, "* TEST CODE NOT IMPLEMENTED (%ld, %ld)\n", cell.Row, cell.Column);
439
fprintf(stdout, "* UNKNOWN REFERENCE TYPE (%ld, %ld)\n",
440
cell.Row, cell.Column);
445
void ResultTester::fail()
447
throw RuntimeException();