Skip to content
Extraits de code Groupes Projets
DataTableTest.php 40 ko
Newer Older
  • Learn to ignore specific revisions
  • sgiehl's avatar
    sgiehl a validé
    <?php
    /**
    
     * Piwik - free/libre analytics platform
    
    sgiehl's avatar
    sgiehl a validé
     *
     * @link http://piwik.org
     * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
     */
    
    namespace Piwik\Tests\Unit;
    
    
    use Piwik\Common;
    use Piwik\DataTable\Manager;
    use Piwik\DataTable\Row;
    
    use Piwik\DataTable;
    
    use Symfony\Component\VarDumper\Cloner\Data;
    
    mattab's avatar
    mattab a validé
    /**
     * @group DataTableTest
    
    mattab's avatar
    mattab a validé
     */
    
    class DataTableTest extends \PHPUnit_Framework_TestCase
    
    sgiehl's avatar
    sgiehl a validé
    {
        public function testApplyFilter()
        {
            $table = $this->_getDataTable1ForTest();
            $this->assertEquals(4, $table->getRowsCount());
    
            $table->filter('Limit', array(2, 2));
    
    sgiehl's avatar
    sgiehl a validé
            $this->assertEquals(2, $table->getRowsCount());
    
            $table->filter('Limit', array(0, 1));
    
    sgiehl's avatar
    sgiehl a validé
            $this->assertEquals(1, $table->getRowsCount());
        }
    
    sgiehl's avatar
    sgiehl a validé
        protected function _getSimpleTestDataTable()
        {
    
    sgiehl's avatar
    sgiehl a validé
            $table->addRowsFromArray(
    
                     array(Row::COLUMNS => array('label' => 'ten', 'count' => 10)),
                     array(Row::COLUMNS => array('label' => 'ninety', 'count' => 90)),
                     array(Row::COLUMNS => array('label' => 'hundred', 'count' => 100)),
                     DataTable::ID_SUMMARY_ROW => array(Row::COLUMNS => array('label' => 'summary', 'count' => 200))
    
    sgiehl's avatar
    sgiehl a validé
                )
            );
            return $table;
        }
    
    sgiehl's avatar
    sgiehl a validé
        public function testRenameColumn()
        {
            $table = $this->_getSimpleTestDataTable();
    
            $this->assertEquals(array(10, 90, 100, 200), $table->getColumn('count'));
    
    sgiehl's avatar
    sgiehl a validé
            $table->renameColumn('count', 'renamed');
            $this->assertEquals(array(false, false, false, false), $table->getColumn('count'));
    
            $this->assertEquals(array(10, 90, 100, 200), $table->getColumn('renamed'));
    
    sgiehl's avatar
    sgiehl a validé
        }
    
        public function testDeleteColumn()
        {
            $table = $this->_getSimpleTestDataTable();
    
            $this->assertEquals(array(10, 90, 100, 200), $table->getColumn('count'));
    
    sgiehl's avatar
    sgiehl a validé
            $table->deleteColumn('count');
            $this->assertEquals(array(false, false, false, false), $table->getColumn('count'));
        }
    
        public function testDeleteRow()
        {
            $table = $this->_getSimpleTestDataTable();
    
    sgiehl's avatar
    sgiehl a validé
            // normal row
            $idToDelete = 1;
            $this->assertEquals(2, count($table->getRowFromId($idToDelete)->getColumns()));
            $table->deleteRow($idToDelete);
            $this->assertFalse($table->getRowFromId($idToDelete));
    
            // summary row special case
    
            $idToDelete = DataTable::ID_SUMMARY_ROW;
    
    sgiehl's avatar
    sgiehl a validé
            $this->assertEquals(2, count($table->getRowFromId($idToDelete)->getColumns()));
            $table->deleteRow($idToDelete);
            $this->assertFalse($table->getRowFromId($idToDelete));
        }
    
    sgiehl's avatar
    sgiehl a validé
        public function testGetLastRow()
        {
            $table = $this->_getSimpleTestDataTable();
            $rowsCount = $table->getRowsCount();
    
    
            $this->assertEquals($table->getLastRow(), $table->getRowFromId(DataTable::ID_SUMMARY_ROW));
            $table->deleteRow(DataTable::ID_SUMMARY_ROW);
    
    
            $this->assertEquals($table->getLastRow(), $table->getRowFromId($rowsCount - 2));
    
    sgiehl's avatar
    sgiehl a validé
        }
    
    sgiehl's avatar
    sgiehl a validé
        public function testGetRowFromIdSubDataTable()
        {
            $table1 = $this->_getDataTable1ForTest();
            $idTable1 = $table1->getId();
            $table2 = $this->_getDataTable2ForTest();
            $this->assertFalse($table2->getRowFromIdSubDataTable($idTable1));
    
            $table2->getFirstRow()->setSubtable($table1);
    
    sgiehl's avatar
    sgiehl a validé
            $this->assertEquals($table2->getRowFromIdSubDataTable($idTable1), $table2->getFirstRow());
    
    sgiehl's avatar
    sgiehl a validé
            $table3 = $this->_getDataTable1ForTest();
            $idTable3 = $table3->getId();
    
            $table2->getLastRow()->setSubtable($table3);
    
    sgiehl's avatar
    sgiehl a validé
            $this->assertEquals($table2->getRowFromIdSubDataTable($idTable3), $table2->getLastRow());
        }
    
        public function test_clone_shouldIncreasesTableId()
        {
            $table = new DataTable;
            $rows = array(
                array(Row::COLUMNS => array('label' => 'google')),
            );
            $table->addRowsFromArray($rows);
    
            $table2 = clone $table;
    
            $this->assertSame($table2->getId(), $table->getId() + 1);
        }
    
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * we test the count rows and the count rows recursive version
         * on a Simple array (1 level only)
         */
    
        public function testCountRowsSimple()
    
    sgiehl's avatar
    sgiehl a validé
        {
    
            $table = new DataTable;
            $idcol = Row::COLUMNS;
    
            $rows = array(
                array($idcol => array('label' => 'google')),
                array($idcol => array('label' => 'ask')),
                array($idcol => array('label' => 'piwik')),
                array($idcol => array('label' => 'yahoo')),
                array($idcol => array('label' => 'amazon')),
                array($idcol => array('label' => '238975247578949')),
    
                array($idcol => array('label' => 'Q*(%&*("$&%*(&"$*")"))'))
            );
    
            $this->assertEquals(7, $table->getRowsCount());
            $this->assertEquals(7, $table->getRowsCountRecursive());
    
    sgiehl's avatar
    sgiehl a validé
        }
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * we test the count rows and the count rows recursive version
         * on a Complex array (rows with 2 and 3 levels only)
    
         *
         * the recursive count returns
         *         the sum of the number of rows of all the subtables
    
    sgiehl's avatar
    sgiehl a validé
         *         + the number of rows in the parent table
         */
    
        public function testCountRowsComplex()
    
    sgiehl's avatar
    sgiehl a validé
        {
    
            $idcol = Row::COLUMNS;
            $idsubtable = Row::DATATABLE_ASSOCIATED;
    
    sgiehl's avatar
    sgiehl a validé
            // table to go in the SUB table of RoW1
    
            $tableSubOfSubOfRow1 = new DataTable;
    
    sgiehl's avatar
    sgiehl a validé
            $rows1sub = array(
    
                array($idcol => array('label' => 'google')),
                array($idcol => array('label' => 'google78')),
                array($idcol => array('label' => 'googlaegge')),
                array($idcol => array('label' => 'gogeoggle')),
                array($idcol => array('label' => 'goaegaegaogle')),
                array($idcol => array('label' => 'ask')),
                array($idcol => array('label' => '238975247578949')),
    
    sgiehl's avatar
    sgiehl a validé
            );
    
            $tableSubOfSubOfRow1->addRowsFromArray($rows1sub);
    
    
    sgiehl's avatar
    sgiehl a validé
            // table to go in row1
    
    sgiehl's avatar
    sgiehl a validé
            $rows1 = array(
    
                array($idcol => array('label' => 'google'), $idsubtable => $tableSubOfSubOfRow1),
                array($idcol => array('label' => 'ask')),
                array($idcol => array('label' => '238975247578949')),
    
    sgiehl's avatar
    sgiehl a validé
            );
    
            $tableSubOfRow1->addRowsFromArray($rows1);
    
    
    sgiehl's avatar
    sgiehl a validé
            // table to go in row2
    
    sgiehl's avatar
    sgiehl a validé
            $rows2 = array(
    
                array($idcol => array('label' => 'google')),
                array($idcol => array('label' => 'ask')),
                array($idcol => array('label' => '238975247578949')),
                array($idcol => array('label' => 'agaegaesk')),
                array($idcol => array('label' => '23g  8975247578949')),
    
    sgiehl's avatar
    sgiehl a validé
            );
    
            $tableSubOfRow2->addRowsFromArray($rows2);
    
    
    sgiehl's avatar
    sgiehl a validé
            // main parent table
    
    sgiehl's avatar
    sgiehl a validé
            $rows = array(
    
                array($idcol => array('label' => 'row1')),
                array($idcol      => array('label' => 'row2'),
                      $idsubtable => $tableSubOfRow1),
                array($idcol      => array('label' => 'row3'),
                      $idsubtable => $tableSubOfRow2),
    
    sgiehl's avatar
    sgiehl a validé
            );
    
            $this->assertEquals(3, $table->getRowsCount());
            $this->assertEquals(18, $table->getRowsCountRecursive());
    
    sgiehl's avatar
    sgiehl a validé
        }
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * Simple test of the DataTable_Row
         */
    
        public function testRow()
    
    sgiehl's avatar
    sgiehl a validé
        {
    
            $columns = array('test_column' => 145,
    
                             'super'       => array('this column has an array value, amazing'));
            $metadata = array('logo'  => 'piwik.png',
                              'super' => array('this column has an array value, amazing'));
    
    sgiehl's avatar
    sgiehl a validé
            $arrayRow = array(
    
                Row::COLUMNS  => $columns,
                Row::METADATA => $metadata,
    
                'fake useless key'            => 38959,
                43905724897                   => 'value');
    
    sgiehl's avatar
    sgiehl a validé
            $this->assertEquals($columns, $row->getColumns());
            $this->assertEquals($metadata, $row->getMetadata());
            $this->assertNull($row->getIdSubDataTable());
    
    sgiehl's avatar
    sgiehl a validé
        }
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * Simple test of the DataTable_Row
         */
    
        public function testSumRow()
    
    sgiehl's avatar
    sgiehl a validé
        {
    
            $columns = array('test_int'          => 145,
                             'test_float'        => 145.5,
                             'test_float3'       => 1.5,
                             'test_stringint'    => "145",
                             "test"              => 'string fake',
                             'integerArrayToSum' => array(1 => 1, 2 => 10.0, 3 => array(1 => 2, 2 => 3)),
            );
            $metadata = array('logo'  => 'piwik.png',
                              'super' => array('this column has an array value, amazing'));
    
    sgiehl's avatar
    sgiehl a validé
            $arrayRow = array(
    
                Row::COLUMNS  => $columns,
                Row::METADATA => $metadata,
    
    
            $columns2 = array('test_int'          => 5,
                              'test_float'        => 4.5,
                              'test_float2'       => 14.5,
                              'test_stringint'    => "5",
    
                              'integerArrayToSum' => array(1 => 5, 2 => 5.5, 3 => array(2 => 4)),
            );
    
            $finalRow = new Row(array(Row::COLUMNS => $columns2));
    
    sgiehl's avatar
    sgiehl a validé
            $finalRow->sumRow($row1);
    
            $columnsWanted = array('test_int'          => 150,
                                   'test_float'        => 150.0,
                                   'test_float2'       => 14.5,
                                   'test_float3'       => 1.5,
                                   'test_stringint'    => 150, //add also strings!!
                                   'test'              => 'string fake',
                                   'integerArrayToSum' => array(1 => 6, 2 => 15.5, 3 => array(1 => 2, 2 => 7)),
    
            );
    
            // Also testing that metadata is copied over
    
            $rowWanted = new Row(array(Row::COLUMNS => $columnsWanted, Row::METADATA => $metadata));
            $this->assertTrue(Row::isEqual($rowWanted, $finalRow));
    
    
            // testing that, 'sumRow' does not result in extra unwanted attributes being serialized
    
    
            $expectedRow = 'a:3:{i:0;a:8:{s:8:"test_int";i:150;s:10:"test_float";d:150;s:11:"test_float2";d:14.5;s:14:"test_stringint";i:150;i:925824;s:4:"toto";s:17:"integerArrayToSum";a:3:{i:1;i:6;i:2;d:15.5;i:3;a:2:{i:2;i:7;i:1;i:2;}}s:11:"test_float3";d:1.5;s:4:"test";s:11:"string fake";}i:1;a:2:{s:4:"logo";s:9:"piwik.png";s:5:"super";a:1:{i:0;s:39:"this column has an array value, amazing";}}i:3;N;}';
            $this->assertEquals($expectedRow, serialize($finalRow->export()));
    
    
            // Testing sumRow with disabled metadata sum
    
            $rowWanted = new Row(array(Row::COLUMNS => $columnsWanted)); // no metadata
            $finalRow = new Row(array(Row::COLUMNS => $columns2));
    
            $finalRow->sumRow($row1, $enableCopyMetadata = false);
    
            $this->assertTrue(Row::isEqual($rowWanted, $finalRow));
        }
    
    
         * @dataProvider unserializeTestsDataProvider
    
        public function test_unserializeWorks_WithAllDataTableFormats($indexToRead, $label, $column2, $subtable)
    
            $serializedDatatable = array();
            // Prior Piwik 2.13, we serialized the actual Row or DataTableSummaryRow instances, afterwards only arrays
            require PIWIK_INCLUDE_PATH . "/tests/resources/DataTables-archived-different-formats.php";
    
            require_once PIWIK_INCLUDE_PATH . "/core/DataTable/Bridges.php";
    
            $table = $serializedDatatable[$indexToRead];
            $this->assertTrue(strlen($table) > 1000);
    
            $table = DataTable::fromSerializedArray($table);
            $row1  = $table->getFirstRow();
            $this->assertTrue($row1 instanceof \Piwik\DataTable\Row);
    
            $this->assertFalse($row1 instanceof \Piwik\DataTable\Row\DataTableSummaryRow); // we convert summary rows to Row instances
    
            $this->assertEquals($label, $row1->getColumn('label'));
            $this->assertEquals($column2, $row1->getColumn(2));
            $this->assertEquals($subtable, $row1->getIdSubDataTable());
        }
    
    
        public function testSumRowMetadata_CustomAggregationOperation()
        {
            $metadata1 = array('mytest' => 'value1');
            $metadata2 = array('mytest' => 'value2');
    
    
            $row1 = new Row(array(Row::COLUMNS => array('test_int' => 145), Row::METADATA => $metadata1));
            $finalRow = new Row(array(Row::COLUMNS => array('test_int' => 5), Row::METADATA => $metadata2));
    
            $finalRow->sumRowMetadata($row1, array('mytest' => function ($thisValue, $otherValue, $thisRow, $otherRow) use ($self, $row1, $finalRow) {
                $self->assertEquals('value2', $thisValue);
                $self->assertEquals('value1', $otherValue);
                $self->assertSame($thisRow, $finalRow);
                $self->assertSame($otherRow, $row1);
    
    
                if (!is_array($thisValue)) {
                    $thisValue = array($thisValue);
                }
    
                $thisValue[] = $otherValue;
                return $thisValue;
            }));
    
            $this->assertEquals(array('value2', 'value1'), $finalRow->getMetadata('mytest'));
        }
    
        public function testSumRow_CustomAggregationOperation()
        {
            $columns = array('test_int' => 145, 'test_float' => 145.5);
    
            $row1 = new Row(array(Row::COLUMNS => $columns));
    
            $columns2 = array('test_int' => 5);
            $finalRow = new Row(array(Row::COLUMNS => $columns2));
    
    
    
            $self = $this;
    
            $finalRow->sumRow($row1, $copyMetadata = true, $operation = array('test_int' => function ($thisValue, $otherValue, $thisRow, $otherRow) use ($self, $row1, $finalRow) {
                $self->assertEquals(5, $thisValue);
                $self->assertEquals(145, $otherValue);
                $self->assertSame($thisRow, $finalRow);
                $self->assertSame($otherRow, $row1);
    
    
                if (!is_array($thisValue)) {
                    $thisValue = array($thisValue);
                }
    
                $thisValue[] = $otherValue;
                return $thisValue;
            }));
    
            $this->assertEquals(array(5, 145), $finalRow->getColumn('test_int'));
        }
    
        /**
         * @expectedException  \Exception
         * @expectedExceptionMessage Unknown operation 'foobarinvalid'
         */
        public function testSumRow_ShouldThrowExceptionIfInvalidOperationIsGiven()
        {
            $row1 = new Row(array(Row::COLUMNS => array('test_int' => 145)));
            $finalRow = new Row(array(Row::COLUMNS => array('test_int' => 5)));
            $finalRow->sumRow($row1, $copyMetadata = true, $operation = array('test_int' => 'fooBarInvalid'));
    
            $this->assertEquals(array(5, 145), $finalRow->getColumn('test_int'));
        }
    
    
        public function unserializeTestsDataProvider()
        {
            return array(
    
                array($index = 0, $label = 'piwik.org', $column2 = 10509, $idSubtable = 1581), // pre Piwik 2.0 (without namespaces, Piwik_DataTable_Row)
                array($index = 1, $label = 'piwikactions.org', $column2 = 10508, $idSubtable = 1581), // pre Piwik 2.0 Actions (without namespaces, Piwik_DataTable_Row_DataTableSummary)
                array($index = 2, $label = 'start', $column2 = 89, $idSubtable = 2260), // >= Piwik 2.0 < Piwik 2.13 Actions (DataTableSummaryRow)
                array($index = 3, $label = 'Ask',   $column2 = 11, $idSubtable = 3335), // >= Piwik 2.0 < Piwik 2.13 Referrers (Row)
                array($index = 4, $label = 'MyLabel Test',   $column2 = 447, $idSubtable = 1), // >= Piwik 2.0 < Piwik 2.13 Referrers (Row)
    
    sgiehl's avatar
    sgiehl a validé
        }
    
        /**
         * Test that adding two string column values results in an exception.
         */
        public function testSumRow_stringException()
        {
            $columns = array(
                'super' => array('this column has an array string that will be 0 when algorithm sums the value'),
            );
    
            $row1 = new Row(array(Row::COLUMNS => $columns));
    
    
            $columns2 = array(
                'super' => array('this column has geagaean array value, amazing'),
            );
    
            $row2 = new Row(array(Row::COLUMNS => $columns2));
    
    sgiehl's avatar
    sgiehl a validé
            $row2->sumRow($row1);
    
            $this->assertTrue($noException = true);
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * Test serialize with an infinite recursion (a row linked to a table in the parent hierarchy)
         * After 100 recursion must throw an exception
    
         * @expectedException \Exception
    
    sgiehl's avatar
    sgiehl a validé
         */
    
        public function testSerializeWithInfiniteRecursion()
    
    sgiehl's avatar
    sgiehl a validé
        {
    
    sgiehl's avatar
    sgiehl a validé
            $table = new DataTable;
    
            $table->addRowFromArray(array(Row::COLUMNS => array('visits' => 245, 'visitors' => 245),
                                          Row::DATATABLE_ASSOCIATED => $table));
    
    sgiehl's avatar
    sgiehl a validé
    
            $table->getSerialized();
    
    sgiehl's avatar
    sgiehl a validé
        }
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * Test queing filters
         */
    
        public function testFilterQueueSortString()
        {
    
    sgiehl's avatar
    sgiehl a validé
            $rows = array(
    
                array($idcol => array('label' => 'google')), //0
                array($idcol => array('label' => 'tsk')), //1
                array($idcol => array('label' => 'Q*(%&*("$&%*(&"$*")"))')), //2
            );
            $table->addRowsFromArray($rows);
    
    
    sgiehl's avatar
    sgiehl a validé
            $rows = array(
    
                array($idcol => array('label' => 'google')), //0
                array($idcol => array('label' => 'Q*(%&*("$&%*(&"$*")"))')), //2
                array($idcol => array('label' => 'tsk')), //1
            );
            $expectedtable->addRowsFromArray($rows);
    
    
            $expectedtableReverse = new DataTable;
    
    sgiehl's avatar
    sgiehl a validé
            $expectedtableReverse->addRowsFromArray(array_reverse($rows));
    
    sgiehl's avatar
    sgiehl a validé
            $tableCopy = clone $table;
    
            $this->assertTrue(DataTable::isEqual($tableCopy, $table));
    
    sgiehl's avatar
    sgiehl a validé
            // queue the filter and check the table didnt change
            $table->queueFilter("Sort", array('label', 'asc'));
    
            $this->assertTrue(DataTable::isEqual($tableCopy, $table));
    
    sgiehl's avatar
    sgiehl a validé
            // apply filter and check the table is sorted
            $table->applyQueuedFilters();
    
            $this->assertTrue(DataTable::isEqual($expectedtable, $table));
    
    sgiehl's avatar
    sgiehl a validé
            // apply one more filter check it hasnt changed
            $table->queueFilter("Sort", array('label', 'desc'));
    
            $this->assertTrue(DataTable::isEqual($expectedtable, $table));
    
    sgiehl's avatar
    sgiehl a validé
            // now apply the second sort and check it is correctly sorted
            $table->applyQueuedFilters();
    
            $this->assertTrue(DataTable::isEqual($expectedtableReverse, $table));
    
    sgiehl's avatar
    sgiehl a validé
            // do one more time to make sure it doesnt change
            $table->applyQueuedFilters();
    
            $this->assertTrue(DataTable::isEqual($expectedtableReverse, $table));
    
    sgiehl's avatar
    sgiehl a validé
    
        /**
         * General tests that tries to test the normal behaviour of DataTable
    
    sgiehl's avatar
    sgiehl a validé
         * We create some tables, add rows, some of the rows link to sub tables
    
    sgiehl's avatar
    sgiehl a validé
         * Then we serialize everything, and we check that the unserialize give the same object back
         */
    
        public function testGeneral()
    
    sgiehl's avatar
    sgiehl a validé
        {
            /*
             * create some fake tables to make sure that the serialized array of the first TABLE
             * does not take in consideration those tables
             */
    
            $useless1 = $this->createDataTable(array(array(13,)));
    
    sgiehl's avatar
    sgiehl a validé
            /*
             * end fake tables
             */
    
    sgiehl's avatar
    sgiehl a validé
            /*
             * MAIN TABLE
             */
    
            $table = new DataTable;
            $subtable = new DataTable;
    
    sgiehl's avatar
    sgiehl a validé
            $idtable = $table->getId();
    
    sgiehl's avatar
    sgiehl a validé
            /*
             * create some fake tables to make sure that the serialized array of the first TABLE
             * does not take in consideration those tables
    
             * -> we check that the DataTable_Manager is not impacting DataTable
    
    sgiehl's avatar
    sgiehl a validé
             */
    
            $useless1->addRowFromArray(array(Row::COLUMNS => array(8487,),));
    
            $useless3 = $this->createDataTable(array(array(8487)));
    
    sgiehl's avatar
    sgiehl a validé
            /*
             * end fake tables
             */
    
            $row = array(Row::COLUMNS  => array(0 => 1554, 1 => 42, 2 => 657, 3 => 155744,),
                         Row::METADATA => array('logo' => 'test.png'));
            $row = new Row($row);
    
    sgiehl's avatar
    sgiehl a validé
            $table->addRow($row);
    
            $table->addRowFromArray(array(Row::COLUMNS  => array(0 => 1554, 1 => 42,),
                                          Row::METADATA => array('url' => 'piwik.org')));
    
            $table->addRowFromArray(array(Row::COLUMNS              => array(0 => 787877888787,),
                                          Row::METADATA             => array('url' => 'OUPLA ADDED'),
                                          Row::DATATABLE_ASSOCIATED => $subtable));
    
    sgiehl's avatar
    sgiehl a validé
            /*
             * SUB TABLE
    
            $row = array(Row::COLUMNS  => array(0 => 1554,),
                         Row::METADATA => array('searchengine' => 'google'),
    
    sgiehl's avatar
    sgiehl a validé
            $subtable->addRowFromArray($row);
    
            $row = array(Row::COLUMNS  => array(0 => 84894,),
                         Row::METADATA => array('searchengine' => 'yahoo'),
    
    sgiehl's avatar
    sgiehl a validé
            $subtable->addRowFromArray($row);
    
            $row = array(Row::COLUMNS  => array(0 => 4898978989,),
                         Row::METADATA => array('searchengine' => 'ask'),
    
    sgiehl's avatar
    sgiehl a validé
            $subtable->addRowFromArray($row);
    
    sgiehl's avatar
    sgiehl a validé
            /*
             * SUB SUB TABLE
             */
    
            $subsubtable = new DataTable;
            $subsubtable->addRowFromArray(array(Row::COLUMNS  => array(245),
                                                Row::METADATA => array('yes' => 'subsubmetadata1'),)
    
            $subsubtable->addRowFromArray(array(Row::COLUMNS  => array(13,),
                                                Row::METADATA => array('yes' => 'subsubmetadata2'),)
    
            $row = array(Row::COLUMNS              => array(0 => 666666666666666,),
                         Row::METADATA             => array('url' => 'NEW ROW ADDED'),
                         Row::DATATABLE_ASSOCIATED => $subsubtable);
    
    sgiehl's avatar
    sgiehl a validé
            $subtable->addRowFromArray($row);
    
    sgiehl's avatar
    sgiehl a validé
            $idsubsubtable = $subsubtable->getId();
    
            $this->assertEquals(array_keys($serialized), array(2, 1, 0)); // subtableIds are now consecutive
    
    
            // In the next test we compare an unserialized datatable with its original instance.
            // The unserialized datatable rows will have positive DATATABLE_ASSOCIATED ids.
            // Positive DATATABLE_ASSOCIATED ids mean that the associated sub-datatables are not loaded in memory.
            // In this case, this is NOT true: we know that the sub-datatable is loaded in memory.
            // HOWEVER, because of datatable id conflicts happening in the datatable manager, it is not yet
            // possible to know, after unserializing a datatable, if its sub-datatables are loaded in memory.
            $expectedTableRows = array();
    
            foreach ($table->getRows() as $currentRow) {
                $expectedTableRow = clone $currentRow;
    
    
                $currentRowAssociatedDatatableId = $currentRow->subtableId;
    
                if ($currentRowAssociatedDatatableId != null) {
    
                    $expectedTableRow->setNonLoadedSubtableId(++$i); // subtableIds are consecutive
    
                }
    
                $expectedTableRows[] = $expectedTableRow;
            }
    
    sgiehl's avatar
    sgiehl a validé
            $tableAfter->addRowsFromSerializedArray($serialized[0]);
    
    
            $this->assertEquals($expectedTableRows, $tableAfter->getRows());
    
    sgiehl's avatar
    sgiehl a validé
    
    
            $subsubtableAfter->addRowsFromSerializedArray($serialized[$consecutiveSubtableId = 2]);
    
            $this->assertEquals($subsubtable->getRows(), $subsubtableAfter->getRows());
    
            $this->assertEquals($subsubtable->getRows(), DataTable::fromSerializedArray($serialized[$consecutiveSubtableId = 2])->getRows());
    
            $this->assertTrue($subsubtable->getRowsCount() > 0);
    
            $this->assertEquals($table, Manager::getInstance()->getTable($idtable));
            $this->assertEquals($subsubtable, Manager::getInstance()->getTable($idsubsubtable));
    
    sgiehl's avatar
    sgiehl a validé
        }
    
        public function test_getSerialized_shouldCreateConsecutiveSubtableIds()
        {
            $numRowsInRoot = 10;
            $numRowsInSubtables = 5;
    
            $rootTable = new DataTable();
            $this->addManyRows($rootTable, 100);
    
            foreach ($rootTable->getRows() as $row) {
                $subtable = new DataTable();
                $this->addManyRows($subtable, 100);
                $row->setSubtable($subtable);
    
                foreach ($subtable->getRows() as $subRow) {
                    $subRow->setSubtable(new DataTable());
                }
            }
    
            // we want to make sure the tables have high ids but we will ignore them and just give them Ids starting from 0
            $recentId = Manager::getInstance()->getMostRecentTableId();
            $this->assertGreaterThanOrEqual(5000, $recentId);
    
            $tables = $rootTable->getSerialized($numRowsInRoot, $numRowsInSubtables);
    
            // make sure subtableIds are consecutive. Why "-1"? Because if we want 10 rows, there will be 9 subtables + 1 summary row which won't have a subtable
            $sumSubTables = ($numRowsInRoot - 1) + (($numRowsInRoot - 1) * ($numRowsInSubtables - 1));
            $subtableIds  = array_keys($tables);
            sort($subtableIds);
            $this->assertEquals(range(0, $sumSubTables), $subtableIds);
    
            // make sure the rows subtableId were updated as well.
            foreach ($tables as $index => $serializedRows) {
                $rows = unserialize($serializedRows);
    
                $this->assertTrue(is_array($rows));
    
    
                if (0 === $index) {
                    // root table, make sure correct amount of rows are in subtables
                    $this->assertCount($numRowsInRoot, $rows);
                }
    
                foreach ($rows as $row) {
    
                    $subtableId = $row[Row::DATATABLE_ASSOCIATED];
    
                    if ($row[Row::COLUMNS]['label'] === DataTable::LABEL_SUMMARY_ROW) {
                        $this->assertNull($subtableId);
                    } else {
    
                        $this->assertLessThanOrEqual($sumSubTables, $subtableId); // make sure row was actually updated
                        $this->assertGreaterThanOrEqual(0, $subtableId);
                        $subrows = unserialize($tables[$subtableId]);
    
                        // this way we make sure the rows point to the correct subtable. only 2nd level rows have actually
                        // subtables. All 3rd level datatables do not have a row see table creation further above
                        if ($index === 0) {
                            $this->assertCount($numRowsInSubtables, $subrows);
                        } else {
                            $this->assertCount(0, $subrows);
                        }
                    }
                }
            }
        }
    
        public function test_getSerialized_shouldExportOnlyTheSerializedArrayOfAllTableRows()
        {
            $rootTable = new DataTable();
            $this->addManyRows($rootTable, 2);
    
            foreach ($rootTable->getRows() as $row) {
                $subtable = new DataTable();
                $this->addManyRows($subtable, 2);
                $row->setSubtable($subtable);
            }
    
            $tables = $rootTable->getSerialized();
    
            // we also make sure it actually handles the subtableIds correct etc
            $this->assertEquals(array(
                0 => 'a:2:{i:0;a:3:{i:0;a:1:{s:5:"label";s:6:"label0";}i:1;a:0:{}i:3;i:1;}i:1;a:3:{i:0;a:1:{s:5:"label";s:6:"label1";}i:1;a:0:{}i:3;i:2;}}',
                1 => 'a:2:{i:0;a:3:{i:0;a:1:{s:5:"label";s:6:"label0";}i:1;a:0:{}i:3;N;}i:1;a:3:{i:0;a:1:{s:5:"label";s:6:"label1";}i:1;a:0:{}i:3;N;}}',
                2 => 'a:2:{i:0;a:3:{i:0;a:1:{s:5:"label";s:6:"label0";}i:1;a:0:{}i:3;N;}i:1;a:3:{i:0;a:1:{s:5:"label";s:6:"label1";}i:1;a:0:{}i:3;N;}}',
            ), $tables);
        }
    
        private function addManyRows(DataTable $table, $numRows)
        {
            for ($i = 0; $i < $numRows; $i++) {
                $table->addRowFromArray(array(Row::COLUMNS => array('label' => 'label' . $i)));
            }
        }
    
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * for all datatable->addDatatable tests we check that
         * - row uniqueness is based on the label + presence of the SUBTABLE id
         *         => the label is the criteria used to match 2 rows in 2 datatable
         * - no metadata are lost in the first datatable rows that have been changed
         * - when a subtable
         */
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * add an empty datatable to a normal datatable
         */
        public function testAddSimpleNoRowTable2()
        {
            $table = $this->_getDataTable1ForTest();
    
    sgiehl's avatar
    sgiehl a validé
            $tableAfter = clone $table;
            $tableAfter->addDataTable($tableEmpty);
    
            $this->assertTrue(DataTable::isEqual($table, $tableAfter));
    
    sgiehl's avatar
    sgiehl a validé
        }
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * add a normal datatable to an empty datatable
         */
        public function testAddSimpleNoRowTable1()
        {
            $table = $this->_getDataTable1ForTest();
    
    sgiehl's avatar
    sgiehl a validé
            $tableEmpty->addDataTable($table);
    
            $this->assertTrue(DataTable::isEqual($tableEmpty, $table));
    
    sgiehl's avatar
    sgiehl a validé
        }
    
        /**
         * add to the datatable another datatable// they don't have any row in common
         */
        public function testAddSimpleNoCommonRow()
        {
            $table1 = $this->_getDataTable1ForTest();
            $table2 = $this->_getDataTable2ForTest();
    
    sgiehl's avatar
    sgiehl a validé
            $table1->addDataTable($table2);
    
    
            $rowsExpected = array_merge($this->_getRowsDataTable1ForTest(), $this->_getRowsDataTable2ForTest());
    
            $tableExpected->addRowsFromArray($rowsExpected);
    
    
            $this->assertTrue(DataTable::isEqual($table1, $tableExpected));
    
    sgiehl's avatar
    sgiehl a validé
        }
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * add 2 datatable with some common rows
         */
        public function testAddSimpleSomeCommonRow()
        {
    
    sgiehl's avatar
    sgiehl a validé
            $rows = array(
    
                array($idcol => array('label' => 'google', 'visits' => 1)),
                array($idcol => array('label' => 'ask', 'visits' => 2)),
                array($idcol => array('label' => '123', 'visits' => 2)),
    
                DataTable::ID_SUMMARY_ROW => array($idcol => array('label' => DataTable::LABEL_SUMMARY_ROW, 'visits' => 7))
    
    sgiehl's avatar
    sgiehl a validé
            $rows2 = array(
    
                array($idcol => array('label' => 'test', 'visits' => 1)),
                array($idcol => array('label' => 'ask', 'visits' => 111)),
                array($idcol => array('label' => ' google ', 'visits' => 5)),
                array($idcol => array('label' => '123', 'visits' => 2)),
            );
    
    sgiehl's avatar
    sgiehl a validé
            $table->addDataTable($table2);
    
    sgiehl's avatar
    sgiehl a validé
            $rowsExpected = array(
    
                array($idcol => array('label' => 'google', 'visits' => 1)),
                array($idcol => array('label' => 'ask', 'visits' => 113)),
                array($idcol => array('label' => '123', 'visits' => 4)),
                array($idcol => array('label' => 'test', 'visits' => 1)),
                array($idcol => array('label' => ' google ', 'visits' => 5)),
    
                DataTable::ID_SUMMARY_ROW => array($idcol => array('label' => DataTable::LABEL_SUMMARY_ROW, 'visits' => 7))
    
            $tableExpected->addRowsFromArray($rowsExpected);
    
    
            $this->assertTrue(DataTable::isEqual($table, $tableExpected));
    
    sgiehl's avatar
    sgiehl a validé
        }
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * add 2 datatable with only common rows
         */
        public function testAddSimpleAllCommonRow()
        {
    
    sgiehl's avatar
    sgiehl a validé
            $rows = array(
    
                array($idcol => array('label' => 'google', 'visits' => 1)),
                array($idcol => array('label' => 'ask', 'visits' => 2)),
                array($idcol => array('label' => '123', 'visits' => 2)),
    
                DataTable::ID_SUMMARY_ROW => array($idcol => array('label' => DataTable::LABEL_SUMMARY_ROW, 'visits' => 7))
    
    sgiehl's avatar
    sgiehl a validé
            $rows2 = array(
    
                array($idcol => array('label' => 'google', 'visits' => -1)),
                array($idcol => array('label' => 'ask', 'visits' => 0)),
                array($idcol => array('label' => '123', 'visits' => 1.5)),
    
                DataTable::ID_SUMMARY_ROW => array($idcol => array('label' => DataTable::LABEL_SUMMARY_ROW, 'visits' => 8))
    
    sgiehl's avatar
    sgiehl a validé
            $table->addDataTable($table2);
    
    sgiehl's avatar
    sgiehl a validé
            $rowsExpected = array(
    
                array($idcol => array('label' => 'google', 'visits' => 0)),
                array($idcol => array('label' => 'ask', 'visits' => 2)),
                array($idcol => array('label' => '123', 'visits' => 3.5)),
    
                DataTable::ID_SUMMARY_ROW => array($idcol => array('label' => DataTable::LABEL_SUMMARY_ROW, 'visits' => 15))
    
            $tableExpected->addRowsFromArray($rowsExpected);
    
    
            $this->assertTrue(DataTable::isEqual($table, $tableExpected));
    
    sgiehl's avatar
    sgiehl a validé
        }
    
    sgiehl's avatar
    sgiehl a validé
        /**
         * test add 2 different tables to the same table
         */
        public function testAddDataTable2times()
        {
    
    sgiehl's avatar
    sgiehl a validé
            $rows = array(
    
                array($idcol => array('label' => 'google', 'visits' => 1)),
                array($idcol => array('label' => 'ask', 'visits' => 0)),
                array($idcol => array('label' => '123', 'visits' => 2)),
    
                DataTable::ID_SUMMARY_ROW => array($idcol => array('label' => DataTable::LABEL_SUMMARY_ROW, 'visits' => 1))
    
    sgiehl's avatar
    sgiehl a validé
            $rows2 = array(
    
                array($idcol => array('label' => 'google2', 'visits' => -1)),
                array($idcol => array('label' => 'ask', 'visits' => 100)),
                array($idcol => array('label' => '123456', 'visits' => 1.5)),
            );
    
    sgiehl's avatar
    sgiehl a validé
            $rows3 = array(
    
                array($idcol => array('label' => 'google2', 'visits' => -1)),
                array($idcol => array('label' => 'ask', 'visits' => -10)),
                array($idcol => array('label' => '123ab', 'visits' => 1.5)),
    
                DataTable::ID_SUMMARY_ROW => array($idcol => array('label' => DataTable::LABEL_SUMMARY_ROW, 'visits' => 3))
    
    sgiehl's avatar
    sgiehl a validé
            // add the 2 tables
            $table->addDataTable($table2);
            $table->addDataTable($table3);
    
    sgiehl's avatar
    sgiehl a validé
            $rowsExpected = array(
    
                array($idcol => array('label' => 'google', 'visits' => 1)),
                array($idcol => array('label' => 'ask', 'visits' => 90)),
                array($idcol => array('label' => '123', 'visits' => 2)),
                array($idcol => array('label' => 'google2', 'visits' => -2)),
                array($idcol => array('label' => '123456', 'visits' => 1.5)),
                array($idcol => array('label' => '123ab', 'visits' => 1.5)),
    
                DataTable::ID_SUMMARY_ROW => array($idcol => array('label' => DataTable::LABEL_SUMMARY_ROW, 'visits' => 4))
    
    sgiehl's avatar
    sgiehl a validé
            );
    
            $tableExpected->addRowsFromArray($rowsExpected);
    
    
            $this->assertTrue(DataTable::isEqual($table, $tableExpected));
    
        }
    
        public function testUnrelatedDataTableNotDestructed()
        {
    
            $mockedDataTable = $this->getMock('\Piwik\DataTable', array('__destruct'));
    
            $mockedDataTable->expects($this->never())->method('__destruct');
    
    
            // we simulate the fact that the value of Row::DATATABLE_ASSOCIATED retrieved
            // from the database is in conflict with one of the Manager managed table identifiers.
    
            // This is a rare but legitimate case as identifiers are not thoroughly synchronized
            // when the expanded parameter is false.
    
            $rowBeingDestructed->subtableId = $mockedDataTable->getId();
    
            Common::destroy($rowBeingDestructed);
    
    sgiehl's avatar
    sgiehl a validé
        }
    
        /**
         * @group Core
         */
        public function test_disableFilter_DoesActuallyDisableAFilter()
        {
            $dataTable = DataTable::makeFromSimpleArray(array_fill(0, 100, array()));
            $this->assertSame(100, $dataTable->getRowsCount());
    
            $dataTable2 = clone $dataTable;
    
            // verify here the filter is applied
            $dataTable->filter('Limit', array(10, 10));
            $this->assertSame(10, $dataTable->getRowsCount());
    
            // verify here the filter is not applied as it is disabled
            $dataTable2->disableFilter('Limit');
            $dataTable2->filter('Limit', array(10, 10));
            $this->assertSame(100, $dataTable2->getRowsCount());
    
            // passing a whole className is expected to work. This way we also make sure not all filters are disabled
            // and it only blocks the given one
            $dataTable2->filter('Piwik\DataTable\Filter\Limit', array(10, 10));
            $this->assertSame(10, $dataTable2->getRowsCount());
        }
    
        /**
         * @group Core
         */
    
        public function testSubDataTableIsDestructed()
        {
    
            $mockedDataTable = $this->getMock('\Piwik\DataTable', array('__destruct'));
    
            $mockedDataTable->expects($this->once())->method('__destruct');
    
    
            $rowBeingDestructed->setSubtable($mockedDataTable);
    
    
            Common::destroy($rowBeingDestructed);
    
        public function test_serializeFails_onSubTableNotFound()
        {
            // create a simple table with a subtable
            $table1 = $this->_getDataTable1ForTest();
            $table2 = $this->_getDataTable2ForTest();
    
            $table2->getFirstRow()->setSubtable($table1);
    
            $idSubtable = 1; // subtableIds are consecutive, we cannot use $table->getId()
    
    
            /* Check it looks good:
            $renderer = DataTable\Renderer::factory('xml');
            $renderer->setTable($table2);
            $renderer->setRenderSubTables(true);
            echo $renderer->render();
            */
    
            // test serialize:
            // - subtable is serialized as expected
            $serializedStrings = $table2->getSerialized();
    
            // both the main table and the sub table are serialized
            $this->assertEquals(sizeof($serializedStrings), 2);
    
            // the serialized string references the id subtable
    
            $unserialized = unserialize($serializedStrings[0]);
            $this->assertSame($idSubtable, $unserialized[0][3], "not found the id sub table in the serialized, not expected");
    
    
            // KABOOM, we delete the subtable, reproducing a "random data issue"
    
            Manager::getInstance()->deleteTable($table1->getId());
    
    
            // Now we will serialize this "broken datatable" and check it works.
    
            // - it does not throw an exception
            $serializedStrings = $table2->getSerialized();
    
            // - the serialized table does NOT contain the sub table
            $this->assertEquals(sizeof($serializedStrings), 1); // main table only is serialized
    
            $unserialized = unserialize($serializedStrings[0]);
    
    
            // - the serialized string does NOT contain the id subtable (the row was cleaned up as expected)
    
            $this->assertNull($unserialized[0][3], "found the id sub table in the serialized, not expected");
        }
    
    
        public function testMergeSubtablesKeepsMetadata()
        {
            $dataTable = $this->_getDataTable1ForTest();
            $dataTable->setMetadata('additionalMetadata', 'test');
            $dataTable = $dataTable->mergeSubtables();
            $this->assertEquals('test', $dataTable->getMetadata('additionalMetadata'));
        }
    
    
        private function createDataTable($rows)
        {
            $useless1 = new DataTable;
            foreach ($rows as $row) {
                $useless1->addRowFromArray(array(Row::COLUMNS => $row));
            }
    
        protected function _getDataTable1ForTest()
    
    sgiehl's avatar
    sgiehl a validé
        {
            $rows = $this->_getRowsDataTable1ForTest();
    
            $table->addRowsFromArray($rows);
    
    sgiehl's avatar
    sgiehl a validé
            return $table;
        }
    
        protected function _getDataTable2ForTest()
        {
    
            $rows = $this->_getRowsDataTable2ForTest();
    
            $table->addRowsFromArray($rows);
    
    sgiehl's avatar
    sgiehl a validé
            return $table;
        }