/* -*- 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/.
*/
/** * Function for data field. It's used only for data field. When 0, the * default function (SUM) is used.
*/
ScGeneralFunction eFunc; bool bRepeatItemLabels;
};
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(aFields[i].eOrient);
pDim->SetUsedHierarchy(0);
if (aFields[i].eOrient == sheet::DataPilotFieldOrientation_DATA)
{
ScGeneralFunction eFunc = ScGeneralFunction::SUM; if (aFields[i].eFunc != ScGeneralFunction::NONE)
eFunc = aFields[i].eFunc;
ScRange refreshGroups(ScDPCollection* pDPs, ScDPObject* pDPObj)
{ // We need to first create group data in the cache, then the group data in // the object.
o3tl::sorted_vector<ScDPObject*> aRefs; bool bSuccess = pDPs->ReloadGroupsInCache(pDPObj, aRefs);
CPPUNIT_ASSERT_MESSAGE("Failed to reload group data in cache.", bSuccess);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only one table linked to this cache.", size_t(1), aRefs.size());
pDPObj->ReloadGroupTableData();
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
bool bSuccess = checkDPTableOutput(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
}
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only one data cache.", size_t(1), pDPs->GetSheetCaches().size());
// 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]);
}
// 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(std::unique_ptr<ScDPObject>(pDPObj2));
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only one data cache.", size_t(1), pDPs->GetSheetCaches().size());
// 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_EQUAL_MESSAGE("There should be only one data cache.", size_t(1), pDPs->GetSheetCaches().size());
// 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());
o3tl::sorted_vector<ScDPObject*> aRefs;
TranslateId pErrId = pDPs->ReloadCache(pDPObj2, aRefs);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Cache reload failed.", false, bool(pErrId));
CPPUNIT_ASSERT_EQUAL_MESSAGE("Reloading a cache shouldn't remove any cache.", static_cast<size_t>(1), pDPs->GetSheetCaches().size());
CPPUNIT_ASSERT_MESSAGE("Cache should be here.", pDPs->GetSheetCaches().hasCache(aSrcRange));
// Swap the two sheets.
m_pDoc->MoveTab(1, 0);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Swapping the sheets shouldn't remove the cache.",
size_t(1), pDPs->GetSheetCaches().size());
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_EQUAL_MESSAGE("There shouldn't be any data pilot table stored with the document.",
size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more data cache.",
size_t(0), pDPs->GetSheetCaches().size());
// 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, u"Table"_ustr);
pDPObj = createDPFromRange(
m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Data cache shouldn't exist yet before creating the table output.",
size_t(0), pDPs->GetSheetCaches().size());
// 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_EQUAL_MESSAGE("It should return the same object as a reference.",
o3tl::sorted_vector<ScDPObject*>::size_type(1), aRefs.size());
CPPUNIT_ASSERT_EQUAL_MESSAGE("It should return the same object as a reference.",
pDPObj, *aRefs.begin());
pDPs->FreeTable(pDPObj);
m_pDoc->DeleteTab(1);
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableLabels)
{ /** * Test against unwanted automatic format detection on field names and * field members in pivot tables.
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableDateLabels)
{ /** * Make sure that we set cells displaying date values numeric cells, * rather than text cells. Grouping by date or number functionality * depends on this.
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
// 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);
}
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableFilters)
{ /** * Test for pivot table's filtering functionality by page fields.
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
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(),
u"=B6"_ustr); double fTest = m_pDoc->GetValue(aFormulaAddr);
ASSERT_DOUBLES_EQUAL_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", 80.0, fTest);
fTest = m_pDoc->GetValue(aFormulaAddr);
ASSERT_DOUBLES_EQUAL_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", 40.0, fTest);
fTest = m_pDoc->GetValue(aFormulaAddr);
ASSERT_DOUBLES_EQUAL_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", 20.0, fTest);
// Set the current page of 'Group2' back to '- all -'. The query filter // should still be in effect.
pPageDim->SetCurrentPage(nullptr); // Remove the page.
pDPObj->SetSaveData(aSaveData);
aOutRange = refresh(pDPObj);
{ // Expected output table content. 0 = empty cell
std::vector<std::vector<constchar*>> aOutputCheck = {
{ "Filter", nullptr },
{ "Group2", "- all -" },
{ nullptr, nullptr },
{ "Data", nullptr },
{ "Sum - Val1", "4" },
{ "Sum - Val2", "40" }
};
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any data pilot table stored with the document.",
size_t(0), pDPs->GetCount());
m_pDoc->DeleteTab(1);
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableNamedSource)
{ /** * Test for pivot table's named source range.
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
// Insert the raw data.
ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
OUString aRangeStr(aSrcRange.Format(*m_pDoc, ScRefFlags::RANGE_ABS_3D));
// Name this range.
OUString aRangeName(u"MyData"_ustr);
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();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one named range data cache.",
size_t(1), pDPs->GetNameCaches().size());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one named range data cache.",
size_t(0), pDPs->GetSheetCaches().size());
// 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_EQUAL_MESSAGE( "Wrong sheet name.", u"Table"_ustr, aTabName);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Pivot table output is on the wrong sheet!", static_cast<SCTAB>(0), pDPObj->GetOutRange().aStart.Tab());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Moving the pivot table to another sheet shouldn't have changed the cache state.",
size_t(1), pDPs->GetNameCaches().size());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Moving the pivot table to another sheet shouldn't have changed the cache state.",
size_t(0), pDPs->GetSheetCaches().size());
const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
CPPUNIT_ASSERT_MESSAGE("Sheet source description doesn't exist.", pDesc);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Named source range has been altered unexpectedly!",
pDesc->GetRangeName(), aRangeName);
CPPUNIT_ASSERT_MESSAGE("Cache should exist.", pDPs->GetNameCaches().hasCache(aRangeName));
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetNameCaches().size());
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableCache)
{ /** * Test for pivot table cache. Each dimension in the pivot cache stores * only unique values that are sorted in ascending order.
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
// 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.
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(), false);
}
}
}
// TODO : Add test for filtered caches.
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableDuplicateDataFields)
{ /** * Test for pivot table containing data fields that reference the same * source field but different functions.
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
ScAddress aPos(2,2,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
// 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);
ScPivotParam aParam;
pDPObj->FillLabelData(aParam);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 4 labels (2 original, 1 data layout, and 1 duplicate dimensions).",
size_t(4), aParam.maLabelArray.size());
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
{ // Group A, B and C together.
ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
OUString aGroupName = aGroupDim.CreateGroupName(aGroupPrefix);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected group name", u"Group1"_ustr, aGroupName);
ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
pSaveData->SetPosition(pDim, 0); // Set it before the base dimension.
}
{ // 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_EQUAL_MESSAGE("Unexpected group name", u"Group2"_ustr, aGroupName);
bool bSuccess = checkDPTableOutput(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.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
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);
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
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(u"Date"_ustr);
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, nullptr);
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, nullptr);
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.
}
bool bSuccess = checkDPTableOutput(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();
bool bSuccess = checkDPTableOutput(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.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
// Extend the range downward to include some trailing empty rows.
aDataRange.aEnd.IncRow(2);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
// Modify the source to remove member 'A', then refresh the table.
m_pDoc->SetString(1, 2, 0, u"B"_ustr);
o3tl::sorted_vector<ScDPObject*> aRefs;
TranslateId pErr = pDPs->ReloadCache(pDPObj, aRefs);
CPPUNIT_ASSERT_MESSAGE("Failed to reload cache.", !pErr);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should only be one pivot table linked to this cache.",
o3tl::sorted_vector<ScDPObject*>::size_type(1), aRefs.size());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should only be one pivot table linked to this cache.",
pDPObj, *aRefs.begin());
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
// Insert raw data such that the first column values are entered as text. for (size_t nRow = 0; nRow < SAL_N_ELEMENTS(aData); ++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));
}
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
bool bSuccess = checkDPTableOutput(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.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
m_pDoc->DeleteTab(1);
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableCaseInsensitiveStrings)
{ /** * Test for checking that pivot table treats strings in a case insensitive * manner.
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
m_pDoc->DeleteTab(1);
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableNumStability)
{ /** * Test for pivot table's handling of double-precision numbers that are * very close together.
*/
FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
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.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
m_pDoc->DeleteTab(1);
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableFieldReference)
{ /** * Test for pivot table that include field with various non-default field * references.
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
m_pDoc->DeleteTab(1);
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableDocFunc)
{ /** * Test pivot table functionality performed via ScDBDocFunc.
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
bSuccess = aFunc.RemovePivotTable(*pDPObject, false, true);
CPPUNIT_ASSERT_MESSAGE("Pivot table should not be allowed to remove.", !bSuccess);
bSuccess = aFunc.UpdatePivotTable(*pDPObject, false, true);
CPPUNIT_ASSERT_MESSAGE("Pivot table should be allowed to update.", bSuccess);
aProtect.setProtected(false);
aProtect.setOption(ScTableProtection::PIVOT_TABLES, false);
m_pDoc->SetTabProtection(1, &aProtect); // End: Test Pivot table with tab protection
// Remove this pivot table output. This should also clear the pivot cache // it was referencing.
bSuccess = aFunc.RemovePivotTable(*pDPObject, 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());
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
ScAddress aPos(1,1,0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
// Create pivot table at A1 on 2nd sheet.
pDPObj = createDPFromRange(m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
ScRange aOutRange = refresh(pDPObj);
for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
m_pDoc->SetString(ScAddress(4,i,1), OUString::createFromAscii(aChecks[i].mpFormula));
m_pDoc->CalcAll();
for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
{
FormulaError nErr = m_pDoc->GetErrCode(ScAddress(4,i,1));
CPPUNIT_ASSERT_EQUAL(sal_uInt16(FormulaError::NONE), static_cast<sal_uInt16>(nErr)); double fVal = m_pDoc->GetValue(ScAddress(4,i,1));
CPPUNIT_ASSERT_EQUAL(aChecks[i].mfResult, fVal);
}
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
ScDPCollection* pDPs = m_pDoc->GetDPCollection();
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
size_t(1), pDPs->GetCount());
pDPObj->SetName(pDPs->CreateNewName());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be only one data cache.", size_t(1), pDPs->GetSheetCaches().size());
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", size_t(0), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
size_t(0), pDPs->GetSheetCaches().size());
m_pDoc->DeleteTab(1);
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableDPCollection)
{ /** * Test DPCollection public methods
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
// Add 2 DP objects
ScDPObject* pDPObj = createDPFromRange(m_pDoc, aDataRange , aFields, nFieldCount, false);
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj));
pDPObj->SetName(u"DP1"_ustr); // set custom name
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.", size_t(1), pDPs->GetCount());
ScDPObject* pDPObj2 = createDPFromRange(m_pDoc, aDataRange, aFields, nFieldCount, false);
pDPs->InsertNewTable(std::unique_ptr<ScDPObject>(pDPObj2));
pDPObj2->SetName(u"DP2"_ustr); // set custom name
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be two DP tables", size_t(2), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("should return first DPObject",
pDPObj, pDPs->GetByName(u"DP1"));
CPPUNIT_ASSERT_EQUAL_MESSAGE("should return second DPObject",
pDPObj2, pDPs->GetByName(u"DP2"));
CPPUNIT_ASSERT_EQUAL_MESSAGE("empty string should return nullptr", static_cast<ScDPObject*>(nullptr), pDPs->GetByName(u""));
CPPUNIT_ASSERT_EQUAL_MESSAGE("non existent name should return nullptr", static_cast<ScDPObject*>(nullptr), pDPs->GetByName(u"Non")); // Remove first DP Object
pDPs->FreeTable(pDPObj);
CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one DP table", size_t(1), pDPs->GetCount());
CPPUNIT_ASSERT_EQUAL_MESSAGE("first DP object was deleted, should return nullptr", static_cast<ScDPObject*>(nullptr), pDPs->GetByName(u"DP1"));
CPPUNIT_ASSERT_EQUAL_MESSAGE("should return second DPObject",
pDPObj2, pDPs->GetByName(u"DP2"));
CPPUNIT_ASSERT_EQUAL_MESSAGE("empty string should return nullptr", static_cast<ScDPObject*>(nullptr), pDPs->GetByName(u""));
CPPUNIT_ASSERT_EQUAL_MESSAGE("non existent name should return nullptr", static_cast<ScDPObject*>(nullptr), pDPs->GetByName(u"Non"));
// Remove second DP Object
pDPs->FreeTable(pDPObj2);
CPPUNIT_ASSERT_EQUAL_MESSAGE("first DP object was deleted, should return nullptr", static_cast<ScDPObject*>(nullptr), pDPs->GetByName(u"DP1"));
CPPUNIT_ASSERT_EQUAL_MESSAGE("second DP object was deleted, should return nullptr", static_cast<ScDPObject*>(nullptr), pDPs->GetByName(u"DP2"));
CPPUNIT_ASSERT_EQUAL_MESSAGE("empty string should return nullptr", static_cast<ScDPObject*>(nullptr), pDPs->GetByName(u""));
CPPUNIT_ASSERT_EQUAL_MESSAGE("non existent name should return nullptr", static_cast<ScDPObject*>(nullptr), pDPs->GetByName(u"Non"));
CPPUNIT_TEST_FIXTURE(TestPivottable, testPivotTableMedianFunc)
{ /** * Test pivot table median function
*/
m_pDoc->InsertTab(0, u"Data"_ustr);
m_pDoc->InsertTab(1, u"Table"_ustr);
ScAddress aPos(1, 1, 0);
ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData);
CPPUNIT_ASSERT_EQUAL_MESSAGE("failed to insert range data at correct position", aPos, aDataRange.aStart);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.