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

Generated by: LCOV version 1.10