Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiosmosis <benaka@piwik.pro>2014-09-18 07:40:38 +0400
committerdiosmosis <benaka@piwik.pro>2014-09-18 07:40:38 +0400
commit41fabcb3488f00f5840dc2c231519488322b1837 (patch)
tree32021d167f45a4047e0195841fbb4fba8eed167f /tests/PHPUnit/Core
parentaafb07c75b86b7905da1d7525e2800c8dbad2cde (diff)
Adding new PivotByDimension DataTable filter that can pivot a report by (almost) any dimension. The filter can pivot reports by their subtable dimension and can also pivot by other dimensions (by using segments).
Notes: - in the UI, only pivoting by subtable is supported - change to CSV DataTable renderer so column names w/ commas & quotes can appear in text - change to XML DataTable renderer so column names w/ invalid XML characters can be rendered (bit of an iffy change, XML format needs an overhaul I think) - includes new config option 'pivot_by_filter_enable_fetch_by_segment' - includes additions to component metadata classes (ie, Report/Dimension)
Diffstat (limited to 'tests/PHPUnit/Core')
-rw-r--r--tests/PHPUnit/Core/Columns/DimensionTest.php2
-rw-r--r--tests/PHPUnit/Core/DataTable/Filter/PivotByDimensionTest.php351
-rw-r--r--tests/PHPUnit/Core/DataTable/Renderer/CSVTest.php27
-rw-r--r--tests/PHPUnit/Core/DataTable/Renderer/XMLTest.php54
-rw-r--r--tests/PHPUnit/Core/Plugin/ComponentFactoryTest.php57
5 files changed, 489 insertions, 2 deletions
diff --git a/tests/PHPUnit/Core/Columns/DimensionTest.php b/tests/PHPUnit/Core/Columns/DimensionTest.php
index 477ce7114a..6952b3880f 100644
--- a/tests/PHPUnit/Core/Columns/DimensionTest.php
+++ b/tests/PHPUnit/Core/Columns/DimensionTest.php
@@ -171,5 +171,5 @@ namespace Piwik\Tests\Core\Columns
$dimension = Dimension::factory("ExampleTracker.ExampleDimension");
$this->assertInstanceOf("Piwik\\Plugins\\ExampleTracker\\Columns\\ExampleDimension", $dimension);
}
- }
+ }
} \ No newline at end of file
diff --git a/tests/PHPUnit/Core/DataTable/Filter/PivotByDimensionTest.php b/tests/PHPUnit/Core/DataTable/Filter/PivotByDimensionTest.php
new file mode 100644
index 0000000000..e20cdaf682
--- /dev/null
+++ b/tests/PHPUnit/Core/DataTable/Filter/PivotByDimensionTest.php
@@ -0,0 +1,351 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Tests\Core\DataTable\Filter;
+
+use Piwik\API\Proxy;
+use Piwik\DataTable;
+use Piwik\DataTable\Filter\PivotByDimension;
+use Piwik\DataTable\Row;
+use Piwik\Plugin\Manager as PluginManager;
+use PHPUnit_Framework_TestCase;
+use Exception;
+
+/**
+ * @group Core
+ * @group PivotByDimensionTest
+ */
+class PivotByDimensionTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * The number of segment tables that have been created. Used when injecting API results to make sure each
+ * segment table is different.
+ *
+ * @var int
+ */
+ private $segmentTableCount;
+
+ public function setUp()
+ {
+ $self = $this;
+
+ $proxyMock = $this->getMock('stdClass', array('call'));
+ $proxyMock->expects($this->any())->method('call')->willReturnCallback(function ($className, $methodName, $parameters) use ($self) {
+ if ($className == "\\Piwik\\Plugins\\UserCountry\\API"
+ && $methodName == 'getCity'
+ ) {
+ return $self->getSegmentTable();
+ } else {
+ throw new Exception("Unknown API request: $className::$methodName.");
+ }
+ });
+ Proxy::setSingletonInstance($proxyMock);
+
+ $this->segmentTableCount = 0;
+ }
+
+ public function tearDown()
+ {
+ PluginManager::unsetInstance();
+ Proxy::unsetInstance();
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Unsupported pivot: report 'ExampleReport.ExampleReportName' has no subtable dimension.
+ */
+ public function testConstructionFailsWhenReportHasNoSubtableAndSegmentFetchingIsDisabled()
+ {
+ PluginManager::getInstance()->loadPlugins(array('ExampleReport', 'UserCountry'));
+
+ new PivotByDimension(new DataTable(), "ExampleReport.GetExampleReport", "UserCountry.City", 'nb_visits', $columnLimit = -1, $enableFetchBySegment = false);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Unsupported pivot: the subtable dimension for 'Referrers.Referrers_Keywords' does not match the requested pivotBy dimension.
+ */
+ public function testConstructionFailsWhenDimensionIsNotSubtableAndSegmentFetchingIsDisabled()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Referrers', 'UserCountry'));
+
+ new PivotByDimension(new DataTable(), "Referrers.getKeywords", "UserCountry.City", "nb_visits", $columnLimit = -1, $enableFetchBySegment = false);
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Unsupported pivot: No segment for dimension of report 'UserSettings.UserSettings_WidgetBrowserFamilies'
+ */
+ public function testConstructionFailsWhenDimensionIsNotSubtableAndSegmentFetchingIsEnabledButThereIsNoSegment()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Referrers', 'UserSettings'));
+
+ new PivotByDimension(new DataTable(), "UserSettings.getBrowserType", "Referrers.Keyword", "nb_visits");
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Invalid dimension 'ExampleTracker.InvalidDimension'
+ */
+ public function testConstructionFailsWhenDimensionDoesNotExist()
+ {
+ PluginManager::getInstance()->loadPlugins(array('ExampleReport', 'ExampleTracker'));
+
+ new PivotByDimension(new DataTable(), "ExampleReport.GetExampleReport", "ExampleTracker.InvalidDimension", 'nb_visits');
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Unsupported pivot: No report for pivot dimension 'ExampleTracker.ExampleDimension'
+ */
+ public function testConstructionFailsWhenThereIsNoReportForADimension()
+ {
+ PluginManager::getInstance()->loadPlugins(array('ExampleReport', 'ExampleTracker'));
+
+ new PivotByDimension(new DataTable(), "ExampleReport.GetExampleReport", "ExampleTracker.ExampleDimension", "nb_visits");
+ }
+
+ /**
+ * @expectedException Exception
+ * @expectedExceptionMessage Unable to find report 'ExampleReport.InvalidReport'
+ */
+ public function testConstructionFailsWhenSpecifiedReportIsNotValid()
+ {
+ PluginManager::getInstance()->loadPlugins(array('ExampleReport', 'Referrers'));
+
+ new PivotByDimension(new DataTable(), "ExampleReport.InvalidReport", "Referrers.Keyword", "nb_visits");
+ }
+
+ public function testFilterReturnsEmptyResultWhenTableToFilterIsEmpty()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Referrers', 'UserCountry', 'CustomVariables'));
+
+ $table = new DataTable();
+
+ $pivotFilter = new PivotByDimension($table, "Referrers.getKeywords", "Referrers.SearchEngine", 'nb_visits');
+ $pivotFilter->filter($table);
+
+ $expectedRows = array();
+ $this->assertEquals($expectedRows, $table->getRows());
+ }
+
+ public function testFilterCorrectlyCreatesPivotTableUsingSubtableReport()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Referrers', 'UserCountry', 'CustomVariables'));
+
+ $table = $this->getTableToFilter(true);
+
+ $pivotFilter = new PivotByDimension($table, "Referrers.getKeywords", "Referrers.SearchEngine", 'nb_actions', $columnLimit = -1, $fetchBySegment = false);
+ $pivotFilter->filter($table);
+
+ $expectedRows = array(
+ array('label' => 'row 1', 'col 1' => 2, 'col 2' => false, 'col 3' => false, 'col 4' => false),
+ array('label' => 'row 2', 'col 1' => 4, 'col 2' => 6, 'col 3' => false, 'col 4' => false),
+ array('label' => 'row 3', 'col 1' => false, 'col 2' => 8, 'col 3' => 31, 'col 4' => 33)
+ );
+ $this->assertTableRowsEquals($expectedRows, $table);
+ }
+
+ public function testFilterCorrectlyCreatesPivotTableUsingSegment()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Referrers', 'UserCountry', 'CustomVariables'));
+
+ $table = $this->getTableToFilter(true);
+
+ $pivotFilter = new PivotByDimension($table, "Referrers.getKeywords", "UserCountry.City", 'nb_visits');
+ $pivotFilter->filter($table);
+
+ $expectedRows = array(
+ array('label' => 'row 1', 'col 0' => 2, 'col 1' => false, 'col 2' => false),
+ array('label' => 'row 2', 'col 0' => 2, 'col 1' => 4, 'col 2' => false),
+ array('label' => 'row 3', 'col 0' => 2, 'col 1' => 4, 'col 2' => 6)
+ );
+ $this->assertTableRowsEquals($expectedRows, $table);
+ }
+
+ public function testFilterCorrectlyCreatesPivotTableWhenPivotMetricDoesNotExistInTable()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Referrers', 'UserCountry', 'CustomVariables'));
+
+ $table = $this->getTableToFilter(true);
+
+ $pivotFilter = new PivotByDimension($table, "Referrers.getKeywords", "Referrers.SearchEngine", 'invalid_metric');
+ $pivotFilter->filter($table);
+
+ $expectedRows = array(
+ array('label' => 'row 1', 'col 1' => false, 'col 2' => false, 'col 3' => false, 'col 4' => false),
+ array('label' => 'row 2', 'col 1' => false, 'col 2' => false, 'col 3' => false, 'col 4' => false),
+ array('label' => 'row 3', 'col 1' => false, 'col 2' => false, 'col 3' => false, 'col 4' => false)
+ );
+ $this->assertTableRowsEquals($expectedRows, $table);
+ }
+
+ public function testFilterCorrectlyCreatesPivotTableWhenSubtablesHaveNoRows()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Referrers', 'UserCountry', 'CustomVariables'));
+
+ $table = $this->getTableToFilter(false);
+
+ $pivotFilter = new PivotByDimension($table, "CustomVariables.getCustomVariables", "CustomVariables.CustomVariableValue",
+ 'nb_visits', $fetchBySegment = false);
+ $pivotFilter->filter($table);
+
+ $expectedRows = array(
+ array('label' => 'row 1'),
+ array('label' => 'row 2'),
+ array('label' => 'row 3')
+ );
+ $this->assertTableRowsEquals($expectedRows, $table);
+ }
+
+ public function testFilterCorrectlyDefaultsPivotByColumnWhenNoneProvided()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Referrers', 'UserCountry', 'CustomVariables'));
+
+ $table = $this->getTableToFilter(true);
+
+ $pivotFilter = new PivotByDimension($table, "Referrers.getKeywords", "Referrers.SearchEngine", $column = false, $columnLimit = -1, $fetchBySegment = false);
+ $pivotFilter->filter($table);
+
+ $expectedRows = array(
+ array('label' => 'row 1', 'col 1' => 1, 'col 2' => false, 'col 3' => false, 'col 4' => false),
+ array('label' => 'row 2', 'col 1' => 3, 'col 2' => 5, 'col 3' => false, 'col 4' => false),
+ array('label' => 'row 3', 'col 1' => false, 'col 2' => 7, 'col 3' => 9, 'col 4' => 32)
+ );
+ $this->assertTableRowsEquals($expectedRows, $table);
+ }
+
+ public function testFilterCorrectlyLimitsTheColumnNumberWhenColumnLimitProvided()
+ {
+ PluginManager::getInstance()->loadPlugins(array('Referrers', 'UserCountry', 'CustomVariables'));
+
+ $table = $this->getTableToFilter(true);
+
+ $pivotFilter = new PivotByDimension($table, "Referrers.getKeywords", "Referrers.SearchEngine", $column = 'nb_visits', $columnLimit = 3, $fetchBySegment = false);
+ $pivotFilter->filter($table);
+
+ $expectedRows = array(
+ array('label' => 'row 1', 'col 2' => false, 'col 3' => false, 'col 4' => false),
+ array('label' => 'row 2', 'col 2' => 5, 'col 3' => false, 'col 4' => false),
+ array('label' => 'row 3', 'col 2' => 7, 'col 3' => 9, 'col 4' => 32)
+ );
+ $this->assertTableRowsEquals($expectedRows, $table);
+ }
+
+ private function getTableToFilter($addSubtables = false)
+ {
+ $row1 = new Row(array(Row::COLUMNS => array(
+ 'label' => 'row 1',
+ 'nb_visits' => 10,
+ 'nb_actions' => 15
+ )));
+ if ($addSubtables) {
+ $row1->setSubtable($this->getRow1Subtable());
+ }
+
+ $row2 = new Row(array(Row::COLUMNS => array(
+ 'label' => 'row 2',
+ 'nb_visits' => 13,
+ 'nb_actions' => 18
+ )));
+ if ($addSubtables) {
+ $row2->setSubtable($this->getRow2Subtable());
+ }
+
+ $row3 = new Row(array(Row::COLUMNS => array(
+ 'label' => 'row 3',
+ 'nb_visits' => 20,
+ 'nb_actions' => 25
+ )));
+ if ($addSubtables) {
+ $row3->setSubtable($this->getRow3Subtable());
+ }
+
+ $table = new DataTable();
+ $table->addRowsFromArray(array($row1, $row2, $row3));
+ return $table;
+ }
+
+ private function getRow1Subtable()
+ {
+ $table = new DataTable();
+ $table->addRowsFromArray(array(
+ new Row(array(Row::COLUMNS => array(
+ 'label' => 'col 1',
+ 'nb_visits' => 1,
+ 'nb_actions' => 2
+ )))
+ ));
+ return $table;
+ }
+
+ private function getRow2Subtable()
+ {
+ $table = new DataTable();
+ $table->addRowsFromArray(array(
+ new Row(array(Row::COLUMNS => array(
+ 'label' => 'col 1',
+ 'nb_visits' => 3,
+ 'nb_actions' => 4
+ ))),
+ new Row(array(Row::COLUMNS => array(
+ 'label' => 'col 2',
+ 'nb_visits' => 5,
+ 'nb_actions' => 6
+ )))
+ ));
+ return $table;
+ }
+
+ private function getRow3Subtable()
+ {
+ $table = new DataTable();
+ $table->addRowsFromArray(array(
+ new Row(array(Row::COLUMNS => array(
+ 'label' => 'col 2',
+ 'nb_visits' => 7,
+ 'nb_actions' => 8
+ ))),
+ new Row(array(Row::COLUMNS => array(
+ 'label' => 'col 3',
+ 'nb_visits' => 9,
+ 'nb_actions' => 31
+ ))),
+ new Row(array(Row::COLUMNS => array(
+ 'label' => 'col 4',
+ 'nb_visits' => 32,
+ 'nb_actions' => 33
+ )))
+ ));
+ return $table;
+ }
+
+ private function getSegmentTable()
+ {
+ ++$this->segmentTableCount;
+
+ $table = new DataTable();
+ for ($i = 0; $i != $this->segmentTableCount; ++$i) {
+ $row = new Row(array(Row::COLUMNS => array(
+ 'label' => 'col ' . $i,
+ 'nb_visits' => ($i + 1) * 2,
+ 'nb_actions' => ($i + 1) * 3
+ )));
+ $table->addRow($row);
+ }
+ return $table;
+ }
+
+ private function assertTableRowsEquals($expectedRows, $table)
+ {
+ $renderer = new DataTable\Renderer\Php();
+ $renderer->setSerialize(false);
+ $actualRows = $renderer->render($table);
+
+ $this->assertEquals($expectedRows, $actualRows);
+ }
+} \ No newline at end of file
diff --git a/tests/PHPUnit/Core/DataTable/Renderer/CSVTest.php b/tests/PHPUnit/Core/DataTable/Renderer/CSVTest.php
index 4c5c77a355..64ffcf6a06 100644
--- a/tests/PHPUnit/Core/DataTable/Renderer/CSVTest.php
+++ b/tests/PHPUnit/Core/DataTable/Renderer/CSVTest.php
@@ -179,6 +179,22 @@ class DataTable_Renderer_CSVTest extends PHPUnit_Framework_TestCase
}
/**
+ * @group Core
+ */
+ public function testCSVRendererCorrectlyEscapesHeadersAndValues()
+ {
+ $dataTable = $this->_getDataTableSimpleWithCommasInCells();
+ $render = new Csv();
+ $render->setTable($dataTable);
+ $render->convertToUnicode = false;
+
+ $expected = '"col,1","col,2"
+"val""1","val"",2"';
+ $actual = $render->render();
+ $this->assertEquals($expected, $actual);
+ }
+
+ /**
* DATA OF DATATABLE_ARRAY
* -------------------------
*/
@@ -440,4 +456,13 @@ b,d,f,g';
$this->assertEquals($expected, $render->render());
}
-}
+
+ private function _getDataTableSimpleWithCommasInCells()
+ {
+ $table = new DataTable();
+ $table->addRowsFromSimpleArray(array(
+ array("col,1" => "val\"1", "col,2" => "val\",2")
+ ));
+ return $table;
+ }
+} \ No newline at end of file
diff --git a/tests/PHPUnit/Core/DataTable/Renderer/XMLTest.php b/tests/PHPUnit/Core/DataTable/Renderer/XMLTest.php
index 40596e0e23..40b58bdc13 100644
--- a/tests/PHPUnit/Core/DataTable/Renderer/XMLTest.php
+++ b/tests/PHPUnit/Core/DataTable/Renderer/XMLTest.php
@@ -11,6 +11,9 @@ use Piwik\DataTable\Renderer\Xml;
use Piwik\DataTable\Row;
use Piwik\DataTable\Simple;
+/**
+ * @group Only
+ */
class DataTable_Renderer_XMLTest extends PHPUnit_Framework_TestCase
{
public function setUp()
@@ -222,6 +225,39 @@ class DataTable_Renderer_XMLTest extends PHPUnit_Framework_TestCase
}
/**
+ * @group Core
+ */
+ public function testXMLRendererSuccessfullyRendersWhenSimpleDataTableColumnsHaveInvalidXmlCharacters()
+ {
+ $dataTable = $this->_getDataTableSimpleWithInvalidChars();
+ $render = new Xml();
+ $render->setTable($dataTable);
+ $expected = '<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <col name="$%@(%">1</col>
+ <col name="avbs$">2</col>
+ <col name="b/">2</col>
+</result>';
+ $this->assertEquals($expected, $render->render());
+ }
+
+ public function testXMLRendererSuccessfullyRendersWhenDataTableColumnsHaveInvalidXmlCharacters()
+ {
+ $dataTable = $this->_getDataTableWithInvalidChars();
+ $render = new Xml();
+ $render->setTable($dataTable);
+ $expected = '<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <col name="$%@(%">1</col>
+ <col name="avbs$">2</col>
+ <col name="b/">2</col>
+ </row>
+</result>';
+ $this->assertEquals($expected, $render->render());
+ }
+
+ /**
* DATA OF DATATABLE_ARRAY
* -------------------------
*/
@@ -601,4 +637,22 @@ class DataTable_Renderer_XMLTest extends PHPUnit_Framework_TestCase
$this->assertEquals($expected, $render->render());
}
+
+ private function _getDataTableSimpleWithInvalidChars()
+ {
+ $table = new DataTable\Simple();
+ $table->addRowsFromSimpleArray(
+ array("$%@(%" => 1, "avbs$" => 2, "b/" => 2)
+ );
+ return $table;
+ }
+
+ private function _getDataTableWithInvalidChars()
+ {
+ $table = new DataTable();
+ $table->addRowsFromSimpleArray(
+ array("$%@(%" => 1, "avbs$" => 2, "b/" => 2)
+ );
+ return $table;
+ }
}
diff --git a/tests/PHPUnit/Core/Plugin/ComponentFactoryTest.php b/tests/PHPUnit/Core/Plugin/ComponentFactoryTest.php
index d41149c8cd..b7b0f30fc3 100644
--- a/tests/PHPUnit/Core/Plugin/ComponentFactoryTest.php
+++ b/tests/PHPUnit/Core/Plugin/ComponentFactoryTest.php
@@ -11,6 +11,7 @@ use PHPUnit_Framework_TestCase;
use Piwik\Config;
use Piwik\Plugin\ComponentFactory;
use Piwik\Plugin\Manager as PluginManager;
+use Piwik\Plugin\Report;
/**
* @group Core
@@ -74,6 +75,62 @@ class ComponentFactoryTest extends PHPUnit_Framework_TestCase
$this->assertNull($report);
}
+ public function test_getComponentIf_shouldNotFindAComponentIfComponentExistsButPluginIsNotLoaded()
+ {
+ $this->unloadAllPlugins();
+
+ $report = ComponentFactory::getComponentIf(self::REPORT_CLASS_NAME, 'ExampleReport', function (Report $report) {
+ return $report->getAction() == 'getExampleReport';
+ });
+
+ $this->assertNull($report);
+ }
+
+ public function test_getComponentIf_shouldFindAComponent_ThatExists()
+ {
+ $this->loadExampleReportPlugin();
+
+ $report = ComponentFactory::getComponentIf(self::REPORT_CLASS_NAME, 'ExampleReport', function (Report $report) {
+ return $report->getAction() == 'getExampleReport';
+ });
+
+ $this->assertInstanceOf('Piwik\Plugins\ExampleReport\Reports\GetExampleReport', $report);
+ }
+
+ public function test_getComponentIf_shouldNotFindAComponent_IfPluginIsActivatedButComponentNotExists()
+ {
+ $this->loadExampleReportPlugin();
+
+ $report = ComponentFactory::getComponentIf(self::REPORT_CLASS_NAME, 'ExampleReport', function (Report $report) {
+ return false;
+ });
+
+ $this->assertNull($report);
+ }
+
+ public function test_getComponentIf_shouldNotFindAComponent_IfPluginIsLoadedButNotActivated()
+ {
+ PluginManager::getInstance()->loadPlugin('ExampleReport');
+
+ $report = ComponentFactory::getComponentIf(self::REPORT_CLASS_NAME, 'ExampleReport', function (Report $report) {
+ return $report->getAction() == 'getExampleReport';
+ });
+
+ $this->assertNull($report);
+ }
+
+ public function test_getComponentIf_shouldSearchThroughAllPlugins_IfNoPluginNameIsSupplied()
+ {
+ PluginManager::getInstance()->loadPlugins(array('ExampleReport', 'Referrers'));
+
+ $reports = array();
+ ComponentFactory::getComponentIf(self::REPORT_CLASS_NAME, null, function (Report $report) use (&$reports) {
+ $reports[] = $report;
+ });
+
+ $this->assertGreaterThan(1, count($reports));
+ }
+
private function unloadAllPlugins()
{
PluginManager::getInstance()->loadPlugins(array());