summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sc/CppunitTest_sc_ucalc.mk1
-rw-r--r--sc/qa/unit/ucalc.cxx2127
-rw-r--r--sc/qa/unit/ucalc.hxx28
-rw-r--r--sc/qa/unit/ucalc_pivottable.cxx2079
4 files changed, 2127 insertions, 2108 deletions
diff --git a/sc/CppunitTest_sc_ucalc.mk b/sc/CppunitTest_sc_ucalc.mk
index 15e1b616fd1a..623639b091ed 100644
--- a/sc/CppunitTest_sc_ucalc.mk
+++ b/sc/CppunitTest_sc_ucalc.mk
@@ -13,6 +13,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,sc_ucalc))
$(eval $(call gb_CppunitTest_add_exception_objects,sc_ucalc, \
sc/qa/unit/ucalc \
+ sc/qa/unit/ucalc_pivottable \
sc/qa/unit/ucalc_sharedformula \
))
diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 06c5b83c85fd..6d2d0fcaf1d7 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -15,7 +15,6 @@
#include "scdll.hxx"
#include "formulacell.hxx"
-#include "document.hxx"
#include "stringutil.hxx"
#include "scmatrix.hxx"
#include "drwlayer.hxx"
@@ -39,12 +38,6 @@
#include "funcdesc.hxx"
#include "externalrefmgr.hxx"
-#include "dpshttab.hxx"
-#include "dpobject.hxx"
-#include "dpsave.hxx"
-#include "dpdimsave.hxx"
-#include "dpcache.hxx"
-#include "dpfilteredcache.hxx"
#include "calcconfig.hxx"
#include "interpre.hxx"
#include "columniterator.hxx"
@@ -55,6 +48,7 @@
#include "scopetools.hxx"
#include "dociter.hxx"
#include "docsh.hxx"
+#include "queryparam.hxx"
#include "formula/IFunctionDescription.hxx"
@@ -69,13 +63,6 @@
#include <sfx2/docfile.hxx>
-#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
-#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
-#include <com/sun/star/sheet/DataPilotFieldReference.hpp>
-#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
-#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
-#include <com/sun/star/sheet/GeneralFunction.hpp>
-
#include <iostream>
#include <sstream>
#include <vector>
@@ -98,48 +85,6 @@ FormulaGrammarSwitch::~FormulaGrammarSwitch()
mpDoc->SetGrammar(meOldGrammar);
}
-void printRange(ScDocument* pDoc, const ScRange& rRange, const char* pCaption)
-{
- SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
- SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
- SheetPrinter printer(nRow2 - nRow1 + 1, nCol2 - nCol1 + 1);
- for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
- {
- for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
- {
- OUString aVal = pDoc->GetString(nCol, nRow, rRange.aStart.Tab());
- printer.set(nRow-nRow1, nCol-nCol1, aVal);
- }
- }
- printer.print(pCaption);
-}
-
-template<size_t _Size>
-ScRange insertRangeData(ScDocument* pDoc, const ScAddress& rPos, const char* aData[][_Size], size_t nRowCount)
-{
- ScRange aRange(rPos);
- aRange.aEnd.SetCol(rPos.Col()+_Size-1);
- aRange.aEnd.SetRow(rPos.Row()+nRowCount-1);
-
- Test::clearRange(pDoc, aRange);
-
- for (size_t i = 0; i < _Size; ++i)
- {
- for (size_t j = 0; j < nRowCount; ++j)
- {
- if (!aData[j][i])
- continue;
-
- SCCOL nCol = i + rPos.Col();
- SCROW nRow = j + rPos.Row();
- pDoc->SetString(nCol, nRow, rPos.Tab(), OUString(aData[j][i], strlen(aData[j][i]), RTL_TEXTENCODING_UTF8));
- }
- }
-
- printRange(pDoc, aRange, "Range data content");
- return aRange;
-}
-
class MeasureTimeSwitch
{
double& mrDiff;
@@ -1027,7 +972,7 @@ void runTestMATCH(ScDocument* pDoc, const char* aData[_DataSize], StrStrCheck aC
}
pDoc->CalcAll();
- printRange(pDoc, ScRange(0, 0, 0, 2, _FormulaSize-1, 0), "MATCH");
+ Test::printRange(pDoc, ScRange(0, 0, 0, 2, _FormulaSize-1, 0), "MATCH");
// verify the results.
for (size_t i = 0; i < _FormulaSize; ++i)
@@ -1505,7 +1450,7 @@ template<size_t _Size>
bool checkHorizontalIterator(ScDocument* pDoc, const char* pData[][_Size], size_t nDataCount, const HoriIterCheck* pChecks, size_t nCheckCount)
{
ScAddress aPos(0,0,0);
- insertRangeData(pDoc, aPos, pData, nDataCount);
+ Test::insertRangeData(pDoc, aPos, pData, nDataCount);
ScHorizontalCellIterator aIter(pDoc, 0, 0, 0, 1, nDataCount-1);
SCCOL nCol;
@@ -2308,2056 +2253,6 @@ void Test::testEnterMixedMatrix()
m_pDoc->DeleteTab(0);
}
-namespace {
-
-struct DPFieldDef
-{
- const char* pName;
- sheet::DataPilotFieldOrientation eOrient;
-
- /**
- * Function for data field. It's used only for data field. When 0, the
- * default function (SUM) is used.
- */
- int eFunc;
-};
-
-template<size_t _Size>
-ScRange insertDPSourceData(ScDocument* pDoc, DPFieldDef aFields[], size_t nFieldCount, const char* aData[][_Size], size_t nDataCount)
-{
- // Insert field names in row 0.
- for (size_t i = 0; i < nFieldCount; ++i)
- pDoc->SetString(static_cast<SCCOL>(i), 0, 0, OUString(aFields[i].pName, strlen(aFields[i].pName), RTL_TEXTENCODING_UTF8));
-
- // Insert data into row 1 and downward.
- for (size_t i = 0; i < nDataCount; ++i)
- {
- SCROW nRow = static_cast<SCROW>(i) + 1;
- for (size_t j = 0; j < nFieldCount; ++j)
- {
- SCCOL nCol = static_cast<SCCOL>(j);
- pDoc->SetString(
- nCol, nRow, 0, OUString(aData[i][j], strlen(aData[i][j]), RTL_TEXTENCODING_UTF8));
- }
- }
-
- SCROW nRow1 = 0, nRow2 = 0;
- SCCOL nCol1 = 0, nCol2 = 0;
- pDoc->GetDataArea(0, nCol1, nRow1, nCol2, nRow2, true, false);
- CPPUNIT_ASSERT_MESSAGE("Data is expected to start from (col=0,row=0).", nCol1 == 0 && nRow1 == 0);
- CPPUNIT_ASSERT_MESSAGE("Unexpected data range.",
- nCol2 == static_cast<SCCOL>(nFieldCount - 1) && nRow2 == static_cast<SCROW>(nDataCount));
-
- ScRange aSrcRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
- printRange(pDoc, aSrcRange, "Data sheet content");
- return aSrcRange;
-}
-
-template<size_t _Size>
-bool checkDPTableOutput(ScDocument* pDoc, const ScRange& aOutRange, const char* aOutputCheck[][_Size], const char* pCaption)
-{
- bool bResult = true;
- const ScAddress& s = aOutRange.aStart;
- const ScAddress& e = aOutRange.aEnd;
- SheetPrinter printer(e.Row() - s.Row() + 1, e.Col() - s.Col() + 1);
- SCROW nOutRowSize = e.Row() - s.Row() + 1;
- SCCOL nOutColSize = e.Col() - s.Col() + 1;
- for (SCROW nRow = 0; nRow < nOutRowSize; ++nRow)
- {
- for (SCCOL nCol = 0; nCol < nOutColSize; ++nCol)
- {
- OUString aVal = pDoc->GetString(nCol + s.Col(), nRow + s.Row(), s.Tab());
- printer.set(nRow, nCol, aVal);
- const char* p = aOutputCheck[nRow][nCol];
- if (p)
- {
- OUString aCheckVal = OUString::createFromAscii(p);
- bool bEqual = aCheckVal.equals(aVal);
- if (!bEqual)
- {
- cout << "Expected: " << aCheckVal << " Actual: " << aVal << endl;
- bResult = false;
- }
- }
- else if (!aVal.isEmpty())
- {
- cout << "Empty cell expected" << endl;
- bResult = false;
- }
- }
- }
- printer.print(pCaption);
- return bResult;
-}
-
-ScDPObject* createDPFromSourceDesc(
- ScDocument* pDoc, const ScSheetSourceDesc& rDesc, DPFieldDef aFields[], size_t nFieldCount,
- bool bFilterButton)
-{
- ScDPObject* pDPObj = new ScDPObject(pDoc);
- pDPObj->SetSheetDesc(rDesc);
- pDPObj->SetOutRange(ScAddress(0, 0, 1));
-
- ScDPSaveData aSaveData;
- // Set data pilot table output options.
- aSaveData.SetIgnoreEmptyRows(false);
- aSaveData.SetRepeatIfEmpty(false);
- aSaveData.SetColumnGrand(true);
- aSaveData.SetRowGrand(true);
- aSaveData.SetFilterButton(bFilterButton);
- aSaveData.SetDrillDown(true);
-
- // Check the sanity of the source range.
- const ScRange& rSrcRange = rDesc.GetSourceRange();
- SCROW nRow1 = rSrcRange.aStart.Row();
- SCROW nRow2 = rSrcRange.aEnd.Row();
- CPPUNIT_ASSERT_MESSAGE("source range contains no data!", nRow2 - nRow1 > 1);
-
- // Set the dimension information.
- for (size_t i = 0; i < nFieldCount; ++i)
- {
- OUString aDimName = OUString::createFromAscii(aFields[i].pName);
- ScDPSaveDimension* pDim = aSaveData.GetNewDimensionByName(aDimName);
- pDim->SetOrientation(static_cast<sal_uInt16>(aFields[i].eOrient));
- pDim->SetUsedHierarchy(0);
-
- if (aFields[i].eOrient == sheet::DataPilotFieldOrientation_DATA)
- {
- sheet::GeneralFunction eFunc = sheet::GeneralFunction_SUM;
- if (aFields[i].eFunc)
- eFunc = static_cast<sheet::GeneralFunction>(aFields[i].eFunc);
-
- pDim->SetFunction(eFunc);
- pDim->SetReferenceValue(NULL);
- }
- else
- {
- sheet::DataPilotFieldSortInfo aSortInfo;
- aSortInfo.IsAscending = true;
- aSortInfo.Mode = 2;
- pDim->SetSortInfo(&aSortInfo);
-
- sheet::DataPilotFieldLayoutInfo aLayInfo;
- aLayInfo.LayoutMode = 0;
- aLayInfo.AddEmptyLines = false;
- pDim->SetLayoutInfo(&aLayInfo);
- sheet::DataPilotFieldAutoShowInfo aShowInfo;
- aShowInfo.IsEnabled = false;
- aShowInfo.ShowItemsMode = 0;
- aShowInfo.ItemCount = 0;
- pDim->SetAutoShowInfo(&aShowInfo);
- }
- }
-
- // Don't forget the data layout dimension.
- ScDPSaveDimension* pDim = aSaveData.GetDataLayoutDimension();
- pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
- pDim->SetShowEmpty(true);
-
- pDPObj->SetSaveData(aSaveData);
- pDPObj->InvalidateData();
-
- return pDPObj;
-}
-
-ScDPObject* createDPFromRange(
- ScDocument* pDoc, const ScRange& rRange, DPFieldDef aFields[], size_t nFieldCount,
- bool bFilterButton)
-{
- ScSheetSourceDesc aSheetDesc(pDoc);
- aSheetDesc.SetSourceRange(rRange);
- return createDPFromSourceDesc(pDoc, aSheetDesc, aFields, nFieldCount, bFilterButton);
-}
-
-ScRange refresh(ScDPObject* pDPObj)
-{
- bool bOverFlow = false;
- ScRange aOutRange = pDPObj->GetNewOutputRange(bOverFlow);
- CPPUNIT_ASSERT_MESSAGE("Table overflow!?", !bOverFlow);
-
- pDPObj->Output(aOutRange.aStart);
- aOutRange = pDPObj->GetOutRange();
- return aOutRange;
-}
-
-ScRange refreshGroups(ScDPCollection* pDPs, ScDPObject* pDPObj)
-{
- // We need to first create group data in the cache, then the group data in
- // the object.
- std::set<ScDPObject*> aRefs;
- bool bSuccess = pDPs->ReloadGroupsInCache(pDPObj, aRefs);
- CPPUNIT_ASSERT_MESSAGE("Failed to reload group data in cache.", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("There should be only one table linked to this cache.", aRefs.size() == 1);
- pDPObj->ReloadGroupTableData();
-
- return refresh(pDPObj);
-}
-
-}
-
-void Test::testPivotTable()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Group", sheet::DataPilotFieldOrientation_COLUMN, 0 },
- { "Score", sheet::DataPilotFieldOrientation_DATA, 0 }
- };
-
- // Raw data
- const char* aData[][3] = {
- { "Andy", "A", "30" },
- { "Bruce", "A", "20" },
- { "Charlie", "B", "45" },
- { "David", "B", "12" },
- { "Edward", "C", "8" },
- { "Frank", "C", "15" },
- };
-
- size_t nFieldCount = SAL_N_ELEMENTS(aFields);
- size_t nDataCount = SAL_N_ELEMENTS(aData);
-
- ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
- SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
- SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- bool bOverFlow = false;
- ScRange aOutRange = pDPObj->GetNewOutputRange(bOverFlow);
- CPPUNIT_ASSERT_MESSAGE("Table overflow!?", !bOverFlow);
-
- pDPObj->Output(aOutRange.aStart);
- aOutRange = pDPObj->GetOutRange();
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][5] = {
- { "Sum - Score", "Group", 0, 0, 0 },
- { "Name", "A", "B", "C", "Total Result" },
- { "Andy", "30", 0, 0, "30" },
- { "Bruce", "20", 0, 0, "20" },
- { "Charlie", 0, "45", 0, "45" },
- { "David", 0, "12", 0, "12" },
- { "Edward", 0, 0, "8", "8" },
- { "Frank", 0, 0, "15", "15" },
- { "Total Result", "50", "57", "23", "130" }
- };
-
- bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
- CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
-
- // Update the cell values.
- double aData2[] = { 100, 200, 300, 400, 500, 600 };
- for (size_t i = 0; i < SAL_N_ELEMENTS(aData2); ++i)
- {
- SCROW nRow = i + 1;
- m_pDoc->SetValue(2, nRow, 0, aData2[i]);
- }
-
- printRange(m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), "Data sheet content (modified)");
-
- // Now, create a copy of the datapilot object for the updated table, but
- // don't reload the cache which should force the copy to use the old data
- // from the cache.
- ScDPObject* pDPObj2 = new ScDPObject(*pDPObj);
- pDPs->InsertNewTable(pDPObj2);
-
- aOutRange = pDPObj2->GetOutRange();
- pDPObj2->ClearTableData();
- pDPObj2->Output(aOutRange.aStart);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][5] = {
- { "Sum - Score", "Group", 0, 0, 0 },
- { "Name", "A", "B", "C", "Total Result" },
- { "Andy", "30", 0, 0, "30" },
- { "Bruce", "20", 0, 0, "20" },
- { "Charlie", 0, "45", 0, "45" },
- { "David", 0, "12", 0, "12" },
- { "Edward", 0, 0, "8", "8" },
- { "Frank", 0, 0, "15", "15" },
- { "Total Result", "50", "57", "23", "130" }
- };
-
- bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (from old cache)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
-
- // Free the first datapilot object after the 2nd one gets reloaded, to
- // prevent the data cache from being deleted before the reload.
- pDPs->FreeTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
-
- // This time clear the cache to refresh the data from the source range.
- CPPUNIT_ASSERT_MESSAGE("This datapilot should be based on sheet data.", pDPObj2->IsSheetData());
- std::set<ScDPObject*> aRefs;
- sal_uLong nErrId = pDPs->ReloadCache(pDPObj2, aRefs);
- CPPUNIT_ASSERT_MESSAGE("Cache reload failed.", nErrId == 0);
- CPPUNIT_ASSERT_MESSAGE("Reloading a cache shouldn't remove any cache.",
- pDPs->GetSheetCaches().size() == 1);
-
- pDPObj2->ClearTableData();
- pDPObj2->Output(aOutRange.aStart);
-
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][5] = {
- { "Sum - Score", "Group", 0, 0, 0 },
- { "Name", "A", "B", "C", "Total Result" },
- { "Andy", "100", 0, 0, "100" },
- { "Bruce", "200", 0, 0, "200" },
- { "Charlie", 0, "300", 0, "300" },
- { "David", 0, "400", 0, "400" },
- { "Edward", 0, 0, "500", "500" },
- { "Frank", 0, 0, "600", "600" },
- { "Total Result", "300", "700", "1100", "2100" }
- };
-
- bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (refreshed)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- CPPUNIT_ASSERT_MESSAGE("Cache should be here.", pDPs->GetSheetCaches().hasCache(aSrcRange));
-
- // Swap the two sheets.
- m_pDoc->MoveTab(1, 0);
- CPPUNIT_ASSERT_MESSAGE("Swapping the sheets shouldn't remove the cache.",
- pDPs->GetSheetCaches().size() == 1);
- CPPUNIT_ASSERT_MESSAGE("Cache should have moved.", !pDPs->GetSheetCaches().hasCache(aSrcRange));
- aSrcRange.aStart.SetTab(1);
- aSrcRange.aEnd.SetTab(1);
- CPPUNIT_ASSERT_MESSAGE("Cache should be here.", pDPs->GetSheetCaches().hasCache(aSrcRange));
-
- pDPs->FreeTable(pDPObj2);
- CPPUNIT_ASSERT_MESSAGE("There shouldn't be any data pilot table stored with the document.",
- pDPs->GetCount() == 0);
-
- CPPUNIT_ASSERT_MESSAGE("There shouldn't be any more data cache.",
- pDPs->GetSheetCaches().size() == 0);
-
- // Insert a brand new pivot table object once again, but this time, don't
- // create the output to avoid creating a data cache.
- m_pDoc->DeleteTab(1);
- m_pDoc->InsertTab(1, OUString("Table"));
-
- pDPObj = createDPFromRange(
- m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
- bSuccess = pDPs->InsertNewTable(pDPObj);
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
- CPPUNIT_ASSERT_MESSAGE("Data cache shouldn't exist yet before creating the table output.",
- pDPs->GetSheetCaches().size() == 0);
-
- // Now, "refresh" the table. This should still return a reference to self
- // even with the absence of data cache.
- aRefs.clear();
- pDPs->ReloadCache(pDPObj, aRefs);
- CPPUNIT_ASSERT_MESSAGE("It should return the same object as a reference.",
- aRefs.size() == 1 && *aRefs.begin() == pDPObj);
-
- pDPs->FreeTable(pDPObj);
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableLabels()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Software", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Version", sheet::DataPilotFieldOrientation_COLUMN, 0 },
- { "1.2.3", sheet::DataPilotFieldOrientation_DATA, 0 }
- };
-
- // Raw data
- const char* aData[][3] = {
- { "LibreOffice", "3.3.0", "30" },
- { "LibreOffice", "3.3.1", "20" },
- { "LibreOffice", "3.4.0", "45" },
- };
-
- size_t nFieldCount = SAL_N_ELEMENTS(aFields);
- size_t nDataCount = SAL_N_ELEMENTS(aData);
-
- ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
- SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
- SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][5] = {
- { "Sum - 1.2.3", "Version", 0, 0, 0 },
- { "Software", "3.3.0", "3.3.1", "3.4.0", "Total Result" },
- { "LibreOffice", "30", "20", "45", "95" },
- { "Total Result", "30", "20", "45", "95" }
- };
-
- bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- pDPs->FreeTable(pDPObj);
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableDateLabels()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Date", sheet::DataPilotFieldOrientation_COLUMN, 0 },
- { "Value", sheet::DataPilotFieldOrientation_DATA, 0 }
- };
-
- // Raw data
- const char* aData[][3] = {
- { "Zena", "2011-1-1", "30" },
- { "Yodel", "2011-1-2", "20" },
- { "Xavior", "2011-1-3", "45" }
- };
-
- size_t nFieldCount = SAL_N_ELEMENTS(aFields);
- size_t nDataCount = SAL_N_ELEMENTS(aData);
-
- ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
- SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
- SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][5] = {
- { "Sum - Value", "Date", 0, 0, 0 },
- { "Name", "2011-01-01", "2011-01-02", "2011-01-03", "Total Result" },
- { "Xavior", 0, 0, "45", "45" },
- { "Yodel", 0, "20", 0, "20" },
- { "Zena", "30", 0, 0, "30" },
- { "Total Result", "30", "20", "45", "95" }
- };
-
- bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- {
- const char* aChecks[] = {
- "2011-01-01", "2011-01-02", "2011-01-03"
- };
-
- // Make sure those cells that contain dates are numeric.
- SCROW nRow = aOutRange.aStart.Row() + 1;
- nCol1 = aOutRange.aStart.Col() + 1;
- nCol2 = nCol1 + 2;
- for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
- {
- OUString aVal = m_pDoc->GetString(nCol, nRow, 1);
- CPPUNIT_ASSERT_MESSAGE("Cell value is not as expected.", aVal.equalsAscii(aChecks[nCol-nCol1]));
- CPPUNIT_ASSERT_MESSAGE("This cell contains a date value and is supposed to be numeric.",
- m_pDoc->HasValueData(nCol, nRow, 1));
- }
- }
-
- pDPs->FreeTable(pDPObj);
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableFilters()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_HIDDEN, 0 },
- { "Group1", sheet::DataPilotFieldOrientation_HIDDEN, 0 },
- { "Group2", sheet::DataPilotFieldOrientation_PAGE, 0 },
- { "Val1", sheet::DataPilotFieldOrientation_DATA, 0 },
- { "Val2", sheet::DataPilotFieldOrientation_DATA, 0 }
- };
-
- // Raw data
- const char* aData[][5] = {
- { "A", "1", "A", "1", "10" },
- { "B", "1", "A", "1", "10" },
- { "C", "1", "B", "1", "10" },
- { "D", "1", "B", "1", "10" },
- { "E", "2", "A", "1", "10" },
- { "F", "2", "A", "1", "10" },
- { "G", "2", "B", "1", "10" },
- { "H", "2", "B", "1", "10" }
- };
-
- size_t nFieldCount = SAL_N_ELEMENTS(aFields);
- size_t nDataCount = SAL_N_ELEMENTS(aData);
-
- ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
- SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
- SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, true);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Filter", 0 },
- { "Group2", "- all -" },
- { 0, 0 },
- { "Data", 0 },
- { "Sum - Val1", "8" },
- { "Sum - Val2", "80" }
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (unfiltered)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation.
-
- ScAddress aFormulaAddr = aOutRange.aEnd;
- aFormulaAddr.IncRow(2);
- m_pDoc->SetString(aFormulaAddr.Col(), aFormulaAddr.Row(), aFormulaAddr.Tab(),
- OUString("=B6"));
- double fTest = m_pDoc->GetValue(aFormulaAddr);
- CPPUNIT_ASSERT_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", fTest == 80.0);
-
- // Set current page of 'Group2' to 'A'.
- pDPObj->BuildAllDimensionMembers();
- ScDPSaveData aSaveData(*pDPObj->GetSaveData());
- ScDPSaveDimension* pPageDim = aSaveData.GetDimensionByName(
- OUString("Group2"));
- CPPUNIT_ASSERT_MESSAGE("Dimension not found", pPageDim);
- OUString aPage("A");
- pPageDim->SetCurrentPage(&aPage);
- pDPObj->SetSaveData(aSaveData);
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Filter", 0 },
- { "Group2", "A" },
- { 0, 0 },
- { "Data", 0 },
- { "Sum - Val1", "4" },
- { "Sum - Val2", "40" }
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by page)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- fTest = m_pDoc->GetValue(aFormulaAddr);
- CPPUNIT_ASSERT_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", fTest == 40.0);
-
- // Set query filter.
- ScSheetSourceDesc aDesc(*pDPObj->GetSheetDesc());
- ScQueryParam aQueryParam(aDesc.GetQueryParam());
- CPPUNIT_ASSERT_MESSAGE("There should be at least one query entry.", aQueryParam.GetEntryCount() > 0);
- ScQueryEntry& rEntry = aQueryParam.GetEntry(0);
- rEntry.bDoQuery = true;
- rEntry.nField = 1; // Group1
- rEntry.GetQueryItem().mfVal = 1;
- aDesc.SetQueryParam(aQueryParam);
- pDPObj->SetSheetDesc(aDesc);
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Filter", 0 },
- { "Group2", "A" },
- { 0, 0 },
- { "Data", 0 },
- { "Sum - Val1", "2" },
- { "Sum - Val2", "20" }
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by query)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- fTest = m_pDoc->GetValue(aFormulaAddr);
- CPPUNIT_ASSERT_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", fTest == 20.0);
-
- // Set the current page of 'Group2' back to '- all -'. The query filter
- // should still be in effect.
- pPageDim->SetCurrentPage(NULL); // Remove the page.
- pDPObj->SetSaveData(aSaveData);
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Filter", 0 },
- { "Group2", "- all -" },
- { 0, 0 },
- { "Data", 0 },
- { "Sum - Val1", "4" },
- { "Sum - Val2", "40" }
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by page)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_MESSAGE("There shouldn't be any data pilot table stored with the document.",
- pDPs->GetCount() == 0);
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableNamedSource()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Group", sheet::DataPilotFieldOrientation_COLUMN, 0 },
- { "Score", sheet::DataPilotFieldOrientation_DATA, 0 }
- };
-
- // Raw data
- const char* aData[][3] = {
- { "Andy", "A", "30" },
- { "Bruce", "A", "20" },
- { "Charlie", "B", "45" },
- { "David", "B", "12" },
- { "Edward", "C", "8" },
- { "Frank", "C", "15" },
- };
-
- size_t nFieldCount = SAL_N_ELEMENTS(aFields);
- size_t nDataCount = SAL_N_ELEMENTS(aData);
-
- // Insert the raw data.
- ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
- OUString aRangeStr;
- aSrcRange.Format(aRangeStr, SCR_ABS_3D, m_pDoc);
-
- // Name this range.
- OUString aRangeName("MyData");
- ScRangeName* pNames = m_pDoc->GetRangeName();
- CPPUNIT_ASSERT_MESSAGE("Failed to get global range name container.", pNames);
- ScRangeData* pName = new ScRangeData(
- m_pDoc, aRangeName, aRangeStr);
- bool bSuccess = pNames->insert(pName);
- CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bSuccess);
-
- ScSheetSourceDesc aSheetDesc(m_pDoc);
- aSheetDesc.SetRangeName(aRangeName);
- ScDPObject* pDPObj = createDPFromSourceDesc(m_pDoc, aSheetDesc, aFields, nFieldCount, false);
- CPPUNIT_ASSERT_MESSAGE("Failed to create a new pivot table object.", pDPObj);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bSuccess = pDPs->InsertNewTable(pDPObj);
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][5] = {
- { "Sum - Score", "Group", 0, 0, 0 },
- { "Name", "A", "B", "C", "Total Result" },
- { "Andy", "30", 0, 0, "30" },
- { "Bruce", "20", 0, 0, "20" },
- { "Charlie", 0, "45", 0, "45" },
- { "David", 0, "12", 0, "12" },
- { "Edward", 0, 0, "8", "8" },
- { "Frank", 0, 0, "15", "15" },
- { "Total Result", "50", "57", "23", "130" }
- };
-
- bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- CPPUNIT_ASSERT_MESSAGE("There should be one named range data cache.",
- pDPs->GetNameCaches().size() == 1 && pDPs->GetSheetCaches().size() == 0);
-
- // Move the table with pivot table to the left of the source data sheet.
- m_pDoc->MoveTab(1, 0);
- OUString aTabName;
- m_pDoc->GetName(0, aTabName);
- CPPUNIT_ASSERT_MESSAGE( "Wrong sheet name.", aTabName == "Table" );
- CPPUNIT_ASSERT_MESSAGE("Pivot table output is on the wrong sheet!",
- pDPObj->GetOutRange().aStart.Tab() == 0);
-
- CPPUNIT_ASSERT_MESSAGE("Moving the pivot table to another sheet shouldn't have changed the cache state.",
- pDPs->GetNameCaches().size() == 1 && pDPs->GetSheetCaches().size() == 0);
-
- const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
- CPPUNIT_ASSERT_MESSAGE("Sheet source description doesn't exist.", pDesc);
- CPPUNIT_ASSERT_MESSAGE("Named source range has been altered unexpectedly!",
- pDesc->GetRangeName().equals(aRangeName));
-
- CPPUNIT_ASSERT_MESSAGE("Cache should exist.", pDPs->GetNameCaches().hasCache(aRangeName));
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_MESSAGE("There should be no more tables.", pDPs->GetCount() == 0);
- CPPUNIT_ASSERT_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetNameCaches().size() == 0);
-
- pNames->clear();
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableCache()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
-
- // Raw data
- const char* aData[][3] = {
- { "F1", "F2", "F3" },
- { "Z", "A", "30" },
- { "R", "A", "20" },
- { "A", "B", "45" },
- { "F", "B", "12" },
- { "Y", "C", "8" },
- { "12", "C", "15" },
- };
-
- ScAddress aPos(1,1,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
- CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-
- ScDPCache aCache(m_pDoc);
- aCache.InitFromDoc(m_pDoc, aDataRange);
- long nDimCount = aCache.GetColumnCount();
- CPPUNIT_ASSERT_MESSAGE("wrong dimension count.", nDimCount == 3);
- OUString aDimName = aCache.GetDimensionName(0);
- CPPUNIT_ASSERT_MESSAGE("wrong dimension name", aDimName.equalsAscii("F1"));
- aDimName = aCache.GetDimensionName(1);
- CPPUNIT_ASSERT_MESSAGE("wrong dimension name", aDimName.equalsAscii("F2"));
- aDimName = aCache.GetDimensionName(2);
- CPPUNIT_ASSERT_MESSAGE("wrong dimension name", aDimName.equalsAscii("F3"));
-
- // In each dimension, member ID values also represent their sort order (in
- // source dimensions only, not in group dimensions). Value items are
- // sorted before string ones. Also, no duplicate dimension members should
- // exist.
-
- // Dimension 0 - a mix of strings and values.
- long nMemCount = aCache.GetDimMemberCount(0);
- CPPUNIT_ASSERT_MESSAGE("wrong dimension member count", nMemCount == 6);
- const ScDPItemData* pItem = aCache.GetItemDataById(0, 0);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::Value &&
- pItem->GetValue() == 12);
- pItem = aCache.GetItemDataById(0, 1);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::String &&
- pItem->GetString().equalsAscii("A"));
- pItem = aCache.GetItemDataById(0, 2);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::String &&
- pItem->GetString().equalsAscii("F"));
- pItem = aCache.GetItemDataById(0, 3);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::String &&
- pItem->GetString().equalsAscii("R"));
- pItem = aCache.GetItemDataById(0, 4);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::String &&
- pItem->GetString().equalsAscii("Y"));
- pItem = aCache.GetItemDataById(0, 5);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::String &&
- pItem->GetString().equalsAscii("Z"));
- pItem = aCache.GetItemDataById(0, 6);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", !pItem);
-
- // Dimension 1 - duplicate values in source.
- nMemCount = aCache.GetDimMemberCount(1);
- CPPUNIT_ASSERT_MESSAGE("wrong dimension member count", nMemCount == 3);
- pItem = aCache.GetItemDataById(1, 0);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::String &&
- pItem->GetString().equalsAscii("A"));
- pItem = aCache.GetItemDataById(1, 1);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::String &&
- pItem->GetString().equalsAscii("B"));
- pItem = aCache.GetItemDataById(1, 2);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::String &&
- pItem->GetString().equalsAscii("C"));
- pItem = aCache.GetItemDataById(1, 3);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", !pItem);
-
- // Dimension 2 - values only.
- nMemCount = aCache.GetDimMemberCount(2);
- CPPUNIT_ASSERT_MESSAGE("wrong dimension member count", nMemCount == 6);
- pItem = aCache.GetItemDataById(2, 0);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::Value &&
- pItem->GetValue() == 8);
- pItem = aCache.GetItemDataById(2, 1);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::Value &&
- pItem->GetValue() == 12);
- pItem = aCache.GetItemDataById(2, 2);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::Value &&
- pItem->GetValue() == 15);
- pItem = aCache.GetItemDataById(2, 3);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::Value &&
- pItem->GetValue() == 20);
- pItem = aCache.GetItemDataById(2, 4);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::Value &&
- pItem->GetValue() == 30);
- pItem = aCache.GetItemDataById(2, 5);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
- pItem->GetType() == ScDPItemData::Value &&
- pItem->GetValue() == 45);
- pItem = aCache.GetItemDataById(2, 6);
- CPPUNIT_ASSERT_MESSAGE("wrong item value", !pItem);
-
- {
- // Check the integrity of the source data.
- ScDPItemData aTest;
- long nDim;
-
- {
- // Dimension 0: Z, R, A, F, Y, 12
- nDim = 0;
- const char* aChecks[] = { "Z", "R", "A", "F", "Y" };
- for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
- {
- pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, i, false));
- aTest.SetString(OUString::createFromAscii(aChecks[i]));
- CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
- }
-
- pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, 5, false));
- aTest.SetValue(12);
- CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
- }
-
- {
- // Dimension 1: A, A, B, B, C, C
- nDim = 1;
- const char* aChecks[] = { "A", "A", "B", "B", "C", "C" };
- for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
- {
- pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, i, false));
- aTest.SetString(OUString::createFromAscii(aChecks[i]));
- CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
- }
- }
-
- {
- // Dimension 2: 30, 20, 45, 12, 8, 15
- nDim = 2;
- double aChecks[] = { 30, 20, 45, 12, 8, 15 };
- for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
- {
- pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, i, false));
- aTest.SetValue(aChecks[i]);
- CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
- }
- }
- }
-
- // Now, on to testing the filtered cache.
-
- {
- // Non-filtered cache - everything should be visible.
- ScDPFilteredCache aFilteredCache(aCache);
- aFilteredCache.fillTable();
-
- sal_Int32 nRows = aFilteredCache.getRowSize();
- CPPUNIT_ASSERT_MESSAGE("Wrong dimension.", nRows == 6 && aFilteredCache.getColSize() == 3);
-
- for (sal_Int32 i = 0; i < nRows; ++i)
- {
- if (!aFilteredCache.isRowActive(i))
- {
- std::ostringstream os;
- os << "Row " << i << " should be visible but it isn't.";
- CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), false);
- }
- }
- }
-
- // TODO : Add test for filtered caches.
-
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableDuplicateDataFields()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Raw data
- const char* aData[][2] = {
- { "Name", "Value" },
- { "A", "45" },
- { "A", "5" },
- { "A", "41" },
- { "A", "49" },
- { "A", "4" },
- { "B", "33" },
- { "B", "84" },
- { "B", "74" },
- { "B", "8" },
- { "B", "68" }
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_COUNT }
- };
-
- ScAddress aPos(2,2,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
- CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount(), static_cast<size_t>(1));
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][3] = {
- { "Name", "Data", 0 },
- { "A", "Sum - Value", "144" },
- { 0, "Count - Value", "5" },
- { "B", "Sum - Value", "267" },
- { 0, "Count - Value", "5" },
- { "Total Sum - Value", 0, "411" },
- { "Total Count - Value", 0, "10" },
- };
-
- bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- // Move the data layout dimension from row to column.
- ScDPSaveData* pSaveData = pDPObj->GetSaveData();
- CPPUNIT_ASSERT_MESSAGE("No save data!?", pSaveData);
- ScDPSaveDimension* pDataLayout = pSaveData->GetDataLayoutDimension();
- CPPUNIT_ASSERT_MESSAGE("No data layout dimension.", pDataLayout);
- pDataLayout->SetOrientation(sheet::DataPilotFieldOrientation_COLUMN);
- pDPObj->SetSaveData(*pSaveData);
-
- // Refresh the table output.
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][3] = {
- { 0, "Data", 0 },
- { "Name", "Sum - Value", "Count - Value" },
- { "A", "144", "5" },
- { "B", "267", "5" },
- { "Total Result", "411", "10" }
- };
-
- bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- ScPivotParam aParam;
- pDPObj->FillLabelData(aParam);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 4 labels (2 original, 1 data layout, and 1 duplicate dimensions).",
- aParam.maLabelArray.size(), static_cast<size_t>(4));
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableNormalGrouping()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Raw data
- const char* aData[][2] = {
- { "Name", "Value" },
- { "A", "1" },
- { "B", "2" },
- { "C", "3" },
- { "D", "4" },
- { "E", "5" },
- { "F", "6" },
- { "G", "7" }
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- };
-
- ScAddress aPos(1,1,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
- CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount(), static_cast<size_t>(1));
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", "1" },
- { "B", "2" },
- { "C", "3" },
- { "D", "4" },
- { "E", "5" },
- { "F", "6" },
- { "G", "7" },
- { "Total Result", "28" }
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Initial output without grouping");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- ScDPSaveData* pSaveData = pDPObj->GetSaveData();
- CPPUNIT_ASSERT_MESSAGE("No save data !?", pSaveData);
- ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();
- CPPUNIT_ASSERT_MESSAGE("Failed to create dimension data.", pDimData);
-
- OUString aGroupPrefix("Group");
- OUString aBaseDimName("Name");
- OUString aGroupDimName =
- pDimData->CreateGroupDimName(aBaseDimName, *pDPObj, false, NULL);
-
- {
- // Group A, B and C together.
- ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
- OUString aGroupName = aGroupDim.CreateGroupName(aGroupPrefix);
- CPPUNIT_ASSERT_MESSAGE("Unexpected group name", aGroupName.equalsAscii("Group1"));
-
- ScDPSaveGroupItem aGroup(aGroupName);
- aGroup.AddElement(OUString("A"));
- aGroup.AddElement(OUString("B"));
- aGroup.AddElement(OUString("C"));
- aGroupDim.AddGroupItem(aGroup);
- pDimData->AddGroupDimension(aGroupDim);
-
- ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
- pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
- pSaveData->SetPosition(pDim, 0); // Set it before the base dimension.
- }
-
- pDPObj->SetSaveData(*pSaveData);
- aOutRange = refreshGroups(pDPs, pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][3] = {
- { "Name2", "Name", 0 },
- { "D", "D", "4" },
- { "E", "E", "5" },
- { "F", "F", "6" },
- { "G", "G", "7" },
- { "Group1", "A", "1" },
- { 0, "B", "2" },
- { 0, "C", "3" },
- { "Total Result", 0, "28" }
- };
-
- bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "A, B, C grouped by Group1.");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- pSaveData = pDPObj->GetSaveData();
- pDimData = pSaveData->GetDimensionData();
-
- {
- // Group D, E, F together.
- ScDPSaveGroupDimension* pGroupDim = pDimData->GetGroupDimAccForBase(aBaseDimName);
- CPPUNIT_ASSERT_MESSAGE("There should be an existing group dimension.", pGroupDim);
- OUString aGroupName = pGroupDim->CreateGroupName(aGroupPrefix);
- CPPUNIT_ASSERT_MESSAGE("Unexpected group name", aGroupName.equalsAscii("Group2"));
-
- ScDPSaveGroupItem aGroup(aGroupName);
- aGroup.AddElement(OUString("D"));
- aGroup.AddElement(OUString("E"));
- aGroup.AddElement(OUString("F"));
- pGroupDim->AddGroupItem(aGroup);
- }
-
- pDPObj->SetSaveData(*pSaveData);
- aOutRange = refreshGroups(pDPs, pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][3] = {
- { "Name2", "Name", 0 },
- { "G", "G", "7" },
- { "Group1", "A", "1" },
- { 0, "B", "2" },
- { 0, "C", "3" },
- { "Group2", "D", "4" },
- { 0, "E", "5" },
- { 0, "F", "6" },
- { "Total Result", 0, "28" }
- };
-
- bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "D, E, F grouped by Group2.");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableNumberGrouping()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Raw data
- const char* aData[][2] = {
- { "Order", "Score" },
- { "43", "171" },
- { "18", "20" },
- { "69", "159" },
- { "95", "19" },
- { "96", "163" },
- { "46", "70" },
- { "22", "36" },
- { "81", "49" },
- { "54", "61" },
- { "39", "62" },
- { "86", "17" },
- { "34", "0" },
- { "30", "25" },
- { "24", "103" },
- { "16", "59" },
- { "24", "119" },
- { "15", "86" },
- { "69", "170" }
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Order", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Score", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- };
-
- ScAddress aPos(1,1,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
- CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount(), static_cast<size_t>(1));
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScDPSaveData* pSaveData = pDPObj->GetSaveData();
- CPPUNIT_ASSERT_MESSAGE("No save data !?", pSaveData);
- ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();
- CPPUNIT_ASSERT_MESSAGE("No dimension data !?", pDimData);
-
- {
- ScDPNumGroupInfo aInfo;
- aInfo.mbEnable = true;
- aInfo.mbAutoStart = false;
- aInfo.mbAutoEnd = false;
- aInfo.mbDateValues = false;
- aInfo.mbIntegerOnly = true;
- aInfo.mfStart = 30;
- aInfo.mfEnd = 60;
- aInfo.mfStep = 10;
- ScDPSaveNumGroupDimension aGroup(OUString("Order"), aInfo);
- pDimData->AddNumGroupDimension(aGroup);
- }
-
- pDPObj->SetSaveData(*pSaveData);
- ScRange aOutRange = refreshGroups(pDPs, pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Order", 0 },
- { "<30", "423" },
- { "30-39", "87" },
- { "40-49", "241" },
- { "50-60", "61" },
- { ">60", "577" },
- { "Total Result", "1389" }
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Order grouped by numbers");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableDateGrouping()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Raw data
- const char* aData[][2] = {
- { "Date", "Value" },
- { "2011-01-01", "1" },
- { "2011-03-02", "2" },
- { "2012-01-04", "3" },
- { "2012-02-23", "4" },
- { "2012-02-24", "5" },
- { "2012-03-15", "6" },
- { "2011-09-03", "7" },
- { "2012-12-25", "8" }
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Date", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- };
-
- ScAddress aPos(1,1,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
- CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScDPSaveData* pSaveData = pDPObj->GetSaveData();
- CPPUNIT_ASSERT_MESSAGE("No save data !?", pSaveData);
- ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();
- CPPUNIT_ASSERT_MESSAGE("No dimension data !?", pDimData);
-
- OUString aBaseDimName("Date");
-
- ScDPNumGroupInfo aInfo;
- aInfo.mbEnable = true;
- aInfo.mbAutoStart = true;
- aInfo.mbAutoEnd = true;
- {
- // Turn the Date dimension into months. The first of the date
- // dimensions is always a number-group dimension which replaces the
- // original dimension.
- ScDPSaveNumGroupDimension aGroup(aBaseDimName, aInfo, sheet::DataPilotFieldGroupBy::MONTHS);
- pDimData->AddNumGroupDimension(aGroup);
- }
-
- {
- // Add quarter dimension. This will be an additional dimension.
- OUString aGroupDimName =
- pDimData->CreateDateGroupDimName(
- sheet::DataPilotFieldGroupBy::QUARTERS, *pDPObj, true, NULL);
- ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
- aGroupDim.SetDateInfo(aInfo, sheet::DataPilotFieldGroupBy::QUARTERS);
- pDimData->AddGroupDimension(aGroupDim);
-
- // Set orientation.
- ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
- pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
- pSaveData->SetPosition(pDim, 0); // set it to the left end.
- }
-
- {
- // Add year dimension. This is a new dimension also.
- OUString aGroupDimName =
- pDimData->CreateDateGroupDimName(
- sheet::DataPilotFieldGroupBy::YEARS, *pDPObj, true, NULL);
- ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
- aGroupDim.SetDateInfo(aInfo, sheet::DataPilotFieldGroupBy::YEARS);
- pDimData->AddGroupDimension(aGroupDim);
-
- // Set orientation.
- ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
- pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
- pSaveData->SetPosition(pDim, 0); // set it to the left end.
- }
-
- pDPObj->SetSaveData(*pSaveData);
- ScRange aOutRange = refreshGroups(pDPs, pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][4] = {
- { "Years", "Quarters", "Date", 0 },
- { "2011", "Q1", "Jan", "1" },
- { 0, 0, "Mar", "2" },
- { 0, "Q3", "Sep", "7" },
- { "2012", "Q1", "Jan", "3" },
- { 0, 0, "Feb", "9" },
- { 0, 0, "Mar", "6" },
- { 0, "Q4", "Dec", "8" },
- { "Total Result", 0, 0, "36" },
- };
-
- bSuccess = checkDPTableOutput<4>(m_pDoc, aOutRange, aOutputCheck, "Years, quarters and months date groups.");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- {
- // Let's hide year 2012.
- pSaveData = pDPObj->GetSaveData();
- ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(OUString("Years"));
- CPPUNIT_ASSERT_MESSAGE("Years dimension should exist.", pDim);
- ScDPSaveMember* pMem = pDim->GetMemberByName(OUString("2012"));
- CPPUNIT_ASSERT_MESSAGE("Member should exist.", pMem);
- pMem->SetIsVisible(false);
- }
- pDPObj->SetSaveData(*pSaveData);
- pDPObj->ReloadGroupTableData();
- pDPObj->InvalidateData();
-
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][4] = {
- { "Years", "Quarters", "Date", 0 },
- { "2011", "Q1", "Jan", "1" },
- { 0, 0, "Mar", "2" },
- { 0, "Q3", "Sep", "7" },
- { "Total Result", 0, 0, "10" },
- };
-
- bSuccess = checkDPTableOutput<4>(m_pDoc, aOutRange, aOutputCheck, "Year 2012 data now hidden");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- // Remove all date grouping. The source dimension "Date" has two
- // external dimensions ("Years" and "Quarters") and one internal ("Date"
- // the same name but different hierarchy). Remove all of them.
- pSaveData = pDPObj->GetSaveData();
- pSaveData->RemoveAllGroupDimensions(aBaseDimName);
- pDPObj->SetSaveData(*pSaveData);
- pDPObj->ReloadGroupTableData();
- pDPObj->InvalidateData();
-
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Date", 0 },
- { "2011-01-01", "1" },
- { "2011-03-02", "2" },
- { "2011-09-03", "7" },
- { "2012-01-04", "3" },
- { "2012-02-23", "4" },
- { "2012-02-24", "5" },
- { "2012-03-15", "6" },
- { "2012-12-25", "8" },
- { "Total Result", "36" }
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Remove all date grouping.");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableEmptyRows()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Raw data
- const char* aData[][2] = {
- { "Name", "Value" },
- { "A", "1" },
- { "B", "2" },
- { "C", "3" },
- { "D", "4" },
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- };
-
- ScAddress aPos(1,1,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
- CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-
- // Extend the range downward to include some trailing empty rows.
- aDataRange.aEnd.IncRow(2);
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
-
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", "1" },
- { "B", "2" },
- { "C", "3" },
- { "D", "4" },
- { "(empty)", 0 },
- { "Total Result", "10" },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Include empty rows");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- // This time, ignore empty rows.
- ScDPSaveData* pSaveData = pDPObj->GetSaveData();
- CPPUNIT_ASSERT_MESSAGE("Save data doesn't exist.", pSaveData);
- pSaveData->SetIgnoreEmptyRows(true);
- pDPObj->ClearTableData();
- aOutRange = refresh(pDPObj);
-
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", "1" },
- { "B", "2" },
- { "C", "3" },
- { "D", "4" },
- { "Total Result", "10" },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Ignore empty rows");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- // Modify the source to remove member 'A', then refresh the table.
- m_pDoc->SetString(1, 2, 0, "B");
-
- std::set<ScDPObject*> aRefs;
- sal_uLong nErr = pDPs->ReloadCache(pDPObj, aRefs);
- CPPUNIT_ASSERT_MESSAGE("Failed to reload cache.", !nErr);
- CPPUNIT_ASSERT_MESSAGE("There should only be one pivot table linked to this cache.",
- aRefs.size() == 1 && *aRefs.begin() == pDPObj);
-
- pDPObj->ClearTableData();
- aOutRange = refresh(pDPObj);
-
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "B", "3" },
- { "C", "3" },
- { "D", "4" },
- { "Total Result", "10" },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Ignore empty rows");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableTextNumber()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Raw data
- const char* aData[][2] = {
- { "Name", "Value" },
- { "0001", "1" },
- { "0002", "2" },
- { "0003", "3" },
- { "0004", "4" },
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- };
-
- // Insert raw data such that the first column values are entered as text.
- size_t nRowCount = SAL_N_ELEMENTS(aData);
- for (size_t nRow = 0; nRow < nRowCount; ++nRow)
- {
- ScSetStringParam aParam;
- aParam.mbDetectNumberFormat = false;
- aParam.meSetTextNumFormat = ScSetStringParam::Always;
- m_pDoc->SetString(0, nRow, 0, OUString::createFromAscii(aData[nRow][0]), &aParam);
- aParam.meSetTextNumFormat = ScSetStringParam::Never;
- m_pDoc->SetString(1, nRow, 0, OUString::createFromAscii(aData[nRow][1]), &aParam);
-
- if (nRow == 0)
- // Don't check the header row.
- continue;
-
- // Check the data rows.
- CPPUNIT_ASSERT_MESSAGE("This cell is supposed to be text.", m_pDoc->HasStringData(0, nRow, 0));
- CPPUNIT_ASSERT_MESSAGE("This cell is supposed to be numeric.", m_pDoc->HasValueData(1, nRow, 0));
- }
-
- ScRange aDataRange(0, 0, 0, 1, 4, 0);
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
-
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "0001", "1" },
- { "0002", "2" },
- { "0003", "3" },
- { "0004", "4" },
- { "Total Result", "10" },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Text number field members");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableCaseInsensitiveStrings()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Raw data
- const char* aData[][2] = {
- { "Name", "Value" },
- { "A", "1" },
- { "a", "2" },
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- };
-
- ScAddress aPos(1,1,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
- CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
-
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", "3" },
- { "Total Result", "3" },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Case insensitive strings");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableNumStability()
-{
- FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
-
- // Raw Data
- const char* aData[][4] = {
- { "Name", "Time Start", "Time End", "Total" },
- { "Sam", "07:48 AM", "09:00 AM", "=RC[-1]-RC[-2]" },
- { "Sam", "09:00 AM", "10:30 AM", "=RC[-1]-RC[-2]" },
- { "Sam", "10:30 AM", "12:30 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "12:30 PM", "01:00 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "01:00 PM", "01:30 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "01:30 PM", "02:00 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "02:00 PM", "07:15 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "07:47 AM", "09:00 AM", "=RC[-1]-RC[-2]" },
- { "Sam", "09:00 AM", "10:00 AM", "=RC[-1]-RC[-2]" },
- { "Sam", "10:00 AM", "11:00 AM", "=RC[-1]-RC[-2]" },
- { "Sam", "11:00 AM", "11:30 AM", "=RC[-1]-RC[-2]" },
- { "Sam", "11:30 AM", "12:45 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "12:45 PM", "01:15 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "01:15 PM", "02:30 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "02:30 PM", "02:45 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "02:45 PM", "04:30 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "04:30 PM", "06:00 PM", "=RC[-1]-RC[-2]" },
- { "Sam", "06:00 PM", "07:15 PM", "=RC[-1]-RC[-2]" },
- { "Mike", "06:15 AM", "08:30 AM", "=RC[-1]-RC[-2]" },
- { "Mike", "08:30 AM", "10:03 AM", "=RC[-1]-RC[-2]" },
- { "Mike", "10:03 AM", "12:00 PM", "=RC[-1]-RC[-2]" },
- { "Dennis", "11:00 AM", "01:00 PM", "=RC[-1]-RC[-2]" },
- { "Dennis", "01:00 PM", "02:00 PM", "=RC[-1]-RC[-2]" }
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Total", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- };
-
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- size_t nRowCount = SAL_N_ELEMENTS(aData);
- ScAddress aPos(1,1,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, nRowCount);
-
- // Insert formulas to manually calculate sums for each name.
- m_pDoc->SetString(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+1, aDataRange.aStart.Tab(), "=SUMIF(R[-23]C:R[-1]C;\"Dennis\";R[-23]C[3]:R[-1]C[3])");
- m_pDoc->SetString(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+2, aDataRange.aStart.Tab(), "=SUMIF(R[-24]C:R[-2]C;\"Mike\";R[-24]C[3]:R[-2]C[3])");
- m_pDoc->SetString(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+3, aDataRange.aStart.Tab(), "=SUMIF(R[-25]C:R[-3]C;\"Sam\";R[-25]C[3]:R[-3]C[3])");
-
- m_pDoc->CalcAll();
-
- // Get correct sum values.
- double fDennisTotal = m_pDoc->GetValue(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+1, aDataRange.aStart.Tab());
- double fMikeTotal = m_pDoc->GetValue(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+2, aDataRange.aStart.Tab());
- double fSamTotal = m_pDoc->GetValue(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+3, aDataRange.aStart.Tab());
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount(), static_cast<size_t>(1));
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
-
- // Manually check the total value for each name.
- //
- // +--------------+----------------+
- // | Name | |
- // +--------------+----------------+
- // | Dennis | <Dennis total> |
- // +--------------+----------------+
- // | Mike | <Miks total> |
- // +--------------+----------------+
- // | Sam | <Sam total> |
- // +--------------+----------------+
- // | Total Result | ... |
- // +--------------+----------------+
-
- aPos = aOutRange.aStart;
- aPos.IncCol();
- aPos.IncRow();
- double fTest = m_pDoc->GetValue(aPos);
- CPPUNIT_ASSERT_MESSAGE("Incorrect value for Dennis.", rtl::math::approxEqual(fTest, fDennisTotal));
- aPos.IncRow();
- fTest = m_pDoc->GetValue(aPos);
- CPPUNIT_ASSERT_MESSAGE("Incorrect value for Mike.", rtl::math::approxEqual(fTest, fMikeTotal));
- aPos.IncRow();
- fTest = m_pDoc->GetValue(aPos);
- CPPUNIT_ASSERT_MESSAGE("Incorrect value for Sam.", rtl::math::approxEqual(fTest, fSamTotal));
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableFieldReference()
-{
- m_pDoc->InsertTab(0, OUString("Data"));
- m_pDoc->InsertTab(1, OUString("Table"));
-
- // Raw data
- const char* aData[][2] = {
- { "Name", "Value" },
- { "A", "1" },
- { "B", "2" },
- { "C", "4" },
- { "D", "8" },
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- };
-
- ScAddress aPos(1,1,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
- CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- bool bSuccess = pDPs->InsertNewTable(pDPObj);
-
- CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
- CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
- pDPs->GetCount() == 1);
- pDPObj->SetName(pDPs->CreateNewName());
-
- ScRange aOutRange = refresh(pDPObj);
-
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", "1" },
- { "B", "2" },
- { "C", "4" },
- { "D", "8" },
- { "Total Result", "15" },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (none)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- ScDPSaveData aSaveData = *pDPObj->GetSaveData();
- sheet::DataPilotFieldReference aFieldRef;
- aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE;
- aFieldRef.ReferenceField = "Name";
- aFieldRef.ReferenceItemType = sheet::DataPilotFieldReferenceItemType::NAMED;
- aFieldRef.ReferenceItemName = "A";
- ScDPSaveDimension* pDim = aSaveData.GetDimensionByName("Value");
- CPPUNIT_ASSERT_MESSAGE("Failed to retrieve dimension 'Value'.", pDim);
- pDim->SetReferenceValue(&aFieldRef);
- pDPObj->SetSaveData(aSaveData);
-
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", 0 },
- { "B", "1" },
- { "C", "3" },
- { "D", "7" },
- { "Total Result", 0 },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (difference from)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE;
- pDim->SetReferenceValue(&aFieldRef);
- pDPObj->SetSaveData(aSaveData);
-
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", "100.00%" },
- { "B", "200.00%" },
- { "C", "400.00%" },
- { "D", "800.00%" },
- { "Total Result", 0 },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (% of)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE;
- pDim->SetReferenceValue(&aFieldRef);
- pDPObj->SetSaveData(aSaveData);
-
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", 0 },
- { "B", "100.00%" },
- { "C", "300.00%" },
- { "D", "700.00%" },
- { "Total Result", 0 },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (% difference from)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::RUNNING_TOTAL;
- pDim->SetReferenceValue(&aFieldRef);
- pDPObj->SetSaveData(aSaveData);
-
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", "1" },
- { "B", "3" },
- { "C", "7" },
- { "D", "15" },
- { "Total Result", 0 },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (Running total)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE;
- pDim->SetReferenceValue(&aFieldRef);
- pDPObj->SetSaveData(aSaveData);
-
- aOutRange = refresh(pDPObj);
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "A", "6.67%" },
- { "B", "13.33%" },
- { "C", "26.67%" },
- { "D", "53.33%" },
- { "Total Result", "100.00%" },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (% of column)");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- pDPs->FreeTable(pDPObj);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
- CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
- pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
-void Test::testPivotTableDocFunc()
-{
- m_pDoc->InsertTab(0, "Data");
- m_pDoc->InsertTab(1, "Table");
-
- // Raw data
- const char* aData[][2] = {
- { "Name", "Value" },
- { "Sun", "1" },
- { "Oracle", "2" },
- { "Red Hat", "4" },
- { "SUSE", "8" },
- { "Apple", "16" },
- { "Microsoft", "32" },
- };
-
- // Dimension definition
- DPFieldDef aFields[] = {
- { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
- { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
- };
-
- ScAddress aPos(1,1,0);
- ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
- CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
-
- ScDPObject* pDPObj = createDPFromRange(
- m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
-
- CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table object.", pDPObj);
-
- // Craete a new pivot table output.
- ScDBDocFunc aFunc(getDocShell());
- bool bSuccess = aFunc.CreatePivotTable(*pDPObj, false, true);
- CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table output via ScDBDocFunc.", bSuccess);
- ScDPCollection* pDPs = m_pDoc->GetDPCollection();
- CPPUNIT_ASSERT_MESSAGE("Failed to get pivot table collection.", pDPs);
- CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDPs->GetCount());
- pDPObj = (*pDPs)[0];
- CPPUNIT_ASSERT_MESSAGE("Failed to retrieve pivot table object from the collection", pDPObj);
- ScRange aOutRange = pDPObj->GetOutRange();
- {
- // Expected output table content. 0 = empty cell
- const char* aOutputCheck[][2] = {
- { "Name", 0 },
- { "Apple", "16" },
- { "Microsoft", "32" },
- { "Oracle", "2" },
- { "Red Hat", "4" },
- { "Sun", "1" },
- { "SUSE", "8" },
- { "Total Result", "63" },
- };
-
- bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Pivot table created via ScDBDocFunc");
- CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
- }
-
- // Remove this pivot table output. This should also clear the pivot cache
- // it was referencing.
- bSuccess = aFunc.RemovePivotTable(*pDPObj, false, true);
- CPPUNIT_ASSERT_MESSAGE("Failed to remove pivot table output via ScDBDocFunc.", bSuccess);
- CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pDPs->GetCount());
- CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pDPs->GetSheetCaches().size());
-
- m_pDoc->DeleteTab(1);
- m_pDoc->DeleteTab(0);
-}
-
void Test::testSheetCopy()
{
m_pDoc->InsertTab(0, "TestTab");
@@ -6930,6 +4825,22 @@ void Test::testCondFormatINSDEL()
m_pDoc->DeleteTab(0);
}
+void Test::printRange(ScDocument* pDoc, const ScRange& rRange, const char* pCaption)
+{
+ SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
+ SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
+ SheetPrinter printer(nRow2 - nRow1 + 1, nCol2 - nCol1 + 1);
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ {
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ {
+ OUString aVal = pDoc->GetString(nCol, nRow, rRange.aStart.Tab());
+ printer.set(nRow-nRow1, nCol-nCol1, aVal);
+ }
+ }
+ printer.print(pCaption);
+}
+
void Test::clearRange(ScDocument* pDoc, const ScRange& rRange)
{
ScMarkData aMarkData;
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 04896833a0cc..55e3f7ce678d 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -11,6 +11,7 @@
#define SC_UCALC_HXX
#include "helper/qahelper.hxx"
+#include "document.hxx"
struct TestImpl;
class ScUndoPaste;
@@ -31,11 +32,38 @@ class Test : public test::BootstrapFixture
{
public:
+ static void printRange(ScDocument* pDoc, const ScRange& rRange, const char* pCaption);
static void clearRange(ScDocument* pDoc, const ScRange& rRange);
static void copyToClip(ScDocument* pSrcDoc, const ScRange& rRange, ScDocument* pClipDoc);
static void pasteFromClip(ScDocument* pDestDoc, const ScRange& rDestRange, ScDocument* pClipDoc);
static ScUndoPaste* createUndoPaste(ScDocShell& rDocSh, const ScRange& rRange, ScDocument* pUndoDoc);
+ template<size_t _Size>
+ static ScRange insertRangeData(ScDocument* pDoc, const ScAddress& rPos, const char* aData[][_Size], size_t nRowCount)
+ {
+ ScRange aRange(rPos);
+ aRange.aEnd.SetCol(rPos.Col()+_Size-1);
+ aRange.aEnd.SetRow(rPos.Row()+nRowCount-1);
+
+ clearRange(pDoc, aRange);
+
+ for (size_t i = 0; i < _Size; ++i)
+ {
+ for (size_t j = 0; j < nRowCount; ++j)
+ {
+ if (!aData[j][i])
+ continue;
+
+ SCCOL nCol = i + rPos.Col();
+ SCROW nRow = j + rPos.Row();
+ pDoc->SetString(nCol, nRow, rPos.Tab(), OUString(aData[j][i], strlen(aData[j][i]), RTL_TEXTENCODING_UTF8));
+ }
+ }
+
+ printRange(pDoc, aRange, "Range data content");
+ return aRange;
+ }
+
Test();
~Test();
diff --git a/sc/qa/unit/ucalc_pivottable.cxx b/sc/qa/unit/ucalc_pivottable.cxx
new file mode 100644
index 000000000000..94d897941345
--- /dev/null
+++ b/sc/qa/unit/ucalc_pivottable.cxx
@@ -0,0 +1,2079 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ucalc.hxx"
+#include "dpshttab.hxx"
+#include "dpobject.hxx"
+#include "dpsave.hxx"
+#include "dpdimsave.hxx"
+#include "dpcache.hxx"
+#include "dpfilteredcache.hxx"
+#include "scopetools.hxx"
+#include "queryentry.hxx"
+#include "stringutil.hxx"
+#include "dbdocfun.hxx"
+
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReference.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
+#include <com/sun/star/sheet/GeneralFunction.hpp>
+
+namespace {
+
+struct DPFieldDef
+{
+ const char* pName;
+ sheet::DataPilotFieldOrientation eOrient;
+
+ /**
+ * Function for data field. It's used only for data field. When 0, the
+ * default function (SUM) is used.
+ */
+ int eFunc;
+};
+
+template<size_t _Size>
+ScRange insertDPSourceData(ScDocument* pDoc, DPFieldDef aFields[], size_t nFieldCount, const char* aData[][_Size], size_t nDataCount)
+{
+ // Insert field names in row 0.
+ for (size_t i = 0; i < nFieldCount; ++i)
+ pDoc->SetString(static_cast<SCCOL>(i), 0, 0, OUString(aFields[i].pName, strlen(aFields[i].pName), RTL_TEXTENCODING_UTF8));
+
+ // Insert data into row 1 and downward.
+ for (size_t i = 0; i < nDataCount; ++i)
+ {
+ SCROW nRow = static_cast<SCROW>(i) + 1;
+ for (size_t j = 0; j < nFieldCount; ++j)
+ {
+ SCCOL nCol = static_cast<SCCOL>(j);
+ pDoc->SetString(
+ nCol, nRow, 0, OUString(aData[i][j], strlen(aData[i][j]), RTL_TEXTENCODING_UTF8));
+ }
+ }
+
+ SCROW nRow1 = 0, nRow2 = 0;
+ SCCOL nCol1 = 0, nCol2 = 0;
+ pDoc->GetDataArea(0, nCol1, nRow1, nCol2, nRow2, true, false);
+ CPPUNIT_ASSERT_MESSAGE("Data is expected to start from (col=0,row=0).", nCol1 == 0 && nRow1 == 0);
+ CPPUNIT_ASSERT_MESSAGE("Unexpected data range.",
+ nCol2 == static_cast<SCCOL>(nFieldCount - 1) && nRow2 == static_cast<SCROW>(nDataCount));
+
+ ScRange aSrcRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
+ Test::printRange(pDoc, aSrcRange, "Data sheet content");
+ return aSrcRange;
+}
+
+template<size_t _Size>
+bool checkDPTableOutput(ScDocument* pDoc, const ScRange& aOutRange, const char* aOutputCheck[][_Size], const char* pCaption)
+{
+ bool bResult = true;
+ const ScAddress& s = aOutRange.aStart;
+ const ScAddress& e = aOutRange.aEnd;
+ SheetPrinter printer(e.Row() - s.Row() + 1, e.Col() - s.Col() + 1);
+ SCROW nOutRowSize = e.Row() - s.Row() + 1;
+ SCCOL nOutColSize = e.Col() - s.Col() + 1;
+ for (SCROW nRow = 0; nRow < nOutRowSize; ++nRow)
+ {
+ for (SCCOL nCol = 0; nCol < nOutColSize; ++nCol)
+ {
+ OUString aVal = pDoc->GetString(nCol + s.Col(), nRow + s.Row(), s.Tab());
+ printer.set(nRow, nCol, aVal);
+ const char* p = aOutputCheck[nRow][nCol];
+ if (p)
+ {
+ OUString aCheckVal = OUString::createFromAscii(p);
+ bool bEqual = aCheckVal.equals(aVal);
+ if (!bEqual)
+ {
+ cout << "Expected: " << aCheckVal << " Actual: " << aVal << endl;
+ bResult = false;
+ }
+ }
+ else if (!aVal.isEmpty())
+ {
+ cout << "Empty cell expected" << endl;
+ bResult = false;
+ }
+ }
+ }
+ printer.print(pCaption);
+ return bResult;
+}
+
+ScDPObject* createDPFromSourceDesc(
+ ScDocument* pDoc, const ScSheetSourceDesc& rDesc, DPFieldDef aFields[], size_t nFieldCount,
+ bool bFilterButton)
+{
+ ScDPObject* pDPObj = new ScDPObject(pDoc);
+ pDPObj->SetSheetDesc(rDesc);
+ pDPObj->SetOutRange(ScAddress(0, 0, 1));
+
+ ScDPSaveData aSaveData;
+ // Set data pilot table output options.
+ aSaveData.SetIgnoreEmptyRows(false);
+ aSaveData.SetRepeatIfEmpty(false);
+ aSaveData.SetColumnGrand(true);
+ aSaveData.SetRowGrand(true);
+ aSaveData.SetFilterButton(bFilterButton);
+ aSaveData.SetDrillDown(true);
+
+ // Check the sanity of the source range.
+ const ScRange& rSrcRange = rDesc.GetSourceRange();
+ SCROW nRow1 = rSrcRange.aStart.Row();
+ SCROW nRow2 = rSrcRange.aEnd.Row();
+ CPPUNIT_ASSERT_MESSAGE("source range contains no data!", nRow2 - nRow1 > 1);
+
+ // Set the dimension information.
+ for (size_t i = 0; i < nFieldCount; ++i)
+ {
+ OUString aDimName = OUString::createFromAscii(aFields[i].pName);
+ ScDPSaveDimension* pDim = aSaveData.GetNewDimensionByName(aDimName);
+ pDim->SetOrientation(static_cast<sal_uInt16>(aFields[i].eOrient));
+ pDim->SetUsedHierarchy(0);
+
+ if (aFields[i].eOrient == sheet::DataPilotFieldOrientation_DATA)
+ {
+ sheet::GeneralFunction eFunc = sheet::GeneralFunction_SUM;
+ if (aFields[i].eFunc)
+ eFunc = static_cast<sheet::GeneralFunction>(aFields[i].eFunc);
+
+ pDim->SetFunction(eFunc);
+ pDim->SetReferenceValue(NULL);
+ }
+ else
+ {
+ sheet::DataPilotFieldSortInfo aSortInfo;
+ aSortInfo.IsAscending = true;
+ aSortInfo.Mode = 2;
+ pDim->SetSortInfo(&aSortInfo);
+
+ sheet::DataPilotFieldLayoutInfo aLayInfo;
+ aLayInfo.LayoutMode = 0;
+ aLayInfo.AddEmptyLines = false;
+ pDim->SetLayoutInfo(&aLayInfo);
+ sheet::DataPilotFieldAutoShowInfo aShowInfo;
+ aShowInfo.IsEnabled = false;
+ aShowInfo.ShowItemsMode = 0;
+ aShowInfo.ItemCount = 0;
+ pDim->SetAutoShowInfo(&aShowInfo);
+ }
+ }
+
+ // Don't forget the data layout dimension.
+ ScDPSaveDimension* pDim = aSaveData.GetDataLayoutDimension();
+ pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
+ pDim->SetShowEmpty(true);
+
+ pDPObj->SetSaveData(aSaveData);
+ pDPObj->InvalidateData();
+
+ return pDPObj;
+}
+
+ScDPObject* createDPFromRange(
+ ScDocument* pDoc, const ScRange& rRange, DPFieldDef aFields[], size_t nFieldCount,
+ bool bFilterButton)
+{
+ ScSheetSourceDesc aSheetDesc(pDoc);
+ aSheetDesc.SetSourceRange(rRange);
+ return createDPFromSourceDesc(pDoc, aSheetDesc, aFields, nFieldCount, bFilterButton);
+}
+
+ScRange refresh(ScDPObject* pDPObj)
+{
+ bool bOverFlow = false;
+ ScRange aOutRange = pDPObj->GetNewOutputRange(bOverFlow);
+ CPPUNIT_ASSERT_MESSAGE("Table overflow!?", !bOverFlow);
+
+ pDPObj->Output(aOutRange.aStart);
+ aOutRange = pDPObj->GetOutRange();
+ return aOutRange;
+}
+
+ScRange refreshGroups(ScDPCollection* pDPs, ScDPObject* pDPObj)
+{
+ // We need to first create group data in the cache, then the group data in
+ // the object.
+ std::set<ScDPObject*> aRefs;
+ bool bSuccess = pDPs->ReloadGroupsInCache(pDPObj, aRefs);
+ CPPUNIT_ASSERT_MESSAGE("Failed to reload group data in cache.", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("There should be only one table linked to this cache.", aRefs.size() == 1);
+ pDPObj->ReloadGroupTableData();
+
+ return refresh(pDPObj);
+}
+
+}
+
+void Test::testPivotTable()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Group", sheet::DataPilotFieldOrientation_COLUMN, 0 },
+ { "Score", sheet::DataPilotFieldOrientation_DATA, 0 }
+ };
+
+ // Raw data
+ const char* aData[][3] = {
+ { "Andy", "A", "30" },
+ { "Bruce", "A", "20" },
+ { "Charlie", "B", "45" },
+ { "David", "B", "12" },
+ { "Edward", "C", "8" },
+ { "Frank", "C", "15" },
+ };
+
+ size_t nFieldCount = SAL_N_ELEMENTS(aFields);
+ size_t nDataCount = SAL_N_ELEMENTS(aData);
+
+ ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
+ SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
+ SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ bool bOverFlow = false;
+ ScRange aOutRange = pDPObj->GetNewOutputRange(bOverFlow);
+ CPPUNIT_ASSERT_MESSAGE("Table overflow!?", !bOverFlow);
+
+ pDPObj->Output(aOutRange.aStart);
+ aOutRange = pDPObj->GetOutRange();
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][5] = {
+ { "Sum - Score", "Group", 0, 0, 0 },
+ { "Name", "A", "B", "C", "Total Result" },
+ { "Andy", "30", 0, 0, "30" },
+ { "Bruce", "20", 0, 0, "20" },
+ { "Charlie", 0, "45", 0, "45" },
+ { "David", 0, "12", 0, "12" },
+ { "Edward", 0, 0, "8", "8" },
+ { "Frank", 0, 0, "15", "15" },
+ { "Total Result", "50", "57", "23", "130" }
+ };
+
+ bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+ CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
+
+ // Update the cell values.
+ double aData2[] = { 100, 200, 300, 400, 500, 600 };
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aData2); ++i)
+ {
+ SCROW nRow = i + 1;
+ m_pDoc->SetValue(2, nRow, 0, aData2[i]);
+ }
+
+ printRange(m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), "Data sheet content (modified)");
+
+ // Now, create a copy of the datapilot object for the updated table, but
+ // don't reload the cache which should force the copy to use the old data
+ // from the cache.
+ ScDPObject* pDPObj2 = new ScDPObject(*pDPObj);
+ pDPs->InsertNewTable(pDPObj2);
+
+ aOutRange = pDPObj2->GetOutRange();
+ pDPObj2->ClearTableData();
+ pDPObj2->Output(aOutRange.aStart);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][5] = {
+ { "Sum - Score", "Group", 0, 0, 0 },
+ { "Name", "A", "B", "C", "Total Result" },
+ { "Andy", "30", 0, 0, "30" },
+ { "Bruce", "20", 0, 0, "20" },
+ { "Charlie", 0, "45", 0, "45" },
+ { "David", 0, "12", 0, "12" },
+ { "Edward", 0, 0, "8", "8" },
+ { "Frank", 0, 0, "15", "15" },
+ { "Total Result", "50", "57", "23", "130" }
+ };
+
+ bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (from old cache)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
+
+ // Free the first datapilot object after the 2nd one gets reloaded, to
+ // prevent the data cache from being deleted before the reload.
+ pDPs->FreeTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
+
+ // This time clear the cache to refresh the data from the source range.
+ CPPUNIT_ASSERT_MESSAGE("This datapilot should be based on sheet data.", pDPObj2->IsSheetData());
+ std::set<ScDPObject*> aRefs;
+ sal_uLong nErrId = pDPs->ReloadCache(pDPObj2, aRefs);
+ CPPUNIT_ASSERT_MESSAGE("Cache reload failed.", nErrId == 0);
+ CPPUNIT_ASSERT_MESSAGE("Reloading a cache shouldn't remove any cache.",
+ pDPs->GetSheetCaches().size() == 1);
+
+ pDPObj2->ClearTableData();
+ pDPObj2->Output(aOutRange.aStart);
+
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][5] = {
+ { "Sum - Score", "Group", 0, 0, 0 },
+ { "Name", "A", "B", "C", "Total Result" },
+ { "Andy", "100", 0, 0, "100" },
+ { "Bruce", "200", 0, 0, "200" },
+ { "Charlie", 0, "300", 0, "300" },
+ { "David", 0, "400", 0, "400" },
+ { "Edward", 0, 0, "500", "500" },
+ { "Frank", 0, 0, "600", "600" },
+ { "Total Result", "300", "700", "1100", "2100" }
+ };
+
+ bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (refreshed)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ CPPUNIT_ASSERT_MESSAGE("Cache should be here.", pDPs->GetSheetCaches().hasCache(aSrcRange));
+
+ // Swap the two sheets.
+ m_pDoc->MoveTab(1, 0);
+ CPPUNIT_ASSERT_MESSAGE("Swapping the sheets shouldn't remove the cache.",
+ pDPs->GetSheetCaches().size() == 1);
+ CPPUNIT_ASSERT_MESSAGE("Cache should have moved.", !pDPs->GetSheetCaches().hasCache(aSrcRange));
+ aSrcRange.aStart.SetTab(1);
+ aSrcRange.aEnd.SetTab(1);
+ CPPUNIT_ASSERT_MESSAGE("Cache should be here.", pDPs->GetSheetCaches().hasCache(aSrcRange));
+
+ pDPs->FreeTable(pDPObj2);
+ CPPUNIT_ASSERT_MESSAGE("There shouldn't be any data pilot table stored with the document.",
+ pDPs->GetCount() == 0);
+
+ CPPUNIT_ASSERT_MESSAGE("There shouldn't be any more data cache.",
+ pDPs->GetSheetCaches().size() == 0);
+
+ // Insert a brand new pivot table object once again, but this time, don't
+ // create the output to avoid creating a data cache.
+ m_pDoc->DeleteTab(1);
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ pDPObj = createDPFromRange(
+ m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
+ bSuccess = pDPs->InsertNewTable(pDPObj);
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+ CPPUNIT_ASSERT_MESSAGE("Data cache shouldn't exist yet before creating the table output.",
+ pDPs->GetSheetCaches().size() == 0);
+
+ // Now, "refresh" the table. This should still return a reference to self
+ // even with the absence of data cache.
+ aRefs.clear();
+ pDPs->ReloadCache(pDPObj, aRefs);
+ CPPUNIT_ASSERT_MESSAGE("It should return the same object as a reference.",
+ aRefs.size() == 1 && *aRefs.begin() == pDPObj);
+
+ pDPs->FreeTable(pDPObj);
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableLabels()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Software", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Version", sheet::DataPilotFieldOrientation_COLUMN, 0 },
+ { "1.2.3", sheet::DataPilotFieldOrientation_DATA, 0 }
+ };
+
+ // Raw data
+ const char* aData[][3] = {
+ { "LibreOffice", "3.3.0", "30" },
+ { "LibreOffice", "3.3.1", "20" },
+ { "LibreOffice", "3.4.0", "45" },
+ };
+
+ size_t nFieldCount = SAL_N_ELEMENTS(aFields);
+ size_t nDataCount = SAL_N_ELEMENTS(aData);
+
+ ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
+ SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
+ SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][5] = {
+ { "Sum - 1.2.3", "Version", 0, 0, 0 },
+ { "Software", "3.3.0", "3.3.1", "3.4.0", "Total Result" },
+ { "LibreOffice", "30", "20", "45", "95" },
+ { "Total Result", "30", "20", "45", "95" }
+ };
+
+ bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ pDPs->FreeTable(pDPObj);
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableDateLabels()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Date", sheet::DataPilotFieldOrientation_COLUMN, 0 },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, 0 }
+ };
+
+ // Raw data
+ const char* aData[][3] = {
+ { "Zena", "2011-1-1", "30" },
+ { "Yodel", "2011-1-2", "20" },
+ { "Xavior", "2011-1-3", "45" }
+ };
+
+ size_t nFieldCount = SAL_N_ELEMENTS(aFields);
+ size_t nDataCount = SAL_N_ELEMENTS(aData);
+
+ ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
+ SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
+ SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][5] = {
+ { "Sum - Value", "Date", 0, 0, 0 },
+ { "Name", "2011-01-01", "2011-01-02", "2011-01-03", "Total Result" },
+ { "Xavior", 0, 0, "45", "45" },
+ { "Yodel", 0, "20", 0, "20" },
+ { "Zena", "30", 0, 0, "30" },
+ { "Total Result", "30", "20", "45", "95" }
+ };
+
+ bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ {
+ const char* aChecks[] = {
+ "2011-01-01", "2011-01-02", "2011-01-03"
+ };
+
+ // Make sure those cells that contain dates are numeric.
+ SCROW nRow = aOutRange.aStart.Row() + 1;
+ nCol1 = aOutRange.aStart.Col() + 1;
+ nCol2 = nCol1 + 2;
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ {
+ OUString aVal = m_pDoc->GetString(nCol, nRow, 1);
+ CPPUNIT_ASSERT_MESSAGE("Cell value is not as expected.", aVal.equalsAscii(aChecks[nCol-nCol1]));
+ CPPUNIT_ASSERT_MESSAGE("This cell contains a date value and is supposed to be numeric.",
+ m_pDoc->HasValueData(nCol, nRow, 1));
+ }
+ }
+
+ pDPs->FreeTable(pDPObj);
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableFilters()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_HIDDEN, 0 },
+ { "Group1", sheet::DataPilotFieldOrientation_HIDDEN, 0 },
+ { "Group2", sheet::DataPilotFieldOrientation_PAGE, 0 },
+ { "Val1", sheet::DataPilotFieldOrientation_DATA, 0 },
+ { "Val2", sheet::DataPilotFieldOrientation_DATA, 0 }
+ };
+
+ // Raw data
+ const char* aData[][5] = {
+ { "A", "1", "A", "1", "10" },
+ { "B", "1", "A", "1", "10" },
+ { "C", "1", "B", "1", "10" },
+ { "D", "1", "B", "1", "10" },
+ { "E", "2", "A", "1", "10" },
+ { "F", "2", "A", "1", "10" },
+ { "G", "2", "B", "1", "10" },
+ { "H", "2", "B", "1", "10" }
+ };
+
+ size_t nFieldCount = SAL_N_ELEMENTS(aFields);
+ size_t nDataCount = SAL_N_ELEMENTS(aData);
+
+ ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
+ SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
+ SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, true);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Filter", 0 },
+ { "Group2", "- all -" },
+ { 0, 0 },
+ { "Data", 0 },
+ { "Sum - Val1", "8" },
+ { "Sum - Val2", "80" }
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (unfiltered)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation.
+
+ ScAddress aFormulaAddr = aOutRange.aEnd;
+ aFormulaAddr.IncRow(2);
+ m_pDoc->SetString(aFormulaAddr.Col(), aFormulaAddr.Row(), aFormulaAddr.Tab(),
+ OUString("=B6"));
+ double fTest = m_pDoc->GetValue(aFormulaAddr);
+ CPPUNIT_ASSERT_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", fTest == 80.0);
+
+ // Set current page of 'Group2' to 'A'.
+ pDPObj->BuildAllDimensionMembers();
+ ScDPSaveData aSaveData(*pDPObj->GetSaveData());
+ ScDPSaveDimension* pPageDim = aSaveData.GetDimensionByName(
+ OUString("Group2"));
+ CPPUNIT_ASSERT_MESSAGE("Dimension not found", pPageDim);
+ OUString aPage("A");
+ pPageDim->SetCurrentPage(&aPage);
+ pDPObj->SetSaveData(aSaveData);
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Filter", 0 },
+ { "Group2", "A" },
+ { 0, 0 },
+ { "Data", 0 },
+ { "Sum - Val1", "4" },
+ { "Sum - Val2", "40" }
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by page)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ fTest = m_pDoc->GetValue(aFormulaAddr);
+ CPPUNIT_ASSERT_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", fTest == 40.0);
+
+ // Set query filter.
+ ScSheetSourceDesc aDesc(*pDPObj->GetSheetDesc());
+ ScQueryParam aQueryParam(aDesc.GetQueryParam());
+ CPPUNIT_ASSERT_MESSAGE("There should be at least one query entry.", aQueryParam.GetEntryCount() > 0);
+ ScQueryEntry& rEntry = aQueryParam.GetEntry(0);
+ rEntry.bDoQuery = true;
+ rEntry.nField = 1; // Group1
+ rEntry.GetQueryItem().mfVal = 1;
+ aDesc.SetQueryParam(aQueryParam);
+ pDPObj->SetSheetDesc(aDesc);
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Filter", 0 },
+ { "Group2", "A" },
+ { 0, 0 },
+ { "Data", 0 },
+ { "Sum - Val1", "2" },
+ { "Sum - Val2", "20" }
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by query)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ fTest = m_pDoc->GetValue(aFormulaAddr);
+ CPPUNIT_ASSERT_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", fTest == 20.0);
+
+ // Set the current page of 'Group2' back to '- all -'. The query filter
+ // should still be in effect.
+ pPageDim->SetCurrentPage(NULL); // Remove the page.
+ pDPObj->SetSaveData(aSaveData);
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Filter", 0 },
+ { "Group2", "- all -" },
+ { 0, 0 },
+ { "Data", 0 },
+ { "Sum - Val1", "4" },
+ { "Sum - Val2", "40" }
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by page)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_MESSAGE("There shouldn't be any data pilot table stored with the document.",
+ pDPs->GetCount() == 0);
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableNamedSource()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Group", sheet::DataPilotFieldOrientation_COLUMN, 0 },
+ { "Score", sheet::DataPilotFieldOrientation_DATA, 0 }
+ };
+
+ // Raw data
+ const char* aData[][3] = {
+ { "Andy", "A", "30" },
+ { "Bruce", "A", "20" },
+ { "Charlie", "B", "45" },
+ { "David", "B", "12" },
+ { "Edward", "C", "8" },
+ { "Frank", "C", "15" },
+ };
+
+ size_t nFieldCount = SAL_N_ELEMENTS(aFields);
+ size_t nDataCount = SAL_N_ELEMENTS(aData);
+
+ // Insert the raw data.
+ ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
+ OUString aRangeStr;
+ aSrcRange.Format(aRangeStr, SCR_ABS_3D, m_pDoc);
+
+ // Name this range.
+ OUString aRangeName("MyData");
+ ScRangeName* pNames = m_pDoc->GetRangeName();
+ CPPUNIT_ASSERT_MESSAGE("Failed to get global range name container.", pNames);
+ ScRangeData* pName = new ScRangeData(
+ m_pDoc, aRangeName, aRangeStr);
+ bool bSuccess = pNames->insert(pName);
+ CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bSuccess);
+
+ ScSheetSourceDesc aSheetDesc(m_pDoc);
+ aSheetDesc.SetRangeName(aRangeName);
+ ScDPObject* pDPObj = createDPFromSourceDesc(m_pDoc, aSheetDesc, aFields, nFieldCount, false);
+ CPPUNIT_ASSERT_MESSAGE("Failed to create a new pivot table object.", pDPObj);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bSuccess = pDPs->InsertNewTable(pDPObj);
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][5] = {
+ { "Sum - Score", "Group", 0, 0, 0 },
+ { "Name", "A", "B", "C", "Total Result" },
+ { "Andy", "30", 0, 0, "30" },
+ { "Bruce", "20", 0, 0, "20" },
+ { "Charlie", 0, "45", 0, "45" },
+ { "David", 0, "12", 0, "12" },
+ { "Edward", 0, 0, "8", "8" },
+ { "Frank", 0, 0, "15", "15" },
+ { "Total Result", "50", "57", "23", "130" }
+ };
+
+ bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ CPPUNIT_ASSERT_MESSAGE("There should be one named range data cache.",
+ pDPs->GetNameCaches().size() == 1 && pDPs->GetSheetCaches().size() == 0);
+
+ // Move the table with pivot table to the left of the source data sheet.
+ m_pDoc->MoveTab(1, 0);
+ OUString aTabName;
+ m_pDoc->GetName(0, aTabName);
+ CPPUNIT_ASSERT_MESSAGE( "Wrong sheet name.", aTabName == "Table" );
+ CPPUNIT_ASSERT_MESSAGE("Pivot table output is on the wrong sheet!",
+ pDPObj->GetOutRange().aStart.Tab() == 0);
+
+ CPPUNIT_ASSERT_MESSAGE("Moving the pivot table to another sheet shouldn't have changed the cache state.",
+ pDPs->GetNameCaches().size() == 1 && pDPs->GetSheetCaches().size() == 0);
+
+ const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
+ CPPUNIT_ASSERT_MESSAGE("Sheet source description doesn't exist.", pDesc);
+ CPPUNIT_ASSERT_MESSAGE("Named source range has been altered unexpectedly!",
+ pDesc->GetRangeName().equals(aRangeName));
+
+ CPPUNIT_ASSERT_MESSAGE("Cache should exist.", pDPs->GetNameCaches().hasCache(aRangeName));
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_MESSAGE("There should be no more tables.", pDPs->GetCount() == 0);
+ CPPUNIT_ASSERT_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetNameCaches().size() == 0);
+
+ pNames->clear();
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableCache()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+
+ // Raw data
+ const char* aData[][3] = {
+ { "F1", "F2", "F3" },
+ { "Z", "A", "30" },
+ { "R", "A", "20" },
+ { "A", "B", "45" },
+ { "F", "B", "12" },
+ { "Y", "C", "8" },
+ { "12", "C", "15" },
+ };
+
+ ScAddress aPos(1,1,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+ CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+
+ ScDPCache aCache(m_pDoc);
+ aCache.InitFromDoc(m_pDoc, aDataRange);
+ long nDimCount = aCache.GetColumnCount();
+ CPPUNIT_ASSERT_MESSAGE("wrong dimension count.", nDimCount == 3);
+ OUString aDimName = aCache.GetDimensionName(0);
+ CPPUNIT_ASSERT_MESSAGE("wrong dimension name", aDimName.equalsAscii("F1"));
+ aDimName = aCache.GetDimensionName(1);
+ CPPUNIT_ASSERT_MESSAGE("wrong dimension name", aDimName.equalsAscii("F2"));
+ aDimName = aCache.GetDimensionName(2);
+ CPPUNIT_ASSERT_MESSAGE("wrong dimension name", aDimName.equalsAscii("F3"));
+
+ // In each dimension, member ID values also represent their sort order (in
+ // source dimensions only, not in group dimensions). Value items are
+ // sorted before string ones. Also, no duplicate dimension members should
+ // exist.
+
+ // Dimension 0 - a mix of strings and values.
+ long nMemCount = aCache.GetDimMemberCount(0);
+ CPPUNIT_ASSERT_MESSAGE("wrong dimension member count", nMemCount == 6);
+ const ScDPItemData* pItem = aCache.GetItemDataById(0, 0);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::Value &&
+ pItem->GetValue() == 12);
+ pItem = aCache.GetItemDataById(0, 1);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::String &&
+ pItem->GetString().equalsAscii("A"));
+ pItem = aCache.GetItemDataById(0, 2);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::String &&
+ pItem->GetString().equalsAscii("F"));
+ pItem = aCache.GetItemDataById(0, 3);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::String &&
+ pItem->GetString().equalsAscii("R"));
+ pItem = aCache.GetItemDataById(0, 4);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::String &&
+ pItem->GetString().equalsAscii("Y"));
+ pItem = aCache.GetItemDataById(0, 5);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::String &&
+ pItem->GetString().equalsAscii("Z"));
+ pItem = aCache.GetItemDataById(0, 6);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", !pItem);
+
+ // Dimension 1 - duplicate values in source.
+ nMemCount = aCache.GetDimMemberCount(1);
+ CPPUNIT_ASSERT_MESSAGE("wrong dimension member count", nMemCount == 3);
+ pItem = aCache.GetItemDataById(1, 0);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::String &&
+ pItem->GetString().equalsAscii("A"));
+ pItem = aCache.GetItemDataById(1, 1);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::String &&
+ pItem->GetString().equalsAscii("B"));
+ pItem = aCache.GetItemDataById(1, 2);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::String &&
+ pItem->GetString().equalsAscii("C"));
+ pItem = aCache.GetItemDataById(1, 3);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", !pItem);
+
+ // Dimension 2 - values only.
+ nMemCount = aCache.GetDimMemberCount(2);
+ CPPUNIT_ASSERT_MESSAGE("wrong dimension member count", nMemCount == 6);
+ pItem = aCache.GetItemDataById(2, 0);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::Value &&
+ pItem->GetValue() == 8);
+ pItem = aCache.GetItemDataById(2, 1);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::Value &&
+ pItem->GetValue() == 12);
+ pItem = aCache.GetItemDataById(2, 2);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::Value &&
+ pItem->GetValue() == 15);
+ pItem = aCache.GetItemDataById(2, 3);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::Value &&
+ pItem->GetValue() == 20);
+ pItem = aCache.GetItemDataById(2, 4);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::Value &&
+ pItem->GetValue() == 30);
+ pItem = aCache.GetItemDataById(2, 5);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
+ pItem->GetType() == ScDPItemData::Value &&
+ pItem->GetValue() == 45);
+ pItem = aCache.GetItemDataById(2, 6);
+ CPPUNIT_ASSERT_MESSAGE("wrong item value", !pItem);
+
+ {
+ // Check the integrity of the source data.
+ ScDPItemData aTest;
+ long nDim;
+
+ {
+ // Dimension 0: Z, R, A, F, Y, 12
+ nDim = 0;
+ const char* aChecks[] = { "Z", "R", "A", "F", "Y" };
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
+ {
+ pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, i, false));
+ aTest.SetString(OUString::createFromAscii(aChecks[i]));
+ CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
+ }
+
+ pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, 5, false));
+ aTest.SetValue(12);
+ CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
+ }
+
+ {
+ // Dimension 1: A, A, B, B, C, C
+ nDim = 1;
+ const char* aChecks[] = { "A", "A", "B", "B", "C", "C" };
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
+ {
+ pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, i, false));
+ aTest.SetString(OUString::createFromAscii(aChecks[i]));
+ CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
+ }
+ }
+
+ {
+ // Dimension 2: 30, 20, 45, 12, 8, 15
+ nDim = 2;
+ double aChecks[] = { 30, 20, 45, 12, 8, 15 };
+ for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
+ {
+ pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, i, false));
+ aTest.SetValue(aChecks[i]);
+ CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
+ }
+ }
+ }
+
+ // Now, on to testing the filtered cache.
+
+ {
+ // Non-filtered cache - everything should be visible.
+ ScDPFilteredCache aFilteredCache(aCache);
+ aFilteredCache.fillTable();
+
+ sal_Int32 nRows = aFilteredCache.getRowSize();
+ CPPUNIT_ASSERT_MESSAGE("Wrong dimension.", nRows == 6 && aFilteredCache.getColSize() == 3);
+
+ for (sal_Int32 i = 0; i < nRows; ++i)
+ {
+ if (!aFilteredCache.isRowActive(i))
+ {
+ std::ostringstream os;
+ os << "Row " << i << " should be visible but it isn't.";
+ CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), false);
+ }
+ }
+ }
+
+ // TODO : Add test for filtered caches.
+
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableDuplicateDataFields()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Raw data
+ const char* aData[][2] = {
+ { "Name", "Value" },
+ { "A", "45" },
+ { "A", "5" },
+ { "A", "41" },
+ { "A", "49" },
+ { "A", "4" },
+ { "B", "33" },
+ { "B", "84" },
+ { "B", "74" },
+ { "B", "8" },
+ { "B", "68" }
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_COUNT }
+ };
+
+ ScAddress aPos(2,2,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+ CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount(), static_cast<size_t>(1));
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][3] = {
+ { "Name", "Data", 0 },
+ { "A", "Sum - Value", "144" },
+ { 0, "Count - Value", "5" },
+ { "B", "Sum - Value", "267" },
+ { 0, "Count - Value", "5" },
+ { "Total Sum - Value", 0, "411" },
+ { "Total Count - Value", 0, "10" },
+ };
+
+ bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ // Move the data layout dimension from row to column.
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ CPPUNIT_ASSERT_MESSAGE("No save data!?", pSaveData);
+ ScDPSaveDimension* pDataLayout = pSaveData->GetDataLayoutDimension();
+ CPPUNIT_ASSERT_MESSAGE("No data layout dimension.", pDataLayout);
+ pDataLayout->SetOrientation(sheet::DataPilotFieldOrientation_COLUMN);
+ pDPObj->SetSaveData(*pSaveData);
+
+ // Refresh the table output.
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][3] = {
+ { 0, "Data", 0 },
+ { "Name", "Sum - Value", "Count - Value" },
+ { "A", "144", "5" },
+ { "B", "267", "5" },
+ { "Total Result", "411", "10" }
+ };
+
+ bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ ScPivotParam aParam;
+ pDPObj->FillLabelData(aParam);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 4 labels (2 original, 1 data layout, and 1 duplicate dimensions).",
+ aParam.maLabelArray.size(), static_cast<size_t>(4));
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableNormalGrouping()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Raw data
+ const char* aData[][2] = {
+ { "Name", "Value" },
+ { "A", "1" },
+ { "B", "2" },
+ { "C", "3" },
+ { "D", "4" },
+ { "E", "5" },
+ { "F", "6" },
+ { "G", "7" }
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ };
+
+ ScAddress aPos(1,1,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+ CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount(), static_cast<size_t>(1));
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", "1" },
+ { "B", "2" },
+ { "C", "3" },
+ { "D", "4" },
+ { "E", "5" },
+ { "F", "6" },
+ { "G", "7" },
+ { "Total Result", "28" }
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Initial output without grouping");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ CPPUNIT_ASSERT_MESSAGE("No save data !?", pSaveData);
+ ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();
+ CPPUNIT_ASSERT_MESSAGE("Failed to create dimension data.", pDimData);
+
+ OUString aGroupPrefix("Group");
+ OUString aBaseDimName("Name");
+ OUString aGroupDimName =
+ pDimData->CreateGroupDimName(aBaseDimName, *pDPObj, false, NULL);
+
+ {
+ // Group A, B and C together.
+ ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
+ OUString aGroupName = aGroupDim.CreateGroupName(aGroupPrefix);
+ CPPUNIT_ASSERT_MESSAGE("Unexpected group name", aGroupName.equalsAscii("Group1"));
+
+ ScDPSaveGroupItem aGroup(aGroupName);
+ aGroup.AddElement(OUString("A"));
+ aGroup.AddElement(OUString("B"));
+ aGroup.AddElement(OUString("C"));
+ aGroupDim.AddGroupItem(aGroup);
+ pDimData->AddGroupDimension(aGroupDim);
+
+ ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
+ pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
+ pSaveData->SetPosition(pDim, 0); // Set it before the base dimension.
+ }
+
+ pDPObj->SetSaveData(*pSaveData);
+ aOutRange = refreshGroups(pDPs, pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][3] = {
+ { "Name2", "Name", 0 },
+ { "D", "D", "4" },
+ { "E", "E", "5" },
+ { "F", "F", "6" },
+ { "G", "G", "7" },
+ { "Group1", "A", "1" },
+ { 0, "B", "2" },
+ { 0, "C", "3" },
+ { "Total Result", 0, "28" }
+ };
+
+ bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "A, B, C grouped by Group1.");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ pSaveData = pDPObj->GetSaveData();
+ pDimData = pSaveData->GetDimensionData();
+
+ {
+ // Group D, E, F together.
+ ScDPSaveGroupDimension* pGroupDim = pDimData->GetGroupDimAccForBase(aBaseDimName);
+ CPPUNIT_ASSERT_MESSAGE("There should be an existing group dimension.", pGroupDim);
+ OUString aGroupName = pGroupDim->CreateGroupName(aGroupPrefix);
+ CPPUNIT_ASSERT_MESSAGE("Unexpected group name", aGroupName.equalsAscii("Group2"));
+
+ ScDPSaveGroupItem aGroup(aGroupName);
+ aGroup.AddElement(OUString("D"));
+ aGroup.AddElement(OUString("E"));
+ aGroup.AddElement(OUString("F"));
+ pGroupDim->AddGroupItem(aGroup);
+ }
+
+ pDPObj->SetSaveData(*pSaveData);
+ aOutRange = refreshGroups(pDPs, pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][3] = {
+ { "Name2", "Name", 0 },
+ { "G", "G", "7" },
+ { "Group1", "A", "1" },
+ { 0, "B", "2" },
+ { 0, "C", "3" },
+ { "Group2", "D", "4" },
+ { 0, "E", "5" },
+ { 0, "F", "6" },
+ { "Total Result", 0, "28" }
+ };
+
+ bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "D, E, F grouped by Group2.");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableNumberGrouping()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Raw data
+ const char* aData[][2] = {
+ { "Order", "Score" },
+ { "43", "171" },
+ { "18", "20" },
+ { "69", "159" },
+ { "95", "19" },
+ { "96", "163" },
+ { "46", "70" },
+ { "22", "36" },
+ { "81", "49" },
+ { "54", "61" },
+ { "39", "62" },
+ { "86", "17" },
+ { "34", "0" },
+ { "30", "25" },
+ { "24", "103" },
+ { "16", "59" },
+ { "24", "119" },
+ { "15", "86" },
+ { "69", "170" }
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Order", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Score", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ };
+
+ ScAddress aPos(1,1,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+ CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount(), static_cast<size_t>(1));
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ CPPUNIT_ASSERT_MESSAGE("No save data !?", pSaveData);
+ ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();
+ CPPUNIT_ASSERT_MESSAGE("No dimension data !?", pDimData);
+
+ {
+ ScDPNumGroupInfo aInfo;
+ aInfo.mbEnable = true;
+ aInfo.mbAutoStart = false;
+ aInfo.mbAutoEnd = false;
+ aInfo.mbDateValues = false;
+ aInfo.mbIntegerOnly = true;
+ aInfo.mfStart = 30;
+ aInfo.mfEnd = 60;
+ aInfo.mfStep = 10;
+ ScDPSaveNumGroupDimension aGroup(OUString("Order"), aInfo);
+ pDimData->AddNumGroupDimension(aGroup);
+ }
+
+ pDPObj->SetSaveData(*pSaveData);
+ ScRange aOutRange = refreshGroups(pDPs, pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Order", 0 },
+ { "<30", "423" },
+ { "30-39", "87" },
+ { "40-49", "241" },
+ { "50-60", "61" },
+ { ">60", "577" },
+ { "Total Result", "1389" }
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Order grouped by numbers");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableDateGrouping()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Raw data
+ const char* aData[][2] = {
+ { "Date", "Value" },
+ { "2011-01-01", "1" },
+ { "2011-03-02", "2" },
+ { "2012-01-04", "3" },
+ { "2012-02-23", "4" },
+ { "2012-02-24", "5" },
+ { "2012-03-15", "6" },
+ { "2011-09-03", "7" },
+ { "2012-12-25", "8" }
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Date", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ };
+
+ ScAddress aPos(1,1,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+ CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ CPPUNIT_ASSERT_MESSAGE("No save data !?", pSaveData);
+ ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();
+ CPPUNIT_ASSERT_MESSAGE("No dimension data !?", pDimData);
+
+ OUString aBaseDimName("Date");
+
+ ScDPNumGroupInfo aInfo;
+ aInfo.mbEnable = true;
+ aInfo.mbAutoStart = true;
+ aInfo.mbAutoEnd = true;
+ {
+ // Turn the Date dimension into months. The first of the date
+ // dimensions is always a number-group dimension which replaces the
+ // original dimension.
+ ScDPSaveNumGroupDimension aGroup(aBaseDimName, aInfo, sheet::DataPilotFieldGroupBy::MONTHS);
+ pDimData->AddNumGroupDimension(aGroup);
+ }
+
+ {
+ // Add quarter dimension. This will be an additional dimension.
+ OUString aGroupDimName =
+ pDimData->CreateDateGroupDimName(
+ sheet::DataPilotFieldGroupBy::QUARTERS, *pDPObj, true, NULL);
+ ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
+ aGroupDim.SetDateInfo(aInfo, sheet::DataPilotFieldGroupBy::QUARTERS);
+ pDimData->AddGroupDimension(aGroupDim);
+
+ // Set orientation.
+ ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
+ pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
+ pSaveData->SetPosition(pDim, 0); // set it to the left end.
+ }
+
+ {
+ // Add year dimension. This is a new dimension also.
+ OUString aGroupDimName =
+ pDimData->CreateDateGroupDimName(
+ sheet::DataPilotFieldGroupBy::YEARS, *pDPObj, true, NULL);
+ ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
+ aGroupDim.SetDateInfo(aInfo, sheet::DataPilotFieldGroupBy::YEARS);
+ pDimData->AddGroupDimension(aGroupDim);
+
+ // Set orientation.
+ ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
+ pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
+ pSaveData->SetPosition(pDim, 0); // set it to the left end.
+ }
+
+ pDPObj->SetSaveData(*pSaveData);
+ ScRange aOutRange = refreshGroups(pDPs, pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][4] = {
+ { "Years", "Quarters", "Date", 0 },
+ { "2011", "Q1", "Jan", "1" },
+ { 0, 0, "Mar", "2" },
+ { 0, "Q3", "Sep", "7" },
+ { "2012", "Q1", "Jan", "3" },
+ { 0, 0, "Feb", "9" },
+ { 0, 0, "Mar", "6" },
+ { 0, "Q4", "Dec", "8" },
+ { "Total Result", 0, 0, "36" },
+ };
+
+ bSuccess = checkDPTableOutput<4>(m_pDoc, aOutRange, aOutputCheck, "Years, quarters and months date groups.");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ {
+ // Let's hide year 2012.
+ pSaveData = pDPObj->GetSaveData();
+ ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(OUString("Years"));
+ CPPUNIT_ASSERT_MESSAGE("Years dimension should exist.", pDim);
+ ScDPSaveMember* pMem = pDim->GetMemberByName(OUString("2012"));
+ CPPUNIT_ASSERT_MESSAGE("Member should exist.", pMem);
+ pMem->SetIsVisible(false);
+ }
+ pDPObj->SetSaveData(*pSaveData);
+ pDPObj->ReloadGroupTableData();
+ pDPObj->InvalidateData();
+
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][4] = {
+ { "Years", "Quarters", "Date", 0 },
+ { "2011", "Q1", "Jan", "1" },
+ { 0, 0, "Mar", "2" },
+ { 0, "Q3", "Sep", "7" },
+ { "Total Result", 0, 0, "10" },
+ };
+
+ bSuccess = checkDPTableOutput<4>(m_pDoc, aOutRange, aOutputCheck, "Year 2012 data now hidden");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ // Remove all date grouping. The source dimension "Date" has two
+ // external dimensions ("Years" and "Quarters") and one internal ("Date"
+ // the same name but different hierarchy). Remove all of them.
+ pSaveData = pDPObj->GetSaveData();
+ pSaveData->RemoveAllGroupDimensions(aBaseDimName);
+ pDPObj->SetSaveData(*pSaveData);
+ pDPObj->ReloadGroupTableData();
+ pDPObj->InvalidateData();
+
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Date", 0 },
+ { "2011-01-01", "1" },
+ { "2011-03-02", "2" },
+ { "2011-09-03", "7" },
+ { "2012-01-04", "3" },
+ { "2012-02-23", "4" },
+ { "2012-02-24", "5" },
+ { "2012-03-15", "6" },
+ { "2012-12-25", "8" },
+ { "Total Result", "36" }
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Remove all date grouping.");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableEmptyRows()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Raw data
+ const char* aData[][2] = {
+ { "Name", "Value" },
+ { "A", "1" },
+ { "B", "2" },
+ { "C", "3" },
+ { "D", "4" },
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ };
+
+ ScAddress aPos(1,1,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+ CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+
+ // Extend the range downward to include some trailing empty rows.
+ aDataRange.aEnd.IncRow(2);
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", "1" },
+ { "B", "2" },
+ { "C", "3" },
+ { "D", "4" },
+ { "(empty)", 0 },
+ { "Total Result", "10" },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Include empty rows");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ // This time, ignore empty rows.
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ CPPUNIT_ASSERT_MESSAGE("Save data doesn't exist.", pSaveData);
+ pSaveData->SetIgnoreEmptyRows(true);
+ pDPObj->ClearTableData();
+ aOutRange = refresh(pDPObj);
+
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", "1" },
+ { "B", "2" },
+ { "C", "3" },
+ { "D", "4" },
+ { "Total Result", "10" },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Ignore empty rows");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ // Modify the source to remove member 'A', then refresh the table.
+ m_pDoc->SetString(1, 2, 0, "B");
+
+ std::set<ScDPObject*> aRefs;
+ sal_uLong nErr = pDPs->ReloadCache(pDPObj, aRefs);
+ CPPUNIT_ASSERT_MESSAGE("Failed to reload cache.", !nErr);
+ CPPUNIT_ASSERT_MESSAGE("There should only be one pivot table linked to this cache.",
+ aRefs.size() == 1 && *aRefs.begin() == pDPObj);
+
+ pDPObj->ClearTableData();
+ aOutRange = refresh(pDPObj);
+
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "B", "3" },
+ { "C", "3" },
+ { "D", "4" },
+ { "Total Result", "10" },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Ignore empty rows");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableTextNumber()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Raw data
+ const char* aData[][2] = {
+ { "Name", "Value" },
+ { "0001", "1" },
+ { "0002", "2" },
+ { "0003", "3" },
+ { "0004", "4" },
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ };
+
+ // Insert raw data such that the first column values are entered as text.
+ size_t nRowCount = SAL_N_ELEMENTS(aData);
+ for (size_t nRow = 0; nRow < nRowCount; ++nRow)
+ {
+ ScSetStringParam aParam;
+ aParam.mbDetectNumberFormat = false;
+ aParam.meSetTextNumFormat = ScSetStringParam::Always;
+ m_pDoc->SetString(0, nRow, 0, OUString::createFromAscii(aData[nRow][0]), &aParam);
+ aParam.meSetTextNumFormat = ScSetStringParam::Never;
+ m_pDoc->SetString(1, nRow, 0, OUString::createFromAscii(aData[nRow][1]), &aParam);
+
+ if (nRow == 0)
+ // Don't check the header row.
+ continue;
+
+ // Check the data rows.
+ CPPUNIT_ASSERT_MESSAGE("This cell is supposed to be text.", m_pDoc->HasStringData(0, nRow, 0));
+ CPPUNIT_ASSERT_MESSAGE("This cell is supposed to be numeric.", m_pDoc->HasValueData(1, nRow, 0));
+ }
+
+ ScRange aDataRange(0, 0, 0, 1, 4, 0);
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "0001", "1" },
+ { "0002", "2" },
+ { "0003", "3" },
+ { "0004", "4" },
+ { "Total Result", "10" },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Text number field members");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableCaseInsensitiveStrings()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Raw data
+ const char* aData[][2] = {
+ { "Name", "Value" },
+ { "A", "1" },
+ { "a", "2" },
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ };
+
+ ScAddress aPos(1,1,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+ CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", "3" },
+ { "Total Result", "3" },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Case insensitive strings");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableNumStability()
+{
+ FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
+
+ // Raw Data
+ const char* aData[][4] = {
+ { "Name", "Time Start", "Time End", "Total" },
+ { "Sam", "07:48 AM", "09:00 AM", "=RC[-1]-RC[-2]" },
+ { "Sam", "09:00 AM", "10:30 AM", "=RC[-1]-RC[-2]" },
+ { "Sam", "10:30 AM", "12:30 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "12:30 PM", "01:00 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "01:00 PM", "01:30 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "01:30 PM", "02:00 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "02:00 PM", "07:15 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "07:47 AM", "09:00 AM", "=RC[-1]-RC[-2]" },
+ { "Sam", "09:00 AM", "10:00 AM", "=RC[-1]-RC[-2]" },
+ { "Sam", "10:00 AM", "11:00 AM", "=RC[-1]-RC[-2]" },
+ { "Sam", "11:00 AM", "11:30 AM", "=RC[-1]-RC[-2]" },
+ { "Sam", "11:30 AM", "12:45 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "12:45 PM", "01:15 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "01:15 PM", "02:30 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "02:30 PM", "02:45 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "02:45 PM", "04:30 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "04:30 PM", "06:00 PM", "=RC[-1]-RC[-2]" },
+ { "Sam", "06:00 PM", "07:15 PM", "=RC[-1]-RC[-2]" },
+ { "Mike", "06:15 AM", "08:30 AM", "=RC[-1]-RC[-2]" },
+ { "Mike", "08:30 AM", "10:03 AM", "=RC[-1]-RC[-2]" },
+ { "Mike", "10:03 AM", "12:00 PM", "=RC[-1]-RC[-2]" },
+ { "Dennis", "11:00 AM", "01:00 PM", "=RC[-1]-RC[-2]" },
+ { "Dennis", "01:00 PM", "02:00 PM", "=RC[-1]-RC[-2]" }
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Total", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ };
+
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ size_t nRowCount = SAL_N_ELEMENTS(aData);
+ ScAddress aPos(1,1,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, nRowCount);
+
+ // Insert formulas to manually calculate sums for each name.
+ m_pDoc->SetString(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+1, aDataRange.aStart.Tab(), "=SUMIF(R[-23]C:R[-1]C;\"Dennis\";R[-23]C[3]:R[-1]C[3])");
+ m_pDoc->SetString(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+2, aDataRange.aStart.Tab(), "=SUMIF(R[-24]C:R[-2]C;\"Mike\";R[-24]C[3]:R[-2]C[3])");
+ m_pDoc->SetString(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+3, aDataRange.aStart.Tab(), "=SUMIF(R[-25]C:R[-3]C;\"Sam\";R[-25]C[3]:R[-3]C[3])");
+
+ m_pDoc->CalcAll();
+
+ // Get correct sum values.
+ double fDennisTotal = m_pDoc->GetValue(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+1, aDataRange.aStart.Tab());
+ double fMikeTotal = m_pDoc->GetValue(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+2, aDataRange.aStart.Tab());
+ double fSamTotal = m_pDoc->GetValue(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+3, aDataRange.aStart.Tab());
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount(), static_cast<size_t>(1));
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+
+ // Manually check the total value for each name.
+ //
+ // +--------------+----------------+
+ // | Name | |
+ // +--------------+----------------+
+ // | Dennis | <Dennis total> |
+ // +--------------+----------------+
+ // | Mike | <Miks total> |
+ // +--------------+----------------+
+ // | Sam | <Sam total> |
+ // +--------------+----------------+
+ // | Total Result | ... |
+ // +--------------+----------------+
+
+ aPos = aOutRange.aStart;
+ aPos.IncCol();
+ aPos.IncRow();
+ double fTest = m_pDoc->GetValue(aPos);
+ CPPUNIT_ASSERT_MESSAGE("Incorrect value for Dennis.", rtl::math::approxEqual(fTest, fDennisTotal));
+ aPos.IncRow();
+ fTest = m_pDoc->GetValue(aPos);
+ CPPUNIT_ASSERT_MESSAGE("Incorrect value for Mike.", rtl::math::approxEqual(fTest, fMikeTotal));
+ aPos.IncRow();
+ fTest = m_pDoc->GetValue(aPos);
+ CPPUNIT_ASSERT_MESSAGE("Incorrect value for Sam.", rtl::math::approxEqual(fTest, fSamTotal));
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableFieldReference()
+{
+ m_pDoc->InsertTab(0, OUString("Data"));
+ m_pDoc->InsertTab(1, OUString("Table"));
+
+ // Raw data
+ const char* aData[][2] = {
+ { "Name", "Value" },
+ { "A", "1" },
+ { "B", "2" },
+ { "C", "4" },
+ { "D", "8" },
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ };
+
+ ScAddress aPos(1,1,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+ CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ bool bSuccess = pDPs->InsertNewTable(pDPObj);
+
+ CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
+ CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
+ pDPs->GetCount() == 1);
+ pDPObj->SetName(pDPs->CreateNewName());
+
+ ScRange aOutRange = refresh(pDPObj);
+
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", "1" },
+ { "B", "2" },
+ { "C", "4" },
+ { "D", "8" },
+ { "Total Result", "15" },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (none)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ ScDPSaveData aSaveData = *pDPObj->GetSaveData();
+ sheet::DataPilotFieldReference aFieldRef;
+ aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE;
+ aFieldRef.ReferenceField = "Name";
+ aFieldRef.ReferenceItemType = sheet::DataPilotFieldReferenceItemType::NAMED;
+ aFieldRef.ReferenceItemName = "A";
+ ScDPSaveDimension* pDim = aSaveData.GetDimensionByName("Value");
+ CPPUNIT_ASSERT_MESSAGE("Failed to retrieve dimension 'Value'.", pDim);
+ pDim->SetReferenceValue(&aFieldRef);
+ pDPObj->SetSaveData(aSaveData);
+
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", 0 },
+ { "B", "1" },
+ { "C", "3" },
+ { "D", "7" },
+ { "Total Result", 0 },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (difference from)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE;
+ pDim->SetReferenceValue(&aFieldRef);
+ pDPObj->SetSaveData(aSaveData);
+
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", "100.00%" },
+ { "B", "200.00%" },
+ { "C", "400.00%" },
+ { "D", "800.00%" },
+ { "Total Result", 0 },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (% of)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE;
+ pDim->SetReferenceValue(&aFieldRef);
+ pDPObj->SetSaveData(aSaveData);
+
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", 0 },
+ { "B", "100.00%" },
+ { "C", "300.00%" },
+ { "D", "700.00%" },
+ { "Total Result", 0 },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (% difference from)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::RUNNING_TOTAL;
+ pDim->SetReferenceValue(&aFieldRef);
+ pDPObj->SetSaveData(aSaveData);
+
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", "1" },
+ { "B", "3" },
+ { "C", "7" },
+ { "D", "15" },
+ { "Total Result", 0 },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (Running total)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE;
+ pDim->SetReferenceValue(&aFieldRef);
+ pDPObj->SetSaveData(aSaveData);
+
+ aOutRange = refresh(pDPObj);
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "A", "6.67%" },
+ { "B", "13.33%" },
+ { "C", "26.67%" },
+ { "D", "53.33%" },
+ { "Total Result", "100.00%" },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (% of column)");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ pDPs->FreeTable(pDPObj);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
+ pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+void Test::testPivotTableDocFunc()
+{
+ m_pDoc->InsertTab(0, "Data");
+ m_pDoc->InsertTab(1, "Table");
+
+ // Raw data
+ const char* aData[][2] = {
+ { "Name", "Value" },
+ { "Sun", "1" },
+ { "Oracle", "2" },
+ { "Red Hat", "4" },
+ { "SUSE", "8" },
+ { "Apple", "16" },
+ { "Microsoft", "32" },
+ };
+
+ // Dimension definition
+ DPFieldDef aFields[] = {
+ { "Name", sheet::DataPilotFieldOrientation_ROW, 0 },
+ { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM },
+ };
+
+ ScAddress aPos(1,1,0);
+ ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+ CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
+
+ ScDPObject* pDPObj = createDPFromRange(
+ m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
+
+ CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table object.", pDPObj);
+
+ // Craete a new pivot table output.
+ ScDBDocFunc aFunc(getDocShell());
+ bool bSuccess = aFunc.CreatePivotTable(*pDPObj, false, true);
+ CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table output via ScDBDocFunc.", bSuccess);
+ ScDPCollection* pDPs = m_pDoc->GetDPCollection();
+ CPPUNIT_ASSERT_MESSAGE("Failed to get pivot table collection.", pDPs);
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDPs->GetCount());
+ pDPObj = (*pDPs)[0];
+ CPPUNIT_ASSERT_MESSAGE("Failed to retrieve pivot table object from the collection", pDPObj);
+ ScRange aOutRange = pDPObj->GetOutRange();
+ {
+ // Expected output table content. 0 = empty cell
+ const char* aOutputCheck[][2] = {
+ { "Name", 0 },
+ { "Apple", "16" },
+ { "Microsoft", "32" },
+ { "Oracle", "2" },
+ { "Red Hat", "4" },
+ { "Sun", "1" },
+ { "SUSE", "8" },
+ { "Total Result", "63" },
+ };
+
+ bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Pivot table created via ScDBDocFunc");
+ CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
+ }
+
+ // Remove this pivot table output. This should also clear the pivot cache
+ // it was referencing.
+ bSuccess = aFunc.RemovePivotTable(*pDPObj, false, true);
+ CPPUNIT_ASSERT_MESSAGE("Failed to remove pivot table output via ScDBDocFunc.", bSuccess);
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pDPs->GetCount());
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pDPs->GetSheetCaches().size());
+
+ m_pDoc->DeleteTab(1);
+ m_pDoc->DeleteTab(0);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */