LCOV - code coverage report
Current view: top level - sc/qa/unit - ucalc_pivottable.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1086 1089 99.7 %
Date: 2015-06-13 12:38:46 Functions: 32 32 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  */
       9             : 
      10             : #include "ucalc.hxx"
      11             : #include "dpshttab.hxx"
      12             : #include "dpobject.hxx"
      13             : #include "dpsave.hxx"
      14             : #include "dpdimsave.hxx"
      15             : #include "dpcache.hxx"
      16             : #include "dpfilteredcache.hxx"
      17             : #include "scopetools.hxx"
      18             : #include "queryentry.hxx"
      19             : #include "stringutil.hxx"
      20             : #include "dbdocfun.hxx"
      21             : 
      22             : #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
      23             : #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
      24             : #include <com/sun/star/sheet/DataPilotFieldReference.hpp>
      25             : #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
      26             : #include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
      27             : #include <com/sun/star/sheet/GeneralFunction.hpp>
      28             : 
      29             : namespace {
      30             : 
      31             : struct DPFieldDef
      32             : {
      33             :     const char* pName;
      34             :     sheet::DataPilotFieldOrientation eOrient;
      35             : 
      36             :     /**
      37             :      * Function for data field.  It's used only for data field.  When 0, the
      38             :      * default function (SUM) is used.
      39             :      */
      40             :     int eFunc;
      41             :     bool bRepeatItemLabels;
      42             : };
      43             : 
      44             : template<size_t _Size>
      45           6 : ScRange insertDPSourceData(ScDocument* pDoc, DPFieldDef aFields[], size_t nFieldCount, const char* aData[][_Size], size_t nDataCount)
      46             : {
      47             :     // Insert field names in row 0.
      48          27 :     for (size_t i = 0; i < nFieldCount; ++i)
      49          21 :         pDoc->SetString(static_cast<SCCOL>(i), 0, 0, OUString(aFields[i].pName, strlen(aFields[i].pName), RTL_TEXTENCODING_UTF8));
      50             : 
      51             :     // Insert data into row 1 and downward.
      52          40 :     for (size_t i = 0; i < nDataCount; ++i)
      53             :     {
      54          34 :         SCROW nRow = static_cast<SCROW>(i) + 1;
      55         160 :         for (size_t j = 0; j < nFieldCount; ++j)
      56             :         {
      57         126 :             SCCOL nCol = static_cast<SCCOL>(j);
      58         126 :             pDoc->SetString(
      59         252 :                 nCol, nRow, 0, OUString(aData[i][j], strlen(aData[i][j]), RTL_TEXTENCODING_UTF8));
      60             :         }
      61             :     }
      62             : 
      63           6 :     SCROW nRow1 = 0, nRow2 = 0;
      64           6 :     SCCOL nCol1 = 0, nCol2 = 0;
      65           6 :     pDoc->GetDataArea(0, nCol1, nRow1, nCol2, nRow2, true, false);
      66           6 :     CPPUNIT_ASSERT_MESSAGE("Data is expected to start from (col=0,row=0).", nCol1 == 0 && nRow1 == 0);
      67           6 :     CPPUNIT_ASSERT_MESSAGE("Unexpected data range.",
      68             :                            nCol2 == static_cast<SCCOL>(nFieldCount - 1) && nRow2 == static_cast<SCROW>(nDataCount));
      69             : 
      70           6 :     ScRange aSrcRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
      71           6 :     Test::printRange(pDoc, aSrcRange, "Data sheet content");
      72           6 :     return aSrcRange;
      73             : }
      74             : 
      75             : template<size_t _Size>
      76          36 : bool checkDPTableOutput(ScDocument* pDoc, const ScRange& aOutRange, const char* aOutputCheck[][_Size], const char* pCaption)
      77             : {
      78          36 :     return checkOutput<_Size>(pDoc, aOutRange, aOutputCheck, pCaption);
      79             : }
      80             : 
      81          20 : ScDPObject* createDPFromSourceDesc(
      82             :     ScDocument* pDoc, const ScSheetSourceDesc& rDesc, DPFieldDef aFields[], size_t nFieldCount,
      83             :     bool bFilterButton)
      84             : {
      85          20 :     ScDPObject* pDPObj = new ScDPObject(pDoc);
      86          20 :     pDPObj->SetSheetDesc(rDesc);
      87          20 :     pDPObj->SetOutRange(ScAddress(0, 0, 1));
      88             : 
      89          20 :     ScDPSaveData aSaveData;
      90             :     // Set data pilot table output options.
      91          20 :     aSaveData.SetIgnoreEmptyRows(false);
      92          20 :     aSaveData.SetRepeatIfEmpty(false);
      93          20 :     aSaveData.SetColumnGrand(true);
      94          20 :     aSaveData.SetRowGrand(true);
      95          20 :     aSaveData.SetFilterButton(bFilterButton);
      96          20 :     aSaveData.SetDrillDown(true);
      97             : 
      98             :     // Check the sanity of the source range.
      99          20 :     const ScRange& rSrcRange = rDesc.GetSourceRange();
     100          20 :     SCROW nRow1 = rSrcRange.aStart.Row();
     101          20 :     SCROW nRow2 = rSrcRange.aEnd.Row();
     102          20 :     CPPUNIT_ASSERT_MESSAGE("source range contains no data!", nRow2 - nRow1 > 1);
     103             : 
     104             :     // Set the dimension information.
     105          73 :     for (size_t i = 0; i < nFieldCount; ++i)
     106             :     {
     107          53 :         OUString aDimName = OUString::createFromAscii(aFields[i].pName);
     108          53 :         ScDPSaveDimension* pDim = aSaveData.GetNewDimensionByName(aDimName);
     109          53 :         pDim->SetOrientation(static_cast<sal_uInt16>(aFields[i].eOrient));
     110          53 :         pDim->SetUsedHierarchy(0);
     111             : 
     112          53 :         if (aFields[i].eOrient == sheet::DataPilotFieldOrientation_DATA)
     113             :         {
     114          23 :             sheet::GeneralFunction eFunc = sheet::GeneralFunction_SUM;
     115          23 :             if (aFields[i].eFunc)
     116          15 :                 eFunc = static_cast<sheet::GeneralFunction>(aFields[i].eFunc);
     117             : 
     118          23 :             pDim->SetFunction(eFunc);
     119          23 :             pDim->SetReferenceValue(NULL);
     120             :         }
     121             :         else
     122             :         {
     123          30 :             sheet::DataPilotFieldSortInfo aSortInfo;
     124          30 :             aSortInfo.IsAscending = true;
     125          30 :             aSortInfo.Mode = 2;
     126          30 :             pDim->SetSortInfo(&aSortInfo);
     127             : 
     128          30 :             sheet::DataPilotFieldLayoutInfo aLayInfo;
     129          30 :             aLayInfo.LayoutMode = 0;
     130          30 :             aLayInfo.AddEmptyLines = false;
     131          30 :             pDim->SetLayoutInfo(&aLayInfo);
     132          60 :             sheet::DataPilotFieldAutoShowInfo aShowInfo;
     133          30 :             aShowInfo.IsEnabled = false;
     134          30 :             aShowInfo.ShowItemsMode = 0;
     135          30 :             aShowInfo.ItemCount = 0;
     136          30 :             pDim->SetAutoShowInfo(&aShowInfo);
     137          60 :             pDim->SetRepeatItemLabels(aFields[i].bRepeatItemLabels);
     138             :         }
     139          53 :     }
     140             : 
     141             :     // Don't forget the data layout dimension.
     142          20 :     ScDPSaveDimension* pDim = aSaveData.GetDataLayoutDimension();
     143          20 :     pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
     144          20 :     pDim->SetShowEmpty(true);
     145             : 
     146          20 :     pDPObj->SetSaveData(aSaveData);
     147          20 :     pDPObj->InvalidateData();
     148             : 
     149          20 :     return pDPObj;
     150             : }
     151             : 
     152          19 : ScDPObject* createDPFromRange(
     153             :     ScDocument* pDoc, const ScRange& rRange, DPFieldDef aFields[], size_t nFieldCount,
     154             :     bool bFilterButton)
     155             : {
     156          19 :     ScSheetSourceDesc aSheetDesc(pDoc);
     157          19 :     aSheetDesc.SetSourceRange(rRange);
     158          19 :     return createDPFromSourceDesc(pDoc, aSheetDesc, aFields, nFieldCount, bFilterButton);
     159             : }
     160             : 
     161          32 : ScRange refresh(ScDPObject* pDPObj)
     162             : {
     163          32 :     bool bOverflow = false;
     164          32 :     ScRange aOutRange = pDPObj->GetNewOutputRange(bOverflow);
     165          32 :     CPPUNIT_ASSERT_MESSAGE("Table overflow!?", !bOverflow);
     166             : 
     167          32 :     pDPObj->Output(aOutRange.aStart);
     168          32 :     aOutRange = pDPObj->GetOutRange();
     169          32 :     return aOutRange;
     170             : }
     171             : 
     172           4 : ScRange refreshGroups(ScDPCollection* pDPs, ScDPObject* pDPObj)
     173             : {
     174             :     // We need to first create group data in the cache, then the group data in
     175             :     // the object.
     176           4 :     std::set<ScDPObject*> aRefs;
     177           4 :     bool bSuccess = pDPs->ReloadGroupsInCache(pDPObj, aRefs);
     178           4 :     CPPUNIT_ASSERT_MESSAGE("Failed to reload group data in cache.", bSuccess);
     179           4 :     CPPUNIT_ASSERT_MESSAGE("There should be only one table linked to this cache.", aRefs.size() == 1);
     180           4 :     pDPObj->ReloadGroupTableData();
     181             : 
     182           4 :     return refresh(pDPObj);
     183             : }
     184             : 
     185             : }
     186             : 
     187           1 : void Test::testPivotTable()
     188             : {
     189           1 :     m_pDoc->InsertTab(0, OUString("Data"));
     190           1 :     m_pDoc->InsertTab(1, OUString("Table"));
     191             : 
     192             :     // Dimension definition
     193             :     DPFieldDef aFields[] = {
     194             :         { "Name",  sheet::DataPilotFieldOrientation_ROW, 0, false },
     195             :         { "Group", sheet::DataPilotFieldOrientation_COLUMN, 0, false },
     196             :         { "Score", sheet::DataPilotFieldOrientation_DATA, 0, false }
     197           1 :     };
     198             : 
     199             :     // Raw data
     200             :     const char* aData[][3] = {
     201             :         { "Andy",    "A", "30" },
     202             :         { "Bruce",   "A", "20" },
     203             :         { "Charlie", "B", "45" },
     204             :         { "David",   "B", "12" },
     205             :         { "Edward",  "C",  "8" },
     206             :         { "Frank",   "C", "15" },
     207           1 :     };
     208             : 
     209           1 :     size_t nFieldCount = SAL_N_ELEMENTS(aFields);
     210           1 :     size_t nDataCount = SAL_N_ELEMENTS(aData);
     211             : 
     212           1 :     ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
     213           1 :     SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
     214           1 :     SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
     215             : 
     216             :     ScDPObject* pDPObj = createDPFromRange(
     217           1 :         m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
     218             : 
     219           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
     220           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
     221           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
     222           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
     223           1 :                            pDPs->GetCount() == 1);
     224           1 :     pDPObj->SetName(pDPs->CreateNewName());
     225             : 
     226           1 :     bool bOverflow = false;
     227           1 :     ScRange aOutRange = pDPObj->GetNewOutputRange(bOverflow);
     228           1 :     CPPUNIT_ASSERT_MESSAGE("Table overflow!?", !bOverflow);
     229             : 
     230           1 :     pDPObj->Output(aOutRange.aStart);
     231           1 :     aOutRange = pDPObj->GetOutRange();
     232             :     {
     233             :         // Expected output table content.  0 = empty cell
     234             :         const char* aOutputCheck[][5] = {
     235             :             { "Sum - Score", "Group", 0, 0, 0 },
     236             :             { "Name", "A", "B", "C", "Total Result" },
     237             :             { "Andy", "30", 0, 0, "30" },
     238             :             { "Bruce", "20", 0, 0, "20" },
     239             :             { "Charlie", 0, "45", 0, "45" },
     240             :             { "David", 0, "12", 0, "12" },
     241             :             { "Edward", 0, 0, "8", "8" },
     242             :             { "Frank", 0, 0, "15", "15" },
     243             :             { "Total Result", "50", "57", "23", "130" }
     244           1 :         };
     245             : 
     246           1 :         bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
     247           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     248             :     }
     249           1 :     CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
     250             : 
     251             :     // Update the cell values.
     252           1 :     double aData2[] = { 100, 200, 300, 400, 500, 600 };
     253           7 :     for (size_t i = 0; i < SAL_N_ELEMENTS(aData2); ++i)
     254             :     {
     255           6 :         SCROW nRow = i + 1;
     256           6 :         m_pDoc->SetValue(2, nRow, 0, aData2[i]);
     257             :     }
     258             : 
     259           1 :     printRange(m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), "Data sheet content (modified)");
     260             : 
     261             :     // Now, create a copy of the datapilot object for the updated table, but
     262             :     // don't reload the cache which should force the copy to use the old data
     263             :     // from the cache.
     264           1 :     ScDPObject* pDPObj2 = new ScDPObject(*pDPObj);
     265           1 :     pDPs->InsertNewTable(pDPObj2);
     266             : 
     267           1 :     aOutRange = pDPObj2->GetOutRange();
     268           1 :     pDPObj2->ClearTableData();
     269           1 :     pDPObj2->Output(aOutRange.aStart);
     270             :     {
     271             :         // Expected output table content.  0 = empty cell
     272             :         const char* aOutputCheck[][5] = {
     273             :             { "Sum - Score", "Group", 0, 0, 0 },
     274             :             { "Name", "A", "B", "C", "Total Result" },
     275             :             { "Andy", "30", 0, 0, "30" },
     276             :             { "Bruce", "20", 0, 0, "20" },
     277             :             { "Charlie", 0, "45", 0, "45" },
     278             :             { "David", 0, "12", 0, "12" },
     279             :             { "Edward", 0, 0, "8", "8" },
     280             :             { "Frank", 0, 0, "15", "15" },
     281             :             { "Total Result", "50", "57", "23", "130" }
     282           1 :         };
     283             : 
     284           1 :         bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (from old cache)");
     285           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     286             :     }
     287             : 
     288           1 :     CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
     289             : 
     290             :     // Free the first datapilot object after the 2nd one gets reloaded, to
     291             :     // prevent the data cache from being deleted before the reload.
     292           1 :     pDPs->FreeTable(pDPObj);
     293             : 
     294           1 :     CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
     295             : 
     296             :     // This time clear the cache to refresh the data from the source range.
     297           1 :     CPPUNIT_ASSERT_MESSAGE("This datapilot should be based on sheet data.", pDPObj2->IsSheetData());
     298           1 :     std::set<ScDPObject*> aRefs;
     299           1 :     sal_uLong nErrId = pDPs->ReloadCache(pDPObj2, aRefs);
     300           1 :     CPPUNIT_ASSERT_MESSAGE("Cache reload failed.", nErrId == 0);
     301           2 :     CPPUNIT_ASSERT_MESSAGE("Reloading a cache shouldn't remove any cache.",
     302           1 :                            pDPs->GetSheetCaches().size() == 1);
     303             : 
     304           1 :     pDPObj2->ClearTableData();
     305           1 :     pDPObj2->Output(aOutRange.aStart);
     306             : 
     307             :     {
     308             :         // Expected output table content.  0 = empty cell
     309             :         const char* aOutputCheck[][5] = {
     310             :             { "Sum - Score", "Group", 0, 0, 0 },
     311             :             { "Name", "A", "B", "C", "Total Result" },
     312             :             { "Andy", "100", 0, 0, "100" },
     313             :             { "Bruce", "200", 0, 0, "200" },
     314             :             { "Charlie", 0, "300", 0, "300" },
     315             :             { "David", 0, "400", 0, "400" },
     316             :             { "Edward", 0, 0, "500", "500" },
     317             :             { "Frank", 0, 0, "600", "600" },
     318             :             { "Total Result", "300", "700", "1100", "2100" }
     319           1 :         };
     320             : 
     321           1 :         bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (refreshed)");
     322           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     323             :     }
     324             : 
     325           1 :     CPPUNIT_ASSERT_MESSAGE("Cache should be here.", pDPs->GetSheetCaches().hasCache(aSrcRange));
     326             : 
     327             :     // Swap the two sheets.
     328           1 :     m_pDoc->MoveTab(1, 0);
     329           2 :     CPPUNIT_ASSERT_MESSAGE("Swapping the sheets shouldn't remove the cache.",
     330           1 :                            pDPs->GetSheetCaches().size() == 1);
     331           1 :     CPPUNIT_ASSERT_MESSAGE("Cache should have moved.", !pDPs->GetSheetCaches().hasCache(aSrcRange));
     332           1 :     aSrcRange.aStart.SetTab(1);
     333           1 :     aSrcRange.aEnd.SetTab(1);
     334           1 :     CPPUNIT_ASSERT_MESSAGE("Cache should be here.", pDPs->GetSheetCaches().hasCache(aSrcRange));
     335             : 
     336           1 :     pDPs->FreeTable(pDPObj2);
     337           2 :     CPPUNIT_ASSERT_MESSAGE("There shouldn't be any data pilot table stored with the document.",
     338           1 :                            pDPs->GetCount() == 0);
     339             : 
     340           2 :     CPPUNIT_ASSERT_MESSAGE("There shouldn't be any more data cache.",
     341           1 :                            pDPs->GetSheetCaches().size() == 0);
     342             : 
     343             :     // Insert a brand new pivot table object once again, but this time, don't
     344             :     // create the output to avoid creating a data cache.
     345           1 :     m_pDoc->DeleteTab(1);
     346           1 :     m_pDoc->InsertTab(1, OUString("Table"));
     347             : 
     348             :     pDPObj = createDPFromRange(
     349           1 :         m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
     350           1 :     bSuccess = pDPs->InsertNewTable(pDPObj);
     351           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
     352           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
     353           1 :                            pDPs->GetCount() == 1);
     354           1 :     pDPObj->SetName(pDPs->CreateNewName());
     355           2 :     CPPUNIT_ASSERT_MESSAGE("Data cache shouldn't exist yet before creating the table output.",
     356           1 :                            pDPs->GetSheetCaches().size() == 0);
     357             : 
     358             :     // Now, "refresh" the table.  This should still return a reference to self
     359             :     // even with the absence of data cache.
     360           1 :     aRefs.clear();
     361           1 :     pDPs->ReloadCache(pDPObj, aRefs);
     362           2 :     CPPUNIT_ASSERT_MESSAGE("It should return the same object as a reference.",
     363           1 :                            aRefs.size() == 1 && *aRefs.begin() == pDPObj);
     364             : 
     365           1 :     pDPs->FreeTable(pDPObj);
     366             : 
     367           1 :     m_pDoc->DeleteTab(1);
     368           1 :     m_pDoc->DeleteTab(0);
     369           1 : }
     370             : 
     371           1 : void Test::testPivotTableLabels()
     372             : {
     373           1 :     m_pDoc->InsertTab(0, OUString("Data"));
     374           1 :     m_pDoc->InsertTab(1, OUString("Table"));
     375             : 
     376             :     // Dimension definition
     377             :     DPFieldDef aFields[] = {
     378             :         { "Software", sheet::DataPilotFieldOrientation_ROW, 0, false },
     379             :         { "Version",  sheet::DataPilotFieldOrientation_COLUMN, 0, false },
     380             :         { "1.2.3",    sheet::DataPilotFieldOrientation_DATA, 0, false }
     381           1 :     };
     382             : 
     383             :     // Raw data
     384             :     const char* aData[][3] = {
     385             :         { "LibreOffice", "3.3.0", "30" },
     386             :         { "LibreOffice", "3.3.1", "20" },
     387             :         { "LibreOffice", "3.4.0", "45" },
     388           1 :     };
     389             : 
     390           1 :     size_t nFieldCount = SAL_N_ELEMENTS(aFields);
     391           1 :     size_t nDataCount = SAL_N_ELEMENTS(aData);
     392             : 
     393           1 :     ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
     394           1 :     SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
     395           1 :     SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
     396             : 
     397             :     ScDPObject* pDPObj = createDPFromRange(
     398           1 :         m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
     399             : 
     400           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
     401           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
     402           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
     403           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
     404           1 :                            pDPs->GetCount() == 1);
     405           1 :     pDPObj->SetName(pDPs->CreateNewName());
     406             : 
     407           1 :     ScRange aOutRange = refresh(pDPObj);
     408             :     {
     409             :         // Expected output table content.  0 = empty cell
     410             :         const char* aOutputCheck[][5] = {
     411             :             { "Sum - 1.2.3", "Version", 0, 0, 0 },
     412             :             { "Software", "3.3.0", "3.3.1", "3.4.0", "Total Result" },
     413             :             { "LibreOffice", "30", "20", "45", "95" },
     414             :             { "Total Result", "30", "20", "45", "95" }
     415           1 :         };
     416             : 
     417           1 :         bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
     418           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     419             :     }
     420             : 
     421           1 :     pDPs->FreeTable(pDPObj);
     422             : 
     423           1 :     m_pDoc->DeleteTab(1);
     424           1 :     m_pDoc->DeleteTab(0);
     425           1 : }
     426             : 
     427           1 : void Test::testPivotTableDateLabels()
     428             : {
     429           1 :     m_pDoc->InsertTab(0, OUString("Data"));
     430           1 :     m_pDoc->InsertTab(1, OUString("Table"));
     431             : 
     432             :     // Dimension definition
     433             :     DPFieldDef aFields[] = {
     434             :         { "Name",  sheet::DataPilotFieldOrientation_ROW, 0, false },
     435             :         { "Date",  sheet::DataPilotFieldOrientation_COLUMN, 0, false },
     436             :         { "Value", sheet::DataPilotFieldOrientation_DATA, 0, false }
     437           1 :     };
     438             : 
     439             :     // Raw data
     440             :     const char* aData[][3] = {
     441             :         { "Zena",   "2011-1-1", "30" },
     442             :         { "Yodel",  "2011-1-2", "20" },
     443             :         { "Xavior", "2011-1-3", "45" }
     444           1 :     };
     445             : 
     446           1 :     size_t nFieldCount = SAL_N_ELEMENTS(aFields);
     447           1 :     size_t nDataCount = SAL_N_ELEMENTS(aData);
     448             : 
     449           1 :     ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
     450           1 :     SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
     451           1 :     SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
     452             : 
     453             :     ScDPObject* pDPObj = createDPFromRange(
     454           1 :         m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
     455             : 
     456           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
     457           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
     458           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
     459           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
     460           1 :                            pDPs->GetCount() == 1);
     461           1 :     pDPObj->SetName(pDPs->CreateNewName());
     462             : 
     463           1 :     ScRange aOutRange = refresh(pDPObj);
     464             :     {
     465             :         // Expected output table content.  0 = empty cell
     466             :         const char* aOutputCheck[][5] = {
     467             :             { "Sum - Value", "Date", 0, 0, 0 },
     468             :             { "Name", "2011-01-01", "2011-01-02", "2011-01-03", "Total Result" },
     469             :             { "Xavior",  0, 0, "45", "45" },
     470             :             { "Yodel",  0, "20", 0, "20" },
     471             :             { "Zena",  "30", 0, 0, "30" },
     472             :             { "Total Result", "30", "20", "45", "95" }
     473           1 :         };
     474             : 
     475           1 :         bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
     476           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     477             :     }
     478             : 
     479             :     {
     480             :         const char* aChecks[] = {
     481             :             "2011-01-01", "2011-01-02", "2011-01-03"
     482           1 :         };
     483             : 
     484             :         // Make sure those cells that contain dates are numeric.
     485           1 :         SCROW nRow = aOutRange.aStart.Row() + 1;
     486           1 :         nCol1 = aOutRange.aStart.Col() + 1;
     487           1 :         nCol2 = nCol1 + 2;
     488           4 :         for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
     489             :         {
     490           3 :             OUString aVal = m_pDoc->GetString(nCol, nRow, 1);
     491           3 :             CPPUNIT_ASSERT_MESSAGE("Cell value is not as expected.", aVal.equalsAscii(aChecks[nCol-nCol1]));
     492           6 :             CPPUNIT_ASSERT_MESSAGE("This cell contains a date value and is supposed to be numeric.",
     493           3 :                                    m_pDoc->HasValueData(nCol, nRow, 1));
     494           3 :         }
     495             :     }
     496             : 
     497           1 :     pDPs->FreeTable(pDPObj);
     498             : 
     499           1 :     m_pDoc->DeleteTab(1);
     500           1 :     m_pDoc->DeleteTab(0);
     501           1 : }
     502             : 
     503           1 : void Test::testPivotTableFilters()
     504             : {
     505           1 :     m_pDoc->InsertTab(0, OUString("Data"));
     506           1 :     m_pDoc->InsertTab(1, OUString("Table"));
     507             : 
     508             :     // Dimension definition
     509             :     DPFieldDef aFields[] = {
     510             :         { "Name",   sheet::DataPilotFieldOrientation_HIDDEN, 0, false },
     511             :         { "Group1", sheet::DataPilotFieldOrientation_HIDDEN, 0, false },
     512             :         { "Group2", sheet::DataPilotFieldOrientation_PAGE, 0, false },
     513             :         { "Val1",   sheet::DataPilotFieldOrientation_DATA, 0, false },
     514             :         { "Val2",   sheet::DataPilotFieldOrientation_DATA, 0, false }
     515           1 :     };
     516             : 
     517             :     // Raw data
     518             :     const char* aData[][5] = {
     519             :         { "A", "1", "A", "1", "10" },
     520             :         { "B", "1", "A", "1", "10" },
     521             :         { "C", "1", "B", "1", "10" },
     522             :         { "D", "1", "B", "1", "10" },
     523             :         { "E", "2", "A", "1", "10" },
     524             :         { "F", "2", "A", "1", "10" },
     525             :         { "G", "2", "B", "1", "10" },
     526             :         { "H", "2", "B", "1", "10" }
     527           1 :     };
     528             : 
     529           1 :     size_t nFieldCount = SAL_N_ELEMENTS(aFields);
     530           1 :     size_t nDataCount = SAL_N_ELEMENTS(aData);
     531             : 
     532           1 :     ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
     533           1 :     SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
     534           1 :     SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
     535             : 
     536             :     ScDPObject* pDPObj = createDPFromRange(
     537           1 :         m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, true);
     538             : 
     539           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
     540           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
     541           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
     542           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
     543           1 :                            pDPs->GetCount() == 1);
     544           1 :     pDPObj->SetName(pDPs->CreateNewName());
     545             : 
     546           1 :     ScRange aOutRange = refresh(pDPObj);
     547             :     {
     548             :         // Expected output table content.  0 = empty cell
     549             :         const char* aOutputCheck[][2] = {
     550             :             { "Filter", 0 },
     551             :             { "Group2", "- all -" },
     552             :             { 0, 0 },
     553             :             { "Data", 0 },
     554             :             { "Sum - Val1", "8" },
     555             :             { "Sum - Val2", "80" }
     556           1 :         };
     557             : 
     558           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (unfiltered)");
     559           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     560             :     }
     561             : 
     562           1 :     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation.
     563             : 
     564           1 :     ScAddress aFormulaAddr = aOutRange.aEnd;
     565           1 :     aFormulaAddr.IncRow(2);
     566           2 :     m_pDoc->SetString(aFormulaAddr.Col(), aFormulaAddr.Row(), aFormulaAddr.Tab(),
     567           3 :                       OUString("=B6"));
     568           1 :     double fTest = m_pDoc->GetValue(aFormulaAddr);
     569           1 :     CPPUNIT_ASSERT_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", fTest == 80.0);
     570             : 
     571             :     // Set current page of 'Group2' to 'A'.
     572           1 :     pDPObj->BuildAllDimensionMembers();
     573           2 :     ScDPSaveData aSaveData(*pDPObj->GetSaveData());
     574             :     ScDPSaveDimension* pPageDim = aSaveData.GetDimensionByName(
     575           1 :         OUString("Group2"));
     576           1 :     CPPUNIT_ASSERT_MESSAGE("Dimension not found", pPageDim);
     577           2 :     OUString aPage("A");
     578           1 :     pPageDim->SetCurrentPage(&aPage);
     579           1 :     pDPObj->SetSaveData(aSaveData);
     580           1 :     aOutRange = refresh(pDPObj);
     581             :     {
     582             :         // Expected output table content.  0 = empty cell
     583             :         const char* aOutputCheck[][2] = {
     584             :             { "Filter", 0 },
     585             :             { "Group2", "A" },
     586             :             { 0, 0 },
     587             :             { "Data", 0 },
     588             :             { "Sum - Val1", "4" },
     589             :             { "Sum - Val2", "40" }
     590           1 :         };
     591             : 
     592           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by page)");
     593           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     594             :     }
     595             : 
     596           1 :     fTest = m_pDoc->GetValue(aFormulaAddr);
     597           1 :     CPPUNIT_ASSERT_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", fTest == 40.0);
     598             : 
     599             :     // Set query filter.
     600           2 :     ScSheetSourceDesc aDesc(*pDPObj->GetSheetDesc());
     601           2 :     ScQueryParam aQueryParam(aDesc.GetQueryParam());
     602           1 :     CPPUNIT_ASSERT_MESSAGE("There should be at least one query entry.", aQueryParam.GetEntryCount() > 0);
     603           1 :     ScQueryEntry& rEntry = aQueryParam.GetEntry(0);
     604           1 :     rEntry.bDoQuery = true;
     605           1 :     rEntry.nField = 1;  // Group1
     606           1 :     rEntry.GetQueryItem().mfVal = 1;
     607           1 :     aDesc.SetQueryParam(aQueryParam);
     608           1 :     pDPObj->SetSheetDesc(aDesc);
     609           1 :     aOutRange = refresh(pDPObj);
     610             :     {
     611             :         // Expected output table content.  0 = empty cell
     612             :         const char* aOutputCheck[][2] = {
     613             :             { "Filter", 0 },
     614             :             { "Group2", "A" },
     615             :             { 0, 0 },
     616             :             { "Data", 0 },
     617             :             { "Sum - Val1", "2" },
     618             :             { "Sum - Val2", "20" }
     619           1 :         };
     620             : 
     621           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by query)");
     622           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     623             :     }
     624             : 
     625           1 :     fTest = m_pDoc->GetValue(aFormulaAddr);
     626           1 :     CPPUNIT_ASSERT_MESSAGE("Incorrect formula value that references a cell in the pivot table output.", fTest == 20.0);
     627             : 
     628             :     // Set the current page of 'Group2' back to '- all -'. The query filter
     629             :     // should still be in effect.
     630           1 :     pPageDim->SetCurrentPage(NULL); // Remove the page.
     631           1 :     pDPObj->SetSaveData(aSaveData);
     632           1 :     aOutRange = refresh(pDPObj);
     633             :     {
     634             :         // Expected output table content.  0 = empty cell
     635             :         const char* aOutputCheck[][2] = {
     636             :             { "Filter", 0 },
     637             :             { "Group2", "- all -" },
     638             :             { 0, 0 },
     639             :             { "Data", 0 },
     640             :             { "Sum - Val1", "4" },
     641             :             { "Sum - Val2", "40" }
     642           1 :         };
     643             : 
     644           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output (filtered by page)");
     645           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     646             :     }
     647             : 
     648           1 :     pDPs->FreeTable(pDPObj);
     649           2 :     CPPUNIT_ASSERT_MESSAGE("There shouldn't be any data pilot table stored with the document.",
     650           1 :                            pDPs->GetCount() == 0);
     651             : 
     652           1 :     m_pDoc->DeleteTab(1);
     653           2 :     m_pDoc->DeleteTab(0);
     654           1 : }
     655             : 
     656           1 : void Test::testPivotTableNamedSource()
     657             : {
     658           1 :     m_pDoc->InsertTab(0, OUString("Data"));
     659           1 :     m_pDoc->InsertTab(1, OUString("Table"));
     660             : 
     661             :     // Dimension definition
     662             :     DPFieldDef aFields[] = {
     663             :         { "Name",  sheet::DataPilotFieldOrientation_ROW, 0, false },
     664             :         { "Group", sheet::DataPilotFieldOrientation_COLUMN, 0, false },
     665             :         { "Score", sheet::DataPilotFieldOrientation_DATA, 0, false }
     666           1 :     };
     667             : 
     668             :     // Raw data
     669             :     const char* aData[][3] = {
     670             :         { "Andy",    "A", "30" },
     671             :         { "Bruce",   "A", "20" },
     672             :         { "Charlie", "B", "45" },
     673             :         { "David",   "B", "12" },
     674             :         { "Edward",  "C",  "8" },
     675             :         { "Frank",   "C", "15" },
     676           1 :     };
     677             : 
     678           1 :     size_t nFieldCount = SAL_N_ELEMENTS(aFields);
     679           1 :     size_t nDataCount = SAL_N_ELEMENTS(aData);
     680             : 
     681             :     // Insert the raw data.
     682           1 :     ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
     683           1 :     OUString aRangeStr(aSrcRange.Format(SCR_ABS_3D, m_pDoc));
     684             : 
     685             :     // Name this range.
     686           2 :     OUString aRangeName("MyData");
     687           1 :     ScRangeName* pNames = m_pDoc->GetRangeName();
     688           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get global range name container.", pNames);
     689             :     ScRangeData* pName = new ScRangeData(
     690           1 :         m_pDoc, aRangeName, aRangeStr);
     691           1 :     bool bSuccess = pNames->insert(pName);
     692           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bSuccess);
     693             : 
     694           2 :     ScSheetSourceDesc aSheetDesc(m_pDoc);
     695           1 :     aSheetDesc.SetRangeName(aRangeName);
     696           1 :     ScDPObject* pDPObj = createDPFromSourceDesc(m_pDoc, aSheetDesc, aFields, nFieldCount, false);
     697           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to create a new pivot table object.", pDPObj);
     698             : 
     699           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
     700           1 :     bSuccess = pDPs->InsertNewTable(pDPObj);
     701           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
     702           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
     703           1 :                            pDPs->GetCount() == 1);
     704           1 :     pDPObj->SetName(pDPs->CreateNewName());
     705             : 
     706           1 :     ScRange aOutRange = refresh(pDPObj);
     707             :     {
     708             :         // Expected output table content.  0 = empty cell
     709             :         const char* aOutputCheck[][5] = {
     710             :             { "Sum - Score", "Group", 0, 0, 0 },
     711             :             { "Name", "A", "B", "C", "Total Result" },
     712             :             { "Andy", "30", 0, 0, "30" },
     713             :             { "Bruce", "20", 0, 0, "20" },
     714             :             { "Charlie", 0, "45", 0, "45" },
     715             :             { "David", 0, "12", 0, "12" },
     716             :             { "Edward", 0, 0, "8", "8" },
     717             :             { "Frank", 0, 0, "15", "15" },
     718             :             { "Total Result", "50", "57", "23", "130" }
     719           1 :         };
     720             : 
     721           1 :         bSuccess = checkDPTableOutput<5>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
     722           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     723             :     }
     724             : 
     725           2 :     CPPUNIT_ASSERT_MESSAGE("There should be one named range data cache.",
     726           1 :                            pDPs->GetNameCaches().size() == 1 && pDPs->GetSheetCaches().size() == 0);
     727             : 
     728             :     // Move the table with pivot table to the left of the source data sheet.
     729           1 :     m_pDoc->MoveTab(1, 0);
     730           2 :     OUString aTabName;
     731           1 :     m_pDoc->GetName(0, aTabName);
     732           1 :     CPPUNIT_ASSERT_MESSAGE( "Wrong sheet name.", aTabName == "Table" );
     733           2 :     CPPUNIT_ASSERT_MESSAGE("Pivot table output is on the wrong sheet!",
     734           1 :                            pDPObj->GetOutRange().aStart.Tab() == 0);
     735             : 
     736           2 :     CPPUNIT_ASSERT_MESSAGE("Moving the pivot table to another sheet shouldn't have changed the cache state.",
     737           1 :                            pDPs->GetNameCaches().size() == 1 && pDPs->GetSheetCaches().size() == 0);
     738             : 
     739           1 :     const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
     740           1 :     CPPUNIT_ASSERT_MESSAGE("Sheet source description doesn't exist.", pDesc);
     741           2 :     CPPUNIT_ASSERT_MESSAGE("Named source range has been altered unexpectedly!",
     742           1 :                            pDesc->GetRangeName().equals(aRangeName));
     743             : 
     744           1 :     CPPUNIT_ASSERT_MESSAGE("Cache should exist.", pDPs->GetNameCaches().hasCache(aRangeName));
     745             : 
     746           1 :     pDPs->FreeTable(pDPObj);
     747           1 :     CPPUNIT_ASSERT_MESSAGE("There should be no more tables.", pDPs->GetCount() == 0);
     748           2 :     CPPUNIT_ASSERT_MESSAGE("There shouldn't be any more cache stored.",
     749           1 :                            pDPs->GetNameCaches().size() == 0);
     750             : 
     751           1 :     pNames->clear();
     752           1 :     m_pDoc->DeleteTab(1);
     753           2 :     m_pDoc->DeleteTab(0);
     754           1 : }
     755             : 
     756           1 : void Test::testPivotTableCache()
     757             : {
     758           1 :     m_pDoc->InsertTab(0, OUString("Data"));
     759             : 
     760             :     // Raw data
     761             :     const char* aData[][3] = {
     762             :         { "F1", "F2", "F3" },
     763             :         { "Z",  "A", "30" },
     764             :         { "R",  "A", "20" },
     765             :         { "A",  "B", "45" },
     766             :         { "F",  "B", "12" },
     767             :         { "Y",  "C",  "8" },
     768             :         { "12", "C", "15" },
     769           1 :     };
     770             : 
     771           1 :     ScAddress aPos(1,1,0);
     772           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
     773           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
     774             : 
     775           1 :     ScDPCache aCache(m_pDoc);
     776           1 :     aCache.InitFromDoc(m_pDoc, aDataRange);
     777           1 :     long nDimCount = aCache.GetColumnCount();
     778           1 :     CPPUNIT_ASSERT_MESSAGE("wrong dimension count.", nDimCount == 3);
     779           2 :     OUString aDimName = aCache.GetDimensionName(0);
     780           1 :     CPPUNIT_ASSERT_MESSAGE("wrong dimension name", aDimName == "F1");
     781           1 :     aDimName = aCache.GetDimensionName(1);
     782           1 :     CPPUNIT_ASSERT_MESSAGE("wrong dimension name", aDimName == "F2");
     783           1 :     aDimName = aCache.GetDimensionName(2);
     784           1 :     CPPUNIT_ASSERT_MESSAGE("wrong dimension name", aDimName == "F3");
     785             : 
     786             :     // In each dimension, member ID values also represent their sort order (in
     787             :     // source dimensions only, not in group dimensions). Value items are
     788             :     // sorted before string ones. Also, no duplicate dimension members should
     789             :     // exist.
     790             : 
     791             :     // Dimension 0 - a mix of strings and values.
     792           1 :     long nMemCount = aCache.GetDimMemberCount(0);
     793           1 :     CPPUNIT_ASSERT_MESSAGE("wrong dimension member count", nMemCount == 6);
     794           1 :     const ScDPItemData* pItem = aCache.GetItemDataById(0, 0);
     795           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     796             :                            pItem->GetType() == ScDPItemData::Value &&
     797           1 :                            pItem->GetValue() == 12);
     798           1 :     pItem = aCache.GetItemDataById(0, 1);
     799           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     800             :                            pItem->GetType() == ScDPItemData::String &&
     801           1 :                            pItem->GetString() == "A");
     802           1 :     pItem = aCache.GetItemDataById(0, 2);
     803           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     804             :                            pItem->GetType() == ScDPItemData::String &&
     805           1 :                            pItem->GetString() == "F");
     806           1 :     pItem = aCache.GetItemDataById(0, 3);
     807           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     808             :                            pItem->GetType() == ScDPItemData::String &&
     809           1 :                            pItem->GetString() == "R");
     810           1 :     pItem = aCache.GetItemDataById(0, 4);
     811           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     812             :                            pItem->GetType() == ScDPItemData::String &&
     813           1 :                            pItem->GetString() == "Y");
     814           1 :     pItem = aCache.GetItemDataById(0, 5);
     815           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     816             :                            pItem->GetType() == ScDPItemData::String &&
     817           1 :                            pItem->GetString() == "Z");
     818           1 :     pItem = aCache.GetItemDataById(0, 6);
     819           1 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", !pItem);
     820             : 
     821             :     // Dimension 1 - duplicate values in source.
     822           1 :     nMemCount = aCache.GetDimMemberCount(1);
     823           1 :     CPPUNIT_ASSERT_MESSAGE("wrong dimension member count", nMemCount == 3);
     824           1 :     pItem = aCache.GetItemDataById(1, 0);
     825           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     826             :                            pItem->GetType() == ScDPItemData::String &&
     827           1 :                            pItem->GetString() == "A");
     828           1 :     pItem = aCache.GetItemDataById(1, 1);
     829           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     830             :                            pItem->GetType() == ScDPItemData::String &&
     831           1 :                            pItem->GetString() == "B");
     832           1 :     pItem = aCache.GetItemDataById(1, 2);
     833           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     834             :                            pItem->GetType() == ScDPItemData::String &&
     835           1 :                            pItem->GetString() == "C");
     836           1 :     pItem = aCache.GetItemDataById(1, 3);
     837           1 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", !pItem);
     838             : 
     839             :     // Dimension 2 - values only.
     840           1 :     nMemCount = aCache.GetDimMemberCount(2);
     841           1 :     CPPUNIT_ASSERT_MESSAGE("wrong dimension member count", nMemCount == 6);
     842           1 :     pItem = aCache.GetItemDataById(2, 0);
     843           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     844             :                            pItem->GetType() == ScDPItemData::Value &&
     845           1 :                            pItem->GetValue() == 8);
     846           1 :     pItem = aCache.GetItemDataById(2, 1);
     847           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     848             :                            pItem->GetType() == ScDPItemData::Value &&
     849           1 :                            pItem->GetValue() == 12);
     850           1 :     pItem = aCache.GetItemDataById(2, 2);
     851           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     852             :                            pItem->GetType() == ScDPItemData::Value &&
     853           1 :                            pItem->GetValue() == 15);
     854           1 :     pItem = aCache.GetItemDataById(2, 3);
     855           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     856             :                            pItem->GetType() == ScDPItemData::Value &&
     857           1 :                            pItem->GetValue() == 20);
     858           1 :     pItem = aCache.GetItemDataById(2, 4);
     859           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     860             :                            pItem->GetType() == ScDPItemData::Value &&
     861           1 :                            pItem->GetValue() == 30);
     862           1 :     pItem = aCache.GetItemDataById(2, 5);
     863           2 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", pItem &&
     864             :                            pItem->GetType() == ScDPItemData::Value &&
     865           1 :                            pItem->GetValue() == 45);
     866           1 :     pItem = aCache.GetItemDataById(2, 6);
     867           1 :     CPPUNIT_ASSERT_MESSAGE("wrong item value", !pItem);
     868             : 
     869             :     {
     870             :         // Check the integrity of the source data.
     871           1 :         ScDPItemData aTest;
     872             :         long nDim;
     873             : 
     874             :         {
     875             :             // Dimension 0: Z, R, A, F, Y, 12
     876           1 :             nDim = 0;
     877           1 :             const char* aChecks[] = { "Z", "R", "A", "F", "Y" };
     878           6 :             for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
     879             :             {
     880           5 :                 pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, i, false));
     881           5 :                 aTest.SetString(OUString::createFromAscii(aChecks[i]));
     882           5 :                 CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
     883             :             }
     884             : 
     885           1 :             pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, 5, false));
     886           1 :             aTest.SetValue(12);
     887           1 :             CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
     888             :         }
     889             : 
     890             :         {
     891             :             // Dimension 1: A, A, B, B, C, C
     892           1 :             nDim = 1;
     893           1 :             const char* aChecks[] = { "A", "A", "B", "B", "C", "C" };
     894           7 :             for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
     895             :             {
     896           6 :                 pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, i, false));
     897           6 :                 aTest.SetString(OUString::createFromAscii(aChecks[i]));
     898           6 :                 CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
     899             :             }
     900             :         }
     901             : 
     902             :         {
     903             :             // Dimension 2: 30, 20, 45, 12, 8, 15
     904           1 :             nDim = 2;
     905           1 :             double aChecks[] = { 30, 20, 45, 12, 8, 15 };
     906           7 :             for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
     907             :             {
     908           6 :                 pItem = aCache.GetItemDataById(nDim, aCache.GetItemDataId(nDim, i, false));
     909           6 :                 aTest.SetValue(aChecks[i]);
     910           6 :                 CPPUNIT_ASSERT_MESSAGE("wrong data value", pItem && *pItem == aTest);
     911             :             }
     912           1 :         }
     913             :     }
     914             : 
     915             :     // Now, on to testing the filtered cache.
     916             : 
     917             :     {
     918             :         // Non-filtered cache - everything should be visible.
     919           1 :         ScDPFilteredCache aFilteredCache(aCache);
     920           1 :         aFilteredCache.fillTable();
     921             : 
     922           1 :         sal_Int32 nRows = aFilteredCache.getRowSize();
     923           1 :         CPPUNIT_ASSERT_MESSAGE("Wrong dimension.", nRows == 6 && aFilteredCache.getColSize() == 3);
     924             : 
     925           7 :         for (sal_Int32 i = 0; i < nRows; ++i)
     926             :         {
     927           6 :             if (!aFilteredCache.isRowActive(i))
     928             :             {
     929           0 :                 std::ostringstream os;
     930           0 :                 os << "Row " << i << " should be visible but it isn't.";
     931           0 :                 CPPUNIT_ASSERT_MESSAGE(os.str().c_str(), false);
     932             :             }
     933           1 :         }
     934             :     }
     935             : 
     936             :     // TODO : Add test for filtered caches.
     937             : 
     938           2 :     m_pDoc->DeleteTab(0);
     939           1 : }
     940             : 
     941           1 : void Test::testPivotTableDuplicateDataFields()
     942             : {
     943           1 :     m_pDoc->InsertTab(0, OUString("Data"));
     944           1 :     m_pDoc->InsertTab(1, OUString("Table"));
     945             : 
     946             :     // Raw data
     947             :     const char* aData[][2] = {
     948             :         { "Name", "Value" },
     949             :         { "A",       "45" },
     950             :         { "A",        "5" },
     951             :         { "A",       "41" },
     952             :         { "A",       "49" },
     953             :         { "A",        "4" },
     954             :         { "B",       "33" },
     955             :         { "B",       "84" },
     956             :         { "B",       "74" },
     957             :         { "B",        "8" },
     958             :         { "B",       "68" }
     959           1 :     };
     960             : 
     961             :     // Dimension definition
     962             :     DPFieldDef aFields[] = {
     963             :         { "Name",  sheet::DataPilotFieldOrientation_ROW, 0, false },
     964             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
     965             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_COUNT, false }
     966           1 :     };
     967             : 
     968           1 :     ScAddress aPos(2,2,0);
     969           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
     970           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
     971             : 
     972             :     ScDPObject* pDPObj = createDPFromRange(
     973           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
     974             : 
     975           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
     976           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
     977             : 
     978           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
     979           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
     980           1 :                            pDPs->GetCount(), static_cast<size_t>(1));
     981           1 :     pDPObj->SetName(pDPs->CreateNewName());
     982             : 
     983           1 :     ScRange aOutRange = refresh(pDPObj);
     984             :     {
     985             :         // Expected output table content.  0 = empty cell
     986             :         const char* aOutputCheck[][3] = {
     987             :             { "Name", "Data", 0 },
     988             :             { "A", "Sum - Value", "144" },
     989             :             { 0, "Count - Value", "5" },
     990             :             { "B", "Sum - Value", "267" },
     991             :             { 0, "Count - Value", "5" },
     992             :             { "Total Sum - Value", 0, "411" },
     993             :             { "Total Count - Value", 0, "10" },
     994           1 :         };
     995             : 
     996           1 :         bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
     997           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
     998             :     }
     999             : 
    1000             :     // Move the data layout dimension from row to column.
    1001           1 :     ScDPSaveData* pSaveData = pDPObj->GetSaveData();
    1002           1 :     CPPUNIT_ASSERT_MESSAGE("No save data!?", pSaveData);
    1003           1 :     ScDPSaveDimension* pDataLayout = pSaveData->GetDataLayoutDimension();
    1004           1 :     CPPUNIT_ASSERT_MESSAGE("No data layout dimension.", pDataLayout);
    1005           1 :     pDataLayout->SetOrientation(sheet::DataPilotFieldOrientation_COLUMN);
    1006           1 :     pDPObj->SetSaveData(*pSaveData);
    1007             : 
    1008             :     // Refresh the table output.
    1009           1 :     aOutRange = refresh(pDPObj);
    1010             :     {
    1011             :         // Expected output table content.  0 = empty cell
    1012             :         const char* aOutputCheck[][3] = {
    1013             :             { 0, "Data", 0 },
    1014             :             { "Name", "Sum - Value", "Count - Value" },
    1015             :             { "A", "144", "5" },
    1016             :             { "B", "267", "5" },
    1017             :             { "Total Result", "411", "10" }
    1018           1 :         };
    1019             : 
    1020           1 :         bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
    1021           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1022             :     }
    1023             : 
    1024           1 :     ScPivotParam aParam;
    1025           1 :     pDPObj->FillLabelData(aParam);
    1026           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be exactly 4 labels (2 original, 1 data layout, and 1 duplicate dimensions).",
    1027           1 :                            aParam.maLabelArray.size(), static_cast<size_t>(4));
    1028             : 
    1029           1 :     pDPs->FreeTable(pDPObj);
    1030           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    1031           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    1032           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    1033             : 
    1034           1 :     m_pDoc->DeleteTab(1);
    1035           1 :     m_pDoc->DeleteTab(0);
    1036           1 : }
    1037             : 
    1038           1 : void Test::testPivotTableNormalGrouping()
    1039             : {
    1040           1 :     m_pDoc->InsertTab(0, OUString("Data"));
    1041           1 :     m_pDoc->InsertTab(1, OUString("Table"));
    1042             : 
    1043             :     // Raw data
    1044             :     const char* aData[][2] = {
    1045             :         { "Name", "Value" },
    1046             :         { "A", "1" },
    1047             :         { "B", "2" },
    1048             :         { "C", "3" },
    1049             :         { "D", "4" },
    1050             :         { "E", "5" },
    1051             :         { "F", "6" },
    1052             :         { "G", "7" }
    1053           1 :     };
    1054             : 
    1055             :     // Dimension definition
    1056             :     DPFieldDef aFields[] = {
    1057             :         { "Name",  sheet::DataPilotFieldOrientation_ROW, 0, false },
    1058             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    1059           1 :     };
    1060             : 
    1061           1 :     ScAddress aPos(1,1,0);
    1062           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    1063           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    1064             : 
    1065             :     ScDPObject* pDPObj = createDPFromRange(
    1066           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    1067             : 
    1068           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    1069           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    1070             : 
    1071           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    1072           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
    1073           1 :                            pDPs->GetCount(), static_cast<size_t>(1));
    1074           1 :     pDPObj->SetName(pDPs->CreateNewName());
    1075             : 
    1076           1 :     ScRange aOutRange = refresh(pDPObj);
    1077             :     {
    1078             :         // Expected output table content.  0 = empty cell
    1079             :         const char* aOutputCheck[][2] = {
    1080             :             { "Name", "Sum - Value" },
    1081             :             { "A", "1" },
    1082             :             { "B", "2" },
    1083             :             { "C", "3" },
    1084             :             { "D", "4" },
    1085             :             { "E", "5" },
    1086             :             { "F", "6" },
    1087             :             { "G", "7" },
    1088             :             { "Total Result", "28" }
    1089           1 :         };
    1090             : 
    1091           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Initial output without grouping");
    1092           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1093             :     }
    1094             : 
    1095           1 :     ScDPSaveData* pSaveData = pDPObj->GetSaveData();
    1096           1 :     CPPUNIT_ASSERT_MESSAGE("No save data !?", pSaveData);
    1097           1 :     ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();
    1098           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to create dimension data.", pDimData);
    1099             : 
    1100           1 :     OUString aGroupPrefix("Group");
    1101           2 :     OUString aBaseDimName("Name");
    1102             :     OUString aGroupDimName =
    1103           2 :         pDimData->CreateGroupDimName(aBaseDimName, *pDPObj, false, NULL);
    1104             : 
    1105             :     {
    1106             :         // Group A, B and C together.
    1107           1 :         ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
    1108           2 :         OUString aGroupName = aGroupDim.CreateGroupName(aGroupPrefix);
    1109           1 :         CPPUNIT_ASSERT_MESSAGE("Unexpected group name", aGroupName == "Group1");
    1110             : 
    1111           2 :         ScDPSaveGroupItem aGroup(aGroupName);
    1112           1 :         aGroup.AddElement(OUString("A"));
    1113           1 :         aGroup.AddElement(OUString("B"));
    1114           1 :         aGroup.AddElement(OUString("C"));
    1115           1 :         aGroupDim.AddGroupItem(aGroup);
    1116           1 :         pDimData->AddGroupDimension(aGroupDim);
    1117             : 
    1118           1 :         ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
    1119           1 :         pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
    1120           2 :         pSaveData->SetPosition(pDim, 0); // Set it before the base dimension.
    1121             :     }
    1122             : 
    1123           1 :     pDPObj->SetSaveData(*pSaveData);
    1124           1 :     aOutRange = refreshGroups(pDPs, pDPObj);
    1125             :     {
    1126             :         // Expected output table content.  0 = empty cell
    1127             :         const char* aOutputCheck[][3] = {
    1128             :             { "Name2", "Name", "Sum - Value" },
    1129             :             { "D", "D", "4" },
    1130             :             { "E", "E", "5" },
    1131             :             { "F", "F", "6" },
    1132             :             { "G", "G", "7" },
    1133             :             { "Group1", "A", "1" },
    1134             :             { 0,        "B", "2" },
    1135             :             { 0,        "C", "3" },
    1136             :             { "Total Result", 0, "28" }
    1137           1 :         };
    1138             : 
    1139           1 :         bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "A, B, C grouped by Group1.");
    1140           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1141             :     }
    1142             : 
    1143           1 :     pSaveData = pDPObj->GetSaveData();
    1144           1 :     pDimData = pSaveData->GetDimensionData();
    1145             : 
    1146             :     {
    1147             :         // Group D, E, F together.
    1148           1 :         ScDPSaveGroupDimension* pGroupDim = pDimData->GetGroupDimAccForBase(aBaseDimName);
    1149           1 :         CPPUNIT_ASSERT_MESSAGE("There should be an existing group dimension.", pGroupDim);
    1150           1 :         OUString aGroupName = pGroupDim->CreateGroupName(aGroupPrefix);
    1151           1 :         CPPUNIT_ASSERT_MESSAGE("Unexpected group name", aGroupName == "Group2");
    1152             : 
    1153           2 :         ScDPSaveGroupItem aGroup(aGroupName);
    1154           1 :         aGroup.AddElement(OUString("D"));
    1155           1 :         aGroup.AddElement(OUString("E"));
    1156           1 :         aGroup.AddElement(OUString("F"));
    1157           2 :         pGroupDim->AddGroupItem(aGroup);
    1158             :     }
    1159             : 
    1160           1 :     pDPObj->SetSaveData(*pSaveData);
    1161           1 :     aOutRange = refreshGroups(pDPs, pDPObj);
    1162             :     {
    1163             :         // Expected output table content.  0 = empty cell
    1164             :         const char* aOutputCheck[][3] = {
    1165             :             { "Name2", "Name", "Sum - Value" },
    1166             :             { "G", "G", "7" },
    1167             :             { "Group1", "A", "1" },
    1168             :             { 0,        "B", "2" },
    1169             :             { 0,        "C", "3" },
    1170             :             { "Group2", "D", "4" },
    1171             :             { 0,        "E", "5" },
    1172             :             { 0,        "F", "6" },
    1173             :             { "Total Result", 0, "28" }
    1174           1 :         };
    1175             : 
    1176           1 :         bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "D, E, F grouped by Group2.");
    1177           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1178             :     }
    1179             : 
    1180           1 :     pDPs->FreeTable(pDPObj);
    1181           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    1182           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    1183           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    1184             : 
    1185           1 :     m_pDoc->DeleteTab(1);
    1186           2 :     m_pDoc->DeleteTab(0);
    1187           1 : }
    1188             : 
    1189           1 : void Test::testPivotTableNumberGrouping()
    1190             : {
    1191           1 :     m_pDoc->InsertTab(0, OUString("Data"));
    1192           1 :     m_pDoc->InsertTab(1, OUString("Table"));
    1193             : 
    1194             :     // Raw data
    1195             :     const char* aData[][2] = {
    1196             :         { "Order", "Score" },
    1197             :         { "43", "171" },
    1198             :         { "18", "20"  },
    1199             :         { "69", "159" },
    1200             :         { "95", "19"  },
    1201             :         { "96", "163" },
    1202             :         { "46", "70"  },
    1203             :         { "22", "36"  },
    1204             :         { "81", "49"  },
    1205             :         { "54", "61"  },
    1206             :         { "39", "62"  },
    1207             :         { "86", "17"  },
    1208             :         { "34", "0"   },
    1209             :         { "30", "25"  },
    1210             :         { "24", "103" },
    1211             :         { "16", "59"  },
    1212             :         { "24", "119" },
    1213             :         { "15", "86"  },
    1214             :         { "69", "170" }
    1215           1 :     };
    1216             : 
    1217             :     // Dimension definition
    1218             :     DPFieldDef aFields[] = {
    1219             :         { "Order", sheet::DataPilotFieldOrientation_ROW, 0, false },
    1220             :         { "Score", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    1221           1 :     };
    1222             : 
    1223           1 :     ScAddress aPos(1,1,0);
    1224           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    1225           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    1226             : 
    1227             :     ScDPObject* pDPObj = createDPFromRange(
    1228           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    1229             : 
    1230           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    1231           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    1232             : 
    1233           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    1234           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
    1235           1 :                            pDPs->GetCount(), static_cast<size_t>(1));
    1236           1 :     pDPObj->SetName(pDPs->CreateNewName());
    1237             : 
    1238           1 :     ScDPSaveData* pSaveData = pDPObj->GetSaveData();
    1239           1 :     CPPUNIT_ASSERT_MESSAGE("No save data !?", pSaveData);
    1240           1 :     ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();
    1241           1 :     CPPUNIT_ASSERT_MESSAGE("No dimension data !?", pDimData);
    1242             : 
    1243             :     {
    1244           1 :         ScDPNumGroupInfo aInfo;
    1245           1 :         aInfo.mbEnable = true;
    1246           1 :         aInfo.mbAutoStart = false;
    1247           1 :         aInfo.mbAutoEnd = false;
    1248           1 :         aInfo.mbDateValues = false;
    1249           1 :         aInfo.mbIntegerOnly = true;
    1250           1 :         aInfo.mfStart = 30;
    1251           1 :         aInfo.mfEnd = 60;
    1252           1 :         aInfo.mfStep = 10;
    1253           1 :         ScDPSaveNumGroupDimension aGroup(OUString("Order"), aInfo);
    1254           1 :         pDimData->AddNumGroupDimension(aGroup);
    1255             :     }
    1256             : 
    1257           1 :     pDPObj->SetSaveData(*pSaveData);
    1258           1 :     ScRange aOutRange = refreshGroups(pDPs, pDPObj);
    1259             :     {
    1260             :         // Expected output table content.  0 = empty cell
    1261             :         const char* aOutputCheck[][2] = {
    1262             :             { "Order", "Sum - Score" },
    1263             :             { "<30",   "423" },
    1264             :             { "30-39", "87"  },
    1265             :             { "40-49", "241" },
    1266             :             { "50-60", "61"  },
    1267             :             { ">60",   "577" },
    1268             :             { "Total Result", "1389" }
    1269           1 :         };
    1270             : 
    1271           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Order grouped by numbers");
    1272           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1273             :     }
    1274             : 
    1275           1 :     pDPs->FreeTable(pDPObj);
    1276           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    1277           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    1278           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    1279             : 
    1280           1 :     m_pDoc->DeleteTab(1);
    1281           1 :     m_pDoc->DeleteTab(0);
    1282           1 : }
    1283             : 
    1284           1 : void Test::testPivotTableDateGrouping()
    1285             : {
    1286           1 :     m_pDoc->InsertTab(0, OUString("Data"));
    1287           1 :     m_pDoc->InsertTab(1, OUString("Table"));
    1288             : 
    1289             :     // Raw data
    1290             :     const char* aData[][2] = {
    1291             :         { "Date", "Value" },
    1292             :         { "2011-01-01", "1" },
    1293             :         { "2011-03-02", "2" },
    1294             :         { "2012-01-04", "3" },
    1295             :         { "2012-02-23", "4" },
    1296             :         { "2012-02-24", "5" },
    1297             :         { "2012-03-15", "6" },
    1298             :         { "2011-09-03", "7" },
    1299             :         { "2012-12-25", "8" }
    1300           1 :     };
    1301             : 
    1302             :     // Dimension definition
    1303             :     DPFieldDef aFields[] = {
    1304             :         { "Date", sheet::DataPilotFieldOrientation_ROW, 0, false },
    1305             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    1306           1 :     };
    1307             : 
    1308           1 :     ScAddress aPos(1,1,0);
    1309           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    1310           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    1311             : 
    1312             :     ScDPObject* pDPObj = createDPFromRange(
    1313           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    1314             : 
    1315           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    1316           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    1317             : 
    1318           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    1319           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
    1320           1 :                            pDPs->GetCount() == 1);
    1321           1 :     pDPObj->SetName(pDPs->CreateNewName());
    1322             : 
    1323           1 :     ScDPSaveData* pSaveData = pDPObj->GetSaveData();
    1324           1 :     CPPUNIT_ASSERT_MESSAGE("No save data !?", pSaveData);
    1325           1 :     ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData();
    1326           1 :     CPPUNIT_ASSERT_MESSAGE("No dimension data !?", pDimData);
    1327             : 
    1328           1 :     OUString aBaseDimName("Date");
    1329             : 
    1330           1 :     ScDPNumGroupInfo aInfo;
    1331           1 :     aInfo.mbEnable = true;
    1332           1 :     aInfo.mbAutoStart = true;
    1333           1 :     aInfo.mbAutoEnd = true;
    1334             :     {
    1335             :         // Turn the Date dimension into months.  The first of the date
    1336             :         // dimensions is always a number-group dimension which replaces the
    1337             :         // original dimension.
    1338           1 :         ScDPSaveNumGroupDimension aGroup(aBaseDimName, aInfo, sheet::DataPilotFieldGroupBy::MONTHS);
    1339           1 :         pDimData->AddNumGroupDimension(aGroup);
    1340             :     }
    1341             : 
    1342             :     {
    1343             :         // Add quarter dimension.  This will be an additional dimension.
    1344             :         OUString aGroupDimName =
    1345             :             pDimData->CreateDateGroupDimName(
    1346           1 :                 sheet::DataPilotFieldGroupBy::QUARTERS, *pDPObj, true, NULL);
    1347           2 :         ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
    1348           1 :         aGroupDim.SetDateInfo(aInfo, sheet::DataPilotFieldGroupBy::QUARTERS);
    1349           1 :         pDimData->AddGroupDimension(aGroupDim);
    1350             : 
    1351             :         // Set orientation.
    1352           1 :         ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
    1353           1 :         pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
    1354           2 :         pSaveData->SetPosition(pDim, 0); // set it to the left end.
    1355             :     }
    1356             : 
    1357             :     {
    1358             :         // Add year dimension.  This is a new dimension also.
    1359             :         OUString aGroupDimName =
    1360             :             pDimData->CreateDateGroupDimName(
    1361           1 :                 sheet::DataPilotFieldGroupBy::YEARS, *pDPObj, true, NULL);
    1362           2 :         ScDPSaveGroupDimension aGroupDim(aBaseDimName, aGroupDimName);
    1363           1 :         aGroupDim.SetDateInfo(aInfo, sheet::DataPilotFieldGroupBy::YEARS);
    1364           1 :         pDimData->AddGroupDimension(aGroupDim);
    1365             : 
    1366             :         // Set orientation.
    1367           1 :         ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aGroupDimName);
    1368           1 :         pDim->SetOrientation(sheet::DataPilotFieldOrientation_ROW);
    1369           2 :         pSaveData->SetPosition(pDim, 0); // set it to the left end.
    1370             :     }
    1371             : 
    1372           1 :     pDPObj->SetSaveData(*pSaveData);
    1373           1 :     ScRange aOutRange = refreshGroups(pDPs, pDPObj);
    1374             :     {
    1375             :         // Expected output table content.  0 = empty cell
    1376             :         const char* aOutputCheck[][4] = {
    1377             :             { "Years", "Quarters", "Date", "Sum - Value" },
    1378             :             { "2011", "Q1", "Jan", "1" },
    1379             :             { 0, 0,         "Mar", "2" },
    1380             :             { 0,      "Q3", "Sep", "7" },
    1381             :             { "2012", "Q1", "Jan", "3" },
    1382             :             { 0, 0,         "Feb", "9" },
    1383             :             { 0, 0,         "Mar", "6" },
    1384             :             { 0,      "Q4", "Dec", "8" },
    1385             :             { "Total Result", 0, 0, "36" },
    1386           1 :         };
    1387             : 
    1388           1 :         bSuccess = checkDPTableOutput<4>(m_pDoc, aOutRange, aOutputCheck, "Years, quarters and months date groups.");
    1389           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1390             :     }
    1391             : 
    1392             :     {
    1393             :         // Let's hide year 2012.
    1394           1 :         pSaveData = pDPObj->GetSaveData();
    1395           1 :         ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(OUString("Years"));
    1396           1 :         CPPUNIT_ASSERT_MESSAGE("Years dimension should exist.", pDim);
    1397           1 :         ScDPSaveMember* pMem = pDim->GetMemberByName(OUString("2012"));
    1398           1 :         CPPUNIT_ASSERT_MESSAGE("Member should exist.", pMem);
    1399           1 :         pMem->SetIsVisible(false);
    1400             :     }
    1401           1 :     pDPObj->SetSaveData(*pSaveData);
    1402           1 :     pDPObj->ReloadGroupTableData();
    1403           1 :     pDPObj->InvalidateData();
    1404             : 
    1405           1 :     aOutRange = refresh(pDPObj);
    1406             :     {
    1407             :         // Expected output table content.  0 = empty cell
    1408             :         const char* aOutputCheck[][4] = {
    1409             :             { "Years", "Quarters", "Date", "Sum - Value" },
    1410             :             { "2011", "Q1", "Jan", "1" },
    1411             :             { 0, 0,         "Mar", "2" },
    1412             :             { 0,      "Q3", "Sep", "7" },
    1413             :             { "Total Result", 0, 0, "10" },
    1414           1 :         };
    1415             : 
    1416           1 :         bSuccess = checkDPTableOutput<4>(m_pDoc, aOutRange, aOutputCheck, "Year 2012 data now hidden");
    1417           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1418             :     }
    1419             : 
    1420             :     // Remove all date grouping. The source dimension "Date" has two
    1421             :     // external dimensions ("Years" and "Quarters") and one internal ("Date"
    1422             :     // the same name but different hierarchy).  Remove all of them.
    1423           1 :     pSaveData = pDPObj->GetSaveData();
    1424           1 :     pSaveData->RemoveAllGroupDimensions(aBaseDimName);
    1425           1 :     pDPObj->SetSaveData(*pSaveData);
    1426           1 :     pDPObj->ReloadGroupTableData();
    1427           1 :     pDPObj->InvalidateData();
    1428             : 
    1429           1 :     aOutRange = refresh(pDPObj);
    1430             :     {
    1431             :         // Expected output table content.  0 = empty cell
    1432             :         const char* aOutputCheck[][2] = {
    1433             :             { "Date", "Sum - Value" },
    1434             :             { "2011-01-01", "1" },
    1435             :             { "2011-03-02", "2" },
    1436             :             { "2011-09-03", "7" },
    1437             :             { "2012-01-04", "3" },
    1438             :             { "2012-02-23", "4" },
    1439             :             { "2012-02-24", "5" },
    1440             :             { "2012-03-15", "6" },
    1441             :             { "2012-12-25", "8" },
    1442             :             { "Total Result", "36" }
    1443           1 :         };
    1444             : 
    1445           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Remove all date grouping.");
    1446           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1447             :     }
    1448             : 
    1449           1 :     pDPs->FreeTable(pDPObj);
    1450           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    1451           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    1452           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    1453             : 
    1454           1 :     m_pDoc->DeleteTab(1);
    1455           1 :     m_pDoc->DeleteTab(0);
    1456           1 : }
    1457             : 
    1458           1 : void Test::testPivotTableEmptyRows()
    1459             : {
    1460           1 :     m_pDoc->InsertTab(0, OUString("Data"));
    1461           1 :     m_pDoc->InsertTab(1, OUString("Table"));
    1462             : 
    1463             :     // Raw data
    1464             :     const char* aData[][2] = {
    1465             :         { "Name", "Value" },
    1466             :         { "A", "1" },
    1467             :         { "B", "2" },
    1468             :         { "C", "3" },
    1469             :         { "D", "4" },
    1470           1 :     };
    1471             : 
    1472             :     // Dimension definition
    1473             :     DPFieldDef aFields[] = {
    1474             :         { "Name", sheet::DataPilotFieldOrientation_ROW, 0, false },
    1475             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    1476           1 :     };
    1477             : 
    1478           1 :     ScAddress aPos(1,1,0);
    1479           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    1480           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    1481             : 
    1482             :     // Extend the range downward to include some trailing empty rows.
    1483           1 :     aDataRange.aEnd.IncRow(2);
    1484             : 
    1485             :     ScDPObject* pDPObj = createDPFromRange(
    1486           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    1487             : 
    1488           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    1489           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    1490             : 
    1491           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    1492           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
    1493           1 :                            pDPs->GetCount() == 1);
    1494           1 :     pDPObj->SetName(pDPs->CreateNewName());
    1495             : 
    1496           1 :     ScRange aOutRange = refresh(pDPObj);
    1497             : 
    1498             :     {
    1499             :         // Expected output table content.  0 = empty cell
    1500             :         const char* aOutputCheck[][2] = {
    1501             :             { "Name", "Sum - Value" },
    1502             :             { "A", "1" },
    1503             :             { "B", "2" },
    1504             :             { "C", "3" },
    1505             :             { "D", "4" },
    1506             :             { "(empty)", 0 },
    1507             :             { "Total Result", "10" },
    1508           1 :         };
    1509             : 
    1510           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Include empty rows");
    1511           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1512             :     }
    1513             : 
    1514             :     // This time, ignore empty rows.
    1515           1 :     ScDPSaveData* pSaveData = pDPObj->GetSaveData();
    1516           1 :     CPPUNIT_ASSERT_MESSAGE("Save data doesn't exist.", pSaveData);
    1517           1 :     pSaveData->SetIgnoreEmptyRows(true);
    1518           1 :     pDPObj->ClearTableData();
    1519           1 :     aOutRange = refresh(pDPObj);
    1520             : 
    1521             :     {
    1522             :         // Expected output table content.  0 = empty cell
    1523             :         const char* aOutputCheck[][2] = {
    1524             :             { "Name", "Sum - Value" },
    1525             :             { "A", "1" },
    1526             :             { "B", "2" },
    1527             :             { "C", "3" },
    1528             :             { "D", "4" },
    1529             :             { "Total Result", "10" },
    1530           1 :         };
    1531             : 
    1532           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Ignore empty rows");
    1533           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1534             :     }
    1535             : 
    1536             :     // Modify the source to remove member 'A', then refresh the table.
    1537           1 :     m_pDoc->SetString(1, 2, 0, "B");
    1538             : 
    1539           1 :     std::set<ScDPObject*> aRefs;
    1540           1 :     sal_uLong nErr = pDPs->ReloadCache(pDPObj, aRefs);
    1541           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to reload cache.", !nErr);
    1542           2 :     CPPUNIT_ASSERT_MESSAGE("There should only be one pivot table linked to this cache.",
    1543           1 :                            aRefs.size() == 1 && *aRefs.begin() == pDPObj);
    1544             : 
    1545           1 :     pDPObj->ClearTableData();
    1546           1 :     aOutRange = refresh(pDPObj);
    1547             : 
    1548             :     {
    1549             :         // Expected output table content.  0 = empty cell
    1550             :         const char* aOutputCheck[][2] = {
    1551             :             { "Name", "Sum - Value" },
    1552             :             { "B", "3" },
    1553             :             { "C", "3" },
    1554             :             { "D", "4" },
    1555             :             { "Total Result", "10" },
    1556           1 :         };
    1557             : 
    1558           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Ignore empty rows");
    1559           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1560             :     }
    1561             : 
    1562           1 :     pDPs->FreeTable(pDPObj);
    1563           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    1564           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    1565           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    1566             : 
    1567           1 :     m_pDoc->DeleteTab(1);
    1568           1 :     m_pDoc->DeleteTab(0);
    1569           1 : }
    1570             : 
    1571           1 : void Test::testPivotTableTextNumber()
    1572             : {
    1573           1 :     m_pDoc->InsertTab(0, OUString("Data"));
    1574           1 :     m_pDoc->InsertTab(1, OUString("Table"));
    1575             : 
    1576             :     // Raw data
    1577             :     const char* aData[][2] = {
    1578             :         { "Name", "Value" },
    1579             :         { "0001", "1" },
    1580             :         { "0002", "2" },
    1581             :         { "0003", "3" },
    1582             :         { "0004", "4" },
    1583           1 :     };
    1584             : 
    1585             :     // Dimension definition
    1586             :     DPFieldDef aFields[] = {
    1587             :         { "Name", sheet::DataPilotFieldOrientation_ROW, 0, false },
    1588             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    1589           1 :     };
    1590             : 
    1591             :     // Insert raw data such that the first column values are entered as text.
    1592           1 :     size_t nRowCount = SAL_N_ELEMENTS(aData);
    1593           6 :     for (size_t nRow = 0; nRow < nRowCount; ++nRow)
    1594             :     {
    1595           5 :         ScSetStringParam aParam;
    1596           5 :         aParam.mbDetectNumberFormat = false;
    1597           5 :         aParam.meSetTextNumFormat = ScSetStringParam::Always;
    1598           5 :         m_pDoc->SetString(0, nRow, 0, OUString::createFromAscii(aData[nRow][0]), &aParam);
    1599           5 :         aParam.meSetTextNumFormat = ScSetStringParam::Never;
    1600           5 :         m_pDoc->SetString(1, nRow, 0, OUString::createFromAscii(aData[nRow][1]), &aParam);
    1601             : 
    1602           5 :         if (nRow == 0)
    1603             :             // Don't check the header row.
    1604           1 :             continue;
    1605             : 
    1606             :         // Check the data rows.
    1607           4 :         CPPUNIT_ASSERT_MESSAGE("This cell is supposed to be text.", m_pDoc->HasStringData(0, nRow, 0));
    1608           4 :         CPPUNIT_ASSERT_MESSAGE("This cell is supposed to be numeric.", m_pDoc->HasValueData(1, nRow, 0));
    1609             :     }
    1610             : 
    1611           1 :     ScRange aDataRange(0, 0, 0, 1, 4, 0);
    1612             : 
    1613             :     ScDPObject* pDPObj = createDPFromRange(
    1614           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    1615             : 
    1616           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    1617           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    1618             : 
    1619           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    1620           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
    1621           1 :                            pDPs->GetCount() == 1);
    1622           1 :     pDPObj->SetName(pDPs->CreateNewName());
    1623             : 
    1624           1 :     ScRange aOutRange = refresh(pDPObj);
    1625             : 
    1626             :     {
    1627             :         // Expected output table content.  0 = empty cell
    1628             :         const char* aOutputCheck[][2] = {
    1629             :             { "Name", "Sum - Value" },
    1630             :             { "0001", "1" },
    1631             :             { "0002", "2" },
    1632             :             { "0003", "3" },
    1633             :             { "0004", "4" },
    1634             :             { "Total Result", "10" },
    1635           1 :         };
    1636             : 
    1637           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Text number field members");
    1638           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1639             :     }
    1640             : 
    1641             :     // Set the Name dimension to page dimension.
    1642           1 :     pDPObj->BuildAllDimensionMembers();
    1643           1 :     ScDPSaveData aSaveData(*pDPObj->GetSaveData());
    1644           1 :     ScDPSaveDimension* pDim = aSaveData.GetExistingDimensionByName("Name");
    1645           1 :     CPPUNIT_ASSERT(pDim);
    1646           1 :     pDim->SetOrientation(sheet::DataPilotFieldOrientation_PAGE);
    1647           2 :     OUString aVisiblePage("0004");
    1648           1 :     pDim->SetCurrentPage(&aVisiblePage);
    1649           1 :     pDPObj->SetSaveData(aSaveData);
    1650             : 
    1651           1 :     aOutRange = refresh(pDPObj);
    1652             : 
    1653             :     {
    1654             :         // Expected output table content.  0 = empty cell
    1655             :         const char* aOutputCheck[][2] = {
    1656             :             { "Name", "0004" },
    1657             :             {  0, 0 },
    1658             :             { "Sum - Value", 0 },
    1659             :             { "4", 0 }
    1660           1 :         };
    1661             : 
    1662           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Text number field members");
    1663           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1664             :     }
    1665             : 
    1666           1 :     pDPs->FreeTable(pDPObj);
    1667           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    1668           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    1669           1 :                                  pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    1670             : 
    1671           1 :     m_pDoc->DeleteTab(1);
    1672           2 :     m_pDoc->DeleteTab(0);
    1673           1 : }
    1674             : 
    1675           1 : void Test::testPivotTableCaseInsensitiveStrings()
    1676             : {
    1677           1 :     m_pDoc->InsertTab(0, OUString("Data"));
    1678           1 :     m_pDoc->InsertTab(1, OUString("Table"));
    1679             : 
    1680             :     // Raw data
    1681             :     const char* aData[][2] = {
    1682             :         { "Name", "Value" },
    1683             :         { "A", "1" },
    1684             :         { "a", "2" },
    1685           1 :     };
    1686             : 
    1687             :     // Dimension definition
    1688             :     DPFieldDef aFields[] = {
    1689             :         { "Name", sheet::DataPilotFieldOrientation_ROW, 0, false },
    1690             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    1691           1 :     };
    1692             : 
    1693           1 :     ScAddress aPos(1,1,0);
    1694           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    1695           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    1696             : 
    1697             :     ScDPObject* pDPObj = createDPFromRange(
    1698           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    1699             : 
    1700           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    1701           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    1702             : 
    1703           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    1704           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
    1705           1 :                            pDPs->GetCount() == 1);
    1706           1 :     pDPObj->SetName(pDPs->CreateNewName());
    1707             : 
    1708           1 :     ScRange aOutRange = refresh(pDPObj);
    1709             : 
    1710             :     {
    1711             :         // Expected output table content.  0 = empty cell
    1712             :         const char* aOutputCheck[][2] = {
    1713             :             { "Name", "Sum - Value" },
    1714             :             { "A", "3" },
    1715             :             { "Total Result", "3" },
    1716           1 :         };
    1717             : 
    1718           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Case insensitive strings");
    1719           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1720             :     }
    1721             : 
    1722           1 :     pDPs->FreeTable(pDPObj);
    1723           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    1724           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    1725           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    1726             : 
    1727           1 :     m_pDoc->DeleteTab(1);
    1728           1 :     m_pDoc->DeleteTab(0);
    1729           1 : }
    1730             : 
    1731           1 : void Test::testPivotTableNumStability()
    1732             : {
    1733           1 :     FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
    1734             : 
    1735             :     // Raw Data
    1736             :     const char* aData[][4] = {
    1737             :         { "Name",   "Time Start", "Time End", "Total"          },
    1738             :         { "Sam",    "07:48 AM",   "09:00 AM", "=RC[-1]-RC[-2]" },
    1739             :         { "Sam",    "09:00 AM",   "10:30 AM", "=RC[-1]-RC[-2]" },
    1740             :         { "Sam",    "10:30 AM",   "12:30 PM", "=RC[-1]-RC[-2]" },
    1741             :         { "Sam",    "12:30 PM",   "01:00 PM", "=RC[-1]-RC[-2]" },
    1742             :         { "Sam",    "01:00 PM",   "01:30 PM", "=RC[-1]-RC[-2]" },
    1743             :         { "Sam",    "01:30 PM",   "02:00 PM", "=RC[-1]-RC[-2]" },
    1744             :         { "Sam",    "02:00 PM",   "07:15 PM", "=RC[-1]-RC[-2]" },
    1745             :         { "Sam",    "07:47 AM",   "09:00 AM", "=RC[-1]-RC[-2]" },
    1746             :         { "Sam",    "09:00 AM",   "10:00 AM", "=RC[-1]-RC[-2]" },
    1747             :         { "Sam",    "10:00 AM",   "11:00 AM", "=RC[-1]-RC[-2]" },
    1748             :         { "Sam",    "11:00 AM",   "11:30 AM", "=RC[-1]-RC[-2]" },
    1749             :         { "Sam",    "11:30 AM",   "12:45 PM", "=RC[-1]-RC[-2]" },
    1750             :         { "Sam",    "12:45 PM",   "01:15 PM", "=RC[-1]-RC[-2]" },
    1751             :         { "Sam",    "01:15 PM",   "02:30 PM", "=RC[-1]-RC[-2]" },
    1752             :         { "Sam",    "02:30 PM",   "02:45 PM", "=RC[-1]-RC[-2]" },
    1753             :         { "Sam",    "02:45 PM",   "04:30 PM", "=RC[-1]-RC[-2]" },
    1754             :         { "Sam",    "04:30 PM",   "06:00 PM", "=RC[-1]-RC[-2]" },
    1755             :         { "Sam",    "06:00 PM",   "07:15 PM", "=RC[-1]-RC[-2]" },
    1756             :         { "Mike",   "06:15 AM",   "08:30 AM", "=RC[-1]-RC[-2]" },
    1757             :         { "Mike",   "08:30 AM",   "10:03 AM", "=RC[-1]-RC[-2]" },
    1758             :         { "Mike",   "10:03 AM",   "12:00 PM", "=RC[-1]-RC[-2]" },
    1759             :         { "Dennis", "11:00 AM",   "01:00 PM", "=RC[-1]-RC[-2]" },
    1760             :         { "Dennis", "01:00 PM",   "02:00 PM", "=RC[-1]-RC[-2]" }
    1761           1 :     };
    1762             : 
    1763             :     // Dimension definition
    1764             :     DPFieldDef aFields[] = {
    1765             :         { "Name",  sheet::DataPilotFieldOrientation_ROW, 0, false },
    1766             :         { "Total", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    1767           1 :     };
    1768             : 
    1769           1 :     m_pDoc->InsertTab(0, OUString("Data"));
    1770           1 :     m_pDoc->InsertTab(1, OUString("Table"));
    1771             : 
    1772           1 :     size_t nRowCount = SAL_N_ELEMENTS(aData);
    1773           1 :     ScAddress aPos(1,1,0);
    1774           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, nRowCount);
    1775             : 
    1776             :     // Insert formulas to manually calculate sums for each name.
    1777           1 :     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])");
    1778           1 :     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])");
    1779           1 :     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])");
    1780             : 
    1781           1 :     m_pDoc->CalcAll();
    1782             : 
    1783             :     // Get correct sum values.
    1784           1 :     double fDennisTotal = m_pDoc->GetValue(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+1, aDataRange.aStart.Tab());
    1785           1 :     double fMikeTotal = m_pDoc->GetValue(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+2, aDataRange.aStart.Tab());
    1786           1 :     double fSamTotal = m_pDoc->GetValue(aDataRange.aStart.Col(), aDataRange.aEnd.Row()+3, aDataRange.aStart.Tab());
    1787             : 
    1788             :     ScDPObject* pDPObj = createDPFromRange(
    1789           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    1790             : 
    1791           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    1792           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    1793             : 
    1794           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    1795           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("there should be only one data pilot table.",
    1796           1 :                            pDPs->GetCount(), static_cast<size_t>(1));
    1797           1 :     pDPObj->SetName(pDPs->CreateNewName());
    1798             : 
    1799           1 :     ScRange aOutRange = refresh(pDPObj);
    1800             : 
    1801             :     // Manually check the total value for each name.
    1802             :     //
    1803             :     // +--------------+----------------+
    1804             :     // | Name         |                |
    1805             :     // +--------------+----------------+
    1806             :     // | Dennis       | <Dennis total> |
    1807             :     // +--------------+----------------+
    1808             :     // | Mike         | <Miks total>   |
    1809             :     // +--------------+----------------+
    1810             :     // | Sam          | <Sam total>    |
    1811             :     // +--------------+----------------+
    1812             :     // | Total Result | ...            |
    1813             :     // +--------------+----------------+
    1814             : 
    1815           1 :     aPos = aOutRange.aStart;
    1816           1 :     aPos.IncCol();
    1817           1 :     aPos.IncRow();
    1818           1 :     double fTest = m_pDoc->GetValue(aPos);
    1819           1 :     CPPUNIT_ASSERT_MESSAGE("Incorrect value for Dennis.", rtl::math::approxEqual(fTest, fDennisTotal));
    1820           1 :     aPos.IncRow();
    1821           1 :     fTest = m_pDoc->GetValue(aPos);
    1822           1 :     CPPUNIT_ASSERT_MESSAGE("Incorrect value for Mike.", rtl::math::approxEqual(fTest, fMikeTotal));
    1823           1 :     aPos.IncRow();
    1824           1 :     fTest = m_pDoc->GetValue(aPos);
    1825           1 :     CPPUNIT_ASSERT_MESSAGE("Incorrect value for Sam.", rtl::math::approxEqual(fTest, fSamTotal));
    1826             : 
    1827           1 :     pDPs->FreeTable(pDPObj);
    1828           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    1829           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    1830           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    1831             : 
    1832           1 :     m_pDoc->DeleteTab(1);
    1833           1 :     m_pDoc->DeleteTab(0);
    1834           1 : }
    1835             : 
    1836           1 : void Test::testPivotTableFieldReference()
    1837             : {
    1838           1 :     m_pDoc->InsertTab(0, OUString("Data"));
    1839           1 :     m_pDoc->InsertTab(1, OUString("Table"));
    1840             : 
    1841             :     // Raw data
    1842             :     const char* aData[][2] = {
    1843             :         { "Name", "Value" },
    1844             :         { "A", "1" },
    1845             :         { "B", "2" },
    1846             :         { "C", "4" },
    1847             :         { "D", "8" },
    1848           1 :     };
    1849             : 
    1850             :     // Dimension definition
    1851             :     DPFieldDef aFields[] = {
    1852             :         { "Name", sheet::DataPilotFieldOrientation_ROW, 0, false },
    1853             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    1854           1 :     };
    1855             : 
    1856           1 :     ScAddress aPos(1,1,0);
    1857           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    1858           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    1859             : 
    1860             :     ScDPObject* pDPObj = createDPFromRange(
    1861           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    1862             : 
    1863           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    1864           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    1865             : 
    1866           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    1867           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
    1868           1 :                            pDPs->GetCount() == 1);
    1869           1 :     pDPObj->SetName(pDPs->CreateNewName());
    1870             : 
    1871           1 :     ScRange aOutRange = refresh(pDPObj);
    1872             : 
    1873             :     {
    1874             :         // Expected output table content.  0 = empty cell
    1875             :         const char* aOutputCheck[][2] = {
    1876             :             { "Name", "Sum - Value" },
    1877             :             { "A", "1" },
    1878             :             { "B", "2" },
    1879             :             { "C", "4" },
    1880             :             { "D", "8" },
    1881             :             { "Total Result", "15" },
    1882           1 :         };
    1883             : 
    1884           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (none)");
    1885           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1886             :     }
    1887             : 
    1888           1 :     ScDPSaveData aSaveData = *pDPObj->GetSaveData();
    1889           2 :     sheet::DataPilotFieldReference aFieldRef;
    1890           1 :     aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE;
    1891           1 :     aFieldRef.ReferenceField = "Name";
    1892           1 :     aFieldRef.ReferenceItemType = sheet::DataPilotFieldReferenceItemType::NAMED;
    1893           1 :     aFieldRef.ReferenceItemName = "A";
    1894           1 :     ScDPSaveDimension* pDim = aSaveData.GetDimensionByName("Value");
    1895           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to retrieve dimension 'Value'.", pDim);
    1896           1 :     pDim->SetReferenceValue(&aFieldRef);
    1897           1 :     pDPObj->SetSaveData(aSaveData);
    1898             : 
    1899           1 :     aOutRange = refresh(pDPObj);
    1900             :     {
    1901             :         // Expected output table content.  0 = empty cell
    1902             :         const char* aOutputCheck[][2] = {
    1903             :             { "Name", "Sum - Value" },
    1904             :             { "A", 0 },
    1905             :             { "B", "1" },
    1906             :             { "C", "3" },
    1907             :             { "D", "7" },
    1908             :             { "Total Result", 0 },
    1909           1 :         };
    1910             : 
    1911           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (difference from)");
    1912           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1913             :     }
    1914             : 
    1915           1 :     aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE;
    1916           1 :     pDim->SetReferenceValue(&aFieldRef);
    1917           1 :     pDPObj->SetSaveData(aSaveData);
    1918             : 
    1919           1 :     aOutRange = refresh(pDPObj);
    1920             :     {
    1921             :         // Expected output table content.  0 = empty cell
    1922             :         const char* aOutputCheck[][2] = {
    1923             :             { "Name", "Sum - Value" },
    1924             :             { "A", "100.00%" },
    1925             :             { "B", "200.00%" },
    1926             :             { "C", "400.00%" },
    1927             :             { "D", "800.00%" },
    1928             :             { "Total Result", 0 },
    1929           1 :         };
    1930             : 
    1931           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (% of)");
    1932           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1933             :     }
    1934             : 
    1935           1 :     aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE;
    1936           1 :     pDim->SetReferenceValue(&aFieldRef);
    1937           1 :     pDPObj->SetSaveData(aSaveData);
    1938             : 
    1939           1 :     aOutRange = refresh(pDPObj);
    1940             :     {
    1941             :         // Expected output table content.  0 = empty cell
    1942             :         const char* aOutputCheck[][2] = {
    1943             :             { "Name", "Sum - Value" },
    1944             :             { "A", 0 },
    1945             :             { "B", "100.00%" },
    1946             :             { "C", "300.00%" },
    1947             :             { "D", "700.00%" },
    1948             :             { "Total Result", 0 },
    1949           1 :         };
    1950             : 
    1951           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (% difference from)");
    1952           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1953             :     }
    1954             : 
    1955           1 :     aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::RUNNING_TOTAL;
    1956           1 :     pDim->SetReferenceValue(&aFieldRef);
    1957           1 :     pDPObj->SetSaveData(aSaveData);
    1958             : 
    1959           1 :     aOutRange = refresh(pDPObj);
    1960             :     {
    1961             :         // Expected output table content.  0 = empty cell
    1962             :         const char* aOutputCheck[][2] = {
    1963             :             { "Name", "Sum - Value" },
    1964             :             { "A", "1" },
    1965             :             { "B", "3" },
    1966             :             { "C", "7" },
    1967             :             { "D", "15" },
    1968             :             { "Total Result", 0 },
    1969           1 :         };
    1970             : 
    1971           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (Running total)");
    1972           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1973             :     }
    1974             : 
    1975           1 :     aFieldRef.ReferenceType = sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE;
    1976           1 :     pDim->SetReferenceValue(&aFieldRef);
    1977           1 :     pDPObj->SetSaveData(aSaveData);
    1978             : 
    1979           1 :     aOutRange = refresh(pDPObj);
    1980             :     {
    1981             :         // Expected output table content.  0 = empty cell
    1982             :         const char* aOutputCheck[][2] = {
    1983             :             { "Name", "Sum - Value" },
    1984             :             { "A", "6.67%" },
    1985             :             { "B", "13.33%" },
    1986             :             { "C", "26.67%" },
    1987             :             { "D", "53.33%" },
    1988             :             { "Total Result", "100.00%" },
    1989           1 :         };
    1990             : 
    1991           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Field reference (% of column)");
    1992           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    1993             :     }
    1994             : 
    1995           1 :     pDPs->FreeTable(pDPObj);
    1996           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    1997           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    1998           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    1999             : 
    2000           1 :     m_pDoc->DeleteTab(1);
    2001           2 :     m_pDoc->DeleteTab(0);
    2002           1 : }
    2003             : 
    2004           1 : void Test::testPivotTableDocFunc()
    2005             : {
    2006           1 :     m_pDoc->InsertTab(0, "Data");
    2007           1 :     m_pDoc->InsertTab(1, "Table");
    2008             : 
    2009             :     // Raw data
    2010             :     const char* aData[][2] = {
    2011             :         { "Name",      "Value" },
    2012             :         { "Sun",       "1" },
    2013             :         { "Oracle",    "2" },
    2014             :         { "Red Hat",   "4" },
    2015             :         { "SUSE",      "8" },
    2016             :         { "Apple",     "16" },
    2017             :         { "Microsoft", "32" },
    2018           1 :     };
    2019             : 
    2020             :     // Dimension definition
    2021             :     DPFieldDef aFields[] = {
    2022             :         { "Name", sheet::DataPilotFieldOrientation_ROW, 0, false },
    2023             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    2024           1 :     };
    2025             : 
    2026           1 :     ScAddress aPos(1,1,0);
    2027           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    2028           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    2029             : 
    2030             :     ScDPObject* pDPObj = createDPFromRange(
    2031           1 :         m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    2032             : 
    2033           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table object.", pDPObj);
    2034             : 
    2035             :     // Craete a new pivot table output.
    2036           1 :     ScDBDocFunc aFunc(getDocShell());
    2037           1 :     bool bSuccess = aFunc.CreatePivotTable(*pDPObj, false, true);
    2038           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to create pivot table output via ScDBDocFunc.", bSuccess);
    2039           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    2040           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to get pivot table collection.", pDPs);
    2041           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDPs->GetCount());
    2042           1 :     pDPObj = (*pDPs)[0];
    2043           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to retrieve pivot table object from the collection", pDPObj);
    2044           1 :     ScRange aOutRange = pDPObj->GetOutRange();
    2045             :     {
    2046             :         // Expected output table content.  0 = empty cell
    2047             :         const char* aOutputCheck[][2] = {
    2048             :             { "Name", "Sum - Value" },
    2049             :             { "Apple", "16" },
    2050             :             { "Microsoft", "32" },
    2051             :             { "Oracle", "2" },
    2052             :             { "Red Hat", "4" },
    2053             :             { "Sun", "1" },
    2054             :             { "SUSE", "8" },
    2055             :             { "Total Result", "63" },
    2056           1 :         };
    2057             : 
    2058           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Pivot table created via ScDBDocFunc");
    2059           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    2060             :     }
    2061             : 
    2062             :     // Remove this pivot table output. This should also clear the pivot cache
    2063             :     // it was referencing.
    2064           1 :     bSuccess = aFunc.RemovePivotTable(*pDPObj, false, true);
    2065           1 :     CPPUNIT_ASSERT_MESSAGE("Failed to remove pivot table output via ScDBDocFunc.", bSuccess);
    2066           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pDPs->GetCount());
    2067           1 :     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pDPs->GetSheetCaches().size());
    2068             : 
    2069           1 :     m_pDoc->DeleteTab(1);
    2070           1 :     m_pDoc->DeleteTab(0);
    2071           1 : }
    2072             : 
    2073           1 : void Test::testFuncGETPIVOTDATA()
    2074             : {
    2075           1 :     m_pDoc->InsertTab(0, "Data");
    2076           1 :     m_pDoc->InsertTab(1, "Table");
    2077             : 
    2078             :     // Raw data
    2079             :     const char* aData[][2] = {
    2080             :         { "Name", "Value" },
    2081             :         { "A", "1" },
    2082             :         { "A", "2" },
    2083             :         { "A", "3" },
    2084             :         { "B", "4" },
    2085             :         { "B", "5" },
    2086             :         { "B", "6" },
    2087           1 :     };
    2088             : 
    2089           1 :     ScAddress aPos(1,1,0);
    2090           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    2091           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    2092             : 
    2093           1 :     ScDPObject* pDPObj = NULL;
    2094             : 
    2095             :     {
    2096             :         // Dimension definition
    2097             :         DPFieldDef aFields[] = {
    2098             :             { "Name", sheet::DataPilotFieldOrientation_ROW, 0, false },
    2099             :             { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    2100           1 :         };
    2101             : 
    2102           1 :         pDPObj = createDPFromRange(m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    2103             :     }
    2104             : 
    2105           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    2106           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    2107             : 
    2108           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    2109           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
    2110           1 :                            pDPs->GetCount() == 1);
    2111           1 :     pDPObj->SetName(pDPs->CreateNewName());
    2112             : 
    2113           1 :     ScRange aOutRange = refresh(pDPObj);
    2114             :     {
    2115             :         // Expected output table content.  0 = empty cell
    2116             :         const char* aOutputCheck[][2] = {
    2117             :             { "Name", "Sum - Value" },
    2118             :             { "A", "6" },
    2119             :             { "B", "15" },
    2120             :             { "Total Result", "21" },
    2121           1 :         };
    2122             : 
    2123           1 :         bSuccess = checkDPTableOutput<2>(m_pDoc, aOutRange, aOutputCheck, "Pivot table created for GETPIVOTDATA");
    2124           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    2125             :     }
    2126             : 
    2127           1 :     aPos = aOutRange.aEnd;
    2128           1 :     aPos.IncRow(2); // Move 2 rows down from the table outout.
    2129             : 
    2130           1 :     OUString aPivotPosStr(aOutRange.aStart.Format(SCA_ABS));
    2131             : 
    2132           2 :     sc::AutoCalcSwitch aSwitch(*m_pDoc, true); // turn autocalc on.
    2133             : 
    2134             :     // First, get the grand total.
    2135           2 :     OUString aFormula("=GETPIVOTDATA(\"Value\";");
    2136           1 :     aFormula += aPivotPosStr;
    2137           1 :     aFormula += ")";
    2138           1 :     m_pDoc->SetString(aPos, aFormula);
    2139           1 :     double fVal = m_pDoc->GetValue(aPos);
    2140           1 :     CPPUNIT_ASSERT_EQUAL(21.0, fVal);
    2141             : 
    2142             :     // Get the subtotal for 'A'.
    2143           1 :     aFormula = "=GETPIVOTDATA(\"Value\";" + aPivotPosStr + ";\"Name\";\"A\")";
    2144           1 :     m_pDoc->SetString(aPos, aFormula);
    2145           1 :     fVal = m_pDoc->GetValue(aPos);
    2146           1 :     CPPUNIT_ASSERT_EQUAL(6.0, fVal);
    2147             : 
    2148             :     // Get the subtotal for 'B'.
    2149           1 :     aFormula = "=GETPIVOTDATA(\"Value\";" + aPivotPosStr + ";\"Name\";\"B\")";
    2150           1 :     m_pDoc->SetString(aPos, aFormula);
    2151           1 :     fVal = m_pDoc->GetValue(aPos);
    2152           1 :     CPPUNIT_ASSERT_EQUAL(15.0, fVal);
    2153             : 
    2154           1 :     clearRange(m_pDoc, aPos); // Delete the formula.
    2155             : 
    2156           1 :     pDPs->FreeTable(pDPObj);
    2157             : 
    2158             :     {
    2159             :         // Dimension definition
    2160             :         DPFieldDef aFields[] = {
    2161             :             { "Name", sheet::DataPilotFieldOrientation_ROW, 0, false },
    2162             :             { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    2163             :             { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_COUNT, false },
    2164           1 :         };
    2165             : 
    2166           1 :         pDPObj = createDPFromRange(m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    2167             :     }
    2168             : 
    2169           1 :     bSuccess = pDPs->InsertNewTable(pDPObj);
    2170           1 :     CPPUNIT_ASSERT_MESSAGE("InsertNewTable failed", bSuccess);
    2171           1 :     aOutRange = refresh(pDPObj);
    2172             : 
    2173             :     {
    2174             :         // Expected output table content.  0 = empty cell
    2175             :         const char* aOutputCheck[][3] = {
    2176             :             { "Name",                "Data",           0   },
    2177             :             { "A",                   "Sum - Value",   "6"  },
    2178             :             {  0,                    "Count - Value", "3"  },
    2179             :             { "B",                   "Sum - Value",  "15"  },
    2180             :             {  0,                    "Count - Value", "3"  },
    2181             :             { "Total Sum - Value",   0,               "21" },
    2182             :             { "Total Count - Value", 0,               "6"  },
    2183           1 :         };
    2184             : 
    2185           1 :         bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "Pivot table refreshed");
    2186           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    2187             :     }
    2188             : 
    2189           1 :     aPos = aOutRange.aEnd;
    2190           1 :     aPos.IncRow(2); // move 2 rows down from the output.
    2191             : 
    2192           1 :     aPivotPosStr = aOutRange.aStart.Format(SCA_ABS);
    2193             : 
    2194             :     // First, get the grand totals.
    2195           1 :     aFormula = ("=GETPIVOTDATA(\"Sum - Value\";") + aPivotPosStr + ")";
    2196           1 :     m_pDoc->SetString(aPos, aFormula);
    2197           1 :     fVal = m_pDoc->GetValue(aPos);
    2198           1 :     CPPUNIT_ASSERT_EQUAL(21.0, fVal);
    2199           1 :     aFormula = ("=GETPIVOTDATA(\"Count - Value\";") + aPivotPosStr + ")";
    2200           1 :     m_pDoc->SetString(aPos, aFormula);
    2201           1 :     fVal = m_pDoc->GetValue(aPos);
    2202           1 :     CPPUNIT_ASSERT_EQUAL(6.0, fVal);
    2203             : 
    2204             :     // Get the subtotals for 'A'.
    2205           1 :     aFormula = "=GETPIVOTDATA(\"Sum - Value\";" + aPivotPosStr + ";\"Name\";\"A\")";
    2206           1 :     m_pDoc->SetString(aPos, aFormula);
    2207           1 :     fVal = m_pDoc->GetValue(aPos);
    2208           1 :     CPPUNIT_ASSERT_EQUAL(6.0, fVal);
    2209           1 :     aFormula = "=GETPIVOTDATA(\"Count - Value\";" + aPivotPosStr + ";\"Name\";\"A\")";
    2210           1 :     m_pDoc->SetString(aPos, aFormula);
    2211           1 :     fVal = m_pDoc->GetValue(aPos);
    2212           1 :     CPPUNIT_ASSERT_EQUAL(3.0, fVal);
    2213             : 
    2214             :     // Get the subtotals for 'B'.
    2215           1 :     aFormula = "=GETPIVOTDATA(\"Sum - Value\";" + aPivotPosStr + ";\"Name\";\"B\")";
    2216           1 :     m_pDoc->SetString(aPos, aFormula);
    2217           1 :     fVal = m_pDoc->GetValue(aPos);
    2218           1 :     CPPUNIT_ASSERT_EQUAL(15.0, fVal);
    2219           1 :     aFormula = "=GETPIVOTDATA(\"Count - Value\";" + aPivotPosStr + ";\"Name\";\"B\")";
    2220           1 :     m_pDoc->SetString(aPos, aFormula);
    2221           1 :     fVal = m_pDoc->GetValue(aPos);
    2222           1 :     CPPUNIT_ASSERT_EQUAL(3.0, fVal);
    2223             : 
    2224           1 :     pDPs->FreeTable(pDPObj);
    2225             : 
    2226           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    2227           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    2228           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    2229             : 
    2230           1 :     m_pDoc->DeleteTab(1);
    2231           2 :     m_pDoc->DeleteTab(0);
    2232           1 : }
    2233             : 
    2234           1 : void Test::testFuncGETPIVOTDATALeafAccess()
    2235             : {
    2236           1 :     m_pDoc->InsertTab(0, "Data");
    2237           1 :     m_pDoc->InsertTab(1, "Table");
    2238             : 
    2239             :     // Raw data
    2240             :     const char* aData[][3] = {
    2241             :         { "Type", "Member", "Value" },
    2242             :         { "A", "Anna", "1" },
    2243             :         { "B", "Brittany", "2" },
    2244             :         { "A", "Cecilia", "3" },
    2245             :         { "B", "Donna", "4" },
    2246           1 :     };
    2247             : 
    2248           1 :     ScAddress aPos(1,1,0);
    2249           1 :     ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
    2250           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
    2251             : 
    2252           1 :     ScDPObject* pDPObj = NULL;
    2253             : 
    2254             :     // Dimension definition
    2255             :     DPFieldDef aFields[] = {
    2256             :         { "Type", sheet::DataPilotFieldOrientation_ROW, 0, false },
    2257             :         { "Member", sheet::DataPilotFieldOrientation_ROW, 0, false },
    2258             :         { "Value", sheet::DataPilotFieldOrientation_DATA, sheet::GeneralFunction_SUM, false },
    2259           1 :     };
    2260             : 
    2261             :     // Create pivot table at A1 on 2nd sheet.
    2262           1 :     pDPObj = createDPFromRange(m_pDoc, aDataRange, aFields, SAL_N_ELEMENTS(aFields), false);
    2263             : 
    2264           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    2265           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    2266             : 
    2267           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new pivot table object into document.", bSuccess);
    2268           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
    2269           1 :                            pDPs->GetCount() == 1);
    2270           1 :     pDPObj->SetName(pDPs->CreateNewName());
    2271           1 :     ScRange aOutRange = refresh(pDPObj);
    2272             : 
    2273             :     {
    2274             :         // Expected output table content.  0 = empty cell
    2275             :         const char* aOutputCheck[][3] = {
    2276             :             { "Type",         "Member",   "Sum - Value" },
    2277             :             { "A",            "Anna",     "1"           },
    2278             :             {  0,             "Cecilia",  "3"           },
    2279             :             { "B",            "Brittany", "2"           },
    2280             :             {  0,             "Donna",    "4"           },
    2281             :             { "Total Result",  0,         "10"          },
    2282           1 :         };
    2283             : 
    2284           1 :         bSuccess = checkDPTableOutput<3>(m_pDoc, aOutRange, aOutputCheck, "Pivot table refreshed");
    2285           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    2286             :     }
    2287             : 
    2288             :     // Insert formulas with GETPIVOTDATA in column E, and check their results.
    2289             : 
    2290             :     struct Check
    2291             :     {
    2292             :         const char* mpFormula;
    2293             :         double mfResult;
    2294             :     };
    2295             : 
    2296             :     Check aChecks[] = {
    2297             :         { "=GETPIVOTDATA($A$1;\"Member[Anna]\")",     1.0 },
    2298             :         { "=GETPIVOTDATA($A$1;\"Member[Brittany]\")", 2.0 },
    2299             :         { "=GETPIVOTDATA($A$1;\"Member[Cecilia]\")",  3.0 },
    2300             :         { "=GETPIVOTDATA($A$1;\"Member[Donna]\")",    4.0 },
    2301           1 :     };
    2302             : 
    2303           5 :     for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
    2304           4 :         m_pDoc->SetString(ScAddress(4,i,1), OUString::createFromAscii(aChecks[i].mpFormula));
    2305             : 
    2306           1 :     m_pDoc->CalcAll();
    2307             : 
    2308           1 :     const sal_uInt16 nNoError = 0; // no error
    2309           5 :     for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
    2310             :     {
    2311           4 :         sal_uInt16 nErr = m_pDoc->GetErrCode(ScAddress(4,i,1));
    2312           4 :         CPPUNIT_ASSERT_EQUAL(nNoError, nErr);
    2313           4 :         double fVal = m_pDoc->GetValue(ScAddress(4,i,1));
    2314           4 :         CPPUNIT_ASSERT_EQUAL(aChecks[i].mfResult, fVal);
    2315             :     }
    2316             : 
    2317           1 :     pDPs->FreeTable(pDPObj);
    2318             : 
    2319           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    2320           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    2321           1 :                            pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    2322             : 
    2323           1 :     m_pDoc->DeleteTab(1);
    2324           1 :     m_pDoc->DeleteTab(0);
    2325           1 : }
    2326             : 
    2327           1 : void Test::testPivotTableRepeatItemLabels()
    2328             : {
    2329           1 :     m_pDoc->InsertTab(0, OUString("Data"));
    2330           1 :     m_pDoc->InsertTab(1, OUString("Table"));
    2331             : 
    2332             :     // Dimension definition
    2333             :     DPFieldDef aFields[] = {
    2334             :         { "Name",  sheet::DataPilotFieldOrientation_ROW, 0, true },
    2335             :         { "Country", sheet::DataPilotFieldOrientation_ROW, 0, false },
    2336             :         { "Year", sheet::DataPilotFieldOrientation_ROW, 0, false },
    2337             :         { "Score", sheet::DataPilotFieldOrientation_DATA, 0, false }
    2338           1 :     };
    2339             : 
    2340             :     // Raw data
    2341             :     const char* aData[][4] = {
    2342             :         { "Andy",    "US", "1999", "30" },
    2343             :         { "Andy",    "US", "2002", "20" },
    2344             :         { "Andy",    "US", "2010", "45" },
    2345             :         { "David",   "GB", "1998", "12" },
    2346             :         { "Edward",  "NO", "2000",  "8" },
    2347             :         { "Frank",   "FR", "2009", "15" },
    2348             :         { "Frank",   "FR", "2008", "45" },
    2349             :         { "Frank",   "FR", "2007", "45" },
    2350           1 :     };
    2351             : 
    2352           1 :     size_t nFieldCount = SAL_N_ELEMENTS(aFields);
    2353           1 :     size_t nDataCount = SAL_N_ELEMENTS(aData);
    2354             : 
    2355           1 :     ScRange aSrcRange = insertDPSourceData(m_pDoc, aFields, nFieldCount, aData, nDataCount);
    2356           1 :     SCROW nRow1 = aSrcRange.aStart.Row(), nRow2 = aSrcRange.aEnd.Row();
    2357           1 :     SCCOL nCol1 = aSrcRange.aStart.Col(), nCol2 = aSrcRange.aEnd.Col();
    2358             : 
    2359             :     ScDPObject* pDPObj = createDPFromRange(
    2360           1 :         m_pDoc, ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0), aFields, nFieldCount, false);
    2361             : 
    2362           1 :     ScDPCollection* pDPs = m_pDoc->GetDPCollection();
    2363           1 :     bool bSuccess = pDPs->InsertNewTable(pDPObj);
    2364           1 :     CPPUNIT_ASSERT_MESSAGE("failed to insert a new datapilot object into document", bSuccess);
    2365           2 :     CPPUNIT_ASSERT_MESSAGE("there should be only one data pilot table.",
    2366           1 :                            pDPs->GetCount() == 1);
    2367           1 :     pDPObj->SetName(pDPs->CreateNewName());
    2368             : 
    2369           1 :     bool bOverflow = false;
    2370           1 :     ScRange aOutRange = pDPObj->GetNewOutputRange(bOverflow);
    2371           1 :     CPPUNIT_ASSERT_MESSAGE("Table overflow!?", !bOverflow);
    2372             : 
    2373           1 :     pDPObj->Output(aOutRange.aStart);
    2374           1 :     aOutRange = pDPObj->GetOutRange();
    2375             :     {
    2376             :         // Expected output table content.  0 = empty cell
    2377             :         const char* aOutputCheck[][4] = {
    2378             :             { "Name",         "Country", "Year", "Sum - Score" },
    2379             :             { "Andy",         "US",      "1999", "30"          },
    2380             :             { "Andy",         0,         "2002", "20"          },
    2381             :             { "Andy",         0,         "2010", "45"          },
    2382             :             { "David",        "GB",      "1998", "12"          },
    2383             :             { "Edward",       "NO",      "2000", "8"           },
    2384             :             { "Frank",        "FR",      "2007", "45"          },
    2385             :             { "Frank",        0,         "2008", "45"          },
    2386             :             { "Frank",        0,         "2009", "15"          },
    2387             :             { "Total Result", 0,         0,      "220"         }
    2388           1 :         };
    2389             : 
    2390           1 :         bSuccess = checkDPTableOutput<4>(m_pDoc, aOutRange, aOutputCheck, "DataPilot table output");
    2391           1 :         CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
    2392             :     }
    2393             : 
    2394           1 :     CPPUNIT_ASSERT_MESSAGE("There should be only one data cache.", pDPs->GetSheetCaches().size() == 1);
    2395             : 
    2396           1 :     pDPs->FreeTable(pDPObj);
    2397           1 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be no more tables.", pDPs->GetCount(), static_cast<size_t>(0));
    2398           2 :     CPPUNIT_ASSERT_EQUAL_MESSAGE("There shouldn't be any more cache stored.",
    2399           1 :                                  pDPs->GetSheetCaches().size(), static_cast<size_t>(0));
    2400             : 
    2401           1 :     m_pDoc->DeleteTab(1);
    2402           1 :     m_pDoc->DeleteTab(0);
    2403           4 : }
    2404             : 
    2405             : 
    2406             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11