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:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/API/tests/Integration/RowEvolutionTest.php (renamed from plugins/API/tests/RowEvolutionTest.php)10
-rw-r--r--plugins/API/tests/Integration/RssRendererTest.php (renamed from plugins/API/tests/RssRendererTest.php)7
-rw-r--r--plugins/API/tests/Unit/ConsoleRendererTest.php (renamed from plugins/API/tests/ConsoleRendererTest.php)2
-rw-r--r--plugins/API/tests/Unit/CsvRendererTest.php (renamed from plugins/API/tests/CsvRendererTest.php)2
-rw-r--r--plugins/API/tests/Unit/HtmlRendererTest.php (renamed from plugins/API/tests/HtmlRendererTest.php)2
-rw-r--r--plugins/API/tests/Unit/JsonRendererTest.php (renamed from plugins/API/tests/JsonRendererTest.php)2
-rw-r--r--plugins/API/tests/Unit/OriginalRendererTest.php (renamed from plugins/API/tests/OriginalRendererTest.php)bin4028 -> 4033 bytes
-rw-r--r--plugins/API/tests/Unit/PhpRendererTest.php (renamed from plugins/API/tests/PhpRendererTest.php)2
-rw-r--r--plugins/API/tests/Unit/XmlRendererTest.php (renamed from plugins/API/tests/XmlRendererTest.php)2
-rw-r--r--plugins/Actions/tests/Unit/ArchiverTest.php130
-rw-r--r--plugins/Contents/.gitignore2
-rw-r--r--plugins/Contents/tests/Fixtures/TwoVisitsWithContents.php2
-rw-r--r--plugins/Contents/tests/System/ContentsTest.php (renamed from plugins/Contents/tests/ContentsTest.php)15
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Actions.getPageUrls_day.xml (renamed from plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Actions.getPageUrls_month.xml (renamed from plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_month.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Actions.get_day.xml (renamed from plugins/Contents/tests/expected/test_Contents__Actions.get_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Actions.get_month.xml (renamed from plugins/Contents/tests/expected/test_Contents__Actions.get_month.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Contents.getContentNames_day.xml (renamed from plugins/Contents/tests/expected/test_Contents__Contents.getContentNames_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Contents.getContentNames_month.xml (renamed from plugins/Contents/tests/expected/test_Contents__Contents.getContentNames_month.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Contents.getContentPieces_day.xml (renamed from plugins/Contents/tests/expected/test_Contents__Contents.getContentPieces_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Contents.getContentPieces_month.xml (renamed from plugins/Contents/tests/expected/test_Contents__Contents.getContentPieces_month.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_day.xml (renamed from plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_month.xml (renamed from plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_month.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml (renamed from plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml (renamed from plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml (renamed from plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml (renamed from plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml)0
-rw-r--r--plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml (renamed from plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml)0
-rw-r--r--plugins/Contents/tests/System/processed/.gitkeep (renamed from plugins/Contents/tests/processed/.gitkeep)0
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml83
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml123
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Actions.getPageUrls_day.xml25
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Actions.getPageUrls_month.xml25
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Actions.get_day.xml12
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Actions.get_month.xml12
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Contents.getContentNames_day.xml30
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Contents.getContentNames_month.xml30
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Contents.getContentPieces_day.xml66
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Contents.getContentPieces_month.xml66
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Live.getLastVisitsDetails_day.xml199
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents__Live.getLastVisitsDetails_month.xml199
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml2
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml2
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml2
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml199
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml2
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml12
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml21
-rw-r--r--plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml199
-rw-r--r--plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml2
-rw-r--r--plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml21
-rw-r--r--plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml48
-rw-r--r--plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml199
-rw-r--r--plugins/CoreConsole/Commands/CodeCoverage.php2
-rw-r--r--plugins/CoreConsole/Commands/DevelopmentManageTestFiles.php4
-rw-r--r--plugins/CoreConsole/Commands/GenerateTest.php66
-rw-r--r--plugins/CoreConsole/Commands/GenerateTravisYmlFile.php2
-rw-r--r--plugins/CoreConsole/Commands/TestsRun.php16
-rw-r--r--plugins/CoreConsole/Commands/TestsSetupFixture.php5
-rw-r--r--plugins/CoreConsole/tests/Integration/TravisYmlViewTest.php (renamed from plugins/CoreConsole/tests/Unit/TravisYmlViewTest.php)2
-rw-r--r--plugins/CoreConsole/tests/resources/test.travis.yml2
-rw-r--r--plugins/CorePluginsAdmin/tests/Integration/UpdateCommunicationTest.php186
-rw-r--r--plugins/CoreUpdater/tests/Integration/UpdateCommunicationTest.php122
-rw-r--r--plugins/CoreUpdater/tests/Unit/ModelTest.php (renamed from plugins/CoreUpdater/tests/ModelTest.php)0
-rw-r--r--plugins/CoreVisualizations/Visualizations/Cloud.php2
m---------plugins/CustomAlerts0
-rw-r--r--plugins/CustomVariables/.gitignore1
-rw-r--r--plugins/CustomVariables/tests/Commands/InfoTest.php5
-rw-r--r--plugins/CustomVariables/tests/Commands/SetNumberOfCustomVariablesTest.php5
-rw-r--r--plugins/CustomVariables/tests/Fixtures/VisitWithManyCustomVariables.php2
-rw-r--r--plugins/CustomVariables/tests/Integration/CustomVariablesTest.php (renamed from plugins/CustomVariables/tests/CustomVariablesTest.php)5
-rw-r--r--plugins/CustomVariables/tests/Integration/ModelTest.php (renamed from plugins/CustomVariables/tests/ModelTest.php)7
-rw-r--r--plugins/CustomVariables/tests/System/CustomVariablesSystemTest.php (renamed from plugins/CustomVariables/tests/CustomVariablesIntegrationTest.php)13
-rw-r--r--plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml (renamed from plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__CustomVariables.getCustomVariables_day.xml)0
-rw-r--r--plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml (renamed from plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml)0
-rw-r--r--plugins/CustomVariables/tests/System/processed/test_CustomVariablesIntegrationTest__CustomVariables.getCustomVariables_day.xml (renamed from plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__CustomVariables.getCustomVariables_day.xml)0
-rw-r--r--plugins/CustomVariables/tests/System/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml (renamed from plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml)0
-rw-r--r--plugins/CustomVariables/tests/System/processed/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml395
-rw-r--r--plugins/CustomVariables/tests/System/processed/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml176
-rw-r--r--plugins/ExamplePlugin/.gitignore2
-rw-r--r--plugins/ExamplePlugin/.travis.yml4
-rw-r--r--plugins/ExamplePlugin/tests/Fixtures/SimpleFixtureTrackFewVisits.php (renamed from plugins/ExamplePlugin/tests/fixtures/SimpleFixtureTrackFewVisits.php)8
-rw-r--r--plugins/ExamplePlugin/tests/Integration/SimpleTest.php26
-rw-r--r--plugins/ExamplePlugin/tests/System/SimpleSystemTest.php (renamed from plugins/ExamplePlugin/tests/SimpleIntegrationTest.php)32
-rw-r--r--plugins/ExamplePlugin/tests/System/expected/test___API.get_day.xml (renamed from plugins/ExamplePlugin/tests/expected/test___API.get_day.xml)0
-rw-r--r--plugins/ExamplePlugin/tests/System/expected/test___Goals.getItemsSku_day.xml (renamed from plugins/ExamplePlugin/tests/expected/test___Goals.getItemsSku_day.xml)0
-rw-r--r--plugins/ExamplePlugin/tests/System/processed/.gitkeep (renamed from plugins/ExamplePlugin/tests/processed/.gitkeep)0
-rw-r--r--plugins/ExamplePlugin/tests/System/processed/test___API.get_day.xml30
-rw-r--r--plugins/ExamplePlugin/tests/System/processed/test___Goals.getItemsSku_day.xml12
-rw-r--r--plugins/ExamplePlugin/tests/Unit/SimpleTest.php (renamed from plugins/ExamplePlugin/tests/SimpleTest.php)2
-rw-r--r--plugins/Goals/tests/Integration/APITest.php (renamed from plugins/Goals/tests/APITest.php)10
-rw-r--r--plugins/Insights/tests/Fixtures/SomeVisitsDifferentPathsOnTwoDays.php2
-rw-r--r--plugins/Insights/tests/Integration/ApiTest.php (renamed from plugins/Insights/tests/ApiTest.php)12
-rw-r--r--plugins/Insights/tests/Integration/ModelTest.php (renamed from plugins/Insights/tests/ModelTest.php)6
-rw-r--r--plugins/Insights/tests/Unit/BaseUnitTest.php (renamed from plugins/Insights/tests/BaseUnitTest.php)0
-rw-r--r--plugins/Insights/tests/Unit/FilterExcludeLowValueTest.php (renamed from plugins/Insights/tests/FilterExcludeLowValueTest.php)0
-rw-r--r--plugins/Insights/tests/Unit/FilterInsightTest.php (renamed from plugins/Insights/tests/FilterInsightTest.php)0
-rw-r--r--plugins/Insights/tests/Unit/FilterLimitTest.php (renamed from plugins/Insights/tests/FilterLimitTest.php)0
-rw-r--r--plugins/Insights/tests/Unit/FilterMinGrowthTest.php (renamed from plugins/Insights/tests/FilterMinGrowthTest.php)0
-rw-r--r--plugins/Insights/tests/Unit/FilterOrderByTest.php (renamed from plugins/Insights/tests/FilterOrderByTest.php)0
-rw-r--r--plugins/Insights/tests/Unit/InsightReportTest.php (renamed from plugins/Insights/tests/InsightReportTest.php)0
-rwxr-xr-xplugins/LanguagesManager/tests/Integration/LanguagesManagerTest.php182
-rw-r--r--plugins/LeftMenu/tests/Integration/APITest.php (renamed from plugins/LeftMenu/tests/APITest.php)7
-rw-r--r--plugins/Live/tests/Integration/APITest.php (renamed from plugins/Live/tests/APITest.php)9
-rw-r--r--plugins/Login/tests/Integration/LoginTest.php404
-rw-r--r--plugins/MobileMessaging/tests/Integration/MobileMessagingTest.php262
-rw-r--r--plugins/MultiSites/tests/Integration/MultiSitesTest.php52
-rw-r--r--plugins/PrivacyManager/tests/Integration/PrivacyManagerConfigTest.php102
-rw-r--r--plugins/PrivacyManager/tests/Integration/PrivacyManagerTest.php86
-rw-r--r--plugins/PrivacyManager/tests/Unit/AnonymizeIPTest.php92
-rw-r--r--plugins/Proxy/tests/Unit/ProxyTest.php48
-rw-r--r--plugins/Referrers/tests/Unit/ReferrersTest.php246
-rw-r--r--plugins/SEO/tests/Integration/SEOTest.php68
-rw-r--r--plugins/ScheduledReports/tests/Integration/ApiTest.php514
-rw-r--r--plugins/ScheduledReports/tests/Integration/ScheduledReportsTest.php (renamed from plugins/ScheduledReports/tests/ScheduledReportsTest.php)7
-rw-r--r--plugins/SegmentEditor/tests/Integration/SegmentEditorTest.php210
-rw-r--r--plugins/SitesManager/tests/Integration/SiteUrlsTest.php (renamed from plugins/SitesManager/tests/SiteUrlsTest.php)7
-rw-r--r--plugins/SitesManager/tests/Integration/SitesManagerTest.php1000
-rwxr-xr-xplugins/UserCountry/LocationProvider/GeoIp/Php.php2
-rw-r--r--plugins/UserCountry/tests/Unit/UserCountryTest.php185
-rw-r--r--plugins/UserSettings/.gitignore1
-rw-r--r--plugins/UserSettings/tests/Fixtures/LanguageFixture.php2
-rw-r--r--plugins/UserSettings/tests/System/GetLanguageSystemTest.php (renamed from plugins/UserSettings/tests/GetLanguageIntegrationTest.php)19
-rw-r--r--plugins/UserSettings/tests/System/expected/test___UserSettings.getLanguageCode_day.xml (renamed from plugins/UserSettings/tests/expected/test___UserSettings.getLanguageCode_day.xml)0
-rw-r--r--plugins/UserSettings/tests/System/expected/test___UserSettings.getLanguage_day.xml (renamed from plugins/UserSettings/tests/expected/test___UserSettings.getLanguage_day.xml)0
-rw-r--r--plugins/UserSettings/tests/System/processed/.gitkeep (renamed from plugins/UserSettings/tests/processed/.gitkeep)0
-rw-r--r--plugins/UserSettings/tests/System/processed/test___UserSettings.getLanguageCode_day.xml157
-rw-r--r--plugins/UserSettings/tests/System/processed/test___UserSettings.getLanguage_day.xml135
-rw-r--r--plugins/UserSettings/tests/Unit/UserSettingsTest.php1036
-rw-r--r--plugins/UsersManager/tests/Integration/APITest.php (renamed from plugins/UsersManager/tests/APITest.php)7
-rw-r--r--plugins/UsersManager/tests/Integration/UserPreferencesTest.php (renamed from plugins/UsersManager/tests/UserPreferencesTest.php)8
-rw-r--r--plugins/UsersManager/tests/Integration/UsersManagerTest.php919
141 files changed, 8533 insertions, 155 deletions
diff --git a/plugins/API/tests/RowEvolutionTest.php b/plugins/API/tests/Integration/RowEvolutionTest.php
index b341efd91a..cb3dc66a99 100644
--- a/plugins/API/tests/RowEvolutionTest.php
+++ b/plugins/API/tests/Integration/RowEvolutionTest.php
@@ -6,16 +6,18 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\API\tests;
+namespace Piwik\Plugins\API\tests\Integration;
+
use Piwik\Plugins\API\RowEvolution;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group API
* @group RowEvolutionTest
- * @group Database
+ * @group Plugins
*/
-class RowEvolutionTest extends \DatabaseTestCase
+class RowEvolutionTest extends IntegrationTestCase
{
public function setUp()
diff --git a/plugins/API/tests/RssRendererTest.php b/plugins/API/tests/Integration/RssRendererTest.php
index 175699fca3..3011273d69 100644
--- a/plugins/API/tests/RssRendererTest.php
+++ b/plugins/API/tests/Integration/RssRendererTest.php
@@ -6,18 +6,19 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\API\tests;
+namespace Piwik\Plugins\API\tests\Integration;
use Piwik\Access;
use Piwik\DataTable;
use Piwik\Plugins\API\Renderer\Rss;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group Plugin
* @group API
*/
-class RssRendererTest extends \DatabaseTestCase
+class RssRendererTest extends IntegrationTestCase
{
/**
* @var Rss
diff --git a/plugins/API/tests/ConsoleRendererTest.php b/plugins/API/tests/Unit/ConsoleRendererTest.php
index 26357935ff..bd556809ff 100644
--- a/plugins/API/tests/ConsoleRendererTest.php
+++ b/plugins/API/tests/Unit/ConsoleRendererTest.php
@@ -6,7 +6,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\API\tests;
+namespace Piwik\Plugins\API\tests\Unit;
use Piwik\DataTable;
use Piwik\Plugins\API\Renderer\Console;
diff --git a/plugins/API/tests/CsvRendererTest.php b/plugins/API/tests/Unit/CsvRendererTest.php
index 526d2f3728..76d16ed515 100644
--- a/plugins/API/tests/CsvRendererTest.php
+++ b/plugins/API/tests/Unit/CsvRendererTest.php
@@ -6,7 +6,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\API\tests;
+namespace Piwik\Plugins\API\test\Unit;
use Piwik\DataTable;
use Piwik\Plugins\API\Renderer\Csv;
diff --git a/plugins/API/tests/HtmlRendererTest.php b/plugins/API/tests/Unit/HtmlRendererTest.php
index 4cf4f98c9b..374f33e0b6 100644
--- a/plugins/API/tests/HtmlRendererTest.php
+++ b/plugins/API/tests/Unit/HtmlRendererTest.php
@@ -6,7 +6,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\API\tests;
+namespace Piwik\Plugins\API\tests\Unit;
use Piwik\DataTable;
use Piwik\Plugins\API\Renderer\Html;
diff --git a/plugins/API/tests/JsonRendererTest.php b/plugins/API/tests/Unit/JsonRendererTest.php
index fc1bf5d502..c4fa076483 100644
--- a/plugins/API/tests/JsonRendererTest.php
+++ b/plugins/API/tests/Unit/JsonRendererTest.php
@@ -6,7 +6,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\API\tests;
+namespace Piwik\Plugins\API\tests\Unit;
use Piwik\DataTable;
use Piwik\Plugins\API\Renderer\Json;
diff --git a/plugins/API/tests/OriginalRendererTest.php b/plugins/API/tests/Unit/OriginalRendererTest.php
index 40a3575ec7..bed40d1e29 100644
--- a/plugins/API/tests/OriginalRendererTest.php
+++ b/plugins/API/tests/Unit/OriginalRendererTest.php
Binary files differ
diff --git a/plugins/API/tests/PhpRendererTest.php b/plugins/API/tests/Unit/PhpRendererTest.php
index 5234db8df1..77a5efa568 100644
--- a/plugins/API/tests/PhpRendererTest.php
+++ b/plugins/API/tests/Unit/PhpRendererTest.php
@@ -6,7 +6,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\API\tests;
+namespace Piwik\Plugins\API\tests\Unit;
use Piwik\DataTable;
use Piwik\Plugins\API\Renderer\Php;
diff --git a/plugins/API/tests/XmlRendererTest.php b/plugins/API/tests/Unit/XmlRendererTest.php
index 1d222290bd..f3ca71a10d 100644
--- a/plugins/API/tests/XmlRendererTest.php
+++ b/plugins/API/tests/Unit/XmlRendererTest.php
@@ -6,7 +6,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\API\tests;
+namespace Piwik\Plugins\API\tests\Unit;
use Piwik\DataTable;
use Piwik\Plugins\API\Renderer\Xml;
diff --git a/plugins/Actions/tests/Unit/ArchiverTest.php b/plugins/Actions/tests/Unit/ArchiverTest.php
new file mode 100644
index 0000000000..a3ba57511a
--- /dev/null
+++ b/plugins/Actions/tests/Unit/ArchiverTest.php
@@ -0,0 +1,130 @@
+<?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\Plugins\PrivacyManager\tests\Unit;
+
+use Piwik\Plugins\Actions\ArchivingHelper;
+use Piwik\Tracker\Action;
+use Piwik\Translate;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/Actions/Actions.php';
+
+/**
+ * @group Actions
+ * @group ArchiverTest
+ * @group Plugins
+ */
+class ArchiverTests extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ Translate::reloadLanguage('en');
+ }
+
+ public function tearDown()
+ {
+ Translate::unloadEnglishTranslation();
+ }
+
+ public function getActionNameTestData()
+ {
+ return array(
+ array(
+ 'params' => array('name' => 'http://example.org/', 'type' => Action::TYPE_PAGE_URL, 'urlPrefix' => null),
+ 'expected' => array('/index'),
+ ),
+ array(
+ 'params' => array('name' => 'example.org/', 'type' => Action::TYPE_PAGE_URL, 'urlPrefix' => 1),
+ 'expected' => array('/index'),
+ ),
+ array(
+ 'params' => array('name' => 'example.org/', 'type' => Action::TYPE_PAGE_URL, 'urlPrefix' => 2),
+ 'expected' => array('/index'),
+ ),
+ array(
+ 'params' => array('name' => 'example.org/', 'type' => Action::TYPE_PAGE_URL, 'urlPrefix' => 3),
+ 'expected' => array('/index'),
+ ),
+ array(
+ 'params' => array('name' => 'example.org/', 'type' => Action::TYPE_PAGE_URL, 'urlPrefix' => 4),
+ 'expected' => array('/index'),
+ ),
+ array(
+ 'params' => array('name' => 'example.org/path/', 'type' => Action::TYPE_PAGE_URL, 'urlPrefix' => 4),
+ 'expected' => array('path', '/index'),
+ ),
+ array(
+ 'params' => array('name' => 'example.org/test/path', 'type' => Action::TYPE_PAGE_URL, 'urlPrefix' => 1),
+ 'expected' => array('test', '/path'),
+ ),
+ array(
+ 'params' => array('name' => 'http://example.org/path/', 'type' => Action::TYPE_PAGE_URL),
+ 'expected' => array('path', '/index'),
+ ),
+ array(
+ 'params' => array('name' => 'example.org/test/path', 'type' => Action::TYPE_PAGE_URL, 'urlPrefix' => 1),
+ 'expected' => array('test', '/path'),
+ ),
+ array(
+ 'params' => array('name' => 'Test / Path', 'type' => Action::TYPE_PAGE_URL),
+ 'expected' => array('Test', '/Path'),
+ ),
+ array(
+ 'params' => array('name' => ' Test trim ', 'type' => Action::TYPE_PAGE_URL),
+ 'expected' => array('/Test trim'),
+ ),
+ array(
+ 'params' => array('name' => 'Category / Subcategory', 'type' => Action::TYPE_PAGE_TITLE),
+ 'expected' => array('Category', ' Subcategory'),
+ ),
+ array(
+ 'params' => array('name' => '/path/index.php?var=test', 'type' => Action::TYPE_PAGE_TITLE),
+ 'expected' => array('path', ' index.php?var=test'),
+ ),
+ array(
+ 'params' => array('name' => 'http://example.org/path/Default.aspx#anchor', 'type' => Action::TYPE_PAGE_TITLE),
+ 'expected' => array('path', ' Default.aspx#anchor'),
+ ),
+ array(
+ 'params' => array('name' => '', 'type' => Action::TYPE_PAGE_TITLE),
+ 'expected' => array('Page Name not defined'),
+ ),
+ array(
+ 'params' => array('name' => '', 'type' => Action::TYPE_PAGE_URL),
+ 'expected' => array('Page URL not defined'),
+ ),
+ array(
+ 'params' => array('name' => 'http://example.org/download.zip', 'type' => Action::TYPE_DOWNLOAD),
+ 'expected' => array('example.org', '/download.zip'),
+ ),
+ array(
+ 'params' => array('name' => 'http://example.org/download/1/', 'type' => Action::TYPE_DOWNLOAD),
+ 'expected' => array('example.org', '/download/1/'),
+ ),
+ array(
+ 'params' => array('name' => 'http://example.org/link', 'type' => Action::TYPE_OUTLINK),
+ 'expected' => array('example.org', '/link'),
+ ),
+ array(
+ 'params' => array('name' => 'http://example.org/some/path/', 'type' => Action::TYPE_OUTLINK),
+ 'expected' => array('example.org', '/some/path/'),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider getActionNameTestData
+ */
+ public function testGetActionExplodedNames($params, $expected)
+ {
+ ArchivingHelper::reloadConfig();
+ $processed = ArchivingHelper::getActionExplodedNames($params['name'], $params['type'], (isset($params['urlPrefix']) ? $params['urlPrefix'] : null));
+ $this->assertEquals($expected, $processed);
+ }
+}
+
diff --git a/plugins/Contents/.gitignore b/plugins/Contents/.gitignore
index b141f4501f..c8c9480010 100644
--- a/plugins/Contents/.gitignore
+++ b/plugins/Contents/.gitignore
@@ -1 +1 @@
-tests/processed/*xml \ No newline at end of file
+tests/System/processed/*xml \ No newline at end of file
diff --git a/plugins/Contents/tests/Fixtures/TwoVisitsWithContents.php b/plugins/Contents/tests/Fixtures/TwoVisitsWithContents.php
index 0446672cbd..9d4c08746a 100644
--- a/plugins/Contents/tests/Fixtures/TwoVisitsWithContents.php
+++ b/plugins/Contents/tests/Fixtures/TwoVisitsWithContents.php
@@ -9,7 +9,7 @@ namespace Piwik\Plugins\Contents\tests\Fixtures;
use Piwik\Date;
use Piwik\Plugins\Goals\API as APIGoals;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
use PiwikTracker;
/**
diff --git a/plugins/Contents/tests/ContentsTest.php b/plugins/Contents/tests/System/ContentsTest.php
index 68875db127..c5304fb19e 100644
--- a/plugins/Contents/tests/ContentsTest.php
+++ b/plugins/Contents/tests/System/ContentsTest.php
@@ -5,19 +5,20 @@
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\Contents\tests;
+namespace Piwik\Plugins\Contents\tests\System;
-use Piwik\Tests\IntegrationTestCase;
+use Piwik\Tests\Impl\SystemTestCase;
use Piwik\Plugins\Contents\tests\Fixtures\TwoVisitsWithContents;
+use Piwik\Translate;
/**
* Testing Contents
*
* @group ContentsTest
- * @group Integration
+ * @group System
* @group Plugins
*/
-class ContentsTest extends IntegrationTestCase
+class ContentsTest extends SystemTestCase
{
public static $fixture = null; // initialized below class definition
@@ -40,6 +41,12 @@ class ContentsTest extends IntegrationTestCase
);
}
+ protected function setup()
+ {
+ parent::setup();
+ Translate::reloadLanguage('en');
+ }
+
protected function tearDown()
{
parent::tearDown();
diff --git a/plugins/Contents/tests/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml
index d3e1af1e2e..d3e1af1e2e 100644
--- a/plugins/Contents/tests/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml
index 402909f7d5..402909f7d5 100644
--- a/plugins/Contents/tests/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_day.xml b/plugins/Contents/tests/System/expected/test_Contents__Actions.getPageUrls_day.xml
index fde347f2b5..fde347f2b5 100644
--- a/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Actions.getPageUrls_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_month.xml b/plugins/Contents/tests/System/expected/test_Contents__Actions.getPageUrls_month.xml
index 3dc775d40a..3dc775d40a 100644
--- a/plugins/Contents/tests/expected/test_Contents__Actions.getPageUrls_month.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Actions.getPageUrls_month.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Actions.get_day.xml b/plugins/Contents/tests/System/expected/test_Contents__Actions.get_day.xml
index f51cfaf913..f51cfaf913 100644
--- a/plugins/Contents/tests/expected/test_Contents__Actions.get_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Actions.get_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Actions.get_month.xml b/plugins/Contents/tests/System/expected/test_Contents__Actions.get_month.xml
index f51cfaf913..f51cfaf913 100644
--- a/plugins/Contents/tests/expected/test_Contents__Actions.get_month.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Actions.get_month.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Contents.getContentNames_day.xml b/plugins/Contents/tests/System/expected/test_Contents__Contents.getContentNames_day.xml
index 957c6fa85a..957c6fa85a 100644
--- a/plugins/Contents/tests/expected/test_Contents__Contents.getContentNames_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Contents.getContentNames_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Contents.getContentNames_month.xml b/plugins/Contents/tests/System/expected/test_Contents__Contents.getContentNames_month.xml
index 44bfdfd54e..44bfdfd54e 100644
--- a/plugins/Contents/tests/expected/test_Contents__Contents.getContentNames_month.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Contents.getContentNames_month.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Contents.getContentPieces_day.xml b/plugins/Contents/tests/System/expected/test_Contents__Contents.getContentPieces_day.xml
index 8927f8a8ec..8927f8a8ec 100644
--- a/plugins/Contents/tests/expected/test_Contents__Contents.getContentPieces_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Contents.getContentPieces_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Contents.getContentPieces_month.xml b/plugins/Contents/tests/System/expected/test_Contents__Contents.getContentPieces_month.xml
index b604544417..b604544417 100644
--- a/plugins/Contents/tests/expected/test_Contents__Contents.getContentPieces_month.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Contents.getContentPieces_month.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_day.xml
index 241be92f2f..241be92f2f 100644
--- a/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_month.xml b/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_month.xml
index 241be92f2f..241be92f2f 100644
--- a/plugins/Contents/tests/expected/test_Contents__Live.getLastVisitsDetails_month.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents__Live.getLastVisitsDetails_month.xml
diff --git a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml
index c234bed59e..c234bed59e 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml
index c234bed59e..c234bed59e 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml
index c234bed59e..c234bed59e 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
index 241be92f2f..241be92f2f 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml
index c234bed59e..c234bed59e 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml
index 5212486a1c..5212486a1c 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml
index ac1d39a577..ac1d39a577 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml
diff --git a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
index 241be92f2f..241be92f2f 100644
--- a/plugins/Contents/tests/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/System/expected/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
diff --git a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml
index c234bed59e..c234bed59e 100644
--- a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml
+++ b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml
diff --git a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml
index 17b781db1c..17b781db1c 100644
--- a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml
+++ b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml
diff --git a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml
index 7df6e4f0e1..7df6e4f0e1 100644
--- a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml
+++ b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml
diff --git a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
index 241be92f2f..241be92f2f 100644
--- a/plugins/Contents/tests/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
+++ b/plugins/Contents/tests/System/expected/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
diff --git a/plugins/Contents/tests/processed/.gitkeep b/plugins/Contents/tests/System/processed/.gitkeep
index e69de29bb2..e69de29bb2 100644
--- a/plugins/Contents/tests/processed/.gitkeep
+++ b/plugins/Contents/tests/System/processed/.gitkeep
diff --git a/plugins/Contents/tests/System/processed/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml b/plugins/Contents/tests/System/processed/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml
new file mode 100644
index 0000000000..d3e1af1e2e
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_Contents.getContentNames_lastN__API.getProcessedReport_day.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <website>Piwik test</website>
+ <prettyDate>3 Jan 10 - 9 Jan 10</prettyDate>
+ <metadata>
+ <category>Actions</category>
+ <name>Content Name</name>
+ <module>Contents</module>
+ <action>getContentNames</action>
+ <dimension>Content Name</dimension>
+ <metrics>
+ <nb_impressions>Impressions</nb_impressions>
+ <nb_interactions>Interactions</nb_interactions>
+ </metrics>
+ <processedMetrics>
+ <interaction_rate>Interaction Rate</interaction_rate>
+ </processedMetrics>
+ <actionToLoadSubTables>getContentNames</actionToLoadSubTables>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentNames&amp;period=range&amp;date=2010-01-03,2010-01-09</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentNames&amp;period=day&amp;date=2010-01-03,2010-01-09</imageGraphEvolutionUrl>
+ <uniqueId>Contents_getContentNames</uniqueId>
+ </metadata>
+ <columns>
+ <label>Content Name</label>
+ <nb_impressions>Impressions</nb_impressions>
+ <nb_interactions>Interactions</nb_interactions>
+ <interaction_rate>Interaction Rate</interaction_rate>
+ </columns>
+ <reportData>
+ <result prettyDate="Sunday 3 January 2010">
+ <row>
+ <label>ImageAd</label>
+ <nb_impressions>8</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>25%</interaction_rate>
+ </row>
+ <row>
+ <label>Text Ad</label>
+ <nb_impressions>6</nb_impressions>
+ <nb_interactions>4</nb_interactions>
+ <interaction_rate>66.67%</interaction_rate>
+ </row>
+ <row>
+ <label>Video Ad</label>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ </row>
+ </result>
+ <result prettyDate="Monday 4 January 2010" />
+ <result prettyDate="Tuesday 5 January 2010" />
+ <result prettyDate="Wednesday 6 January 2010" />
+ <result prettyDate="Thursday 7 January 2010" />
+ <result prettyDate="Friday 8 January 2010" />
+ <result prettyDate="Saturday 9 January 2010" />
+ </reportData>
+ <reportMetadata>
+ <result prettyDate="Sunday 3 January 2010">
+ <row>
+ <contentTarget>http://www.example.com</contentTarget>
+
+ </row>
+ <row>
+ <contentTarget>http://piwik.org/</contentTarget>
+
+ </row>
+ <row>
+ <contentTarget />
+
+ </row>
+ </result>
+ <result prettyDate="Monday 4 January 2010" />
+ <result prettyDate="Tuesday 5 January 2010" />
+ <result prettyDate="Wednesday 6 January 2010" />
+ <result prettyDate="Thursday 7 January 2010" />
+ <result prettyDate="Friday 8 January 2010" />
+ <result prettyDate="Saturday 9 January 2010" />
+ </reportMetadata>
+ <reportTotal>
+ <nb_visits>16</nb_visits>
+ <nb_uniq_visitors>16</nb_uniq_visitors>
+ </reportTotal>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml b/plugins/Contents/tests/System/processed/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml
new file mode 100644
index 0000000000..402909f7d5
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <website>Piwik test</website>
+ <prettyDate>3 Jan 10 - 9 Jan 10</prettyDate>
+ <metadata>
+ <category>Actions</category>
+ <name>Content Piece</name>
+ <module>Contents</module>
+ <action>getContentPieces</action>
+ <dimension>Content Piece</dimension>
+ <metrics>
+ <nb_impressions>Impressions</nb_impressions>
+ <nb_interactions>Interactions</nb_interactions>
+ </metrics>
+ <processedMetrics>
+ <interaction_rate>Interaction Rate</interaction_rate>
+ </processedMetrics>
+ <actionToLoadSubTables>getContentPieces</actionToLoadSubTables>
+ <imageGraphUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentPieces&amp;period=range&amp;date=2010-01-03,2010-01-09</imageGraphUrl>
+ <imageGraphEvolutionUrl>index.php?module=API&amp;method=ImageGraph.get&amp;idSite=1&amp;apiModule=Contents&amp;apiAction=getContentPieces&amp;period=day&amp;date=2010-01-03,2010-01-09</imageGraphEvolutionUrl>
+ <uniqueId>Contents_getContentPieces</uniqueId>
+ </metadata>
+ <columns>
+ <label>Content Piece</label>
+ <nb_impressions>Impressions</nb_impressions>
+ <nb_interactions>Interactions</nb_interactions>
+ <interaction_rate>Interaction Rate</interaction_rate>
+ </columns>
+ <reportData>
+ <result prettyDate="Sunday 3 January 2010">
+ <row>
+ <label>Click to download Piwik now</label>
+ <nb_impressions>4</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>50%</interaction_rate>
+ </row>
+ <row>
+ <label>/path/ad.jpg</label>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>100%</interaction_rate>
+ </row>
+ <row>
+ <label>/path/ad2.jpg</label>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ </row>
+ <row>
+ <label>Click NOW</label>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>100%</interaction_rate>
+ </row>
+ <row>
+ <label>movie.mov</label>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ </row>
+ <row>
+ <label>Content Piece not defined</label>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ </row>
+ <row>
+ <label>Unknown</label>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ </row>
+ </result>
+ <result prettyDate="Monday 4 January 2010" />
+ <result prettyDate="Tuesday 5 January 2010" />
+ <result prettyDate="Wednesday 6 January 2010" />
+ <result prettyDate="Thursday 7 January 2010" />
+ <result prettyDate="Friday 8 January 2010" />
+ <result prettyDate="Saturday 9 January 2010" />
+ </reportData>
+ <reportMetadata>
+ <result prettyDate="Sunday 3 January 2010">
+ <row>
+ <contentTarget>http://piwik.org/download</contentTarget>
+
+ </row>
+ <row>
+ <contentTarget>http://www.example.com</contentTarget>
+
+ </row>
+ <row>
+ <contentTarget>http://www.example.com</contentTarget>
+
+ </row>
+ <row>
+ <contentTarget>http://piwik.org/</contentTarget>
+
+ </row>
+ <row>
+ <contentTarget />
+
+ </row>
+ <row>
+ <contentTarget />
+
+ </row>
+ <row>
+ <contentTarget />
+
+ </row>
+ </result>
+ <result prettyDate="Monday 4 January 2010" />
+ <result prettyDate="Tuesday 5 January 2010" />
+ <result prettyDate="Wednesday 6 January 2010" />
+ <result prettyDate="Thursday 7 January 2010" />
+ <result prettyDate="Friday 8 January 2010" />
+ <result prettyDate="Saturday 9 January 2010" />
+ </reportMetadata>
+ <reportTotal>
+ <nb_visits>16</nb_visits>
+ <nb_uniq_visitors>16</nb_uniq_visitors>
+ </reportTotal>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Actions.getPageUrls_day.xml b/plugins/Contents/tests/System/processed/test_Contents__Actions.getPageUrls_day.xml
new file mode 100644
index 0000000000..fde347f2b5
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Actions.getPageUrls_day.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>/page</label>
+ <nb_visits>2</nb_visits>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_hits>2</nb_hits>
+ <sum_time_spent>540</sum_time_spent>
+ <nb_hits_with_time_generation>2</nb_hits_with_time_generation>
+ <min_time_generation>0.333</min_time_generation>
+ <max_time_generation>0.333</max_time_generation>
+ <entry_nb_uniq_visitors>2</entry_nb_uniq_visitors>
+ <entry_nb_visits>2</entry_nb_visits>
+ <entry_nb_actions>2</entry_nb_actions>
+ <entry_sum_visit_length>542</entry_sum_visit_length>
+ <entry_bounce_count>2</entry_bounce_count>
+ <exit_nb_uniq_visitors>2</exit_nb_uniq_visitors>
+ <exit_nb_visits>2</exit_nb_visits>
+ <avg_time_on_page>270</avg_time_on_page>
+ <bounce_rate>100%</bounce_rate>
+ <exit_rate>100%</exit_rate>
+ <avg_time_generation>0.333</avg_time_generation>
+ <url>http://www.example.org/page</url>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Actions.getPageUrls_month.xml b/plugins/Contents/tests/System/processed/test_Contents__Actions.getPageUrls_month.xml
new file mode 100644
index 0000000000..3dc775d40a
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Actions.getPageUrls_month.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>/page</label>
+ <nb_visits>2</nb_visits>
+ <nb_hits>2</nb_hits>
+ <sum_time_spent>540</sum_time_spent>
+ <nb_hits_with_time_generation>2</nb_hits_with_time_generation>
+ <min_time_generation>0.333</min_time_generation>
+ <max_time_generation>0.333</max_time_generation>
+ <entry_nb_visits>2</entry_nb_visits>
+ <entry_nb_actions>2</entry_nb_actions>
+ <entry_sum_visit_length>542</entry_sum_visit_length>
+ <entry_bounce_count>2</entry_bounce_count>
+ <exit_nb_visits>2</exit_nb_visits>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <sum_daily_entry_nb_uniq_visitors>2</sum_daily_entry_nb_uniq_visitors>
+ <sum_daily_exit_nb_uniq_visitors>2</sum_daily_exit_nb_uniq_visitors>
+ <avg_time_on_page>270</avg_time_on_page>
+ <bounce_rate>100%</bounce_rate>
+ <exit_rate>100%</exit_rate>
+ <avg_time_generation>0.333</avg_time_generation>
+ <url>http://www.example.org/page</url>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Actions.get_day.xml b/plugins/Contents/tests/System/processed/test_Contents__Actions.get_day.xml
new file mode 100644
index 0000000000..f51cfaf913
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Actions.get_day.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <nb_pageviews>2</nb_pageviews>
+ <nb_uniq_pageviews>2</nb_uniq_pageviews>
+ <nb_downloads>0</nb_downloads>
+ <nb_uniq_downloads>0</nb_uniq_downloads>
+ <nb_outlinks>0</nb_outlinks>
+ <nb_uniq_outlinks>0</nb_uniq_outlinks>
+ <nb_searches>0</nb_searches>
+ <nb_keywords>0</nb_keywords>
+ <avg_time_generation>0.335</avg_time_generation>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Actions.get_month.xml b/plugins/Contents/tests/System/processed/test_Contents__Actions.get_month.xml
new file mode 100644
index 0000000000..f51cfaf913
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Actions.get_month.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <nb_pageviews>2</nb_pageviews>
+ <nb_uniq_pageviews>2</nb_uniq_pageviews>
+ <nb_downloads>0</nb_downloads>
+ <nb_uniq_downloads>0</nb_uniq_downloads>
+ <nb_outlinks>0</nb_outlinks>
+ <nb_uniq_outlinks>0</nb_uniq_outlinks>
+ <nb_searches>0</nb_searches>
+ <nb_keywords>0</nb_keywords>
+ <avg_time_generation>0.335</avg_time_generation>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentNames_day.xml b/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentNames_day.xml
new file mode 100644
index 0000000000..957c6fa85a
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentNames_day.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>ImageAd</label>
+ <nb_uniq_visitors>8</nb_uniq_visitors>
+ <nb_visits>8</nb_visits>
+ <nb_impressions>8</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>25%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>Text Ad</label>
+ <nb_uniq_visitors>6</nb_uniq_visitors>
+ <nb_visits>6</nb_visits>
+ <nb_impressions>6</nb_impressions>
+ <nb_interactions>4</nb_interactions>
+ <interaction_rate>66.67%</interaction_rate>
+ <contentTarget>http://piwik.org/</contentTarget>
+ </row>
+ <row>
+ <label>Video Ad</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentNames_month.xml b/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentNames_month.xml
new file mode 100644
index 0000000000..44bfdfd54e
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentNames_month.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>ImageAd</label>
+ <nb_visits>8</nb_visits>
+ <nb_impressions>8</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <sum_daily_nb_uniq_visitors>8</sum_daily_nb_uniq_visitors>
+ <interaction_rate>25%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>Text Ad</label>
+ <nb_visits>6</nb_visits>
+ <nb_impressions>6</nb_impressions>
+ <nb_interactions>4</nb_interactions>
+ <sum_daily_nb_uniq_visitors>6</sum_daily_nb_uniq_visitors>
+ <interaction_rate>66.67%</interaction_rate>
+ <contentTarget>http://piwik.org/</contentTarget>
+ </row>
+ <row>
+ <label>Video Ad</label>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentPieces_day.xml b/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentPieces_day.xml
new file mode 100644
index 0000000000..8927f8a8ec
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentPieces_day.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>Click to download Piwik now</label>
+ <nb_uniq_visitors>4</nb_uniq_visitors>
+ <nb_visits>4</nb_visits>
+ <nb_impressions>4</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>50%</interaction_rate>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ </row>
+ <row>
+ <label>/path/ad.jpg</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>100%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>/path/ad2.jpg</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>Click NOW</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>100%</interaction_rate>
+ <contentTarget>http://piwik.org/</contentTarget>
+ </row>
+ <row>
+ <label>movie.mov</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+ <row>
+ <label>Content Piece not defined</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+ <row>
+ <label>Unknown</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentPieces_month.xml b/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentPieces_month.xml
new file mode 100644
index 0000000000..b604544417
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Contents.getContentPieces_month.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>Click to download Piwik now</label>
+ <nb_visits>4</nb_visits>
+ <nb_impressions>4</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <sum_daily_nb_uniq_visitors>4</sum_daily_nb_uniq_visitors>
+ <interaction_rate>50%</interaction_rate>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ </row>
+ <row>
+ <label>/path/ad.jpg</label>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <interaction_rate>100%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>/path/ad2.jpg</label>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>Click NOW</label>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <interaction_rate>100%</interaction_rate>
+ <contentTarget>http://piwik.org/</contentTarget>
+ </row>
+ <row>
+ <label>movie.mov</label>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+ <row>
+ <label>Content Piece not defined</label>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+ <row>
+ <label>Unknown</label>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <sum_daily_nb_uniq_visitors>2</sum_daily_nb_uniq_visitors>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/processed/test_Contents__Live.getLastVisitsDetails_day.xml
new file mode 100644
index 0000000000..989f816722
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Live.getLastVisitsDetails_day.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>1</idVisit>
+ <visitIp>156.5.3.2</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>1</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>flash, java</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
+ <pluginName>flash</pluginName>
+ </row>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
+ <pluginName>java</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>2</idVisit>
+ <visitIp>111.1.1.1</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>13</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>director</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
+ <pluginName>director</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents__Live.getLastVisitsDetails_month.xml b/plugins/Contents/tests/System/processed/test_Contents__Live.getLastVisitsDetails_month.xml
new file mode 100644
index 0000000000..989f816722
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents__Live.getLastVisitsDetails_month.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>1</idVisit>
+ <visitIp>156.5.3.2</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>1</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>flash, java</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
+ <pluginName>flash</pluginName>
+ </row>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
+ <pluginName>java</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>2</idVisit>
+ <visitIp>111.1.1.1</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>13</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>director</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
+ <pluginName>director</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml b/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml
new file mode 100644
index 0000000000..c234bed59e
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Actions.getPageUrls_day.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result /> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml b/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml
new file mode 100644
index 0000000000..c234bed59e
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Contents.getContentNames_day.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result /> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml b/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml
new file mode 100644
index 0000000000..c234bed59e
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Contents.getContentPieces_day.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result /> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
new file mode 100644
index 0000000000..989f816722
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_contentInteractionMatch__Live.getLastVisitsDetails_day.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>1</idVisit>
+ <visitIp>156.5.3.2</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>1</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>flash, java</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
+ <pluginName>flash</pluginName>
+ </row>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
+ <pluginName>java</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>2</idVisit>
+ <visitIp>111.1.1.1</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>13</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>director</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
+ <pluginName>director</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml b/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml
new file mode 100644
index 0000000000..c234bed59e
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Actions.getPageUrls_day.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result /> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml b/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml
new file mode 100644
index 0000000000..5212486a1c
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Contents.getContentNames_day.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>ImageAd</label>
+ <nb_uniq_visitors>4</nb_uniq_visitors>
+ <nb_visits>4</nb_visits>
+ <nb_impressions>4</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>50%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml b/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml
new file mode 100644
index 0000000000..ac1d39a577
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Contents.getContentPieces_day.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>/path/ad.jpg</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>100%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>/path/ad2.jpg</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
new file mode 100644
index 0000000000..989f816722
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_Contents_contentTargetMatch__Live.getLastVisitsDetails_day.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>1</idVisit>
+ <visitIp>156.5.3.2</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>1</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>flash, java</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
+ <pluginName>flash</pluginName>
+ </row>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
+ <pluginName>java</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>2</idVisit>
+ <visitIp>111.1.1.1</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>13</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>director</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
+ <pluginName>director</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml b/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml
new file mode 100644
index 0000000000..c234bed59e
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Actions.getPageUrls_day.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result /> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml b/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml
new file mode 100644
index 0000000000..17b781db1c
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Contents.getContentNames_day.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>ImageAd</label>
+ <nb_uniq_visitors>8</nb_uniq_visitors>
+ <nb_visits>8</nb_visits>
+ <nb_impressions>8</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>25%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>Text Ad</label>
+ <nb_uniq_visitors>4</nb_uniq_visitors>
+ <nb_visits>4</nb_visits>
+ <nb_impressions>4</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>50%</interaction_rate>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml b/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml
new file mode 100644
index 0000000000..7df6e4f0e1
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Contents.getContentPieces_day.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>Click to download Piwik now</label>
+ <nb_uniq_visitors>4</nb_uniq_visitors>
+ <nb_visits>4</nb_visits>
+ <nb_impressions>4</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>50%</interaction_rate>
+ <contentTarget>http://piwik.org/download</contentTarget>
+ </row>
+ <row>
+ <label>/path/ad.jpg</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>2</nb_interactions>
+ <interaction_rate>100%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>/path/ad2.jpg</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget>http://www.example.com</contentTarget>
+ </row>
+ <row>
+ <label>Content Piece not defined</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+ <row>
+ <label>Unknown</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_impressions>2</nb_impressions>
+ <nb_interactions>0</nb_interactions>
+ <interaction_rate>0%</interaction_rate>
+ <contentTarget />
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml b/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
new file mode 100644
index 0000000000..989f816722
--- /dev/null
+++ b/plugins/Contents/tests/System/processed/test_ContentscontentNameOrPieceMatch__Live.getLastVisitsDetails_day.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>1</idVisit>
+ <visitIp>156.5.3.2</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>1</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>flash, java</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
+ <pluginName>flash</pluginName>
+ </row>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
+ <pluginName>java</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>2</idVisit>
+ <visitIp>111.1.1.1</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>action</type>
+ <url>http://www.example.org/page</url>
+ <pageTitle>Ads</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>13</pageId>
+ <generationTime>0.33s</generationTime>
+ <timeSpent>0</timeSpent>
+ <timeSpentPretty>0s</timeSpentPretty>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>0</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>0</visitConverted>
+ <visitConvertedIcon />
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>271</visitDuration>
+ <visitDurationPretty>4 min 31s</visitDurationPretty>
+ <customVariables>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>direct</referrerType>
+ <referrerTypeName>Direct Entry</referrerTypeName>
+ <referrerName />
+ <referrerKeyword />
+ <referrerKeywordPosition />
+ <referrerUrl />
+ <referrerSearchEngineUrl />
+ <referrerSearchEngineIcon />
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>director</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/director.gif</pluginIcon>
+ <pluginName>director</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/CoreConsole/Commands/CodeCoverage.php b/plugins/CoreConsole/Commands/CodeCoverage.php
index 348d7d3980..ff668efdb1 100644
--- a/plugins/CoreConsole/Commands/CodeCoverage.php
+++ b/plugins/CoreConsole/Commands/CodeCoverage.php
@@ -23,7 +23,7 @@ class CodeCoverage extends ConsoleCommand
{
$this->setName('tests:coverage');
$this->setDescription('Run all phpunit tests and generate a combined code coverage');
- $this->addArgument('group', InputArgument::OPTIONAL, 'Run only a specific test group. Separate multiple groups by comma, for instance core,integration', '');
+ $this->addArgument('group', InputArgument::OPTIONAL, 'Run only a specific test group. Separate multiple groups by comma, for instance core,plugins', '');
}
protected function execute(InputInterface $input, OutputInterface $output)
diff --git a/plugins/CoreConsole/Commands/DevelopmentManageTestFiles.php b/plugins/CoreConsole/Commands/DevelopmentManageTestFiles.php
index 429612ae9c..d2d96a8edf 100644
--- a/plugins/CoreConsole/Commands/DevelopmentManageTestFiles.php
+++ b/plugins/CoreConsole/Commands/DevelopmentManageTestFiles.php
@@ -42,7 +42,7 @@ class DevelopmentManageTestFiles extends ConsoleCommand
{
$file = $input->getOption('file');
- $prefix = PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Integration/processed/';
+ $prefix = PIWIK_INCLUDE_PATH . '/tests/PHPUnit/System/processed/';
$guesses = array(
'/' . $file,
$prefix . $file,
@@ -55,6 +55,6 @@ class DevelopmentManageTestFiles extends ConsoleCommand
}
}
- copy($file, PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Integration/expected/' . basename($file));
+ copy($file, PIWIK_INCLUDE_PATH . '/tests/PHPUnit/System/expected/' . basename($file));
}
} \ No newline at end of file
diff --git a/plugins/CoreConsole/Commands/GenerateTest.php b/plugins/CoreConsole/Commands/GenerateTest.php
index ff68eec784..6047f2ddc7 100644
--- a/plugins/CoreConsole/Commands/GenerateTest.php
+++ b/plugins/CoreConsole/Commands/GenerateTest.php
@@ -24,7 +24,7 @@ class GenerateTest extends GeneratePluginBase
->setDescription('Adds a test to an existing plugin')
->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin')
->addOption('testname', null, InputOption::VALUE_REQUIRED, 'The name of the test to create')
- ->addOption('testtype', null, InputOption::VALUE_REQUIRED, 'Whether you want to create a "unit", "integration" or "database" test');
+ ->addOption('testtype', null, InputOption::VALUE_REQUIRED, 'Whether you want to create a "unit", "integration" or "system" test');
}
protected function execute(InputInterface $input, OutputInterface $output)
@@ -35,18 +35,11 @@ class GenerateTest extends GeneratePluginBase
$exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
$replace = array(
- 'ExamplePlugin' => $pluginName,
- 'SimpleTest' => $testName,
- 'SimpleIntegrationTest' => $testName,
- '@group Plugins' => '@group ' . $testType
+ 'ExamplePlugin' => $pluginName,
+ 'SimpleTest' => $testName,
+ 'SimpleSystemTest' => $testName
);
- $testClass = $this->getTestClass($testType);
- if (!empty($testClass)) {
- $replace['\PHPUnit_Framework_TestCase'] = $testClass;
-
- }
-
$whitelistFiles = $this->getTestFilesWhitelist($testType);
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
@@ -113,30 +106,15 @@ class GenerateTest extends GeneratePluginBase
return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName);
}
- /**
- * @param InputInterface $input
- * @return string
- */
- private function getTestClass($testType)
- {
- if ('Database' == $testType) {
- return '\DatabaseTestCase';
- }
- if ('Unit' == $testType) {
- return '\PHPUnit_Framework_TestCase';
- }
- return false;
- }
-
public function getValidTypes()
{
- return array('unit', 'integration', 'database');
+ return array('unit', 'integration', 'system');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
- * @return string Unit, Integration, Database
+ * @return string Unit, Integration, System
*/
private function getTestType(InputInterface $input, OutputInterface $output)
{
@@ -167,23 +145,35 @@ class GenerateTest extends GeneratePluginBase
*/
protected function getTestFilesWhitelist($testType)
{
- if ('Integration' == $testType) {
+ if ('System' == $testType) {
return array(
'/.gitignore',
'/tests',
- '/tests/SimpleIntegrationTest.php',
- '/tests/expected',
- '/tests/expected/test___API.get_day.xml',
- '/tests/expected/test___Goals.getItemsSku_day.xml',
- '/tests/processed',
- '/tests/processed/.gitignore',
- '/tests/fixtures',
- '/tests/fixtures/SimpleFixtureTrackFewVisits.php'
+ '/tests/System',
+ '/tests/System/SimpleSystemTest.php',
+ '/tests/System/expected',
+ '/tests/System/expected/test___API.get_day.xml',
+ '/tests/System/expected/test___Goals.getItemsSku_day.xml',
+ '/tests/System/processed',
+ '/tests/System/processed/.gitignore',
+ '/tests/Fixtures',
+ '/tests/Fixtures/SimpleFixtureTrackFewVisits.php'
+ );
+ }
+
+ if ('Integration' == $testType) {
+
+ return array(
+ '/tests',
+ '/tests/Integration',
+ '/tests/Integration/SimpleTest.php'
);
}
+
return array(
'/tests',
- '/tests/SimpleTest.php'
+ '/tests/Unit',
+ '/tests/Unit/SimpleTest.php'
);
}
}
diff --git a/plugins/CoreConsole/Commands/GenerateTravisYmlFile.php b/plugins/CoreConsole/Commands/GenerateTravisYmlFile.php
index 1bd68cf0f7..13bcc5ad2f 100644
--- a/plugins/CoreConsole/Commands/GenerateTravisYmlFile.php
+++ b/plugins/CoreConsole/Commands/GenerateTravisYmlFile.php
@@ -44,7 +44,7 @@ class GenerateTravisYmlFile extends ConsoleCommand
protected function execute(InputInterface $input, OutputInterface $output)
{
- $targetPlugin = $input->getOption('plugin');
+ $targetPlugin = $input->getOption('plugin');
$outputYmlPath = $this->getTravisYmlOutputPath($input, $targetPlugin);
$view = $this->createTravisYmlView($input, $output, $targetPlugin, $outputYmlPath);
diff --git a/plugins/CoreConsole/Commands/TestsRun.php b/plugins/CoreConsole/Commands/TestsRun.php
index 5f940acb83..4178337057 100644
--- a/plugins/CoreConsole/Commands/TestsRun.php
+++ b/plugins/CoreConsole/Commands/TestsRun.php
@@ -25,16 +25,17 @@ class TestsRun extends ConsoleCommand
{
$this->setName('tests:run');
$this->setDescription('Run Piwik PHPUnit tests one group after the other');
- $this->addArgument('group', InputArgument::OPTIONAL, 'Run only a specific test group. Separate multiple groups by comma, for instance core,integration', '');
+ $this->addArgument('group', InputArgument::OPTIONAL, 'Run only a specific test group. Separate multiple groups by comma, for instance core,plugins', '');
$this->addOption('options', 'o', InputOption::VALUE_OPTIONAL, 'All options will be forwarded to phpunit', '');
$this->addOption('xhprof', null, InputOption::VALUE_NONE, 'Profile using xhprof.');
$this->addOption('file', null, InputOption::VALUE_REQUIRED, 'Execute tests within this file. Should be a path relative to the tests/PHPUnit directory.');
+ $this->addOption('suite', null, InputOption::VALUE_REQUIRED, 'Execute tests of a specific test suite, for instance UnitTests, IntegrationTests or SystemTests.');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$options = $input->getOption('options');
- $groups = $input->getArgument('group');
+ $groups = $input->getArgument('group');
$groups = explode(",", $groups);
$groups = array_map('ucfirst', $groups);
@@ -81,7 +82,8 @@ class TestsRun extends ConsoleCommand
if (!empty($testFile)) {
$this->executeTestFile($testFile, $options, $command, $output);
} else {
- $this->executeTestGroups($groups, $options, $command, $output);
+ $suite = $input->getOption('suite');
+ $this->executeTestGroups($suite, $groups, $options, $command, $output);
}
}
@@ -94,7 +96,7 @@ class TestsRun extends ConsoleCommand
$output->writeln("");
}
- private function executeTestGroups($groups, $options, $command, OutputInterface $output)
+ private function executeTestGroups($suite, $groups, $options, $command, OutputInterface $output)
{
if (empty($groups)) {
$groups = $this->getTestsGroups();
@@ -102,6 +104,10 @@ class TestsRun extends ConsoleCommand
foreach ($groups as $group) {
$params = '--group ' . $group . ' ' . str_replace('%group%', $group, $options);
+ if (!empty($suite)) {
+ $params .= ' --testsuite ' . $suite;
+ }
+
$cmd = sprintf('cd %s/tests/PHPUnit && %s %s', PIWIK_DOCUMENT_ROOT, $command, $params);
$output->writeln('Executing command: <info>' . $cmd . '</info>');
passthru($cmd);
@@ -111,6 +117,6 @@ class TestsRun extends ConsoleCommand
private function getTestsGroups()
{
- return array('Core', 'Plugins', 'Integration', 'UI');
+ return array('Core', 'Plugins', 'UI');
}
} \ No newline at end of file
diff --git a/plugins/CoreConsole/Commands/TestsSetupFixture.php b/plugins/CoreConsole/Commands/TestsSetupFixture.php
index cc5481d7e4..42beae0988 100644
--- a/plugins/CoreConsole/Commands/TestsSetupFixture.php
+++ b/plugins/CoreConsole/Commands/TestsSetupFixture.php
@@ -11,7 +11,7 @@ namespace Piwik\Plugins\CoreConsole\Commands;
use Piwik\Config;
use Piwik\Plugin\ConsoleCommand;
use Piwik\Url;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -217,8 +217,9 @@ class TestsSetupFixture extends ConsoleCommand
require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/FakeAccess.php';
require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/TestingEnvironment.php';
require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/IntegrationTestCase.php';
+ require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Impl/SystemTestCase.php';
+ require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Impl/Fixture.php';
require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/Fixture.php';
- require_once PIWIK_INCLUDE_PATH . '/tests/PHPUnit/IntegrationTestCase.php';
$fixturesToLoad = array(
'/tests/PHPUnit/Fixtures/*.php',
diff --git a/plugins/CoreConsole/tests/Unit/TravisYmlViewTest.php b/plugins/CoreConsole/tests/Integration/TravisYmlViewTest.php
index eba77d25ba..7dd32b2b67 100644
--- a/plugins/CoreConsole/tests/Unit/TravisYmlViewTest.php
+++ b/plugins/CoreConsole/tests/Integration/TravisYmlViewTest.php
@@ -6,7 +6,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
-namespace Piwik\Plugins\CoreConsole\tests\Unit;
+namespace Piwik\Plugins\CoreConsole\tests\Integration;
use Symfony\Component\Console\Output\ConsoleOutput;
use Piwik\Plugins\CoreConsole\TravisYmlView;
diff --git a/plugins/CoreConsole/tests/resources/test.travis.yml b/plugins/CoreConsole/tests/resources/test.travis.yml
index 1cdc845f18..e92dabeba1 100644
--- a/plugins/CoreConsole/tests/resources/test.travis.yml
+++ b/plugins/CoreConsole/tests/resources/test.travis.yml
@@ -8,7 +8,7 @@ env:
- PRESERVED_VAR=123
- secure: anotherpreservedvar
matrix:
- - TEST_SUITE=CoreTests MYSQL_ADAPTER=PDO_MYSQL
+ - TEST_SUITE=UnitTests MYSQL_ADAPTER=PDO_MYSQL
- TEST_SUITE=PluginTests MYSQL_ADAPTER=PDO_MYSQL
script: ./travis.sh
diff --git a/plugins/CorePluginsAdmin/tests/Integration/UpdateCommunicationTest.php b/plugins/CorePluginsAdmin/tests/Integration/UpdateCommunicationTest.php
new file mode 100644
index 0000000000..5743c42e46
--- /dev/null
+++ b/plugins/CorePluginsAdmin/tests/Integration/UpdateCommunicationTest.php
@@ -0,0 +1,186 @@
+<?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\Plugins\CorePluginsAdmin\tests\Integration;
+
+use Piwik\Config;
+use Piwik\Option;
+use Piwik\Plugins\CorePluginsAdmin\UpdateCommunication;
+use Piwik\Tests\Impl\IntegrationTestCase;
+
+/**
+ * Class Plugins_CorePluginsAdmin_UpdateCommunicationTest
+ *
+ * @group Plugins
+ */
+class UpdateCommunicationTest extends IntegrationTestCase
+{
+ /**
+ * @var UpdateCommunication
+ */
+ private $updateCommunication;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->updateCommunication = new UpdateCommunication();
+ $this->updateCommunication->enable();
+ }
+
+ public function test_canBeEnabled()
+ {
+ $this->assertTrue($this->updateCommunication->canBeEnabled());
+
+ Config::getInstance()->General['enable_update_communication'] = 0;
+ $this->assertFalse($this->updateCommunication->canBeEnabled());
+
+ Config::getInstance()->General['enable_update_communication'] = 1;
+ $this->assertTrue($this->updateCommunication->canBeEnabled());
+ }
+
+ public function test_enable()
+ {
+ $this->updateCommunication->enable();
+ $this->assertTrue($this->updateCommunication->isEnabled());
+ }
+
+ public function test_disable()
+ {
+ $this->assertTrue($this->updateCommunication->isEnabled());
+
+ $this->updateCommunication->disable();
+ $this->assertFalse($this->updateCommunication->isEnabled());
+ }
+
+ public function test_isEnabled_shouldReturnFalse_IfCannotBeEnabled()
+ {
+ $this->assertTrue($this->updateCommunication->isEnabled());
+
+ Config::getInstance()->General['enable_update_communication'] = 0;
+ $this->assertFalse($this->updateCommunication->isEnabled());
+ }
+
+ public function test_sendNotificationIfUpdatesAvailable_shouldNotSendNotification_IfNoUpdateAvailable()
+ {
+ $mock = $this->getCommunicationMock(array());
+ $mock->expects($this->never())->method('sendEmailNotification');
+ $mock->sendNotificationIfUpdatesAvailable();
+ }
+
+ /**
+ * @dataProvider provideSendNotificationData
+ */
+ public function test_sendNotificationIfUpdatesAvailable($latestVersion, $lastSentVersion, $expects, $expectedLastSentVersion)
+ {
+ $pluginsHavingUpdate = array(
+ array('name' => 'MyTest', 'latestVersion' => $latestVersion, 'isTheme' => false)
+ );
+ $this->setLastSentVersion('MyTest', $lastSentVersion);
+
+ $mock = $this->getCommunicationMock($pluginsHavingUpdate);
+ $mock->expects($expects)->method('sendEmailNotification');
+ $mock->sendNotificationIfUpdatesAvailable();
+
+ $this->assertEquals($expectedLastSentVersion, $this->getLastSentVersion('MyTest'));
+ }
+
+ public function provideSendNotificationData()
+ {
+ return array(
+ array('33.0.0', '33.0.0', $this->never(), '33.0.0'), // shouldNotSend_IfAlreadyNotified
+ array('31.0.0', '33.0.0', $this->never(), '33.0.0'), // shouldNotSend_IfAlreadyNotifiedAboutLaterRelease
+ array('33.0.0', false, $this->once(), '33.0.0'), // shouldSend_IfUpdateAvailableAndNeverSentAnyBefore
+ array('33.0.0', '31.0.0', $this->once(), '33.0.0'), // shouldSend_IfUpdateAvailable,
+ );
+ }
+
+ public function test_sendNotificationIfUpdatesAvailable_ShouldSendOnlyOneEmail_IfMultipleUpdatesAreAvailable()
+ {
+ $mock = $this->getCommunicationMockHavingManyUpdates();
+ $mock->expects($this->once())->method('sendEmailNotification');
+ $mock->sendNotificationIfUpdatesAvailable();
+ }
+
+ public function test_sendNotificationIfUpdatesAvailable_ShouldUpdateAllSentVersions_IfMultipleUpdatesAreAvailable()
+ {
+ $mock = $this->getCommunicationMockHavingManyUpdates();
+ $mock->expects($this->once())->method('sendEmailNotification');
+ $mock->sendNotificationIfUpdatesAvailable();
+
+ $this->assertEquals('33.0.0', $this->getLastSentVersion('MyTest1'));
+ $this->assertEquals('32.0.0', $this->getLastSentVersion('MyTest2'));
+ $this->assertEquals('31.0.0', $this->getLastSentVersion('MyTest3'));
+ }
+
+ public function test_sendNotificationIfUpdatesAvailable_ShouldSendCorrectText()
+ {
+ $subject = 'CoreUpdater_NotificationSubjectAvailablePluginUpdate';
+ $message = 'ScheduledReports_EmailHello
+
+CoreUpdater_ThereIsNewPluginVersionAvailableForUpdate
+
+ * MyTest1 33.0.0
+ * MyTest2 32.0.0
+ * MyTest3 31.0.0
+
+CoreUpdater_NotificationClickToUpdatePlugins
+index.php?module=CorePluginsAdmin&action=plugins
+
+Installation_HappyAnalysing';
+
+ $mock = $this->getCommunicationMockHavingManyUpdates();
+
+ $mock->expects($this->once())->method('sendEmailNotification')
+ ->with($this->equalTo($subject), $this->equalTo($message));
+
+ $mock->sendNotificationIfUpdatesAvailable();
+ }
+
+ private function setLastSentVersion($pluginName, $version)
+ {
+ Option::set('last_update_communication_sent_plugin_' . $pluginName, $version);
+ }
+
+ private function getLastSentVersion($pluginName)
+ {
+ return Option::get('last_update_communication_sent_plugin_' . $pluginName);
+ }
+
+ /**
+ * @param array $pluginsHavingUpdate
+ * @return UpdateCommunication
+ */
+ private function getCommunicationMock($pluginsHavingUpdate)
+ {
+ $mock = $this->getMock('\Piwik\Plugins\CorePluginsAdmin\UpdateCommunication', array('getPluginsHavingUpdate', 'sendEmailNotification'));
+
+ $mock->expects($this->any())
+ ->method('getPluginsHavingUpdate')
+ ->will($this->returnValue($pluginsHavingUpdate));
+
+ return $mock;
+ }
+
+ private function getCommunicationMockHavingManyUpdates()
+ {
+ $pluginsHavingUpdate = array(
+ array('name' => 'MyTest1', 'latestVersion' => '33.0.0', 'isTheme' => false),
+ array('name' => 'MyTest2', 'latestVersion' => '32.0.0', 'isTheme' => false),
+ array('name' => 'MyTest3', 'latestVersion' => '31.0.0', 'isTheme' => false),
+ );
+
+ $this->setLastSentVersion('MyTest1', false);
+ $this->setLastSentVersion('MyTest2', false);
+ $this->setLastSentVersion('MyTest3', false);
+
+ $mock = $this->getCommunicationMock($pluginsHavingUpdate);
+
+ return $mock;
+ }
+}
diff --git a/plugins/CoreUpdater/tests/Integration/UpdateCommunicationTest.php b/plugins/CoreUpdater/tests/Integration/UpdateCommunicationTest.php
new file mode 100644
index 0000000000..10f408206f
--- /dev/null
+++ b/plugins/CoreUpdater/tests/Integration/UpdateCommunicationTest.php
@@ -0,0 +1,122 @@
+<?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\Plugins\CoreUpdater\tests;
+
+use Piwik\Config;
+use Piwik\Option;
+use Piwik\Plugins\CoreUpdater\UpdateCommunication;
+use Piwik\UpdateCheck;
+use Piwik\Version;
+use Piwik\Tests\Impl\IntegrationTestCase;
+
+/**
+ * Class Plugins_CoreUpdater_UpdateCommunicationTest
+ *
+ * @group Plugins
+ */
+class UpdateCommunicationTest extends IntegrationTestCase
+{
+ public function setUp()
+ {
+ parent::setUp();
+ }
+
+ public function test_isEnabled()
+ {
+ $updateCommunication = new UpdateCommunication();
+
+ $this->assertTrue($updateCommunication->isEnabled());
+
+ Config::getInstance()->General['enable_update_communication'] = 0;
+ $this->assertFalse($updateCommunication->isEnabled());
+
+ Config::getInstance()->General['enable_update_communication'] = 1;
+ $this->assertTrue($updateCommunication->isEnabled());
+ }
+
+ /**
+ * @dataProvider provideSendNotificationData
+ */
+ public function test_sendNotificationIfUpdateAvailable($latestVersion, $lastSentVersion, $expects, $expectedLastSentVersion)
+ {
+ $this->setLatestVersion($latestVersion);
+ $this->setLastSentVersion($lastSentVersion);
+
+ $mock = $this->getCommunicationMock(array('sendNotifications'));
+ $mock->expects($expects)->method('sendNotifications');
+ $mock->sendNotificationIfUpdateAvailable();
+
+ $this->assertEquals($expectedLastSentVersion, $this->getLastSentVersion());
+ }
+
+ public function provideSendNotificationData()
+ {
+ return array(
+ array(Version::VERSION, false, $this->never(), false), // shouldNotSend_IfNoUpdateAvailable
+ array('33.0.0', '33.0.0', $this->never(), '33.0.0'), // shouldNotSend_IfAlreadyNotified
+ array('31.0.0', '33.0.0', $this->never(), '33.0.0'), // shouldNotSend_IfAlreadyNotifiedAboutLaterRelease
+ array('3333.3333.3333-beta10', '31.0.0', $this->never(), '31.0.0'), // shouldNotSend_IfLatestVersionIsNotVersionLike,
+ array('33.0.0', false, $this->once(), '33.0.0'), // shouldSend_IfUpdateAvailableAndNeverSentAnyBefore
+ array('33.0.0', '31.0.0', $this->once(), '33.0.0'), // shouldSend_IfUpdateAvailable
+ );
+ }
+
+ public function test_sendNotifications_shouldSentCorrectEmail()
+ {
+ $this->setLatestVersion('33.0.0');
+
+ $subject = 'CoreUpdater_NotificationSubjectAvailableCoreUpdate';
+ $message = 'ScheduledReports_EmailHello
+
+CoreUpdater_ThereIsNewVersionAvailableForUpdate
+
+CoreUpdater_YouCanUpgradeAutomaticallyOrDownloadPackage
+
+index.php?module=CoreUpdater&action=newVersionAvailable
+
+CoreUpdater_FeedbackRequest
+http://piwik.org/contact/';
+
+ $mock = $this->getCommunicationMock(array('sendEmailNotification'));
+ $mock->expects($this->once())
+ ->method('sendEmailNotification')
+ ->with($this->equalTo($subject), $this->equalTo($message));
+ $mock->sendNotificationIfUpdateAvailable();
+ }
+
+ private function setLastSentVersion($value)
+ {
+ Option::set('last_update_communication_sent_core', $value);
+ }
+
+ private function getLastSentVersion()
+ {
+ return Option::get('last_update_communication_sent_core');
+ }
+
+ private function setLatestVersion($value)
+ {
+ $this->preventVersionIsOverwrittenByActualVersionCheck();
+ Option::set(UpdateCheck::LATEST_VERSION, $value);
+ }
+
+ private function preventVersionIsOverwrittenByActualVersionCheck()
+ {
+ Config::getInstance()->General['enable_auto_update'] = false;
+ }
+
+ /**
+ * @param array $methodsToOverwrite
+ * @return UpdateCommunication
+ */
+ private function getCommunicationMock($methodsToOverwrite)
+ {
+ return $this->getMock('\Piwik\Plugins\CoreUpdater\UpdateCommunication', $methodsToOverwrite);
+ }
+}
diff --git a/plugins/CoreUpdater/tests/ModelTest.php b/plugins/CoreUpdater/tests/Unit/ModelTest.php
index 3098595b77..3098595b77 100644
--- a/plugins/CoreUpdater/tests/ModelTest.php
+++ b/plugins/CoreUpdater/tests/Unit/ModelTest.php
diff --git a/plugins/CoreVisualizations/Visualizations/Cloud.php b/plugins/CoreVisualizations/Visualizations/Cloud.php
index 0a78e219e6..d5a317da25 100644
--- a/plugins/CoreVisualizations/Visualizations/Cloud.php
+++ b/plugins/CoreVisualizations/Visualizations/Cloud.php
@@ -29,7 +29,7 @@ class Cloud extends Visualization
const FOOTER_ICON = 'plugins/Morpheus/images/tagcloud.png';
const FOOTER_ICON_TITLE = 'General_TagCloud';
- /** Used by integration tests to make sure output is consistent. */
+ /** Used by system tests to make sure output is consistent. */
public static $debugDisableShuffle = false;
public $truncatingLimit = 50;
diff --git a/plugins/CustomAlerts b/plugins/CustomAlerts
-Subproject f5557b8bcdb2ef6936b651a39f4e4f510b83bf6
+Subproject 643984c1bab2bc48f120e3cb83fac39b270d948
diff --git a/plugins/CustomVariables/.gitignore b/plugins/CustomVariables/.gitignore
new file mode 100644
index 0000000000..c8c9480010
--- /dev/null
+++ b/plugins/CustomVariables/.gitignore
@@ -0,0 +1 @@
+tests/System/processed/*xml \ No newline at end of file
diff --git a/plugins/CustomVariables/tests/Commands/InfoTest.php b/plugins/CustomVariables/tests/Commands/InfoTest.php
index 28f3d86cc7..455cdd10e2 100644
--- a/plugins/CustomVariables/tests/Commands/InfoTest.php
+++ b/plugins/CustomVariables/tests/Commands/InfoTest.php
@@ -13,14 +13,15 @@ use Piwik\Plugins\CustomVariables\Commands\Info;
use Piwik\Plugins\CustomVariables\Model;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group CustomVariables
* @group CustomVariablesTest
- * @group Database
+ * @group Plugins
* @group Plugins
*/
-class InfoTest extends \DatabaseTestCase
+class InfoTest extends IntegrationTestCase
{
public function testExecute_ShouldOutputInfoSuccess_IfEverythingIsOk()
{
diff --git a/plugins/CustomVariables/tests/Commands/SetNumberOfCustomVariablesTest.php b/plugins/CustomVariables/tests/Commands/SetNumberOfCustomVariablesTest.php
index 521684cac3..f48473b5e9 100644
--- a/plugins/CustomVariables/tests/Commands/SetNumberOfCustomVariablesTest.php
+++ b/plugins/CustomVariables/tests/Commands/SetNumberOfCustomVariablesTest.php
@@ -13,14 +13,15 @@ use Piwik\Plugins\CustomVariables\Commands\SetNumberOfCustomVariables;
use Piwik\Plugins\CustomVariables\CustomVariables;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group CustomVariables
* @group CustomVariablesTest
- * @group Database
+ * @group Plugins
* @group Plugins
*/
-class SetNumberOfCustomVariablesTest extends \DatabaseTestCase
+class SetNumberOfCustomVariablesTest extends IntegrationTestCase
{
/**
* @expectedException \RuntimeException
diff --git a/plugins/CustomVariables/tests/Fixtures/VisitWithManyCustomVariables.php b/plugins/CustomVariables/tests/Fixtures/VisitWithManyCustomVariables.php
index 8060eb25a7..82b8129bbb 100644
--- a/plugins/CustomVariables/tests/Fixtures/VisitWithManyCustomVariables.php
+++ b/plugins/CustomVariables/tests/Fixtures/VisitWithManyCustomVariables.php
@@ -9,7 +9,7 @@ namespace Piwik\Plugins\CustomVariables\tests\Fixtures;
use Piwik\Plugins\CustomVariables\Model;
use Piwik\Plugins\Goals\API;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
/**
* Adds one site with two goals and tracks two visits with custom variables.
diff --git a/plugins/CustomVariables/tests/CustomVariablesTest.php b/plugins/CustomVariables/tests/Integration/CustomVariablesTest.php
index 8e95aff299..5144dc4489 100644
--- a/plugins/CustomVariables/tests/CustomVariablesTest.php
+++ b/plugins/CustomVariables/tests/Integration/CustomVariablesTest.php
@@ -9,13 +9,14 @@
namespace Piwik\Plugins\CustomVariables\tests;
use Piwik\Plugins\CustomVariables\CustomVariables;
use Piwik\Tracker\Cache;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group CustomVariables
* @group CustomVariablesTest
- * @group Database
+ * @group Plugins
*/
-class CustomVariablesTest extends \DatabaseTestCase
+class CustomVariablesTest extends IntegrationTestCase
{
public function testGetMaxCustomVariables_ShouldDetectCorrectNumberOfVariables()
{
diff --git a/plugins/CustomVariables/tests/ModelTest.php b/plugins/CustomVariables/tests/Integration/ModelTest.php
index 3ed82f552a..384d204478 100644
--- a/plugins/CustomVariables/tests/ModelTest.php
+++ b/plugins/CustomVariables/tests/Integration/ModelTest.php
@@ -7,18 +7,17 @@
*/
namespace Piwik\Plugins\CustomVariables\tests;
-use Piwik\Common;
use Piwik\Db;
-use Piwik\DbHelper;
use Piwik\Plugins\CustomVariables\Model;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group CustomVariables
* @group ModelTest
- * @group Database
+ * @group Plugins
* @group CustomVariables_ModelTest
*/
-class ModelTest extends \DatabaseTestCase
+class ModelTest extends IntegrationTestCase
{
private static $cvarScopes = array('log_link_visit_action', 'log_visit', 'log_conversion');
diff --git a/plugins/CustomVariables/tests/CustomVariablesIntegrationTest.php b/plugins/CustomVariables/tests/System/CustomVariablesSystemTest.php
index 0cffce2a7c..00158a1e48 100644
--- a/plugins/CustomVariables/tests/CustomVariablesIntegrationTest.php
+++ b/plugins/CustomVariables/tests/System/CustomVariablesSystemTest.php
@@ -8,14 +8,14 @@
namespace Piwik\Plugins\CustomVariables\tests;
-use Piwik\Tests\IntegrationTestCase;
+use Piwik\Tests\Impl\SystemTestCase;
/**
* @group CustomVariables
- * @group CustomVariablesIntegrationTest
- * @group Database
+ * @group CustomVariablesSystemTest
+ * @group Plugins
*/
-class CustomVariablesIntegrationTest extends IntegrationTestCase
+class CustomVariablesSystemTest extends SystemTestCase
{
/**
* @var Fixtures\VisitWithManyCustomVariables
@@ -24,12 +24,11 @@ class CustomVariablesIntegrationTest extends IntegrationTestCase
public static function getOutputPrefix()
{
- return 'CustomVariablesIntegrationTest';
+ return 'CustomVariablesSystemTest';
}
/**
* @dataProvider getApiForTesting
- * @group Integration
*/
public function testApi($api, $params)
{
@@ -58,4 +57,4 @@ class CustomVariablesIntegrationTest extends IntegrationTestCase
}
}
-CustomVariablesIntegrationTest::$fixture = new Fixtures\VisitWithManyCustomVariables(); \ No newline at end of file
+CustomVariablesSystemTest::$fixture = new Fixtures\VisitWithManyCustomVariables(); \ No newline at end of file
diff --git a/plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__CustomVariables.getCustomVariables_day.xml b/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml
index 1ecaf61b08..1ecaf61b08 100644
--- a/plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__CustomVariables.getCustomVariables_day.xml
+++ b/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml
diff --git a/plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml b/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml
index a02dc66b3a..a02dc66b3a 100644
--- a/plugins/CustomVariables/tests/expected/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
+++ b/plugins/CustomVariables/tests/System/expected/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml
diff --git a/plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__CustomVariables.getCustomVariables_day.xml b/plugins/CustomVariables/tests/System/processed/test_CustomVariablesIntegrationTest__CustomVariables.getCustomVariables_day.xml
index 1ecaf61b08..1ecaf61b08 100644
--- a/plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__CustomVariables.getCustomVariables_day.xml
+++ b/plugins/CustomVariables/tests/System/processed/test_CustomVariablesIntegrationTest__CustomVariables.getCustomVariables_day.xml
diff --git a/plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml b/plugins/CustomVariables/tests/System/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
index a02dc66b3a..a02dc66b3a 100644
--- a/plugins/CustomVariables/tests/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
+++ b/plugins/CustomVariables/tests/System/processed/test_CustomVariablesIntegrationTest__Live.getLastVisitsDetails_day.xml
diff --git a/plugins/CustomVariables/tests/System/processed/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml b/plugins/CustomVariables/tests/System/processed/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml
new file mode 100644
index 0000000000..1ecaf61b08
--- /dev/null
+++ b/plugins/CustomVariables/tests/System/processed/test_CustomVariablesSystemTest__CustomVariables.getCustomVariables_day.xml
@@ -0,0 +1,395 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>Name_PAGE_1</label>
+ <nb_actions>1</nb_actions>
+ <subtable>
+ <row>
+ <label>Val_PAGE1</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_2</label>
+ <nb_actions>1</nb_actions>
+ <subtable>
+ <row>
+ <label>Val_PAGE2</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_3</label>
+ <nb_actions>1</nb_actions>
+ <subtable>
+ <row>
+ <label>Val_PAGE3</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_4</label>
+ <nb_actions>1</nb_actions>
+ <subtable>
+ <row>
+ <label>Val_PAGE4</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_5</label>
+ <nb_actions>1</nb_actions>
+ <subtable>
+ <row>
+ <label>Val_PAGE5</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_6</label>
+ <nb_actions>1</nb_actions>
+ <subtable>
+ <row>
+ <label>Val_PAGE6</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_7</label>
+ <nb_actions>1</nb_actions>
+ <subtable>
+ <row>
+ <label>Val_PAGE7</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_PAGE_8</label>
+ <nb_actions>1</nb_actions>
+ <subtable>
+ <row>
+ <label>Val_PAGE8</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_VISIT_1</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ <subtable>
+ <row>
+ <label>Val_VISIT1</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_VISIT_2</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ <subtable>
+ <row>
+ <label>Val_VISIT2</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_VISIT_3</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ <subtable>
+ <row>
+ <label>Val_VISIT3</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_VISIT_4</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ <subtable>
+ <row>
+ <label>Val_VISIT4</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_VISIT_5</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ <subtable>
+ <row>
+ <label>Val_VISIT5</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_VISIT_6</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ <subtable>
+ <row>
+ <label>Val_VISIT6</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_VISIT_7</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ <subtable>
+ <row>
+ <label>Val_VISIT7</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ </row>
+ </subtable>
+ </row>
+ <row>
+ <label>Name_VISIT_8</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ <subtable>
+ <row>
+ <label>Val_VISIT8</label>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>4</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <goals>
+ <row idgoal='1'>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <revenue>0</revenue>
+ </row>
+ </goals>
+ <nb_conversions>1</nb_conversions>
+ <revenue>0</revenue>
+ </row>
+ </subtable>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/CustomVariables/tests/System/processed/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml b/plugins/CustomVariables/tests/System/processed/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml
new file mode 100644
index 0000000000..a61cb11554
--- /dev/null
+++ b/plugins/CustomVariables/tests/System/processed/test_CustomVariablesSystemTest__Live.getLastVisitsDetails_day.xml
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <idSite>1</idSite>
+ <idVisit>1</idVisit>
+ <visitIp>156.5.3.2</visitIp>
+
+ <actionDetails>
+ <row>
+ <type>goal</type>
+ <goalName>triggered js</goalName>
+ <goalId>1</goalId>
+ <revenue>0</revenue>
+ <goalPageId />
+
+ <url>http://localhost</url>
+ <icon>plugins/Morpheus/images/goal.png</icon>
+ </row>
+ <row>
+ <type>action</type>
+ <url>http://localhost</url>
+ <pageTitle>Profile page</pageTitle>
+ <pageIdAction>2</pageIdAction>
+
+ <pageId>1</pageId>
+ <customVariables>
+ <row>
+ <customVariablePageName1>Name_PAGE_1</customVariablePageName1>
+ <customVariablePageValue1>Val_PAGE1</customVariablePageValue1>
+ </row>
+ <row>
+ <customVariablePageName2>Name_PAGE_2</customVariablePageName2>
+ <customVariablePageValue2>Val_PAGE2</customVariablePageValue2>
+ </row>
+ <row>
+ <customVariablePageName3>Name_PAGE_3</customVariablePageName3>
+ <customVariablePageValue3>Val_PAGE3</customVariablePageValue3>
+ </row>
+ <row>
+ <customVariablePageName4>Name_PAGE_4</customVariablePageName4>
+ <customVariablePageValue4>Val_PAGE4</customVariablePageValue4>
+ </row>
+ <row>
+ <customVariablePageName5>Name_PAGE_5</customVariablePageName5>
+ <customVariablePageValue5>Val_PAGE5</customVariablePageValue5>
+ </row>
+ <row>
+ <customVariablePageName6>Name_PAGE_6</customVariablePageName6>
+ <customVariablePageValue6>Val_PAGE6</customVariablePageValue6>
+ </row>
+ <row>
+ <customVariablePageName7>Name_PAGE_7</customVariablePageName7>
+ <customVariablePageValue7>Val_PAGE7</customVariablePageValue7>
+ </row>
+ <row>
+ <customVariablePageName8>Name_PAGE_8</customVariablePageName8>
+ <customVariablePageValue8>Val_PAGE8</customVariablePageValue8>
+ </row>
+ </customVariables>
+ <icon />
+ </row>
+ </actionDetails>
+ <goalConversions>1</goalConversions>
+ <siteCurrency>USD</siteCurrency>
+ <siteCurrencySymbol>$</siteCurrencySymbol>
+
+
+
+
+ <searches>0</searches>
+ <actions>1</actions>
+ <userId />
+ <visitorType>new</visitorType>
+ <visitorTypeIcon />
+ <visitConverted>1</visitConverted>
+ <visitConvertedIcon>plugins/Morpheus/images/goal.png</visitConvertedIcon>
+ <visitCount>1</visitCount>
+
+ <visitEcommerceStatus>none</visitEcommerceStatus>
+ <visitEcommerceStatusIcon />
+ <daysSinceFirstVisit>0</daysSinceFirstVisit>
+ <daysSinceLastEcommerceOrder>0</daysSinceLastEcommerceOrder>
+ <visitDuration>4</visitDuration>
+ <visitDurationPretty>4s</visitDurationPretty>
+ <customVariables>
+ <row>
+ <customVariableName1>Name_VISIT_1</customVariableName1>
+ <customVariableValue1>Val_VISIT1</customVariableValue1>
+ </row>
+ <row>
+ <customVariableName2>Name_VISIT_2</customVariableName2>
+ <customVariableValue2>Val_VISIT2</customVariableValue2>
+ </row>
+ <row>
+ <customVariableName3>Name_VISIT_3</customVariableName3>
+ <customVariableValue3>Val_VISIT3</customVariableValue3>
+ </row>
+ <row>
+ <customVariableName4>Name_VISIT_4</customVariableName4>
+ <customVariableValue4>Val_VISIT4</customVariableValue4>
+ </row>
+ <row>
+ <customVariableName5>Name_VISIT_5</customVariableName5>
+ <customVariableValue5>Val_VISIT5</customVariableValue5>
+ </row>
+ <row>
+ <customVariableName6>Name_VISIT_6</customVariableName6>
+ <customVariableValue6>Val_VISIT6</customVariableValue6>
+ </row>
+ <row>
+ <customVariableName7>Name_VISIT_7</customVariableName7>
+ <customVariableValue7>Val_VISIT7</customVariableValue7>
+ </row>
+ <row>
+ <customVariableName8>Name_VISIT_8</customVariableName8>
+ <customVariableValue8>Val_VISIT8</customVariableValue8>
+ </row>
+ </customVariables>
+ <deviceType>Desktop</deviceType>
+ <events>0</events>
+ <provider>Unknown</provider>
+ <providerName>Unknown</providerName>
+ <providerUrl>http://piwik.org/faq/general/#faq_52</providerUrl>
+ <referrerType>search</referrerType>
+ <referrerTypeName>Search Engines</referrerTypeName>
+ <referrerName>Google</referrerName>
+ <referrerKeyword>this keyword should be ranked</referrerKeyword>
+ <referrerKeywordPosition>1</referrerKeywordPosition>
+ <referrerUrl>http://www.google.com/search?q=this+keyword+should+be+ranked</referrerUrl>
+ <referrerSearchEngineUrl>http://google.com</referrerSearchEngineUrl>
+ <referrerSearchEngineIcon>plugins/Referrers/images/searchEngines/google.com.png</referrerSearchEngineIcon>
+ <continent>Europe</continent>
+ <continentCode>eur</continentCode>
+ <country>France</country>
+ <countryCode>fr</countryCode>
+ <countryFlag>plugins/UserCountry/images/flags/fr.png</countryFlag>
+ <region />
+ <regionCode />
+ <city />
+ <location>France</location>
+ <latitude />
+ <longitude />
+ <operatingSystem>Windows XP</operatingSystem>
+ <operatingSystemCode>WXP</operatingSystemCode>
+ <operatingSystemShortName>Win XP</operatingSystemShortName>
+ <operatingSystemIcon>plugins/UserSettings/images/os/WXP.gif</operatingSystemIcon>
+ <browserFamily>gecko</browserFamily>
+ <browserFamilyDescription>Gecko (Firefox)</browserFamilyDescription>
+ <browserName>Firefox 3.6</browserName>
+ <browserIcon>plugins/UserSettings/images/browsers/FF.gif</browserIcon>
+ <browserCode>FF</browserCode>
+ <browserVersion>3.6</browserVersion>
+ <screenType>normal</screenType>
+ <resolution>1024x768</resolution>
+ <screenTypeIcon>plugins/UserSettings/images/screens/normal.gif</screenTypeIcon>
+ <plugins>flash, java</plugins>
+ <pluginsIcons>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/flash.gif</pluginIcon>
+ <pluginName>flash</pluginName>
+ </row>
+ <row>
+ <pluginIcon>plugins/UserSettings/images/plugins/java.gif</pluginIcon>
+ <pluginName>java</pluginName>
+ </row>
+ </pluginsIcons>
+ <visitLocalTime>12:34:06</visitLocalTime>
+ <visitLocalHour>12</visitLocalHour>
+ <daysSinceLastVisit>0</daysSinceLastVisit>
+
+
+
+
+
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/ExamplePlugin/.gitignore b/plugins/ExamplePlugin/.gitignore
index b141f4501f..c8c9480010 100644
--- a/plugins/ExamplePlugin/.gitignore
+++ b/plugins/ExamplePlugin/.gitignore
@@ -1 +1 @@
-tests/processed/*xml \ No newline at end of file
+tests/System/processed/*xml \ No newline at end of file
diff --git a/plugins/ExamplePlugin/.travis.yml b/plugins/ExamplePlugin/.travis.yml
index 7dd870605f..f20c564fdf 100644
--- a/plugins/ExamplePlugin/.travis.yml
+++ b/plugins/ExamplePlugin/.travis.yml
@@ -5,8 +5,8 @@ php:
env:
matrix:
- - TEST_SUITE=CoreTests MYSQL_ADAPTER=PDO_MYSQL
- - TEST_SUITE=PluginTests MYSQL_ADAPTER=PDO_MYSQL
+ - TEST_SUITE=UnitTests MYSQL_ADAPTER=PDO_MYSQL
+ - TEST_SUITE=IntegrationTests MYSQL_ADAPTER=PDO_MYSQL
script: ./travis.sh
diff --git a/plugins/ExamplePlugin/tests/fixtures/SimpleFixtureTrackFewVisits.php b/plugins/ExamplePlugin/tests/Fixtures/SimpleFixtureTrackFewVisits.php
index f0515abfb1..2c0b38d172 100644
--- a/plugins/ExamplePlugin/tests/fixtures/SimpleFixtureTrackFewVisits.php
+++ b/plugins/ExamplePlugin/tests/Fixtures/SimpleFixtureTrackFewVisits.php
@@ -5,13 +5,13 @@
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\ExamplePlugin\tests\fixtures;
+namespace Piwik\Plugins\ExamplePlugin\tests\Fixtures;
use Piwik\Date;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
/**
- * Generates tracker testing data for our SimpleIntegrationTest
+ * Generates tracker testing data for our SimpleSystemTest
*
* This Simple fixture adds one website and tracks one visit with couple pageviews and an ecommerce conversion
*/
@@ -55,7 +55,6 @@ class SimpleFixtureTrackFewVisits extends Fixture
$t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.25)->getDatetime());
$t->addEcommerceItem($sku = 'SKU_ID', $name = 'Test item!', $category = 'Test & Category', $price = 777, $quantity = 33);
self::checkResponse($t->doTrackEcommerceOrder('TestingOrder', $grandTotal = 33 * 77));
-
}
protected function trackSecondVisit()
@@ -74,6 +73,5 @@ class SimpleFixtureTrackFewVisits extends Fixture
$t->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.3)->getDatetime());
$t->addEcommerceItem($sku = 'SKU_ID2', $name = 'A durable item', $category = 'Best seller', $price = 321);
self::checkResponse($t->doTrackEcommerceCartUpdate($grandTotal = 33 * 77));
-
}
} \ No newline at end of file
diff --git a/plugins/ExamplePlugin/tests/Integration/SimpleTest.php b/plugins/ExamplePlugin/tests/Integration/SimpleTest.php
new file mode 100644
index 0000000000..01ff197cf8
--- /dev/null
+++ b/plugins/ExamplePlugin/tests/Integration/SimpleTest.php
@@ -0,0 +1,26 @@
+<?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\Plugins\ExamplePlugin\tests\Integration;
+
+use Piwik\Tests\Impl\IntegrationTestCase;
+
+/**
+ * @group ExamplePlugin
+ * @group SimpleTest
+ * @group Plugins
+ */
+class SimpleTest extends IntegrationTestCase
+{
+
+ public function testSimpleAddition()
+ {
+ $this->assertEquals(2, 1+1);
+ }
+
+}
diff --git a/plugins/ExamplePlugin/tests/SimpleIntegrationTest.php b/plugins/ExamplePlugin/tests/System/SimpleSystemTest.php
index f9cebb8c72..873c4e4fbe 100644
--- a/plugins/ExamplePlugin/tests/SimpleIntegrationTest.php
+++ b/plugins/ExamplePlugin/tests/System/SimpleSystemTest.php
@@ -6,17 +6,17 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\ExamplePlugin\tests;
+namespace Piwik\Plugins\ExamplePlugin\tests\System;
use Piwik\Plugins\ExamplePlugin\tests\fixtures\SimpleFixtureTrackFewVisits;
-use Piwik\Tests\IntegrationTestCase;
+use Piwik\Tests\Impl\SystemTestCase;
/**
* @group ExamplePlugin
- * @group SimpleIntegrationTest
+ * @group SimpleSystemTest
* @group Plugins
*/
-class SimpleIntegrationTest extends IntegrationTestCase
+class SimpleSystemTest extends SystemTestCase
{
/**
* @var SimpleFixtureTrackFewVisits
@@ -25,7 +25,6 @@ class SimpleIntegrationTest extends IntegrationTestCase
/**
* @dataProvider getApiForTesting
- * @group SimpleIntegrationTest
*/
public function testApi($api, $params)
{
@@ -34,17 +33,20 @@ class SimpleIntegrationTest extends IntegrationTestCase
public function getApiForTesting()
{
- $api = array('API.get',
- 'Goals.getItemsSku');
+ $api = array(
+ 'API.get',
+ 'Goals.getItemsSku'
+ );
- $apiToTest = array();
+ $apiToTest = array();
$apiToTest[] = array($api,
- array( 'idSite' => 1,
- 'date' => self::$fixture->dateTime,
- 'periods' => array('day'),
- 'testSuffix' => ''
-
- ));
+ array(
+ 'idSite' => 1,
+ 'date' => self::$fixture->dateTime,
+ 'periods' => array('day'),
+ 'testSuffix' => ''
+ )
+ );
return $apiToTest;
}
@@ -61,4 +63,4 @@ class SimpleIntegrationTest extends IntegrationTestCase
}
-SimpleIntegrationTest::$fixture = new SimpleFixtureTrackFewVisits(); \ No newline at end of file
+SimpleSystemTest::$fixture = new SimpleFixtureTrackFewVisits(); \ No newline at end of file
diff --git a/plugins/ExamplePlugin/tests/expected/test___API.get_day.xml b/plugins/ExamplePlugin/tests/System/expected/test___API.get_day.xml
index 58296797c0..58296797c0 100644
--- a/plugins/ExamplePlugin/tests/expected/test___API.get_day.xml
+++ b/plugins/ExamplePlugin/tests/System/expected/test___API.get_day.xml
diff --git a/plugins/ExamplePlugin/tests/expected/test___Goals.getItemsSku_day.xml b/plugins/ExamplePlugin/tests/System/expected/test___Goals.getItemsSku_day.xml
index ba820ed649..ba820ed649 100644
--- a/plugins/ExamplePlugin/tests/expected/test___Goals.getItemsSku_day.xml
+++ b/plugins/ExamplePlugin/tests/System/expected/test___Goals.getItemsSku_day.xml
diff --git a/plugins/ExamplePlugin/tests/processed/.gitkeep b/plugins/ExamplePlugin/tests/System/processed/.gitkeep
index e69de29bb2..e69de29bb2 100644
--- a/plugins/ExamplePlugin/tests/processed/.gitkeep
+++ b/plugins/ExamplePlugin/tests/System/processed/.gitkeep
diff --git a/plugins/ExamplePlugin/tests/System/processed/test___API.get_day.xml b/plugins/ExamplePlugin/tests/System/processed/test___API.get_day.xml
new file mode 100644
index 0000000000..1cfef75f4b
--- /dev/null
+++ b/plugins/ExamplePlugin/tests/System/processed/test___API.get_day.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_users>0</nb_users>
+ <nb_actions>4</nb_actions>
+ <max_actions>2</max_actions>
+ <bounce_rate>0%</bounce_rate>
+ <nb_actions_per_visit>2</nb_actions_per_visit>
+ <avg_time_on_site>632</avg_time_on_site>
+ <nb_visits_returning>0</nb_visits_returning>
+ <nb_actions_returning>0</nb_actions_returning>
+ <nb_uniq_visitors_returning>0</nb_uniq_visitors_returning>
+ <bounce_rate_returning>0%</bounce_rate_returning>
+ <nb_actions_per_visit_returning>0</nb_actions_per_visit_returning>
+ <avg_time_on_site_returning>0</avg_time_on_site_returning>
+ <nb_conversions>1</nb_conversions>
+ <nb_visits_converted>1</nb_visits_converted>
+ <conversion_rate>50</conversion_rate>
+ <revenue>2541</revenue>
+ <nb_pageviews>3</nb_pageviews>
+ <nb_uniq_pageviews>3</nb_uniq_pageviews>
+ <nb_downloads>0</nb_downloads>
+ <nb_uniq_downloads>0</nb_uniq_downloads>
+ <nb_outlinks>0</nb_outlinks>
+ <nb_uniq_outlinks>0</nb_uniq_outlinks>
+ <nb_searches>1</nb_searches>
+ <nb_keywords>1</nb_keywords>
+ <avg_time_generation>0</avg_time_generation>
+</result> \ No newline at end of file
diff --git a/plugins/ExamplePlugin/tests/System/processed/test___Goals.getItemsSku_day.xml b/plugins/ExamplePlugin/tests/System/processed/test___Goals.getItemsSku_day.xml
new file mode 100644
index 0000000000..ba820ed649
--- /dev/null
+++ b/plugins/ExamplePlugin/tests/System/processed/test___Goals.getItemsSku_day.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>SKU_ID</label>
+ <revenue>25641</revenue>
+ <quantity>33</quantity>
+ <orders>1</orders>
+ <avg_price>777</avg_price>
+ <avg_quantity>33</avg_quantity>
+ <conversion_rate>0%</conversion_rate>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/ExamplePlugin/tests/SimpleTest.php b/plugins/ExamplePlugin/tests/Unit/SimpleTest.php
index 0fdc86062c..396ee20785 100644
--- a/plugins/ExamplePlugin/tests/SimpleTest.php
+++ b/plugins/ExamplePlugin/tests/Unit/SimpleTest.php
@@ -6,7 +6,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\ExamplePlugin\tests;
+namespace Piwik\Plugins\ExamplePlugin\tests\Unit;
/**
* @group ExamplePlugin
diff --git a/plugins/Goals/tests/APITest.php b/plugins/Goals/tests/Integration/APITest.php
index 3263bc4972..bc3a960e83 100644
--- a/plugins/Goals/tests/APITest.php
+++ b/plugins/Goals/tests/Integration/APITest.php
@@ -6,19 +6,21 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\Goals\tests;
+namespace Piwik\Plugins\Goals\tests\Integration;
+
use Piwik\Access;
use Piwik\Piwik;
use Piwik\Plugins\Goals\API;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group Goals
* @group Plugins
* @group APITest
- * @group Database
+ * @group Plugins
*/
-class APITest extends \DatabaseTestCase
+class APITest extends IntegrationTestCase
{
/**
* @var API
diff --git a/plugins/Insights/tests/Fixtures/SomeVisitsDifferentPathsOnTwoDays.php b/plugins/Insights/tests/Fixtures/SomeVisitsDifferentPathsOnTwoDays.php
index c5314d3aa3..7041e6b573 100644
--- a/plugins/Insights/tests/Fixtures/SomeVisitsDifferentPathsOnTwoDays.php
+++ b/plugins/Insights/tests/Fixtures/SomeVisitsDifferentPathsOnTwoDays.php
@@ -9,7 +9,7 @@
namespace Piwik\Plugins\Insights\tests\Fixtures;
use Piwik\Date;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
/**
* Adds one website and tracks several visits from one visitor on
diff --git a/plugins/Insights/tests/ApiTest.php b/plugins/Insights/tests/Integration/ApiTest.php
index e769252e9d..f9318903cd 100644
--- a/plugins/Insights/tests/ApiTest.php
+++ b/plugins/Insights/tests/Integration/ApiTest.php
@@ -8,16 +8,20 @@
namespace Piwik\Plugins\Insights\tests;
use Piwik\API\Request as ApiRequest;
+use Piwik\Cache\PluginAwareStaticCache;
+use Piwik\Cache\StaticCache;
use Piwik\DataTable;
use Piwik\DataTable\Row;
use Piwik\Plugins\Insights\API;
use Piwik\Plugins\Insights\tests\Fixtures\SomeVisitsDifferentPathsOnTwoDays;
-use Piwik\Tests\IntegrationTestCase;
+use Piwik\Tests\Impl\IntegrationTestCase;
+use Piwik\Tracker\Cache;
+use Piwik\Translate;
/**
* @group Insights
* @group ApiTest
- * @group Database
+ * @group Plugins
* @group Plugins
*/
class ApiTest extends IntegrationTestCase
@@ -37,6 +41,10 @@ class ApiTest extends IntegrationTestCase
{
parent::setUp();
+ StaticCache::clearAll();
+ PluginAwareStaticCache::clearAll();
+
+ Translate::reloadLanguage('en');
$this->api = API::getInstance();
}
diff --git a/plugins/Insights/tests/ModelTest.php b/plugins/Insights/tests/Integration/ModelTest.php
index fdabe70561..4f62630bd9 100644
--- a/plugins/Insights/tests/ModelTest.php
+++ b/plugins/Insights/tests/Integration/ModelTest.php
@@ -11,15 +11,15 @@ namespace Piwik\Plugins\Insights\tests;
use Piwik\DataTable;
use Piwik\Plugins\Insights\Model;
use Piwik\Plugins\Insights\tests\Fixtures\SomeVisitsDifferentPathsOnTwoDays;
-use Piwik\Tests\IntegrationTestCase;
+use Piwik\Tests\Impl\SystemTestCase;
/**
* @group Insights
* @group ModelTest
- * @group Database
+ * @group Plugins
* @group Plugins
*/
-class ModelTest extends IntegrationTestCase
+class ModelTest extends SystemTestCase
{
/**
* @var SomeVisitsDifferentPathsOnTwoDays
diff --git a/plugins/Insights/tests/BaseUnitTest.php b/plugins/Insights/tests/Unit/BaseUnitTest.php
index 97c2c78580..97c2c78580 100644
--- a/plugins/Insights/tests/BaseUnitTest.php
+++ b/plugins/Insights/tests/Unit/BaseUnitTest.php
diff --git a/plugins/Insights/tests/FilterExcludeLowValueTest.php b/plugins/Insights/tests/Unit/FilterExcludeLowValueTest.php
index 51c0192ef6..51c0192ef6 100644
--- a/plugins/Insights/tests/FilterExcludeLowValueTest.php
+++ b/plugins/Insights/tests/Unit/FilterExcludeLowValueTest.php
diff --git a/plugins/Insights/tests/FilterInsightTest.php b/plugins/Insights/tests/Unit/FilterInsightTest.php
index 67c216b192..67c216b192 100644
--- a/plugins/Insights/tests/FilterInsightTest.php
+++ b/plugins/Insights/tests/Unit/FilterInsightTest.php
diff --git a/plugins/Insights/tests/FilterLimitTest.php b/plugins/Insights/tests/Unit/FilterLimitTest.php
index 6f6d703b0a..6f6d703b0a 100644
--- a/plugins/Insights/tests/FilterLimitTest.php
+++ b/plugins/Insights/tests/Unit/FilterLimitTest.php
diff --git a/plugins/Insights/tests/FilterMinGrowthTest.php b/plugins/Insights/tests/Unit/FilterMinGrowthTest.php
index a53245b891..a53245b891 100644
--- a/plugins/Insights/tests/FilterMinGrowthTest.php
+++ b/plugins/Insights/tests/Unit/FilterMinGrowthTest.php
diff --git a/plugins/Insights/tests/FilterOrderByTest.php b/plugins/Insights/tests/Unit/FilterOrderByTest.php
index 8239204a2f..8239204a2f 100644
--- a/plugins/Insights/tests/FilterOrderByTest.php
+++ b/plugins/Insights/tests/Unit/FilterOrderByTest.php
diff --git a/plugins/Insights/tests/InsightReportTest.php b/plugins/Insights/tests/Unit/InsightReportTest.php
index 32901409ac..32901409ac 100644
--- a/plugins/Insights/tests/InsightReportTest.php
+++ b/plugins/Insights/tests/Unit/InsightReportTest.php
diff --git a/plugins/LanguagesManager/tests/Integration/LanguagesManagerTest.php b/plugins/LanguagesManager/tests/Integration/LanguagesManagerTest.php
new file mode 100755
index 0000000000..3ed219acf4
--- /dev/null
+++ b/plugins/LanguagesManager/tests/Integration/LanguagesManagerTest.php
@@ -0,0 +1,182 @@
+<?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\Plugins\LanguagesManager\tests;
+
+use Piwik\Common;
+use Piwik\Plugins\LanguagesManager\API;
+use Piwik\Translate\Filter\ByParameterCount;
+use Piwik\Translate\Filter\EmptyTranslations;
+use Piwik\Translate\Filter\EncodedEntities;
+use Piwik\Translate\Filter\UnnecassaryWhitespaces;
+use Piwik\Translate\Validate\CoreTranslations;
+use Piwik\Translate\Validate\NoScripts;
+use Piwik\Translate\Writer;
+use \Exception;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/LanguagesManager/API.php';
+
+class LanguagesManagerTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ parent::setUp();
+ include PIWIK_INCLUDE_PATH . '/core/DataFiles/Languages.php';
+ }
+
+ function getTestDataForLanguageFiles()
+ {
+ // we also test that none of the language php files outputs any character on the screen (eg. space before the <?php)
+ $languages = API::getInstance()->getAvailableLanguages();
+
+ $plugins = \Piwik\Plugin\Manager::getInstance()->readPluginsDirectory();
+
+ $pluginsWithTranslation = array();
+
+ foreach ($plugins as $plugin) {
+
+ if (API::getInstance()->getPluginTranslationsForLanguage($plugin, 'en')) {
+
+ $pluginsWithTranslation[] = $plugin;
+ }
+ }
+
+ $return = array();
+ foreach ($languages as $language) {
+ if ($language != 'en') {
+ $return[] = array($language, null);
+
+ foreach ($pluginsWithTranslation as $plugin) {
+
+ $return[] = array($language, $plugin);
+ }
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * test all languages
+ *
+ * @group Plugins
+ *
+ * @dataProvider getTestDataForLanguageFiles
+ */
+ function testGetTranslationsForLanguages($language, $plugin)
+ {
+ $translationWriter = new Writer($language, $plugin);
+
+ $baseTranslations = $translationWriter->getTranslations('en');
+
+ $translationWriter->addValidator(new NoScripts());
+ if (empty($plugin)) {
+ $translationWriter->addValidator(new CoreTranslations($baseTranslations));
+ }
+
+ // prevent build from failing when translations string have been deleted
+// $translationWriter->addFilter(new ByBaseTranslations($baseTranslations));
+ $translationWriter->addFilter(new EmptyTranslations());
+ $translationWriter->addFilter(new ByParameterCount($baseTranslations));
+ $translationWriter->addFilter(new UnnecassaryWhitespaces($baseTranslations));
+ $translationWriter->addFilter(new EncodedEntities());
+
+ $translations = $translationWriter->getTranslations($language);
+
+ if (empty($translations)) {
+ return; // skip language / plugin combinations that aren't present
+ }
+
+ $translationWriter->setTranslations($translations);
+
+ $this->assertTrue($translationWriter->isValid(), $translationWriter->getValidationMessage());
+
+ if ($translationWriter->wasFiltered()) {
+
+ $translationWriter->saveTemporary();
+ $this->fail(implode("\n", $translationWriter->getFilterMessages()) . "\n"
+ . 'Translation file errors detected in ' . $language . "...\n"
+ . "To overwrite you could manually fix the language files, or run the following command may work if you have access to oTrance: \n"
+ . "$ ./console translations:update [--plugin=XYZ] \n");
+ }
+ }
+
+ /**
+ * test language when it's not defined
+ *
+ * @group Plugins
+ *
+ * @expectedException Exception
+ */
+ function testWriterInvalidPlugin()
+ {
+ new Writer('de', 'iNvaLiDPluGin'); // invalid plugin throws exception
+ }
+
+ /**
+ * test language when it's not defined
+ *
+ * @group Plugins
+ */
+ function testGetTranslationsForLanguagesNot()
+ {
+ $this->assertFalse(API::getInstance()->getTranslationsForLanguage("../no-language"));
+ }
+
+ /**
+ * test English short name for language
+ *
+ * @group Plugins
+ */
+ function testGetLanguageNamesInEnglish()
+ {
+ $languages = API::getInstance()->getAvailableLanguages();
+ foreach ($languages as $language) {
+ $data = file_get_contents(PIWIK_INCLUDE_PATH . "/lang/$language.json");
+ $translations = json_decode($data, true);
+ $name = $translations['General']['EnglishLanguageName'];
+
+ if ($language != 'en') {
+ $this->assertFalse($name == 'English', "for $language");
+ }
+
+ $languageCode = substr($language, 0, 2);
+ $this->assertTrue(isset($GLOBALS['Piwik_LanguageList'][$languageCode]));
+ $names = $GLOBALS['Piwik_LanguageList'][$languageCode];
+
+ if (isset($GLOBALS['Piwik_LanguageList'][$language])) {
+ if (is_array($names)) {
+ $this->assertTrue(in_array($name, $names), "$language: failed because $name not a known language name");
+ } else {
+ $this->assertTrue($name == $names, "$language: failed because $name == $names");
+ }
+ } else {
+ if (is_array($names)) {
+ $this->assertTrue(strpos($name, $names[0]) !== false);
+ } else {
+ $this->fail("$language: expected an array of language names");
+ }
+ }
+ }
+ }
+
+ /**
+ * test format of DataFile/Languages.php
+ *
+ * @group Plugins
+ */
+ function testGetLanguagesList()
+ {
+ $languages = Common::getLanguagesList();
+ $this->assertTrue(count($languages) > 0);
+ foreach ($languages as $langCode => $langs) {
+ $this->assertTrue(strlen($langCode) == 2, "$langCode length = 2");
+ $this->assertTrue(is_array($langs) && count($langs) >= 1, "$langCode array(names) >= 1");
+ }
+ }
+}
diff --git a/plugins/LeftMenu/tests/APITest.php b/plugins/LeftMenu/tests/Integration/APITest.php
index 05d0f34aed..e4500b2e41 100644
--- a/plugins/LeftMenu/tests/APITest.php
+++ b/plugins/LeftMenu/tests/Integration/APITest.php
@@ -6,19 +6,20 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\LeftMenu\tests;
+namespace Piwik\Plugins\LeftMenu\tests\Integration;
use Piwik\Access;
use Piwik\Plugins\LeftMenu\API;
use Piwik\Plugins\LeftMenu\Settings;
use \FakeAccess;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group LeftMenu
* @group APITest
- * @group Database
+ * @group Plugins
*/
-class APITest extends \DatabaseTestCase
+class APITest extends IntegrationTestCase
{
/**
* @var API
diff --git a/plugins/Live/tests/APITest.php b/plugins/Live/tests/Integration/APITest.php
index cf48da8d5b..fcfc410bcf 100644
--- a/plugins/Live/tests/APITest.php
+++ b/plugins/Live/tests/Integration/APITest.php
@@ -6,7 +6,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\Live\tests;
+namespace Piwik\Plugins\Live\tests\Integration;
use Piwik\Date;
use Piwik\Db;
@@ -14,16 +14,15 @@ use Piwik\Plugins\Goals\API as GoalsApi;
use Piwik\Plugins\Live\API;
use FakeAccess;
use Piwik\Access;
-use Piwik\Tests\Fixture;
-use Piwik\Tests\IntegrationTestCase;
+use Piwik\Tests\Impl\Fixture;
+use Piwik\Tests\Impl\SystemTestCase;
/**
* @group Live
* @group APITest
- * @group Integration
* @group Plugins
*/
-class APITest extends IntegrationTestCase
+class APITest extends SystemTestCase
{
/**
* @var API
diff --git a/plugins/Login/tests/Integration/LoginTest.php b/plugins/Login/tests/Integration/LoginTest.php
new file mode 100644
index 0000000000..4007061bd5
--- /dev/null
+++ b/plugins/Login/tests/Integration/LoginTest.php
@@ -0,0 +1,404 @@
+<?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\Plugins\Login\tests\Integration;
+
+use Piwik\Access;
+use Piwik\AuthResult;
+use Piwik\DbHelper;
+use Piwik\Plugins\Login\Auth;
+use Piwik\Plugins\UsersManager\API;
+use Piwik\Tests\Impl\IntegrationTestCase;
+use FakeAccess;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/Login/Auth.php';
+
+/**
+ * Class Plugins_LoginTest
+ *
+ * @group Plugins
+ * @group Plugins_LoginTest
+ */
+class LoginTest extends IntegrationTestCase
+{
+
+ /**
+ * @var Auth
+ */
+ private $auth;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ // setup the access layer
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::setIdSitesView(array(1, 2));
+ FakeAccess::setIdSitesAdmin(array(3, 4));
+
+ //finally we set the user as a Super User by default
+ FakeAccess::$superUser = true;
+ Access::setSingletonInstance($pseudoMockAccess);
+
+ $this->auth = new Auth();
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureNoLoginNoTokenAuth()
+ {
+ // no login; no token auth
+ $rc = $this->auth->authenticate();
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureEmptyLoginNoTokenAuth()
+ {
+ // empty login; no token auth
+ $this->auth->setLogin('');
+ $rc = $this->auth->authenticate();
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureNonExistentUser()
+ {
+ // non-existent user
+ $this->auth->setLogin('nobody');
+ $rc = $this->auth->authenticate();
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureAnonymousNotExisting()
+ {
+ // anonymous user doesn't exist yet
+ $rc = $this->authenticate($login = 'anonymous', $authToken = '');
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureAnonymousNotExistentEmptyLogin()
+ {
+ // empty login; anonymous user doesn't exist yet
+ $rc = $this->authenticate($login = '', $authToken = 'anonymous');
+
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureAnonymousNotExistentEmptyLoginWithTokenAuth()
+ {
+ // API authentication; anonymous user doesn't exist yet
+ $rc = $this->authenticate($login = null, $authToken = 'anonymous');
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureAnonymousNotExistentWithLoginAndTokenAuth()
+ {
+ // anonymous user doesn't exist yet
+ $rc = $this->authenticate($login = 'anonymous', $authToken = 'anonymous');
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureAnonymousWithLogin()
+ {
+ DbHelper::createAnonymousUser();
+
+ // missing token_auth
+ $rc = $this->authenticate($login = 'anonymous', $authToken = '');
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureAnonymousEmptyLoginWithTokenAuth()
+ {
+ DbHelper::createAnonymousUser();
+
+ // empty login
+ $rc = $this->authenticate($login = '', $authToken = 'anonymous');
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureAnonymousLoginTokenAuthMissmatch()
+ {
+ DbHelper::createAnonymousUser();
+
+ // not equal
+ $rc = $this->authenticate($login = 'anonymous', $authToken = 0);
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateSuccessAnonymousWithTokenAuth()
+ {
+ DbHelper::createAnonymousUser();
+
+ // API authentication
+ $rc = $this->authenticate($login = null, $authToken = 'anonymous');
+ $this->assertUserLogin($rc, $login = 'anonymous', $tokenLength = 9);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateSuccessAnonymous()
+ {
+ DbHelper::createAnonymousUser();
+
+ // valid login & token auth
+ $rc = $this->authenticate($login = 'anonymous', $authToken = 'anonymous');
+ $this->assertUserLogin($rc, $login = 'anonymous', $tokenLength = 9);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureUserEmptyTokenAuth()
+ {
+ $user = $this->_setUpUser();
+
+ // empty token auth
+ $rc = $this->authenticate($login = $user['login'], $authToken = '');
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureUserInvalidTokenAuth()
+ {
+ $user = $this->_setUpUser();
+
+ // not a token auth
+ $rc = $this->authenticate($login = $user['login'], $authToken = $user['password']);
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureUserInvalidTokenAuth2()
+ {
+ $user = $this->_setUpUser();
+
+ // not a token auth
+ $rc = $this->authenticate($login = $user['login'], $authToken = md5($user['password']));
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureUserEmptyLogin()
+ {
+ $user = $this->_setUpUser();
+
+ // empty login
+ $rc = $this->authenticate($login = '', $user['tokenAuth']);
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureUserWithSuperUserAccessEmptyLogin()
+ {
+ $user = $this->_setUpUser();
+ $this->_setUpSuperUserAccessViaDb();
+
+ // empty login
+ $rc = $this->authenticate($login = '', $user['tokenAuth']);
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureUserLoginTokenAuthMissmatch()
+ {
+ $this->_setUpUser();
+
+ // not equal
+ $rc = $this->authenticate($login = 0, $authToken = 0);
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureUserLoginTokenAuthMissmatch2()
+ {
+ $user = $this->_setUpUser();
+
+ // not equal
+ $rc = $this->authenticate($login = 0, $user['tokenAuth']);
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureUserLoginTokenAuthMissmatch3()
+ {
+ $user = $this->_setUpUser();
+
+ // not equal
+ $rc = $this->authenticate($user['login'], $authToken = 0);
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateFailureUserWithSuperUserAccessLoginTokenAuthMissmatch()
+ {
+ $user = $this->_setUpUser();
+ $this->_setUpSuperUserAccessViaDb();
+
+ // not equal
+ $rc = $this->authenticate($login = null, $authToken = $user['password']);
+ $this->assertFailedLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateSuccessUserTokenAuth()
+ {
+ $user = $this->_setUpUser();
+
+ // API authentication
+ $rc = $this->authenticate($login = null, $user['tokenAuth']);
+ $this->assertUserLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateSuccessUserWithSuperUserAccessByTokenAuth()
+ {
+ $user = $this->_setUpUser();
+ $this->_setUpSuperUserAccessViaDb();
+
+ // API authentication
+ $rc = $this->authenticate($login = null, $user['tokenAuth']);
+ $this->assertSuperUserLogin($rc, 'user');
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateSuccessUserLoginAndTokenAuth()
+ {
+ $user = $this->_setUpUser();
+
+ // valid login & token auth
+ $rc = $this->authenticate($user['login'], $user['tokenAuth']);
+ $this->assertUserLogin($rc);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateSuccessUserWithSuperUserAccessLoginAndTokenAuth()
+ {
+ $user = $this->_setUpUser();
+ $this->_setUpSuperUserAccessViaDb();
+
+ // valid login & token auth
+ $rc = $this->authenticate($user['login'], $user['tokenAuth']);
+ $this->assertSuperUserLogin($rc, 'user');
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAuthenticateSuccessLoginAndHashedTokenAuth()
+ {
+ $user = $this->_setUpUser();
+ $hash = \Piwik\Plugins\Login\SessionInitializer::getHashTokenAuth($user['login'], $user['tokenAuth']);
+
+ // valid login & hashed token auth
+ $rc = $this->authenticate($user['login'], $tokenAuth = $hash);
+ $this->assertUserLogin($rc);
+ }
+
+ protected function _setUpUser()
+ {
+ $user = array('login' => 'user',
+ 'password' => 'geqgeagae',
+ 'email' => 'test@test.com',
+ 'alias' => 'alias',
+ 'superuser_access' => 0);
+
+ API::getInstance()->addUser($user['login'], $user['password'], $user['email'], $user['alias']);
+
+ $user['tokenAuth'] = API::getInstance()->getTokenAuth($user['login'], md5($user['password']));
+
+ return $user;
+ }
+
+ private function _setUpSuperUserAccessViaDb()
+ {
+ API::getInstance()->setSuperUserAccess('user', true);
+ }
+
+ private function authenticate($login, $tokenAuth)
+ {
+ $this->auth->setLogin($login);
+ $this->auth->setTokenAuth($tokenAuth);
+
+ return $this->auth->authenticate();
+ }
+
+ private function assertFailedLogin(AuthResult $authResult)
+ {
+ $this->assertEquals(AuthResult::FAILURE, $authResult->getCode());
+ }
+
+ private function assertSuperUserLogin(AuthResult $authResult, $login = 'superUserLogin', $tokenLength = 32)
+ {
+ $this->assertEquals(AuthResult::SUCCESS_SUPERUSER_AUTH_CODE, $authResult->getCode());
+ $this->assertEquals($login, $authResult->getIdentity());
+ $this->assertEquals($tokenLength, strlen($authResult->getTokenAuth()));
+ }
+
+ private function assertUserLogin(AuthResult $authResult, $login = 'user', $tokenLength = 32)
+ {
+ $this->assertEquals(AuthResult::SUCCESS, $authResult->getCode());
+ $this->assertEquals($login, $authResult->getIdentity());
+ $this->assertEquals($tokenLength, strlen($authResult->getTokenAuth()));
+ }
+
+}
diff --git a/plugins/MobileMessaging/tests/Integration/MobileMessagingTest.php b/plugins/MobileMessaging/tests/Integration/MobileMessagingTest.php
new file mode 100644
index 0000000000..f387534bf3
--- /dev/null
+++ b/plugins/MobileMessaging/tests/Integration/MobileMessagingTest.php
@@ -0,0 +1,262 @@
+<?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\Plugins\MobileMessaging\tests\Integration;
+
+use Piwik\Access;
+use Piwik\Plugins\MobileMessaging\API as APIMobileMessaging;
+use Piwik\Plugins\MobileMessaging\MobileMessaging;
+use Piwik\Plugins\MobileMessaging\SMSProvider;
+use Piwik\Plugins\ScheduledReports\API as APIScheduledReports;
+use Piwik\Plugins\SitesManager\API as APISitesManager;
+use Piwik\Tests\Impl\IntegrationTestCase;
+use FakeAccess;
+
+/**
+ * Class Plugins_MobileMessagingTest
+ *
+ * @group Plugins
+ */
+class MobileMessagingTest extends IntegrationTestCase
+{
+ protected $idSiteAccess;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ // setup the access layer
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::$superUser = true;
+ //finally we set the user as a Super User by default
+ Access::setSingletonInstance($pseudoMockAccess);
+
+ $this->idSiteAccess = APISitesManager::getInstance()->addSite("test", "http://test");
+
+ \Piwik\Plugin\Manager::getInstance()->loadPlugins(array('ScheduledReports', 'MobileMessaging', 'MultiSites'));
+ \Piwik\Plugin\Manager::getInstance()->installLoadedPlugins();
+ }
+
+ /**
+ * When the MultiSites plugin is not activated, the SMS content should invite the user to activate it back
+ *
+ * @group Plugins
+ */
+ public function testWarnUserViaSMSMultiSitesDeactivated()
+ {
+ // safety net
+ \Piwik\Plugin\Manager::getInstance()->loadPlugins(array('ScheduledReports', 'MobileMessaging'));
+ $this->assertFalse(\Piwik\Plugin\Manager::getInstance()->isPluginActivated('MultiSites'));
+
+ $APIScheduledReports = APIScheduledReports::getInstance();
+ $reportId = $APIScheduledReports->addReport(
+ $this->idSiteAccess,
+ 'description',
+ 'month',
+ 0,
+ 'mobile',
+ 'sms',
+ array(),
+ array("phoneNumbers" => array('33698896656'))
+ );
+
+ list($outputFilename, $prettyDate, $websiteName, $additionalFiles) =
+ $APIScheduledReports->generateReport(
+ $reportId,
+ '01-01-2010',
+ 'en',
+ 2
+ );
+
+ $handle = fopen($outputFilename, "r");
+ $contents = fread($handle, filesize($outputFilename));
+ fclose($handle);
+
+ $this->assertEquals(
+ \Piwik\Piwik::translate('MobileMessaging_MultiSites_Must_Be_Activated'),
+ $contents
+ );
+ }
+
+ /**
+ * Dataprovider for testTruncate
+ */
+ public function getTruncateTestCases()
+ {
+
+ $stdGSMx459 = str_repeat('a', 459);
+
+ $extGSMx229 = str_repeat('€', 229);
+
+ $alternatedGSMx153 = str_repeat('a€', 153);
+
+ $GSMWithRegExpSpecialChars = $stdGSMx459 . '[\^$.|?*/+()';
+
+ $UCS2x201 = str_repeat('控', 201);
+
+ // appended strings
+ $stdGSMAppendedString = 'too long';
+ $extGSMAppendedString = '[too long]';
+ $UCS2AppendedString = '[控控]';
+
+ return array(
+
+ // maximum number of standard GSM characters
+ array($stdGSMx459, $stdGSMx459, 3, 'N/A'),
+
+ // maximum number of extended GSM characters
+ array($extGSMx229, $extGSMx229, 3, 'N/A'),
+
+ // maximum number of alternated GSM characters
+ array($alternatedGSMx153, $alternatedGSMx153, 3, 'N/A'),
+
+ // standard GSM, one 'a' too many, appended with standard GSM characters
+ array(str_repeat('a', 451) . $stdGSMAppendedString, $stdGSMx459 . 'a', 3, $stdGSMAppendedString),
+
+ // standard GSM, one 'a' too many, appended with extended GSM characters
+ array(str_repeat('a', 447) . $extGSMAppendedString, $stdGSMx459 . 'a', 3, $extGSMAppendedString),
+
+ // standard GSM, one 'a' too many, appended with UCS2 characters
+ array(str_repeat('a', 197) . $UCS2AppendedString, $stdGSMx459 . 'a', 3, $UCS2AppendedString),
+
+ // extended GSM, one '€' too many, appended with standard GSM characters
+ array(str_repeat('€', 225) . $stdGSMAppendedString, $extGSMx229 . '€', 3, $stdGSMAppendedString),
+
+ // extended GSM, one '€' too many, appended with extended GSM characters
+ array(str_repeat('€', 223) . $extGSMAppendedString, $extGSMx229 . '€', 3, $extGSMAppendedString),
+
+ // extended GSM, one '€' too many, appended with UCS2 characters
+ array(str_repeat('€', 197) . $UCS2AppendedString, $extGSMx229 . '€', 3, $UCS2AppendedString),
+
+ // alternated GSM, one 'a' too many, appended with standard GSM characters
+ array(str_repeat('a€', 150) . 'a' . $stdGSMAppendedString, $alternatedGSMx153 . 'a', 3, $stdGSMAppendedString),
+
+ // alternated GSM, one 'a' too many, appended with extended GSM characters
+ array(str_repeat('a€', 149) . $extGSMAppendedString, $alternatedGSMx153 . 'a', 3, $extGSMAppendedString),
+
+ // alternated GSM, one 'a' too many, appended with UCS2 characters
+ array(str_repeat('a€', 98) . 'a' . $UCS2AppendedString, $alternatedGSMx153 . 'a', 3, $UCS2AppendedString),
+
+ // alternated GSM, one '€' too many, appended with standard GSM characters
+ array(str_repeat('a€', 150) . 'a' . $stdGSMAppendedString, $alternatedGSMx153 . '€', 3, $stdGSMAppendedString),
+
+ // alternated GSM, one '€' too many, appended with extended GSM characters
+ array(str_repeat('a€', 149) . $extGSMAppendedString, $alternatedGSMx153 . '€', 3, $extGSMAppendedString),
+
+ // alternated GSM, one '€' too many, appended with UCS2 characters
+ array(str_repeat('a€', 98) . 'a' . $UCS2AppendedString, $alternatedGSMx153 . '€', 3, $UCS2AppendedString),
+
+ // GSM with RegExp reserved special chars
+ array(str_repeat('a', 451) . $stdGSMAppendedString, $GSMWithRegExpSpecialChars, 3, $stdGSMAppendedString),
+
+ // maximum number of UCS-2 characters
+ array($UCS2x201, $UCS2x201, 3, 'N/A'),
+
+ // UCS-2, one '控' too many, appended with UCS2 characters
+ array(str_repeat('控', 197) . $UCS2AppendedString, $UCS2x201 . '控', 3, $UCS2AppendedString),
+
+ // UCS-2, one '控' too many, appended with standard GSM characters
+ array(str_repeat('控', 193) . $stdGSMAppendedString, $UCS2x201 . '控', 3, $stdGSMAppendedString)
+ );
+ }
+
+ /**
+ * @group Plugins
+ *
+ * @dataProvider getTruncateTestCases
+ */
+ public function testTruncate($expected, $stringToTruncate, $maximumNumberOfConcatenatedSMS, $appendedString)
+ {
+ $this->assertEquals(
+ $expected,
+ SMSProvider::truncate($stringToTruncate, $maximumNumberOfConcatenatedSMS, $appendedString)
+ );
+ }
+
+ /**
+ * Dataprovider for testContainsUCS2Characters
+ */
+ public function getContainsUCS2CharactersTestCases()
+ {
+ return array(
+ array(false, 'too long'),
+ array(false, '[too long]'),
+ array(false, '€'),
+ array(true, '[控控]'),
+ );
+ }
+
+ /**
+ * @group Plugins
+ *
+ * @dataProvider getContainsUCS2CharactersTestCases
+ */
+ public function testContainsUCS2Characters($expected, $stringToTest)
+ {
+ $this->assertEquals(
+ $expected,
+ SMSProvider::containsUCS2Characters($stringToTest)
+ );
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testSanitizePhoneNumber()
+ {
+ $this->assertEquals('676932647', APIMobileMessaging::sanitizePhoneNumber(' 6 76 93 26 47'));
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testPhoneNumberIsSanitized()
+ {
+ $mobileMessagingAPI = APIMobileMessaging::getInstance();
+ $mobileMessagingAPI->setSMSAPICredential('StubbedProvider', '');
+ $mobileMessagingAPI->addPhoneNumber(' 6 76 93 26 47');
+ $this->assertEquals('676932647', key($mobileMessagingAPI->getPhoneNumbers()));
+ }
+
+ /**
+ * Dataprovider for testSendReport
+ */
+ public function getSendReportTestCases()
+ {
+ return array(
+ array('reportContent', '0101010101', 'Piwik.org', 'reportContent', '0101010101', 'Piwik.org'),
+ array('reportContent', '0101010101', 'General_Reports', 'reportContent', '0101010101', 'General_MultiSitesSummary'),
+ );
+ }
+
+ /**
+ * @group Plugins
+ *
+ * @dataProvider getSendReportTestCases
+ */
+ public function testSendReport($expectedReportContent, $expectedPhoneNumber, $expectedFrom, $reportContent, $phoneNumber, $reportSubject)
+ {
+ $report = array(
+ 'parameters' => array(MobileMessaging::PHONE_NUMBERS_PARAMETER => array($phoneNumber)),
+ );
+
+ $stubbedAPIMobileMessaging = $this->getMock('\\Piwik\\Plugins\\MobileMessaging\\API', array('sendSMS', 'getInstance'), $arguments = array(), $mockClassName = '', $callOriginalConstructor = false);
+ $stubbedAPIMobileMessaging->expects($this->once())->method('sendSMS')->with(
+ $this->equalTo($expectedReportContent, 0),
+ $this->equalTo($expectedPhoneNumber, 1),
+ $this->equalTo($expectedFrom, 2)
+ );
+
+ \Piwik\Plugins\MobileMessaging\API::setSingletonInstance($stubbedAPIMobileMessaging);
+
+ $mobileMessaging = new MobileMessaging();
+ $mobileMessaging->sendReport(MobileMessaging::MOBILE_TYPE, $report, $reportContent, null, null, $reportSubject, null, null, null, false);
+
+ \Piwik\Plugins\MobileMessaging\API::unsetInstance();
+ }
+}
diff --git a/plugins/MultiSites/tests/Integration/MultiSitesTest.php b/plugins/MultiSites/tests/Integration/MultiSitesTest.php
new file mode 100644
index 0000000000..a5f372b7a5
--- /dev/null
+++ b/plugins/MultiSites/tests/Integration/MultiSitesTest.php
@@ -0,0 +1,52 @@
+<?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\Plugins\MultiSites\tests\Integration;
+
+use Piwik\Access;
+use Piwik\Plugins\MultiSites\API as APIMultiSites;
+use Piwik\Plugins\SitesManager\API as APISitesManager;
+use Piwik\Tests\Impl\IntegrationTestCase;
+
+/**
+ * Class Plugins_MultiSitesTest
+ *
+ * @group Plugins
+ */
+class MultiSitesTest extends IntegrationTestCase
+{
+ protected $idSiteAccess;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $access = Access::getInstance();
+ $access->setSuperUserAccess(true);
+
+ $this->idSiteAccess = APISitesManager::getInstance()->addSite("test", "http://test");
+
+ \Piwik\Plugin\Manager::getInstance()->loadPlugins(array('MultiSites', 'VisitsSummary', 'Actions'));
+ \Piwik\Plugin\Manager::getInstance()->installLoadedPlugins();
+ }
+
+ /**
+ * Testing that getOne returns a row even when there are no data
+ * This is necessary otherwise ResponseBuilder throws 'Call to a member function getColumns() on a non-object'
+ *
+ * @group Plugins
+ */
+ public function testWhenNoDataGetOneReturnsRow()
+ {
+ $dataTable = APIMultiSites::getInstance()->getOne($this->idSiteAccess, 'month', '01-01-2010');
+ $this->assertEquals(1, $dataTable->getRowsCount());
+
+ // safety net
+ $this->assertEquals(0, $dataTable->getFirstRow()->getColumn('nb_visits'));
+ }
+}
diff --git a/plugins/PrivacyManager/tests/Integration/PrivacyManagerConfigTest.php b/plugins/PrivacyManager/tests/Integration/PrivacyManagerConfigTest.php
new file mode 100644
index 0000000000..07092248fe
--- /dev/null
+++ b/plugins/PrivacyManager/tests/Integration/PrivacyManagerConfigTest.php
@@ -0,0 +1,102 @@
+<?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\Plugins\PrivacyManager\tests;
+
+use Piwik\Option;
+use Piwik\Plugins\PrivacyManager\Config as PrivacyManagerConfig;
+use Piwik\Tests\Impl\IntegrationTestCase;
+
+/**
+ * Class Plugins_SitesManagerTest
+ *
+ * @group Plugins
+ */
+class PrivacyManagerConfigTest extends IntegrationTestCase
+{
+ /**
+ * @var PrivacyManagerConfig
+ */
+ private $config;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->config = new PrivacyManagerConfig();
+ }
+
+ public function test_useAnonymizedIpForVisitEnrichment()
+ {
+ $this->assertTrue($this->config->useAnonymizedIpForVisitEnrichment);
+
+ $this->config->useAnonymizedIpForVisitEnrichment = false;
+
+ $this->assertFalse($this->config->useAnonymizedIpForVisitEnrichment);
+
+ $this->config->useAnonymizedIpForVisitEnrichment = true;
+
+ $this->assertTrue($this->config->useAnonymizedIpForVisitEnrichment);
+ }
+
+ public function test_doNotTrackEnabled()
+ {
+ $this->assertTrue($this->config->doNotTrackEnabled);
+
+ $this->config->doNotTrackEnabled = true;
+
+ $this->assertTrue($this->config->doNotTrackEnabled);
+
+ $this->config->doNotTrackEnabled = false;
+
+ $this->assertFalse($this->config->doNotTrackEnabled);
+ }
+
+ public function test_ipAnonymizerEnabled()
+ {
+ $this->assertFalse($this->config->ipAnonymizerEnabled);
+
+ $this->config->ipAnonymizerEnabled = true;
+
+ $this->assertTrue($this->config->ipAnonymizerEnabled);
+ }
+
+ public function test_ipAddressMaskLength()
+ {
+ $this->assertSame(1, $this->config->ipAddressMaskLength);
+
+ $this->config->ipAddressMaskLength = '19';
+
+ $this->assertSame(19, $this->config->ipAddressMaskLength);
+ }
+
+ public function test_setTrackerCacheContent()
+ {
+ $content = $this->config->setTrackerCacheGeneral(array('existingEntry' => 'test'));
+
+ $expected = array(
+ 'existingEntry' => 'test',
+ 'PrivacyManager.ipAddressMaskLength' => 1,
+ 'PrivacyManager.ipAnonymizerEnabled' => false,
+ 'PrivacyManager.doNotTrackEnabled' => true,
+ 'PrivacyManager.useAnonymizedIpForVisitEnrichment' => true,
+ );
+
+ $this->assertEquals($expected, $content);
+ }
+
+ public function test_setTrackerCacheContent_ShouldGetValuesFromConfig()
+ {
+ Option::set('PrivacyManager.ipAddressMaskLength', '232');
+
+ $content = $this->config->setTrackerCacheGeneral(array('existingEntry' => 'test'));
+
+ $this->assertEquals(232, $content['PrivacyManager.ipAddressMaskLength']);
+ }
+
+}
diff --git a/plugins/PrivacyManager/tests/Integration/PrivacyManagerTest.php b/plugins/PrivacyManager/tests/Integration/PrivacyManagerTest.php
new file mode 100644
index 0000000000..50fce5f0a7
--- /dev/null
+++ b/plugins/PrivacyManager/tests/Integration/PrivacyManagerTest.php
@@ -0,0 +1,86 @@
+<?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\Plugins\PrivacyManager\tests;
+
+use Piwik\Plugins\PrivacyManager\PrivacyManager;
+use Piwik\Tests\Impl\IntegrationTestCase;
+
+/**
+ * Class Plugins_SitesManagerTest
+ *
+ * @group Plugins
+ */
+class PrivacyManagerTest extends IntegrationTestCase
+{
+ /**
+ * @var PrivacyManager
+ */
+ private $manager;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->manager = new PrivacyManager();
+ \Piwik\Option::set('delete_logs_enable', 1);
+ \Piwik\Option::set('delete_logs_older_than', 270);
+ \Piwik\Option::set('delete_reports_keep_week_reports', 1);
+ }
+
+ public function test_getPurgeDataSettings_shouldUseOnlyConfigValuesIfUIisDisabled()
+ {
+ $this->setUIEnabled(false);
+
+ $settings = $this->manager->getPurgeDataSettings();
+ $expected = $this->getDefaultPurgeSettings();
+
+ $this->assertEquals($expected, $settings);
+ }
+
+ public function test_getPurgeDataSettings_shouldAlsoUseOptionValuesIfUIisEnabled()
+ {
+ $this->setUIEnabled(true);
+
+ $settings = $this->manager->getPurgeDataSettings();
+ $expected = $this->getDefaultPurgeSettings();
+
+ $expected['delete_logs_enable'] = 1;
+ $expected['delete_logs_older_than'] = 270;
+ $expected['delete_reports_keep_week_reports'] = 1;
+
+ $this->assertEquals($expected, $settings);
+ }
+
+ private function setUIEnabled($enabled)
+ {
+ \Piwik\Config::getInstance()->General['enable_delete_old_data_settings_admin'] = $enabled;
+ }
+
+ private function getDefaultPurgeSettings()
+ {
+ $expected = array(
+ 'delete_logs_enable' => 0,
+ 'delete_logs_schedule_lowest_interval' => 7,
+ 'delete_logs_older_than' => 180,
+ 'delete_logs_max_rows_per_query' => 100000,
+ 'enable_auto_database_size_estimate' => 1,
+ 'delete_reports_enable' => 0,
+ 'delete_reports_older_than' => 12,
+ 'delete_reports_keep_basic_metrics' => 1,
+ 'delete_reports_keep_day_reports' => 0,
+ 'delete_reports_keep_week_reports' => 0,
+ 'delete_reports_keep_month_reports' => 1,
+ 'delete_reports_keep_year_reports' => 1,
+ 'delete_reports_keep_range_reports' => 0,
+ 'delete_reports_keep_segment_reports' => 0,
+ );
+ return $expected;
+ }
+
+}
diff --git a/plugins/PrivacyManager/tests/Unit/AnonymizeIPTest.php b/plugins/PrivacyManager/tests/Unit/AnonymizeIPTest.php
new file mode 100644
index 0000000000..0ed4e6e4ca
--- /dev/null
+++ b/plugins/PrivacyManager/tests/Unit/AnonymizeIPTest.php
@@ -0,0 +1,92 @@
+<?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\Plugins\PrivacyManager\tests;
+
+use Piwik\IP;
+use Piwik\Plugins\PrivacyManager\IPAnonymizer;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/PrivacyManager/IPAnonymizer.php';
+
+class AnonymizeIPTest extends \PHPUnit_Framework_TestCase
+{
+ // IPv4 addresses and expected results
+ public function getipv4Addresses()
+ {
+ return array(
+ // ip, array( expected0, expected1, expected2, expected3, expected4 ),
+ array('0.0.0.0', array("\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('0.0.0.1', array("\x00\x00\x00\x01", "\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('0.0.0.255', array("\x00\x00\x00\xff", "\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('0.0.1.0', array("\x00\x00\x01\x00", "\x00\x00\x01\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('0.0.1.1', array("\x00\x00\x01\x01", "\x00\x00\x01\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('0.0.255.255', array("\x00\x00\xff\xff", "\x00\x00\xff\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('0.1.0.0', array("\x00\x01\x00\x00", "\x00\x01\x00\x00", "\x00\x01\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('0.1.1.1', array("\x00\x01\x01\x01", "\x00\x01\x01\x00", "\x00\x01\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('0.255.255.255', array("\x00\xff\xff\xff", "\x00\xff\xff\x00", "\x00\xff\x00\x00", "\x00\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('1.0.0.0', array("\x01\x00\x00\x00", "\x01\x00\x00\x00", "\x01\x00\x00\x00", "\x01\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('127.255.255.255', array("\x7f\xff\xff\xff", "\x7f\xff\xff\x00", "\x7f\xff\x00\x00", "\x7f\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('128.0.0.0', array("\x80\x00\x00\x00", "\x80\x00\x00\x00", "\x80\x00\x00\x00", "\x80\x00\x00\x00", "\x00\x00\x00\x00")),
+ array('255.255.255.255', array("\xff\xff\xff\xff", "\xff\xff\xff\x00", "\xff\xff\x00\x00", "\xff\x00\x00\x00", "\x00\x00\x00\x00")),
+ );
+ }
+
+ public function getipv6Addresses()
+ {
+ return array(
+ array('2001:db8:0:8d3:0:8a2e:70:7344', array(
+ "\x20\x01\x0d\xb8\x00\x00\x08\xd3\x00\x00\x8a\x2e\x00\x70\x73\x44",
+ "\x20\x01\x0d\xb8\x00\x00\x08\xd3\x00\x00\x00\x00\x00\x00\x00\x00", // mask 64 bits
+ "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // mask 80 bits
+ "\x20\x01\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" // mask 104 bits
+ )),
+ array('2001:6f8:900:724::2', array(
+ "\x20\x01\x06\xf8\x09\x00\x07\x24\x00\x00\x00\x00\x00\x00\x00\x02",
+ "\x20\x01\x06\xf8\x09\x00\x07\x24\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x20\x01\x06\xf8\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ "\x20\x01\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ ))
+ );
+ }
+
+ /**
+ * @dataProvider getipv4Addresses
+ * @group Plugins
+ */
+ public function testApplyIPMask($ip, $expected)
+ {
+ // each IP is tested with 0 to 4 octets masked
+ for ($maskLength = 0; $maskLength <= 4; $maskLength++) {
+ $res = IPAnonymizer::applyIPMask(IP::P2N($ip), $maskLength);
+ $this->assertEquals($expected[$maskLength], $res, "Got " . bin2hex($res) . ", Expected " . bin2hex($expected[$maskLength]));
+ }
+
+ // edge case (bounds check)
+ $this->assertEquals("\x00\x00\x00\x00", IPAnonymizer::applyIPMask(IP::P2N($ip), 5));
+
+ // mask IPv4 mapped addresses
+ for ($maskLength = 0; $maskLength <= 4; $maskLength++) {
+ $res = IPAnonymizer::applyIPMask(IP::P2N('::ffff:' . $ip), $maskLength);
+ $this->assertEquals($res, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" . $expected[$maskLength], "Got " . bin2hex($res) . ", Expected " . bin2hex($expected[$maskLength]));
+ }
+ $this->assertEquals("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\x00\x00\x00", IPAnonymizer::applyIPMask(IP::P2N('::ffff:' . $ip), 5));
+ }
+
+ /**
+ * @dataProvider getipv6Addresses
+ * @group Plugins
+ */
+ public function testApplyIPMask6($ip, $expected)
+ {
+ // each IP is tested with 0 to 4 octets masked
+ for ($maskLength = 0; $maskLength < 4; $maskLength++) {
+ $res = IPAnonymizer::applyIPMask(IP::P2N($ip), $maskLength);
+ $this->assertEquals($expected[$maskLength], $res, "Got " . bin2hex($res) . ", Expected " . bin2hex($expected[$maskLength]) . ", Mask Level " . $maskLength);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/Proxy/tests/Unit/ProxyTest.php b/plugins/Proxy/tests/Unit/ProxyTest.php
new file mode 100644
index 0000000000..fa0175d040
--- /dev/null
+++ b/plugins/Proxy/tests/Unit/ProxyTest.php
@@ -0,0 +1,48 @@
+<?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\Plugins\Proxy\tests\Unit;
+
+use Piwik\Plugins\Proxy\Controller;
+
+/**
+ * @group Proxy
+ * @group ProxyTest
+ * @group Plugins
+ */
+class ProxyTest extends \PHPUnit_Framework_TestCase
+{
+ public function getAcceptableRemoteUrls()
+ {
+ return array(
+ // piwik white list (and used in homepage)
+ array('http://piwik.org/', true),
+
+ array('http://piwik.org', true),
+ array('http://qa.piwik.org/', true),
+ array('http://forum.piwik.org/', true),
+ array('http://dev.piwik.org/', true),
+ array('http://demo.piwik.org/', true),
+
+ // not in the piwik white list
+ array('http://www.piwik.org/', false),
+ array('https://piwik.org/', false),
+ array('http://example.org/', false),
+ );
+ }
+
+ /**
+ * @dataProvider getAcceptableRemoteUrls
+ * @group Plugins
+ */
+ public function testIsAcceptableRemoteUrl($url, $expected)
+ {
+ $this->assertEquals($expected, Controller::isPiwikUrl($url));
+ }
+}
+
diff --git a/plugins/Referrers/tests/Unit/ReferrersTest.php b/plugins/Referrers/tests/Unit/ReferrersTest.php
new file mode 100644
index 0000000000..909e6bf65e
--- /dev/null
+++ b/plugins/Referrers/tests/Unit/ReferrersTest.php
@@ -0,0 +1,246 @@
+<?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\Plugins\Referrers\tests;
+
+use Piwik\DataTable;
+use Piwik\DataTable\Row;
+use Piwik\Period;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/Referrers/Referrers.php';
+
+class ReferrersTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * Dataprovider serving all search engine data
+ */
+ public function getSearchEngines()
+ {
+ include PIWIK_PATH_TEST_TO_ROOT . '/core/DataFiles/SearchEngines.php';
+
+ $searchEngines = array();
+ foreach ($GLOBALS['Piwik_SearchEngines'] as $url => $searchEngine) {
+ $searchEngines[] = array($url, $searchEngine);
+ }
+ return $searchEngines;
+ }
+
+ /**
+ * search engine has at least one keyword
+ *
+ * @group Plugins
+ *
+ * @dataProvider getSearchEngines
+ */
+ public function testMissingSearchEngineKeyword($url, $searchEngine)
+ {
+ // Get list of search engines and first appearing URL
+ static $searchEngines = array();
+
+ $name = parse_url('http://' . $url);
+ if (!array_key_exists($searchEngine[0], $searchEngines)) {
+ $searchEngines[$searchEngine[0]] = $url;
+
+ $this->assertTrue(!empty($searchEngine[1]), $name['host']);
+ }
+ }
+
+ /**
+ * search engine is defined in DataFiles/SearchEngines.php but there's no favicon
+ *
+ * @group Plugins
+ *
+ * @dataProvider getSearchEngines
+ */
+ public function testMissingSearchEngineIcons($url, $searchEngine)
+ {
+ // Get list of existing favicons
+ $favicons = scandir(PIWIK_PATH_TEST_TO_ROOT . '/plugins/Referrers/images/searchEngines/');
+
+ // Get list of search engines and first appearing URL
+ static $searchEngines = array();
+
+ $name = parse_url('http://' . $url);
+ if (!array_key_exists($searchEngine[0], $searchEngines)) {
+ $searchEngines[$searchEngine[0]] = $url;
+
+ $this->assertTrue(in_array($name['host'] . '.png', $favicons), $name['host']);
+ }
+ }
+
+ /**
+ * favicon exists but there's no corresponding search engine defined in DataFiles/SearchEngines.php
+ *
+ * @group Plugins
+ */
+ public function testObsoleteSearchEngineIcons()
+ {
+ include PIWIK_PATH_TEST_TO_ROOT . '/core/DataFiles/SearchEngines.php';
+
+ // Get list of search engines and first appearing URL
+ $searchEngines = array();
+ foreach ($GLOBALS['Piwik_SearchEngines'] as $url => $searchEngine) {
+ $name = parse_url('http://' . $url);
+ if (!array_key_exists($name['host'], $searchEngines)) {
+ $searchEngines[$name['host']] = true;
+ }
+ }
+
+ // Get list of existing favicons
+ $favicons = scandir(PIWIK_PATH_TEST_TO_ROOT . '/plugins/Referrers/images/searchEngines/');
+ foreach ($favicons as $name) {
+ if ($name[0] == '.' || strpos($name, 'xx.') === 0) {
+ continue;
+ }
+
+ $host = substr($name, 0, -4);
+ $this->assertTrue(array_key_exists($host, $searchEngines), $host);
+ }
+ }
+
+ /**
+ * get search engine host from url
+ *
+ * @group Plugins
+ */
+ public function testGetSearchEngineHostFromUrl()
+ {
+ $data = array(
+ 'http://www.google.com/cse' => array('www.google.com', 'www.google.com/cse'),
+ 'http://www.google.com' => array('www.google.com', 'www.google.com'),
+ );
+
+ foreach ($data as $url => $expected) {
+ $this->assertEquals($expected[0], \Piwik\Plugins\Referrers\getSearchEngineHostFromUrl($url));
+ $this->assertEquals($expected[1], \Piwik\Plugins\Referrers\getSearchEngineHostPathFromUrl($url));
+ }
+ }
+
+ /**
+ * Dataprovider for testGetSearchEngineUrlFromUrlAndKeyword
+ */
+ public function getSearchEngineUrlFromUrlAndKeywordTestData()
+ {
+ return array(
+ array('http://apollo.lv/portal/search/', 'piwik', 'http://apollo.lv/portal/search/?cof=FORID%3A11&q=piwik&search_where=www'),
+ array('http://bing.com/images/search', 'piwik', 'http://bing.com/images/search/?q=piwik'),
+ array('http://google.com', 'piwik', 'http://google.com/search?q=piwik'),
+ );
+ }
+
+ /**
+ * get search engine url from name and keyword
+ *
+ * @group Plugins
+ *
+ * @dataProvider getSearchEngineUrlFromUrlAndKeywordTestData
+ */
+ public function testGetSearchEngineUrlFromUrlAndKeyword($url, $keyword, $expected)
+ {
+ include PIWIK_PATH_TEST_TO_ROOT . '/core/DataFiles/SearchEngines.php';
+ $this->assertEquals($expected, \Piwik\Plugins\Referrers\getSearchEngineUrlFromUrlAndKeyword($url, $keyword));
+ }
+
+ /**
+ * Dataprovider for getSocialNetworkFromDomainTestData
+ */
+ public function getSocialNetworkFromDomainTestData()
+ {
+ return array(
+ array('http://www.facebook.com', 'Facebook'),
+ array('http://www.facebook.com/piwik', 'Facebook'),
+ array('http://m.facebook.com', 'Facebook'),
+ array('https://m.facebook.com', 'Facebook'),
+ array('m.facebook.com', 'Facebook'),
+ array('http://lastfm.com.tr', 'Last.fm'),
+ array('http://t.co/test', 'Twitter'),
+ array('http://xxt.co/test', \Piwik\Piwik::translate('General_Unknown')),
+ array('asdfasdfadsf.com', \Piwik\Piwik::translate('General_Unknown')),
+ array('http://xwayn.com', \Piwik\Piwik::translate('General_Unknown')),
+ array('http://live.com/test', \Piwik\Piwik::translate('General_Unknown')),
+ );
+ }
+
+ /**
+ * @group Plugins
+ *
+ * @dataProvider getSocialNetworkFromDomainTestData
+ */
+ public function testGetSocialNetworkFromDomain($url, $expected)
+ {
+ include PIWIK_INCLUDE_PATH . '/core/DataFiles/Socials.php';
+ $this->assertEquals($expected, \Piwik\Plugins\Referrers\getSocialNetworkFromDomain($url));
+ }
+
+ public function getSocialsLogoFromUrlTestData()
+ {
+ return array(
+ array('http://www.facebook.com', 'facebook.com.png'),
+ array('www.facebook.com', 'facebook.com.png',),
+ array('http://lastfm.com.tr', 'last.fm.png'),
+ array('http://asdfasdf.org/test', 'xx.png'),
+ array('http://www.google.com', 'xx.png'),
+ );
+ }
+
+ /**
+ * @group Plugins
+ *
+ * @dataProvider getSocialsLogoFromUrlTestData
+ */
+ public function testGetSocialsLogoFromUrl($url, $expected)
+ {
+ include PIWIK_INCLUDE_PATH . '/core/DataFiles/Socials.php';
+ $this->assertContains($expected, \Piwik\Plugins\Referrers\getSocialsLogoFromUrl($url));
+ }
+
+ public function isSocialUrlTestData()
+ {
+ return array(
+ array('http://www.facebook.com', 'Facebook', true),
+ array('http://www.facebook.com', 'Twitter', false),
+ array('http://m.facebook.com', false, true),
+ array('http://lastfm.com.tr', 'Last.fm', true),
+ array('http://asdfasdf.org/test', false, false),
+ array('http://asdfasdf.com/test', 'Facebook', false),
+ );
+ }
+
+ /**
+ * @group Plugins
+ *
+ * @dataProvider isSocialUrlTestData
+ */
+ public function testIsSocialUrl($url, $assumedSocial, $expected)
+ {
+ include PIWIK_INCLUDE_PATH . '/core/DataFiles/Socials.php';
+ $this->assertEquals($expected, \Piwik\Plugins\Referrers\isSocialUrl($url, $assumedSocial));
+ }
+
+ public function removeUrlProtocolTestData()
+ {
+ return array(
+ array('http://www.facebook.com', 'www.facebook.com'),
+ array('https://bla.fr', 'bla.fr'),
+ array('ftp://bla.fr', 'bla.fr'),
+ array('udp://bla.fr', 'bla.fr'),
+ array('bla.fr', 'bla.fr'),
+ array('ASDasdASDDasd', 'ASDasdASDDasd'),
+ );
+ }
+
+ /**
+ * @group Plugins
+ *
+ * @dataProvider removeUrlProtocolTestData
+ */
+ public function testRemoveUrlProtocol($url, $expected)
+ {
+ $this->assertEquals($expected, \Piwik\Plugins\Referrers\removeUrlProtocol($url));
+ }
+}
diff --git a/plugins/SEO/tests/Integration/SEOTest.php b/plugins/SEO/tests/Integration/SEOTest.php
new file mode 100644
index 0000000000..14f8666d61
--- /dev/null
+++ b/plugins/SEO/tests/Integration/SEOTest.php
@@ -0,0 +1,68 @@
+<?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\Plugins\SEO\tests\Integration;
+
+use Piwik\Access;
+use Piwik\DataTable\Renderer;
+use Piwik\Plugins\SEO\API;
+use FakeAccess;
+use Exception;
+
+/**
+ * @group SEO
+ * @group SEOTest
+ * @group Plugins
+ */
+class SEOTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ parent::setUp();
+
+ // setup the access layer
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::setIdSitesView(array(1, 2));
+ FakeAccess::setIdSitesAdmin(array(3, 4));
+
+ //finally we set the user as a Super User by default
+ FakeAccess::$superUser = true;
+ Access::setSingletonInstance($pseudoMockAccess);
+
+ $user_agents = array(
+ 'Mozilla/6.0 (Macintosh; I; Intel Mac OS X 11_7_9; de-LI; rv:1.9b4) Gecko/2012010317 Firefox/10.0a4',
+ 'Mozilla/5.0 (compatible; MSIE 10.6; Windows NT 6.1; Trident/5.0; InfoPath.2; SLCC1; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 2.0.50727) 3gpp-gba UNTRUSTED/1.0',
+ 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/18.6.872.0 Safari/535.2 UNTRUSTED/1.0 3gpp-gba UNTRUSTED/1.0',
+ 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1',
+ );
+
+ $_SERVER['HTTP_USER_AGENT'] = $user_agents[mt_rand(0, count($user_agents) - 1)];
+ }
+
+ /**
+ * tell us when the API is broken
+ */
+ public function test_API()
+ {
+ try {
+ $dataTable = API::getInstance()->getRank('http://www.microsoft.com/');
+ } catch(Exception $e) {
+ $this->markTestSkipped('A SEO http request failed, Skipping this test for now. Error was: '.$e->getMessage());
+ }
+ $renderer = Renderer::factory('php');
+ $renderer->setSerialize(false);
+ $ranks = $renderer->render($dataTable);
+ foreach ($ranks as $rank) {
+ $message = $rank['id'] . ' expected non-zero rank, got [' . $rank['rank'] . ']';
+ if(empty($rank['rank'])) {
+ $this->markTestSkipped("Skipped to avoid random build failure: " . $message);
+ }
+ $this->assertNotEmpty($rank['rank'], $message);
+ }
+ }
+}
diff --git a/plugins/ScheduledReports/tests/Integration/ApiTest.php b/plugins/ScheduledReports/tests/Integration/ApiTest.php
new file mode 100644
index 0000000000..be13cb2b10
--- /dev/null
+++ b/plugins/ScheduledReports/tests/Integration/ApiTest.php
@@ -0,0 +1,514 @@
+<?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\Plugins\ScheduledReports\tests;
+
+use Piwik\Access;
+use Piwik\Plugins\MobileMessaging\API as APIMobileMessaging;
+use Piwik\Plugins\MobileMessaging\MobileMessaging;
+use Piwik\Plugins\ScheduledReports\API as APIScheduledReports;
+use Piwik\Plugins\ScheduledReports\Menu;
+use Piwik\Plugins\ScheduledReports\Tasks;
+use Piwik\Plugins\SitesManager\API as APISitesManager;
+use Piwik\ScheduledTask;
+use Piwik\ScheduledTime\Monthly;
+use Piwik\ScheduledTime;
+use Piwik\Site;
+use Piwik\Tests\Impl\IntegrationTestCase;
+use FakeAccess;
+use Exception;
+use ReflectionMethod;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/ScheduledReports/ScheduledReports.php';
+
+/**
+ * Class Plugins_ScheduledReportsTest
+ *
+ * @group Plugins
+ * @group ScheduledReportsTest
+ */
+class ApiTest extends IntegrationTestCase
+{
+ private $idSite = 1;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ // setup the access layer
+ self::setSuperUser();
+ \Piwik\Plugin\Manager::getInstance()->loadPlugins(array('API', 'UserCountry', 'ScheduledReports', 'MobileMessaging'));
+ \Piwik\Plugin\Manager::getInstance()->installLoadedPlugins();
+
+ APISitesManager::getInstance()->addSite("Test", array("http://piwik.net"));
+
+ APISitesManager::getInstance()->addSite("Test", array("http://piwik.net"));
+ FakeAccess::setIdSitesView(array($this->idSite, 2));
+ APIScheduledReports::$cache = array();
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAddReportGetReports()
+ {
+ $data = array(
+ 'idsite' => $this->idSite,
+ 'description' => 'test description"',
+ 'type' => 'email',
+ 'period' => ScheduledTime::PERIOD_DAY,
+ 'hour' => '4',
+ 'format' => 'pdf',
+ 'reports' => array('UserCountry_getCountry'),
+ 'parameters' => array(
+ 'displayFormat' => '1',
+ 'emailMe' => true,
+ 'additionalEmails' => array('test@test.com', 't2@test.com'),
+ 'evolutionGraph' => true
+ )
+ );
+
+ $dataWebsiteTwo = $data;
+ $dataWebsiteTwo['idsite'] = 2;
+ $dataWebsiteTwo['period'] = ScheduledTime::PERIOD_MONTH;
+
+ self::addReport($dataWebsiteTwo);
+
+ // Testing getReports without parameters
+ $tmp = APIScheduledReports::getInstance()->getReports();
+ $report = reset($tmp);
+ $this->assertReportsEqual($report, $dataWebsiteTwo);
+
+ $idReport = self::addReport($data);
+
+ // Passing 3 parameters
+ $tmp = APIScheduledReports::getInstance()->getReports($this->idSite, $data['period'], $idReport);
+ $report = reset($tmp);
+ $this->assertReportsEqual($report, $data);
+
+ // Passing only idsite
+ $tmp = APIScheduledReports::getInstance()->getReports($this->idSite);
+ $report = reset($tmp);
+ $this->assertReportsEqual($report, $data);
+
+ // Passing only period
+ $tmp = APIScheduledReports::getInstance()->getReports($idSite = false, $data['period']);
+ $report = reset($tmp);
+ $this->assertReportsEqual($report, $data);
+
+ // Passing only idreport
+ $tmp = APIScheduledReports::getInstance()->getReports($idSite = false, $period = false, $idReport);
+ $report = reset($tmp);
+ $this->assertReportsEqual($report, $data);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetReportsIdReportNotFound()
+ {
+ try {
+ APIScheduledReports::getInstance()->getReports($idSite = false, $period = false, $idReport = 1);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetReportsInvalidPermission()
+ {
+ try {
+ APIScheduledReports::getInstance()->getReports(
+ $idSite = 44,
+ $period = false,
+ self::addReport(self::getDailyPDFReportData($this->idSite))
+ );
+
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAddReportInvalidWebsite()
+ {
+ try {
+ self::addReport(self::getDailyPDFReportData(33));
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAddReportInvalidPeriod()
+ {
+ try {
+ $data = self::getDailyPDFReportData($this->idSite);
+ $data['period'] = 'dx';
+ self::addReport($data);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testUpdateReport()
+ {
+ $idReport = self::addReport(self::getDailyPDFReportData($this->idSite));
+ $dataAfter = self::getMonthlyEmailReportData($this->idSite);
+
+ self::updateReport($idReport, $dataAfter);
+
+ $reports = APIScheduledReports::getInstance()->getReports($idSite = false, $period = false, $idReport);
+
+ $this->assertReportsEqual(
+ reset($reports),
+ $dataAfter
+ );
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testDeleteReport()
+ {
+ // Deletes non existing report throws exception
+ try {
+ APIScheduledReports::getInstance()->deleteReport($idReport = 1);
+ $this->fail('Exception not raised');
+ } catch (Exception $e) {
+ }
+
+ $idReport = self::addReport(self::getMonthlyEmailReportData($this->idSite));
+ $this->assertEquals(1, count(APIScheduledReports::getInstance()->getReports()));
+ APIScheduledReports::getInstance()->deleteReport($idReport);
+ $this->assertEquals(0, count(APIScheduledReports::getInstance()->getReports()));
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetTopMenuTranslationKeyMobileMessagingInactive()
+ {
+ // unload MobileMessaging plugin
+ \Piwik\Plugin\Manager::getInstance()->loadPlugins(array('ScheduledReports'));
+
+ $pdfReportPlugin = new Menu();
+ $this->assertEquals(
+ Menu::PDF_REPORTS_TOP_MENU_TRANSLATION_KEY,
+ $pdfReportPlugin->getTopMenuTranslationKey()
+ );
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetTopMenuTranslationKeyUserIsAnonymous()
+ {
+ $anonymousAccess = new FakeAccess;
+ FakeAccess::$identity = 'anonymous';
+ Access::setSingletonInstance($anonymousAccess);
+
+ $pdfReportPlugin = new Menu();
+ $this->assertEquals(
+ Menu::MOBILE_MESSAGING_TOP_MENU_TRANSLATION_KEY,
+ $pdfReportPlugin->getTopMenuTranslationKey()
+ );
+ }
+
+ /**
+ * top menu should display 'Email & SMS reports' when the user has set-up a valid mobile provider account
+ * even though there is no sms reports configured
+ *
+ * @group Plugins
+ */
+ public function testGetTopMenuTranslationKeyNoReportMobileAccountOK()
+ {
+ // set mobile provider account
+ self::setSuperUser();
+ APIMobileMessaging::getInstance()->setSMSAPICredential('StubbedProvider', '');
+
+ $pdfReportPlugin = new Menu();
+ $this->assertEquals(
+ Menu::MOBILE_MESSAGING_TOP_MENU_TRANSLATION_KEY,
+ $pdfReportPlugin->getTopMenuTranslationKey()
+ );
+ }
+
+ /**
+ * top menu should display 'Email reports' when the user has not set-up a valid mobile provider account
+ * and no reports at all have been configured
+ *
+ * @group Plugins
+ */
+ public function testGetTopMenuTranslationKeyNoReportMobileAccountKO()
+ {
+ $pdfReportPlugin = new Menu();
+ $this->assertEquals(
+ Menu::PDF_REPORTS_TOP_MENU_TRANSLATION_KEY,
+ $pdfReportPlugin->getTopMenuTranslationKey()
+ );
+ }
+
+ /**
+ * top menu should display 'Email & SMS reports' if there is at least one sms report
+ * whatever the status of the mobile provider account
+ *
+ * @group Plugins
+ */
+ public function testGetTopMenuTranslationKeyOneSMSReportMobileAccountKO()
+ {
+ APIScheduledReports::getInstance()->addReport(
+ 1,
+ '',
+ ScheduledTime::PERIOD_DAY,
+ 0,
+ MobileMessaging::MOBILE_TYPE,
+ MobileMessaging::SMS_FORMAT,
+ array(),
+ array(
+ MobileMessaging::PHONE_NUMBERS_PARAMETER => array()
+ )
+ );
+
+ $pdfReportPlugin = new Menu();
+ $this->assertEquals(
+ Menu::MOBILE_MESSAGING_TOP_MENU_TRANSLATION_KEY,
+ $pdfReportPlugin->getTopMenuTranslationKey()
+ );
+ }
+
+ /**
+ * top menu should display 'Email reports' if there are no SMS reports and at least one email report
+ * whatever the status of the mobile provider account
+ *
+ * @group Plugins
+ */
+ public function testGetTopMenuTranslationKeyNoSMSReportAccountOK()
+ {
+ // set mobile provider account
+ self::setSuperUser();
+ APIMobileMessaging::getInstance()->setSMSAPICredential('StubbedProvider', '');
+
+ self::addReport(self::getMonthlyEmailReportData($this->idSite));
+
+ $pdfReportPlugin = new Menu();
+ $this->assertEquals(
+ Menu::PDF_REPORTS_TOP_MENU_TRANSLATION_KEY,
+ $pdfReportPlugin->getTopMenuTranslationKey()
+ );
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetScheduledTasks()
+ {
+ // stub API to control getReports() return values
+ $report1 = self::getDailyPDFReportData($this->idSite);
+ $report1['idreport'] = 1;
+ $report1['hour'] = 0;
+ $report1['deleted'] = 0;
+
+ $report2 = self::getMonthlyEmailReportData($this->idSite);
+ $report2['idreport'] = 2;
+ $report2['idsite'] = 2;
+ $report2['hour'] = 0;
+ $report2['deleted'] = 0;
+
+ $report3 = self::getMonthlyEmailReportData($this->idSite);
+ $report3['idreport'] = 3;
+ $report3['deleted'] = 1; // should not be scheduled
+
+ $report4 = self::getMonthlyEmailReportData($this->idSite);
+ $report4['idreport'] = 4;
+ $report4['idsite'] = 1;
+ $report4['hour'] = 8;
+ $report4['deleted'] = 0;
+
+ $report5 = self::getMonthlyEmailReportData($this->idSite);
+ $report5['idreport'] = 5;
+ $report5['idsite'] = 2;
+ $report5['hour'] = 8;
+ $report5['deleted'] = 0;
+
+ // test no exception is raised when a scheduled report is set to never send
+ $report6 = self::getMonthlyEmailReportData($this->idSite);
+ $report6['idreport'] = 6;
+ $report6['period'] = ScheduledTime::PERIOD_NEVER;
+ $report6['deleted'] = 0;
+
+ $stubbedAPIScheduledReports = $this->getMock('\\Piwik\\Plugins\\ScheduledReports\\API', array('getReports', 'getInstance'), $arguments = array(), $mockClassName = '', $callOriginalConstructor = false);
+ $stubbedAPIScheduledReports->expects($this->any())->method('getReports')->will($this->returnValue(
+ array($report1, $report2, $report3, $report4, $report5, $report6))
+ );
+ \Piwik\Plugins\ScheduledReports\API::setSingletonInstance($stubbedAPIScheduledReports);
+
+ // initialize sites 1 and 2
+ Site::setSites( array(
+ 1 => array('timezone' => 'Europe/Paris'),
+ 2 => array('timezone' => 'UTC-6.5'),
+ ));
+
+ // expected tasks
+ $scheduleTask1 = ScheduledTime::factory('daily');
+ $scheduleTask1->setHour(0); // paris is UTC-1, period ends at 23h UTC
+ $scheduleTask1->setTimezone('Europe/Paris');
+
+ $scheduleTask2 = new Monthly();
+ $scheduleTask2->setHour(0); // site is UTC-6.5, period ends at 6h30 UTC, smallest resolution is hour
+ $scheduleTask2->setTimezone('UTC-6.5');
+
+ $scheduleTask3 = new Monthly();
+ $scheduleTask3->setHour(8); // paris is UTC-1, configured to be sent at 8h
+ $scheduleTask3->setTimezone('Europe/Paris');
+
+ $scheduleTask4 = new Monthly();
+ $scheduleTask4->setHour(8); // site is UTC-6.5, configured to be sent at 8h
+ $scheduleTask4->setTimezone('UTC-6.5');
+
+ $expectedTasks = array(
+ new ScheduledTask (APIScheduledReports::getInstance(), 'sendReport', 1, $scheduleTask1),
+ new ScheduledTask (APIScheduledReports::getInstance(), 'sendReport', 2, $scheduleTask2),
+ new ScheduledTask (APIScheduledReports::getInstance(), 'sendReport', 4, $scheduleTask3),
+ new ScheduledTask (APIScheduledReports::getInstance(), 'sendReport', 5, $scheduleTask4),
+ );
+
+ $pdfReportPlugin = new Tasks();
+ $pdfReportPlugin->schedule();
+ $tasks = $pdfReportPlugin->getScheduledTasks();
+ $this->assertEquals($expectedTasks, $tasks);
+
+ \Piwik\Plugins\ScheduledReports\API::unsetInstance();
+
+ }
+
+ /**
+ * Dataprovider for testGetReportSubjectAndReportTitle
+ */
+ public function getGetReportSubjectAndReportTitleTestCases()
+ {
+ return array(
+ array('<Piwik.org>', '<Piwik.org>', '<Piwik.org>', array('UserSettings_getBrowserType')),
+ array('Piwik.org', 'Piwik.org', 'Piwik.org', array('MultiSites_getAll', 'UserSettings_getBrowserType')),
+ array('General_MultiSitesSummary', 'General_MultiSitesSummary', 'Piwik.org', array('MultiSites_getAll')),
+ );
+ }
+
+ /**
+ * @group Plugins
+ *
+ * @dataProvider getGetReportSubjectAndReportTitleTestCases
+ */
+ public function testGetReportSubjectAndReportTitle($expectedReportSubject, $expectedReportTitle, $websiteName, $reports)
+ {
+ $getReportSubjectAndReportTitle = new ReflectionMethod(
+ '\\Piwik\\Plugins\\ScheduledReports\\API', 'getReportSubjectAndReportTitle'
+ );
+ $getReportSubjectAndReportTitle->setAccessible(true);
+
+ list($reportSubject, $reportTitle) = $getReportSubjectAndReportTitle->invoke( APIScheduledReports::getInstance(), $websiteName, $reports);
+ $this->assertEquals($expectedReportSubject, $reportSubject);
+ $this->assertEquals($expectedReportTitle, $reportTitle);
+ }
+
+ private function assertReportsEqual($report, $data)
+ {
+ foreach ($data as $key => $value) {
+ if ($key == 'description') $value = substr($value, 0, 250);
+ $this->assertEquals($value, $report[$key], "Error for $key for report " . var_export($report, true) . " and data " . var_export($data, true));
+ }
+ }
+
+ private static function addReport($data)
+ {
+ $idReport = APIScheduledReports::getInstance()->addReport(
+ $data['idsite'],
+ $data['description'],
+ $data['period'],
+ $data['hour'],
+ $data['type'],
+ $data['format'],
+ $data['reports'],
+ $data['parameters']
+ );
+ return $idReport;
+ }
+
+ private static function getDailyPDFReportData($idSite)
+ {
+ return array(
+ 'idsite' => $idSite,
+ 'description' => 'test description"',
+ 'period' => ScheduledTime::PERIOD_DAY,
+ 'hour' => '7',
+ 'type' => 'email',
+ 'format' => 'pdf',
+ 'reports' => array('UserCountry_getCountry'),
+ 'parameters' => array(
+ 'displayFormat' => '1',
+ 'emailMe' => true,
+ 'additionalEmails' => array('test@test.com', 't2@test.com'),
+ 'evolutionGraph' => false
+ )
+ );
+ }
+
+ private static function getMonthlyEmailReportData($idSite)
+ {
+ return array(
+ 'idsite' => $idSite,
+ 'description' => 'very very long and possibly truncated description. very very long and possibly truncated description. very very long and possibly truncated description. very very long and possibly truncated description. very very long and possibly truncated description. ',
+ 'period' => ScheduledTime::PERIOD_MONTH,
+ 'hour' => '0',
+ 'type' => 'email',
+ 'format' => 'pdf',
+ 'reports' => array('UserCountry_getContinent'),
+ 'parameters' => array(
+ 'displayFormat' => '1',
+ 'emailMe' => false,
+ 'additionalEmails' => array('blabla@ec.fr'),
+ 'evolutionGraph' => false
+ )
+ );
+ }
+
+ private static function updateReport($idReport, $data)
+ {
+ $idReport = APIScheduledReports::getInstance()->updateReport(
+ $idReport,
+ $data['idsite'],
+ $data['description'],
+ $data['period'],
+ $data['hour'],
+ $data['type'],
+ $data['format'],
+ $data['reports'],
+ $data['parameters']);
+ return $idReport;
+ }
+
+ private static function setSuperUser()
+ {
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::$superUser = true;
+ Access::setSingletonInstance($pseudoMockAccess);
+ }
+}
diff --git a/plugins/ScheduledReports/tests/ScheduledReportsTest.php b/plugins/ScheduledReports/tests/Integration/ScheduledReportsTest.php
index d11a8e402e..b0bb56363f 100644
--- a/plugins/ScheduledReports/tests/ScheduledReportsTest.php
+++ b/plugins/ScheduledReports/tests/Integration/ScheduledReportsTest.php
@@ -12,14 +12,15 @@ use Piwik\Db;
use Piwik\Piwik;
use Piwik\Plugins\ScheduledReports\API;
use Piwik\Plugins\ScheduledReports\ScheduledReports;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group ScheduledReports
* @group ScheduledReportsTest
- * @group Database
+ * @group Plugins
*/
-class ScheduledReportsTest extends \DatabaseTestCase
+class ScheduledReportsTest extends IntegrationTestCase
{
/**
* @var ScheduledReports
diff --git a/plugins/SegmentEditor/tests/Integration/SegmentEditorTest.php b/plugins/SegmentEditor/tests/Integration/SegmentEditorTest.php
new file mode 100644
index 0000000000..e5d863e92c
--- /dev/null
+++ b/plugins/SegmentEditor/tests/Integration/SegmentEditorTest.php
@@ -0,0 +1,210 @@
+<?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\Plugins\SegmentEditor\tests\Integration;
+
+use Piwik\Access;
+use Piwik\Date;
+use Piwik\Piwik;
+use Piwik\Plugins\SegmentEditor\API;
+use Piwik\Plugins\SegmentEditor\Model;
+use Piwik\Plugins\SitesManager\API as APISitesManager;
+use Piwik\Tests\Impl\IntegrationTestCase;
+use FakeAccess;
+use Exception;
+
+/**
+ * Class Plugins_SegmentEditorTest
+ *
+ * @group Plugins
+ */
+class SegmentEditorTest extends IntegrationTestCase
+{
+ public function setUp()
+ {
+ parent::setUp();
+
+ \Piwik\Plugin\Manager::getInstance()->loadPlugin('SegmentEditor');
+ \Piwik\Plugin\Manager::getInstance()->installLoadedPlugins();
+
+ // setup the access layer
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::setIdSitesView(array(1, 2));
+ FakeAccess::setIdSitesAdmin(array(3, 4));
+
+ //finally we set the user as a Super User by default
+ FakeAccess::$superUser = true;
+ FakeAccess::$superUserLogin = 'superusertest';
+ Access::setSingletonInstance($pseudoMockAccess);
+
+ APISitesManager::getInstance()->addSite('test', 'http://example.org');
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAddInvalidSegment_ShouldThrow()
+ {
+ try {
+ API::getInstance()->add('name', 'test==test2');
+ $this->fail("Exception not raised.");
+ } catch (Exception $expected) {
+ }
+ try {
+ API::getInstance()->add('name', 'test');
+ $this->fail("Exception not raised.");
+ } catch (Exception $expected) {
+ }
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function test_AddAndGet_SimpleSegment()
+ {
+ $name = 'name';
+ $definition = 'searches>1,visitIp!=127.0.0.1';
+ $idSegment = API::getInstance()->add($name, $definition);
+ $this->assertEquals($idSegment, 1);
+ $segment = API::getInstance()->get($idSegment);
+ unset($segment['ts_created']);
+ $expected = array(
+ 'idsegment' => 1,
+ 'name' => $name,
+ 'definition' => $definition,
+ 'login' => 'superUserLogin',
+ 'enable_all_users' => '0',
+ 'enable_only_idsite' => '0',
+ 'auto_archive' => '0',
+ 'ts_last_edit' => null,
+ 'deleted' => '0',
+ );
+
+ $this->assertEquals($segment, $expected);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function test_AddAndGet_AnotherSegment()
+ {
+ $name = 'name';
+ $definition = 'searches>1,visitIp!=127.0.0.1';
+ $idSegment = API::getInstance()->add($name, $definition, $idSite = 1, $autoArchive = 1, $enabledAllUsers = 1);
+ $this->assertEquals($idSegment, 1);
+
+ // Testing get()
+ $segment = API::getInstance()->get($idSegment);
+ $expected = array(
+ 'idsegment' => '1',
+ 'name' => $name,
+ 'definition' => $definition,
+ 'login' => 'superUserLogin',
+ 'enable_all_users' => '1',
+ 'enable_only_idsite' => '1',
+ 'auto_archive' => '1',
+ 'ts_last_edit' => null,
+ 'deleted' => '0',
+ );
+ unset($segment['ts_created']);
+ $this->assertEquals($segment, $expected);
+
+ // There is a segment to process for this particular site
+ $model = new Model();
+ $segments = $model->getSegmentsToAutoArchive($idSite);
+ unset($segments[0]['ts_created']);
+ $this->assertEquals($segments, array($expected));
+
+ // There is no segment to process for a non existing site
+ try {
+ $model->getSegmentsToAutoArchive(33);
+ $this->fail();
+ } catch(Exception $e) {
+ // expected
+ }
+
+ // There is no segment to process across all sites
+ $segments = $model->getSegmentsToAutoArchive($idSite = false);
+ $this->assertEquals($segments, array());
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function test_UpdateSegment()
+ {
+ $name = 'name"';
+ $definition = 'searches>1,visitIp!=127.0.0.1';
+ $nameSegment1 = 'hello';
+ $idSegment1 = API::getInstance()->add($nameSegment1, 'searches==0', $idSite = 1, $autoArchive = 1, $enabledAllUsers = 1);
+ $idSegment2 = API::getInstance()->add($name, $definition, $idSite = 1, $autoArchive = 1, $enabledAllUsers = 1);
+
+ $updatedSegment = array(
+ 'idsegment' => $idSegment2,
+ 'name' => 'NEW name',
+ 'definition' => 'searches==0',
+ 'enable_only_idsite' => '0',
+ 'enable_all_users' => '0',
+ 'auto_archive' => '0',
+ 'ts_last_edit' => Date::now()->getDatetime(),
+ 'ts_created' => Date::now()->getDatetime(),
+ 'login' => Piwik::getCurrentUserLogin(),
+ 'deleted' => '0',
+ );
+ API::getInstance()->update($idSegment2,
+ $updatedSegment['name'],
+ $updatedSegment['definition'],
+ $updatedSegment['enable_only_idsite'],
+ $updatedSegment['auto_archive'],
+ $updatedSegment['enable_all_users']
+ );
+
+ $newSegment = API::getInstance()->get($idSegment2);
+
+ // avoid test failures for when ts_created/ts_last_edit are different by between 1/2 secs
+ $this->removeSecondsFromSegmentInfo($updatedSegment);
+ $this->removeSecondsFromSegmentInfo($newSegment);
+
+ $this->assertEquals($newSegment, $updatedSegment);
+
+ // Check the other segmenet was not updated
+ $newSegment = API::getInstance()->get($idSegment1);
+ $this->assertEquals($newSegment['name'], $nameSegment1);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function test_deleteSegment()
+ {
+ $idSegment1 = API::getInstance()->add('name 1', 'searches==0', $idSite = 1, $autoArchive = 1, $enabledAllUsers = 1);
+ $idSegment2 = API::getInstance()->add('name 2', 'searches>1,visitIp!=127.0.0.1', $idSite = 1, $autoArchive = 1, $enabledAllUsers = 1);
+
+ $deleted = API::getInstance()->delete($idSegment2);
+ $this->assertTrue($deleted);
+ try {
+ API::getInstance()->get($idSegment2);
+ $this->fail("getting deleted segment should have failed");
+ } catch(Exception $e) {
+ // expected
+ }
+
+ // and this should work
+ API::getInstance()->get($idSegment1);
+ }
+
+ private function removeSecondsFromSegmentInfo(&$segmentInfo)
+ {
+ $timestampProperties = array('ts_last_edit', 'ts_created');
+ foreach ($timestampProperties as $propertyName) {
+ if (isset($segmentInfo[$propertyName])) {
+ $segmentInfo[$propertyName] = substr($segmentInfo[$propertyName], 0, strlen($segmentInfo[$propertyName] - 2));
+ }
+ }
+ }
+}
diff --git a/plugins/SitesManager/tests/SiteUrlsTest.php b/plugins/SitesManager/tests/Integration/SiteUrlsTest.php
index e459efb0a6..8cc7cc5b14 100644
--- a/plugins/SitesManager/tests/SiteUrlsTest.php
+++ b/plugins/SitesManager/tests/Integration/SiteUrlsTest.php
@@ -6,17 +6,18 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
-namespace Piwik\Plugins\SitesManager\tests;
+namespace Piwik\Plugins\SitesManager\tests\Integration;
use Piwik\CacheFile;
use Piwik\Plugins\SitesManager\API;
use Piwik\Plugins\SitesManager\SiteUrls;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group SitesManager
* @group SiteUrlsTest
- * @group Database
+ * @group Plugins
*/
-class SiteUrlsTest extends \DatabaseTestCase
+class SiteUrlsTest extends IntegrationTestCase
{
/**
* @var SiteUrls
diff --git a/plugins/SitesManager/tests/Integration/SitesManagerTest.php b/plugins/SitesManager/tests/Integration/SitesManagerTest.php
new file mode 100644
index 0000000000..2d2ac466ef
--- /dev/null
+++ b/plugins/SitesManager/tests/Integration/SitesManagerTest.php
@@ -0,0 +1,1000 @@
+<?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\Plugins\SitesManager\tests\Integration;
+
+use Piwik\Access;
+use Piwik\Plugins\SitesManager\API;
+use Piwik\Plugins\UsersManager\API as APIUsersManager;
+use Piwik\Site;
+use Piwik\Tests\Impl\IntegrationTestCase;
+use FakeAccess;
+use Exception;
+use PHPUnit_Framework_Constraint_IsType;
+
+/**
+ * Class Plugins_SitesManagerTest
+ *
+ * @group Plugins
+ */
+class SitesManagerTest extends IntegrationTestCase
+{
+ public function setUp()
+ {
+ parent::setUp();
+
+ // setup the access layer
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::$superUser = true;
+ Access::setSingletonInstance($pseudoMockAccess);
+ }
+
+ /**
+ * empty name -> exception
+ *
+ * @group Plugins
+ */
+ public function testAddSiteEmptyName()
+ {
+ try {
+ API::getInstance()->addSite("", array("http://piwik.net"));
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * DataProvider for testAddSiteWrongUrls
+ */
+ public function getInvalidUrlData()
+ {
+ return array(
+ array(array()), // no urls
+ array(array("")),
+ array(""),
+ array("httpww://piwik.net"),
+ array("httpww://piwik.net/gqg~#"),
+ );
+ }
+
+ /**
+ * wrong urls -> exception
+ *
+ * @dataProvider getInvalidUrlData
+ * @group Plugins
+ */
+ public function testAddSiteWrongUrls($url)
+ {
+ try {
+ API::getInstance()->addSite("name", $url);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * Test with valid IPs
+ *
+ * @group Plugins
+ */
+ public function testAddSiteExcludedIpsAndtimezoneAndCurrencyAndExcludedQueryParametersValid()
+ {
+ $ips = '1.2.3.4,1.1.1.*,1.2.*.*,1.*.*.*';
+ $timezone = 'Europe/Paris';
+ $currency = 'EUR';
+ $excludedQueryParameters = 'p1,P2, P33333';
+ $expectedExcludedQueryParameters = 'p1,P2,P33333';
+ $excludedUserAgents = " p1,P2, \nP3333 ";
+ $expectedExcludedUserAgents = "p1,P2,P3333";
+ $expectedWebsiteType = 'mobile-\'app';
+ $keepUrlFragment = 1;
+ $idsite = API::getInstance()->addSite("name", "http://piwik.net/", $ecommerce = 1,
+ $siteSearch = 1, $searchKeywordParameters = 'search,param', $searchCategoryParameters = 'cat,category',
+ $ips, $excludedQueryParameters, $timezone, $currency, $group = null, $startDate = null, $excludedUserAgents,
+ $keepUrlFragment, $expectedWebsiteType);
+ $siteInfo = API::getInstance()->getSiteFromId($idsite);
+ $this->assertEquals($ips, $siteInfo['excluded_ips']);
+ $this->assertEquals($timezone, $siteInfo['timezone']);
+ $this->assertEquals($currency, $siteInfo['currency']);
+ $this->assertEquals($ecommerce, $siteInfo['ecommerce']);
+ $this->assertTrue(Site::isEcommerceEnabledFor($idsite));
+ $this->assertEquals($siteSearch, $siteInfo['sitesearch']);
+ $this->assertTrue(Site::isSiteSearchEnabledFor($idsite));
+ $this->assertEquals($expectedWebsiteType, $siteInfo['type']);
+ $this->assertEquals($expectedWebsiteType, Site::getTypeFor($idsite));
+
+ $this->assertEquals($searchKeywordParameters, $siteInfo['sitesearch_keyword_parameters']);
+ $this->assertEquals($searchCategoryParameters, $siteInfo['sitesearch_category_parameters']);
+ $this->assertEquals($expectedExcludedQueryParameters, $siteInfo['excluded_parameters']);
+ $this->assertEquals($expectedExcludedUserAgents, $siteInfo['excluded_user_agents']);
+ }
+
+ /**
+ * dataProvider for testAddSiteExcludedIpsNotValid
+ */
+ public function getInvalidIPsData()
+ {
+ return array(
+ array('35817587341'),
+ array('ieagieha'),
+ array('1.2.3'),
+ array('*.1.1.1'),
+ array('*.*.1.1'),
+ array('*.*.*.1'),
+ array('1.1.1.1.1'),
+ );
+ }
+
+ /**
+ * Test with invalid IPs
+ *
+ * @dataProvider getInvalidIPsData
+ * @group Plugins
+ */
+ public function testAddSiteExcludedIpsNotValid($ip)
+ {
+ try {
+ API::getInstance()->addSite("name", "http://piwik.net/", $ecommerce = 0,
+ $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, $ip);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * one url -> one main_url and nothing inserted as alias urls
+ *
+ * @group Plugins
+ */
+ public function testAddSiteOneUrl()
+ {
+ $url = "http://piwik.net/";
+ $urlOK = "http://piwik.net";
+ $idsite = API::getInstance()->addSite("name", $url);
+ $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_INT, $idsite);
+
+ $siteInfo = API::getInstance()->getSiteFromId($idsite);
+ $this->assertEquals($urlOK, $siteInfo['main_url']);
+ $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($siteInfo['ts_created'])));
+
+ $siteUrls = API::getInstance()->getSiteUrlsFromId($idsite);
+ $this->assertEquals(1, count($siteUrls));
+ }
+
+ /**
+ * several urls -> one main_url and others as alias urls
+ *
+ * @group Plugins
+ */
+ public function testAddSiteSeveralUrls()
+ {
+ $urls = array("http://piwik.net/", "http://piwik.com", "https://piwik.net/test/");
+ $urlsOK = array("http://piwik.net", "http://piwik.com", "https://piwik.net/test");
+ $idsite = API::getInstance()->addSite("super website", $urls);
+ $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_INT, $idsite);
+
+ $siteInfo = API::getInstance()->getSiteFromId($idsite);
+ $this->assertEquals($urlsOK[0], $siteInfo['main_url']);
+
+ $siteUrls = API::getInstance()->getSiteUrlsFromId($idsite);
+ $this->assertEquals($urlsOK, $siteUrls);
+ }
+
+ /**
+ * strange name
+ *
+ * @group Plugins
+ */
+ public function testAddSiteStrangeName()
+ {
+ $name = "supertest(); ~@@()''!£\$'%%^'!£ போ";
+ $idsite = API::getInstance()->addSite($name, "http://piwik.net");
+ $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_INT, $idsite);
+
+ $siteInfo = API::getInstance()->getSiteFromId($idsite);
+ $this->assertEquals($name, $siteInfo['name']);
+
+ }
+
+ /**
+ * adds a site
+ * use by several other unit tests
+ */
+ protected function _addSite()
+ {
+ $name = "website ";
+ $idsite = API::getInstance()->addSite($name, array("http://piwik.net", "http://piwik.com/test/"));
+ $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_INT, $idsite);
+
+ $siteInfo = API::getInstance()->getSiteFromId($idsite);
+ $this->assertEquals($name, $siteInfo['name']);
+ $this->assertEquals("http://piwik.net", $siteInfo['main_url']);
+
+ $siteUrls = API::getInstance()->getSiteUrlsFromId($idsite);
+ $this->assertEquals(array("http://piwik.net", "http://piwik.com/test"), $siteUrls);
+
+ return $idsite;
+ }
+
+ /**
+ * no duplicate -> all the urls are saved
+ *
+ * @group Plugins
+ */
+ public function testAddSiteUrlsnoDuplicate()
+ {
+ $idsite = $this->_addSite();
+
+ $siteUrlsBefore = API::getInstance()->getSiteUrlsFromId($idsite);
+
+ $toAdd = array("http://piwik1.net",
+ "http://piwik2.net",
+ "http://piwik3.net/test/",
+ "http://localhost/test",
+ "http://localho5.st/test",
+ "http://l42578gqege.f4",
+ "http://super.com/test/test/atqata675675/te"
+ );
+ $toAddValid = array("http://piwik1.net",
+ "http://piwik2.net",
+ "http://piwik3.net/test",
+ "http://localhost/test",
+ "http://localho5.st/test",
+ "http://l42578gqege.f4",
+ "http://super.com/test/test/atqata675675/te");
+
+ $insertedUrls = API::getInstance()->addSiteAliasUrls($idsite, $toAdd);
+ $this->assertEquals(count($toAdd), $insertedUrls);
+
+ $siteUrlsAfter = API::getInstance()->getSiteUrlsFromId($idsite);
+
+ $shouldHave = array_merge($siteUrlsBefore, $toAddValid);
+ sort($shouldHave);
+
+ sort($siteUrlsAfter);
+
+ $this->assertEquals($shouldHave, $siteUrlsAfter);
+ }
+
+ /**
+ * duplicate -> don't save the already existing URLs
+ *
+ * @group Plugins
+ */
+ public function testAddSiteUrlsDuplicate()
+ {
+ $idsite = $this->_addSite();
+
+ $siteUrlsBefore = API::getInstance()->getSiteUrlsFromId($idsite);
+
+ $toAdd = array_merge($siteUrlsBefore, array("http://piwik1.net", "http://piwik2.net"));
+
+ $insertedUrls = API::getInstance()->addSiteAliasUrls($idsite, $toAdd);
+ $this->assertEquals(count($toAdd) - count($siteUrlsBefore), $insertedUrls);
+
+ $siteUrlsAfter = API::getInstance()->getSiteUrlsFromId($idsite);
+
+ $shouldHave = $toAdd;
+ sort($shouldHave);
+
+ sort($siteUrlsAfter);
+
+ $this->assertEquals($shouldHave, $siteUrlsAfter);
+ }
+
+ /**
+ * case empty array => nothing happens
+ *
+ * @group Plugins
+ */
+ public function testAddSiteUrlsNoUrlsToAdd1()
+ {
+ $idsite = $this->_addSite();
+
+ $siteUrlsBefore = API::getInstance()->getSiteUrlsFromId($idsite);
+
+ $toAdd = array();
+
+ $insertedUrls = API::getInstance()->addSiteAliasUrls($idsite, $toAdd);
+ $this->assertEquals(count($toAdd), $insertedUrls);
+
+ $siteUrlsAfter = API::getInstance()->getSiteUrlsFromId($idsite);
+
+ $shouldHave = $siteUrlsBefore;
+ sort($shouldHave);
+
+ sort($siteUrlsAfter);
+
+ $this->assertEquals($shouldHave, $siteUrlsAfter);
+ }
+
+ /**
+ * case array only duplicate => nothing happens
+ *
+ * @group Plugins
+ */
+ public function testAddSiteUrlsNoUrlsToAdd2()
+ {
+ $idsite = $this->_addSite();
+
+ $siteUrlsBefore = API::getInstance()->getSiteUrlsFromId($idsite);
+
+ $toAdd = $siteUrlsBefore;
+
+ $insertedUrls = API::getInstance()->addSiteAliasUrls($idsite, $toAdd);
+ $this->assertEquals(0, $insertedUrls);
+
+ $siteUrlsAfter = API::getInstance()->getSiteUrlsFromId($idsite);
+
+ $shouldHave = $siteUrlsBefore;
+ sort($shouldHave);
+
+ sort($siteUrlsAfter);
+
+ $this->assertEquals($shouldHave, $siteUrlsAfter);
+ }
+
+ /**
+ * wrong format urls => exception
+ *
+ * @group Plugins
+ */
+ public function testAddSiteUrlsWrongUrlsFormat3()
+ {
+ try {
+ $idsite = $this->_addSite();
+ $toAdd = array("http:mpigeq");
+ API::getInstance()->addSiteAliasUrls($idsite, $toAdd);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * wrong idsite => no exception because simply no access to this resource
+ *
+ * @group Plugins
+ */
+ public function testAddSiteUrlsWrongIdSite1()
+ {
+ try {
+ $toAdd = array("http://pigeq.com/test");
+ API::getInstance()->addSiteAliasUrls(-1, $toAdd);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * wrong idsite => exception
+ *
+ * @group Plugins
+ */
+ public function testAddSiteUrlsWrongIdSite2()
+ {
+ try {
+ $toAdd = array("http://pigeq.com/test");
+ API::getInstance()->addSiteAliasUrls(155, $toAdd);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * no Id -> empty array
+ *
+ * @group Plugins
+ */
+ public function testGetAllSitesIdNoId()
+ {
+ $ids = API::getInstance()->getAllSitesId();
+ $this->assertEquals(array(), $ids);
+ }
+
+ /**
+ * several Id -> normal array
+ *
+ * @group Plugins
+ */
+ public function testGetAllSitesIdSeveralId()
+ {
+ $name = "tetq";
+ $idsites = array(
+ API::getInstance()->addSite($name, array("http://piwik.net", "http://piwik.com/test/")),
+ API::getInstance()->addSite($name, array("http://piwik.net", "http://piwik.com/test/")),
+ API::getInstance()->addSite($name, array("http://piwik.net", "http://piwik.com/test/")),
+ API::getInstance()->addSite($name, array("http://piwik.net", "http://piwik.com/test/")),
+ API::getInstance()->addSite($name, array("http://piwik.net", "http://piwik.com/test/")),
+ );
+
+ $ids = API::getInstance()->getAllSitesId();
+ $this->assertEquals($idsites, $ids);
+ }
+
+ /**
+ * wrong id => exception
+ *
+ * @group Plugins
+ */
+ public function testGetSiteFromIdWrongId1()
+ {
+ try {
+ API::getInstance()->getSiteFromId(0);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * wrong id => exception
+ *
+ * @group Plugins
+ */
+ public function testGetSiteFromIdWrongId2()
+ {
+ try {
+ API::getInstance()->getSiteFromId("x1");
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * wrong id : no access => exception
+ *
+ * @group Plugins
+ */
+ public function testGetSiteFromIdWrongId3()
+ {
+ $idsite = API::getInstance()->addSite("site", array("http://piwik.net", "http://piwik.com/test/"));
+ $this->assertEquals(1, $idsite);
+
+ // set noaccess to site 1
+ FakeAccess::setIdSitesView(array(2));
+ FakeAccess::setIdSitesAdmin(array());
+
+ try {
+ API::getInstance()->getSiteFromId(1);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * normal case
+ *
+ * @group Plugins
+ */
+ public function testGetSiteFromIdNormalId()
+ {
+ $name = "website ''";
+ $idsite = API::getInstance()->addSite($name, array("http://piwik.net", "http://piwik.com/test/"));
+ $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_INT, $idsite);
+
+ $siteInfo = API::getInstance()->getSiteFromId($idsite);
+ $this->assertEquals($name, $siteInfo['name']);
+ $this->assertEquals("http://piwik.net", $siteInfo['main_url']);
+ }
+
+ /**
+ * there is no admin site available -> array()
+ *
+ * @group Plugins
+ */
+ public function testGetSitesWithAdminAccessNoResult()
+ {
+ FakeAccess::setIdSitesAdmin(array());
+
+ $sites = API::getInstance()->getSitesWithAdminAccess();
+ $this->assertEquals(array(), $sites);
+ }
+
+ /**
+ * normal case, admin and view and noaccess website => return only admin
+ *
+ * @group Plugins
+ */
+ public function testGetSitesWithAdminAccess()
+ {
+ API::getInstance()->addSite("site1", array("http://piwik.net", "http://piwik.com/test/"));
+ API::getInstance()->addSite("site2", array("http://piwik.com/test/"));
+ API::getInstance()->addSite("site3", array("http://piwik.org"));
+
+ $resultWanted = array(
+ 0 => array("idsite" => 1, "name" => "site1", "main_url" => "http://piwik.net", "ecommerce" => 0, "excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => '', 'keep_url_fragment' => 0, 'type' => 'website'),
+ 1 => array("idsite" => 3, "name" => "site3", "main_url" => "http://piwik.org", "ecommerce" => 0, "excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => '', 'keep_url_fragment' => 0, 'type' => 'website'),
+ );
+
+ FakeAccess::setIdSitesAdmin(array(1, 3));
+
+ $sites = API::getInstance()->getSitesWithAdminAccess();
+
+ // we dont test the ts_created
+ unset($sites[0]['ts_created']);
+ unset($sites[1]['ts_created']);
+ $this->assertEquals($resultWanted, $sites);
+ }
+
+ /**
+ * there is no admin site available -> array()
+ *
+ * @group Plugins
+ */
+ public function testGetSitesWithViewAccessNoResult()
+ {
+ FakeAccess::setIdSitesView(array());
+ FakeAccess::setIdSitesAdmin(array());
+
+ $sites = API::getInstance()->getSitesWithViewAccess();
+ $this->assertEquals(array(), $sites);
+ }
+
+ /**
+ * normal case, admin and view and noaccess website => return only admin
+ *
+ * @group Plugins
+ */
+ public function testGetSitesWithViewAccess()
+ {
+ API::getInstance()->addSite("site1", array("http://piwik.net", "http://piwik.com/test/"));
+ API::getInstance()->addSite("site2", array("http://piwik.com/test/"));
+ API::getInstance()->addSite("site3", array("http://piwik.org"));
+
+ $resultWanted = array(
+ 0 => array("idsite" => 1, "name" => "site1", "main_url" => "http://piwik.net", "ecommerce" => 0, 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', "excluded_ips" => "", 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => '', 'keep_url_fragment' => 0, 'type' => 'website'),
+ 1 => array("idsite" => 3, "name" => "site3", "main_url" => "http://piwik.org", "ecommerce" => 0, 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', "excluded_ips" => "", 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => '', 'keep_url_fragment' => 0, 'type' => 'website'),
+ );
+
+ FakeAccess::setIdSitesView(array(1, 3));
+ FakeAccess::setIdSitesAdmin(array());
+
+ $sites = API::getInstance()->getSitesWithViewAccess();
+ // we dont test the ts_created
+ unset($sites[0]['ts_created']);
+ unset($sites[1]['ts_created']);
+ $this->assertEquals($resultWanted, $sites);
+ }
+
+ /**
+ * there is no admin site available -> array()
+ *
+ * @group Plugins
+ */
+ public function testGetSitesWithAtLeastViewAccessNoResult()
+ {
+ FakeAccess::setIdSitesView(array());
+ FakeAccess::setIdSitesAdmin(array());
+
+ $sites = API::getInstance()->getSitesWithAtLeastViewAccess();
+ $this->assertEquals(array(), $sites);
+ }
+
+ /**
+ * normal case, admin and view and noaccess website => return only admin
+ *
+ * @group Plugins
+ */
+ public function testGetSitesWithAtLeastViewAccess()
+ {
+ API::getInstance()->addSite("site1", array("http://piwik.net", "http://piwik.com/test/"), $ecommerce = 1);
+ API::getInstance()->addSite("site2", array("http://piwik.com/test/"));
+ API::getInstance()->addSite("site3", array("http://piwik.org"));
+
+ $resultWanted = array(
+ 0 => array("idsite" => 1, "name" => "site1", "main_url" => "http://piwik.net", "ecommerce" => 1, "excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => '', 'keep_url_fragment' => 0, 'type' => 'website'),
+ 1 => array("idsite" => 3, "name" => "site3", "main_url" => "http://piwik.org", "ecommerce" => 0, "excluded_ips" => "", 'sitesearch' => 1, 'sitesearch_keyword_parameters' => '', 'sitesearch_category_parameters' => '', 'excluded_parameters' => '', 'excluded_user_agents' => '', 'timezone' => 'UTC', 'currency' => 'USD', 'group' => '', 'keep_url_fragment' => 0, 'type' => 'website'),
+ );
+
+ FakeAccess::setIdSitesView(array(1, 3));
+ FakeAccess::setIdSitesAdmin(array());
+
+ $sites = API::getInstance()->getSitesWithAtLeastViewAccess();
+ // we dont test the ts_created
+ unset($sites[0]['ts_created']);
+ unset($sites[1]['ts_created']);
+ $this->assertEquals($resultWanted, $sites);
+ }
+
+ /**
+ * no urls for this site => array()
+ *
+ * @group Plugins
+ */
+ public function testGetSiteUrlsFromIdNoUrls()
+ {
+ $idsite = API::getInstance()->addSite("site1", array("http://piwik.net"));
+
+ $urls = API::getInstance()->getSiteUrlsFromId($idsite);
+ $this->assertEquals(array("http://piwik.net"), $urls);
+ }
+
+ /**
+ * normal case
+ *
+ * @group Plugins
+ */
+ public function testGetSiteUrlsFromIdManyUrls()
+ {
+ $site = array("http://piwik.net",
+ "http://piwik.org",
+ "http://piwik.org",
+ "http://piwik.com");
+ sort($site);
+
+ $idsite = API::getInstance()->addSite("site1", $site);
+
+ $siteWanted = array("http://piwik.net",
+ "http://piwik.org",
+ "http://piwik.com");
+ sort($siteWanted);
+ $urls = API::getInstance()->getSiteUrlsFromId($idsite);
+
+ $this->assertEquals($siteWanted, $urls);
+ }
+
+ /**
+ * wrongId => exception
+ *
+ * @group Plugins
+ */
+ public function testGetSiteUrlsFromIdWrongId()
+ {
+ try {
+ FakeAccess::setIdSitesView(array(3));
+ FakeAccess::setIdSitesAdmin(array());
+ API::getInstance()->getSiteUrlsFromId(1);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * one url => no change to alias urls
+ *
+ * @group Plugins
+ */
+ public function testUpdateSiteOneUrl()
+ {
+ $urls = array("http://piwiknew.com",
+ "http://piwiknew.net",
+ "http://piwiknew.org",
+ "http://piwiknew.fr");
+ $idsite = API::getInstance()->addSite("site1", $urls);
+
+ $newMainUrl = "http://main.url";
+
+ // Also test that the group was set to empty, and is searchable
+ $websites = API::getInstance()->getSitesFromGroup('');
+ $this->assertEquals(1, count($websites));
+
+ // the Update doesn't change the group field
+ API::getInstance()->updateSite($idsite, "test toto@{}", $newMainUrl);
+ $websites = API::getInstance()->getSitesFromGroup('');
+ $this->assertEquals(1, count($websites));
+
+ // Updating the group to something
+ $group = 'something';
+ API::getInstance()->updateSite($idsite, "test toto@{}", $newMainUrl, $ecommerce = 0, $ss = true, $ss_kwd = null, $ss_cat = '', $ips = null, $parametersExclude = null, $timezone = null, $currency = null, $group);
+ $websites = API::getInstance()->getSitesFromGroup($group);
+ $this->assertEquals(1, count($websites));
+ $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($websites[0]['ts_created'])));
+
+ // Updating the group to nothing
+ $group = '';
+ $type = 'mobileAppTest';
+ API::getInstance()->updateSite($idsite, "test toto@{}", $newMainUrl, $ecommerce = 0, $ss = false, $ss_kwd = '', $ss_cat = null, $ips = null, $parametersExclude = null, $timezone = null, $currency = null, $group, $startDate = '2010-01-01', $excludedUserAgent = null, $keepUrlFragment = 1, $type);
+ $websites = API::getInstance()->getSitesFromGroup($group);
+ $this->assertEquals(1, count($websites));
+ $this->assertEquals('2010-01-01', date('Y-m-d', strtotime($websites[0]['ts_created'])));
+
+ // Test setting the website type
+ $this->assertEquals($type, Site::getTypeFor($idsite));
+
+ // Check Alias URLs contain only main url
+ $allUrls = API::getInstance()->getSiteUrlsFromId($idsite);
+ $this->assertEquals($newMainUrl, $allUrls[0]);
+ $aliasUrls = array_slice($allUrls, 1);
+ $this->assertEquals(array(), $aliasUrls);
+
+ }
+
+ /**
+ * strange name and NO URL => name ok, main_url not updated
+ *
+ * @group Plugins
+ */
+ public function testUpdateSiteStrangeNameNoUrl()
+ {
+ $idsite = API::getInstance()->addSite("site1", "http://main.url");
+ $newName = "test toto@{'786'}";
+
+ API::getInstance()->updateSite($idsite, $newName);
+
+ $site = API::getInstance()->getSiteFromId($idsite);
+
+ $this->assertEquals($newName, $site['name']);
+ // url didn't change because parameter url NULL in updateSite
+ $this->assertEquals("http://main.url", $site['main_url']);
+ }
+
+ /**
+ * several urls => both main and alias are updated
+ * also test the update of group field
+ *
+ * @group Plugins
+ */
+ public function testUpdateSiteSeveralUrlsAndGroup()
+ {
+ $urls = array("http://piwiknew.com",
+ "http://piwiknew.net",
+ "http://piwiknew.org",
+ "http://piwiknew.fr");
+
+ $group = 'GROUP Before';
+ $idsite = API::getInstance()->addSite("site1", $urls, $ecommerce = 1,
+ $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null,
+ $excludedIps = null, $excludedQueryParameters = null, $timezone = null, $currency = null, $group, $startDate = '2011-01-01');
+
+ $websites = API::getInstance()->getSitesFromGroup($group);
+ $this->assertEquals(1, count($websites));
+
+ $newurls = array("http://piwiknew2.com",
+ "http://piwiknew2.net",
+ "http://piwiknew2.org",
+ "http://piwiknew2.fr");
+
+ $groupAfter = ' GROUP After';
+ API::getInstance()->updateSite($idsite, "test toto@{}", $newurls, $ecommerce = 0,
+ $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null,
+ $excludedIps = null, $excludedQueryParameters = null, $timezone = null, $currency = null, $groupAfter);
+
+ // no result for the group before update
+ $websites = API::getInstance()->getSitesFromGroup($group);
+ $this->assertEquals(0, count($websites));
+
+ // Testing that the group was updated properly (and testing that the group value is trimmed before inserted/searched)
+ $websites = API::getInstance()->getSitesFromGroup($groupAfter . ' ');
+ $this->assertEquals(1, count($websites));
+ $this->assertEquals('2011-01-01', date('Y-m-d', strtotime($websites[0]['ts_created'])));
+
+ // Test fetch website groups
+ $expectedGroups = array(trim($groupAfter));
+ $fetched = API::getInstance()->getSitesGroups();
+ $this->assertEquals($expectedGroups, $fetched);
+
+ $allUrls = API::getInstance()->getSiteUrlsFromId($idsite);
+ sort($allUrls);
+ sort($newurls);
+ $this->assertEquals($newurls, $allUrls);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetSitesGroups()
+ {
+ $groups = array('group1', ' group1 ', '', 'group2');
+ $expectedGroups = array('group1', '', 'group2');
+ foreach ($groups as $group) {
+ API::getInstance()->addSite("test toto@{}", 'http://example.org', $ecommerce = 1, $siteSearch = null, $searchKeywordParameters = null, $searchCategoryParameters = null, $excludedIps = null, $excludedQueryParameters = null, $timezone = null, $currency = null, $group);
+ }
+
+ $this->assertEquals($expectedGroups, API::getInstance()->getSitesGroups());
+ }
+
+ public function getInvalidTimezoneData()
+ {
+ return array(
+ array('UTC+15'),
+ array('Paris'),
+ );
+ }
+
+ /**
+ *
+ * @dataProvider getInvalidTimezoneData
+ * @group Plugins
+ */
+ public function testAddSitesInvalidTimezone($timezone)
+ {
+ try {
+ API::getInstance()->addSite("site1", array('http://example.org'), $ecommerce = 0,
+ $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, $ip = '', $params = '', $timezone);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testAddSitesInvalidCurrency()
+ {
+ try {
+ $invalidCurrency = '€';
+ API::getInstance()->addSite("site1", array('http://example.org'), $ecommerce = 0,
+ $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, '', 'UTC', $invalidCurrency);
+ } catch (Exception $e) {
+ return;
+ }
+ $this->fail('Expected exception not raised');
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testSetDefaultTimezoneAndCurrencyAndExcludedQueryParametersAndExcludedIps()
+ {
+ // test that they return default values
+ $defaultTimezone = API::getInstance()->getDefaultTimezone();
+ $this->assertEquals('UTC', $defaultTimezone);
+ $defaultCurrency = API::getInstance()->getDefaultCurrency();
+ $this->assertEquals('USD', $defaultCurrency);
+ $excludedIps = API::getInstance()->getExcludedIpsGlobal();
+ $this->assertEquals('', $excludedIps);
+ $excludedQueryParameters = API::getInstance()->getExcludedQueryParametersGlobal();
+ $this->assertEquals('', $excludedQueryParameters);
+
+ // test that when not specified, defaults are set as expected
+ $idsite = API::getInstance()->addSite("site1", array('http://example.org'));
+ $site = new Site($idsite);
+ $this->assertEquals('UTC', $site->getTimezone());
+ $this->assertEquals('USD', $site->getCurrency());
+ $this->assertEquals('', $site->getExcludedQueryParameters());
+ $this->assertEquals('', $site->getExcludedIps());
+ $this->assertEquals(false, $site->isEcommerceEnabled());
+
+ // set the global timezone and get it
+ $newDefaultTimezone = 'UTC+5.5';
+ API::getInstance()->setDefaultTimezone($newDefaultTimezone);
+ $defaultTimezone = API::getInstance()->getDefaultTimezone();
+ $this->assertEquals($newDefaultTimezone, $defaultTimezone);
+
+ // set the default currency and get it
+ $newDefaultCurrency = 'EUR';
+ API::getInstance()->setDefaultCurrency($newDefaultCurrency);
+ $defaultCurrency = API::getInstance()->getDefaultCurrency();
+ $this->assertEquals($newDefaultCurrency, $defaultCurrency);
+
+ // set the global IPs to exclude and get it
+ $newGlobalExcludedIps = '1.1.1.*,1.1.*.*,150.1.1.1';
+ API::getInstance()->setGlobalExcludedIps($newGlobalExcludedIps);
+ $globalExcludedIps = API::getInstance()->getExcludedIpsGlobal();
+ $this->assertEquals($newGlobalExcludedIps, $globalExcludedIps);
+
+ // set the global URL query params to exclude and get it
+ $newGlobalExcludedQueryParameters = 'PHPSESSID,blabla, TesT';
+ // removed the space
+ $expectedGlobalExcludedQueryParameters = 'PHPSESSID,blabla,TesT';
+ API::getInstance()->setGlobalExcludedQueryParameters($newGlobalExcludedQueryParameters);
+ $globalExcludedQueryParameters = API::getInstance()->getExcludedQueryParametersGlobal();
+ $this->assertEquals($expectedGlobalExcludedQueryParameters, $globalExcludedQueryParameters);
+
+ // create a website and check that default currency and default timezone are set
+ // however, excluded IPs and excluded query Params are not returned
+ $idsite = API::getInstance()->addSite("site1", array('http://example.org'), $ecommerce = 0,
+ $siteSearch = 0, $searchKeywordParameters = 'test1,test2', $searchCategoryParameters = 'test2,test1',
+ '', '', $newDefaultTimezone);
+ $site = new Site($idsite);
+ $this->assertEquals($newDefaultTimezone, $site->getTimezone());
+ $this->assertEquals(date('Y-m-d'), $site->getCreationDate()->toString());
+ $this->assertEquals($newDefaultCurrency, $site->getCurrency());
+ $this->assertEquals('', $site->getExcludedIps());
+ $this->assertEquals('', $site->getExcludedQueryParameters());
+ $this->assertEquals('test1,test2', $site->getSearchKeywordParameters());
+ $this->assertEquals('test2,test1', $site->getSearchCategoryParameters());
+ $this->assertFalse($site->isSiteSearchEnabled());
+ $this->assertFalse(Site::isSiteSearchEnabledFor($idsite));
+ $this->assertFalse($site->isEcommerceEnabled());
+ $this->assertFalse(Site::isEcommerceEnabledFor($idsite));
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetSitesIdFromSiteUrlSuperUser()
+ {
+ API::getInstance()->addSite("site1", array("http://piwik.net", "http://piwik.com"));
+ API::getInstance()->addSite("site2", array("http://piwik.com", "http://piwik.net"));
+ API::getInstance()->addSite("site3", array("http://piwik.com", "http://piwik.org"));
+
+ $idsites = API::getInstance()->getSitesIdFromSiteUrl('http://piwik.org');
+ $this->assertTrue(count($idsites) == 1);
+
+ $idsites = API::getInstance()->getSitesIdFromSiteUrl('http://www.piwik.org');
+ $this->assertTrue(count($idsites) == 1);
+
+ $idsites = API::getInstance()->getSitesIdFromSiteUrl('http://piwik.net');
+ $this->assertTrue(count($idsites) == 2);
+
+ $idsites = API::getInstance()->getSitesIdFromSiteUrl('http://piwik.com');
+ $this->assertTrue(count($idsites) == 3);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetSitesIdFromSiteUrlUser()
+ {
+ API::getInstance()->addSite("site1", array("http://www.piwik.net", "http://piwik.com"));
+ API::getInstance()->addSite("site2", array("http://piwik.com", "http://piwik.net"));
+ API::getInstance()->addSite("site3", array("http://piwik.com", "http://piwik.org"));
+
+ $saveAccess = Access::getInstance();
+
+ APIUsersManager::getInstance()->addUser("user1", "geqgegagae", "tegst@tesgt.com", "alias");
+ APIUsersManager::getInstance()->setUserAccess("user1", "view", array(1));
+
+ APIUsersManager::getInstance()->addUser("user2", "geqgegagae", "tegst2@tesgt.com", "alias");
+ APIUsersManager::getInstance()->setUserAccess("user2", "view", array(1));
+ APIUsersManager::getInstance()->setUserAccess("user2", "admin", array(3));
+
+ APIUsersManager::getInstance()->addUser("user3", "geqgegagae", "tegst3@tesgt.com", "alias");
+ APIUsersManager::getInstance()->setUserAccess("user3", "view", array(1, 2));
+ APIUsersManager::getInstance()->setUserAccess("user3", "admin", array(3));
+
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::$superUser = false;
+ FakeAccess::$identity = 'user1';
+ FakeAccess::setIdSitesView(array(1));
+ FakeAccess::setIdSitesAdmin(array());
+ Access::setSingletonInstance($pseudoMockAccess);
+ $idsites = API::getInstance()->getSitesIdFromSiteUrl('http://piwik.com');
+ $this->assertEquals(1, count($idsites));
+
+ // testing URL normalization
+ $idsites = API::getInstance()->getSitesIdFromSiteUrl('http://www.piwik.com');
+ $this->assertEquals(1, count($idsites));
+ $idsites = API::getInstance()->getSitesIdFromSiteUrl('http://piwik.net');
+ $this->assertEquals(1, count($idsites));
+
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::$superUser = false;
+ FakeAccess::$identity = 'user2';
+ FakeAccess::setIdSitesView(array(1));
+ FakeAccess::setIdSitesAdmin(array(3));
+ Access::setSingletonInstance($pseudoMockAccess);
+ $idsites = API::getInstance()->getSitesIdFromSiteUrl('http://piwik.com');
+ $this->assertEquals(2, count($idsites));
+
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::$superUser = false;
+ FakeAccess::$identity = 'user3';
+ FakeAccess::setIdSitesView(array(1, 2));
+ FakeAccess::setIdSitesAdmin(array(3));
+ Access::setSingletonInstance($pseudoMockAccess);
+ $idsites = API::getInstance()->getSitesIdFromSiteUrl('http://piwik.com');
+ $this->assertEquals(3, count($idsites));
+
+ Access::setSingletonInstance($saveAccess);
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetSitesFromTimezones()
+ {
+ API::getInstance()->addSite("site3", array("http://piwik.org"), null, $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, null, null, 'UTC');
+ $idsite2 = API::getInstance()->addSite("site3", array("http://piwik.org"), null, $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, null, null, 'Pacific/Auckland');
+ $idsite3 = API::getInstance()->addSite("site3", array("http://piwik.org"), null, $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, null, null, 'Pacific/Auckland');
+ $idsite4 = API::getInstance()->addSite("site3", array("http://piwik.org"), null, $siteSearch = 1, $searchKeywordParameters = null, $searchCategoryParameters = null, null, null, 'UTC+10');
+ $result = API::getInstance()->getSitesIdFromTimezones(array('UTC+10', 'Pacific/Auckland'));
+ $this->assertEquals(array($idsite2, $idsite3, $idsite4), $result);
+ }
+}
diff --git a/plugins/UserCountry/LocationProvider/GeoIp/Php.php b/plugins/UserCountry/LocationProvider/GeoIp/Php.php
index 1bbf781d4f..2a3fda9dee 100755
--- a/plugins/UserCountry/LocationProvider/GeoIp/Php.php
+++ b/plugins/UserCountry/LocationProvider/GeoIp/Php.php
@@ -135,7 +135,7 @@ class Php extends GeoIp
}
// NOTE: ISP & ORG require commercial dbs to test. this code has been tested manually,
- // but not by integration tests.
+ // but not by system tests.
$ispGeoIp = $this->getGeoIpInstance($key = 'isp');
if ($ispGeoIp) {
$isp = geoip_org_by_addr($ispGeoIp, $ip);
diff --git a/plugins/UserCountry/tests/Unit/UserCountryTest.php b/plugins/UserCountry/tests/Unit/UserCountryTest.php
new file mode 100644
index 0000000000..540be65d70
--- /dev/null
+++ b/plugins/UserCountry/tests/Unit/UserCountryTest.php
@@ -0,0 +1,185 @@
+<?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\Plugins\UserCountry\tests\Unit;
+
+use Piwik\Plugins\UserCountry\GeoIPAutoUpdater;
+use Piwik\Plugins\UserCountry\LocationProvider\GeoIp;
+use Piwik\Plugins\UserCountry;
+use Piwik\Plugins\UserCountry\LocationProvider;
+use Exception;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/UserCountry/UserCountry.php';
+require_once PIWIK_INCLUDE_PATH . '/plugins/UserCountry/functions.php';
+require_once PIWIK_INCLUDE_PATH . '/core/DataFiles/Countries.php';
+
+class UserCountryTest extends \PHPUnit_Framework_Testcase
+{
+ /**
+ * @group Plugins
+ */
+ public function testGetFlagFromCode()
+ {
+ $flag = \Piwik\Plugins\UserCountry\getFlagFromCode("us");
+ $this->assertEquals(basename($flag), "us.png");
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testGetFlagFromInvalidCode()
+ {
+ $flag = \Piwik\Plugins\UserCountry\getFlagFromCode("foo");
+ $this->assertEquals(basename($flag), "xx.png");
+ }
+
+ /**
+ * @group Plugins
+ */
+ public function testFlagsAndContinents()
+ {
+ require PIWIK_PATH_TEST_TO_ROOT . '/core/DataFiles/Countries.php';
+
+ $continents = $GLOBALS['Piwik_ContinentList'];
+ $countries = array_merge($GLOBALS['Piwik_CountryList'], $GLOBALS['Piwik_CountryList_Extras']);
+
+ // Get list of existing flag icons
+ $flags = scandir(PIWIK_PATH_TEST_TO_ROOT . '/plugins/UserCountry/images/flags/');
+
+ // Get list of countries
+ foreach ($countries as $country => $continent) {
+ // test continent
+ $this->assertContains($continent, $continents);
+
+ // test flag
+ $this->assertContains($country . '.png', $flags);
+ }
+
+ foreach ($flags as $filename) {
+ if ($filename == '.' || $filename == '..') {
+ continue;
+ }
+
+ $country = substr($filename, 0, strpos($filename, '.png'));
+
+ // test country
+ $this->assertArrayHasKey($country, $countries, $filename);
+ }
+ }
+
+ /**
+ * Test that redundant checks work.
+ *
+ * @group Plugins
+ */
+ public function testGeoIpUpdaterRedundantChecks()
+ {
+ GeoIp::$geoIPDatabaseDir = 'tests/lib/geoip-files';
+ LocationProvider::$providers = null;
+
+ // create empty ISP & Org files
+ $this->createEmptyISPOrgFiles();
+
+ // run redundant checks
+ $updater = new Piwik_UserCountry_GeoIPAutoUpdater_publictest();
+ $updater->performRedundantDbChecks();
+
+ // check that files are renamed correctly
+ $this->checkBrokenGeoIPState();
+
+ // create empty files again & run checks again
+ $this->createEmptyISPOrgFiles();
+ $updater->performRedundantDbChecks();
+
+ // check that w/ broken files already there, redundant checks still work correctly
+ $this->checkBrokenGeoIPState();
+ }
+
+ /**
+ * @group Plugins
+ *
+ * @dataProvider getInvalidGeoIpUrlsToTest
+ */
+ public function testGeoIpDownloadInvalidUrl($url)
+ {
+ $updater = new Piwik_UserCountry_GeoIPAutoUpdater_publictest();
+ try {
+ $updater->downloadFile('loc', $url);
+ $this->fail("Downloading invalid url succeeded!");
+ } catch (Exception $ex) {
+ $this->assertEquals("UserCountry_UnsupportedArchiveType", $ex->getMessage());
+ }
+ }
+
+ public function getInvalidGeoIpUrlsToTest()
+ {
+ return array(array("http://localhost/tests/resources/geoip.tar"),
+ array("http://localhost/tests/resources/geoip.tar.bz2"),
+ array("http://localhost/tests/resources/geoip.dat"));
+ }
+
+ public function setUp()
+ {
+ // empty
+ }
+
+ public function tearDown()
+ {
+ $geoIpDirPath = PIWIK_INCLUDE_PATH . '/tests/lib/geoip-files';
+ $filesToRemove = array('GeoIPISP.dat.broken', 'GeoIPOrg.dat.broken', 'GeoIPISP.dat', 'GeoIPOrg.dat');
+
+ foreach ($filesToRemove as $name) {
+ $path = $geoIpDirPath . '/' . $name;
+ if (file_exists($path)) {
+ unlink($path);
+ }
+ }
+ }
+
+ private function createEmptyISPOrgFiles()
+ {
+ $geoIpDir = PIWIK_INCLUDE_PATH . '/tests/lib/geoip-files';
+
+ $fd = fopen($geoIpDir . '/GeoIPISP.dat', 'w');
+ fclose($fd);
+
+ $fd = fopen($geoIpDir . '/GeoIPOrg.dat', 'w');
+ fclose($fd);
+ }
+
+ private function checkBrokenGeoIPState()
+ {
+ $geoIpDir = PIWIK_INCLUDE_PATH . '/tests/lib/geoip-files';
+
+ $this->assertFalse(file_exists($geoIpDir . '/GeoIPCity.dat.broken'));
+
+ $this->assertFalse(file_exists($geoIpDir . '/GeoIPISP.dat'));
+ $this->assertTrue(file_exists($geoIpDir . '/GeoIPISP.dat.broken'));
+
+ $this->assertFalse(file_exists($geoIpDir . '/GeoIPOrg.dat'));
+ $this->assertTrue(file_exists($geoIpDir . '/GeoIPOrg.dat.broken'));
+ }
+}
+
+class Piwik_UserCountry_GeoIPAutoUpdater_publictest extends GeoIPAutoUpdater
+{
+ public function __construct()
+ {
+ // empty
+ }
+
+ public function performRedundantDbChecks()
+ {
+ parent::performRedundantDbChecks();
+ }
+
+ public function downloadFile($type, $url)
+ {
+ parent::downloadFile($type, $url);
+ }
+}
diff --git a/plugins/UserSettings/.gitignore b/plugins/UserSettings/.gitignore
new file mode 100644
index 0000000000..c8c9480010
--- /dev/null
+++ b/plugins/UserSettings/.gitignore
@@ -0,0 +1 @@
+tests/System/processed/*xml \ No newline at end of file
diff --git a/plugins/UserSettings/tests/Fixtures/LanguageFixture.php b/plugins/UserSettings/tests/Fixtures/LanguageFixture.php
index 01c5d626a9..dc6b4fcb0b 100644
--- a/plugins/UserSettings/tests/Fixtures/LanguageFixture.php
+++ b/plugins/UserSettings/tests/Fixtures/LanguageFixture.php
@@ -10,7 +10,7 @@
namespace Piwik\Plugins\UserSettings\tests\Fixtures;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
use Piwik\Date;
use Piwik\Common;
diff --git a/plugins/UserSettings/tests/GetLanguageIntegrationTest.php b/plugins/UserSettings/tests/System/GetLanguageSystemTest.php
index 9dac446e6c..70db55616b 100644
--- a/plugins/UserSettings/tests/GetLanguageIntegrationTest.php
+++ b/plugins/UserSettings/tests/System/GetLanguageSystemTest.php
@@ -6,20 +6,20 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
-namespace Piwik\Plugins\UserSettings\tests;
+namespace Piwik\Plugins\UserSettings\tests\System;
use Piwik\Plugins\UserSettings\tests\Fixtures\LanguageFixture;
-use Piwik\Tests\IntegrationTestCase;
+use Piwik\Tests\Impl\SystemTestCase;
/**
- * Class GetLanguageIntegrationTest
+ * Class GetLanguageSystemTest
* @package Piwik\Plugins\UserSettings\tests
- * @group GetLanguageIntegrationTest
+ * @group GetLanguageSystemTest
* @group Plugins
* @group UserSettings
*/
-class GetLanguageIntegrationTest extends IntegrationTestCase {
+class GetLanguageSystemTest extends SystemTestCase {
public static $fixture = null;
@@ -32,7 +32,7 @@ class GetLanguageIntegrationTest extends IntegrationTestCase {
* @param $api
* @param $params
* @dataProvider getApiForTesting
- * @group GetLanguageIntegrationTest
+ * @group GetLanguageSystemTest
*/
public function testApi($api, $params)
{
@@ -44,7 +44,6 @@ class GetLanguageIntegrationTest extends IntegrationTestCase {
*/
public function getApiForTesting()
{
-
$apiToCall = array(
"UserSettings.getLanguage",
"UserSettings.getLanguageCode"
@@ -55,8 +54,8 @@ class GetLanguageIntegrationTest extends IntegrationTestCase {
$apiToTest[] = array(
$apiToCall,
array(
- 'idSite' => self::$fixture->idSite,
- 'date' => self::$fixture->dateTime,
+ 'idSite' => self::$fixture->idSite,
+ 'date' => self::$fixture->dateTime,
'periods' => array('day')
)
);
@@ -72,4 +71,4 @@ class GetLanguageIntegrationTest extends IntegrationTestCase {
}
-GetLanguageIntegrationTest::$fixture = new LanguageFixture(); \ No newline at end of file
+GetLanguageSystemTest::$fixture = new LanguageFixture(); \ No newline at end of file
diff --git a/plugins/UserSettings/tests/expected/test___UserSettings.getLanguageCode_day.xml b/plugins/UserSettings/tests/System/expected/test___UserSettings.getLanguageCode_day.xml
index 689e3d7d37..689e3d7d37 100644
--- a/plugins/UserSettings/tests/expected/test___UserSettings.getLanguageCode_day.xml
+++ b/plugins/UserSettings/tests/System/expected/test___UserSettings.getLanguageCode_day.xml
diff --git a/plugins/UserSettings/tests/expected/test___UserSettings.getLanguage_day.xml b/plugins/UserSettings/tests/System/expected/test___UserSettings.getLanguage_day.xml
index 6bb328c660..6bb328c660 100644
--- a/plugins/UserSettings/tests/expected/test___UserSettings.getLanguage_day.xml
+++ b/plugins/UserSettings/tests/System/expected/test___UserSettings.getLanguage_day.xml
diff --git a/plugins/UserSettings/tests/processed/.gitkeep b/plugins/UserSettings/tests/System/processed/.gitkeep
index e69de29bb2..e69de29bb2 100644
--- a/plugins/UserSettings/tests/processed/.gitkeep
+++ b/plugins/UserSettings/tests/System/processed/.gitkeep
diff --git a/plugins/UserSettings/tests/System/processed/test___UserSettings.getLanguageCode_day.xml b/plugins/UserSettings/tests/System/processed/test___UserSettings.getLanguageCode_day.xml
new file mode 100644
index 0000000000..689e3d7d37
--- /dev/null
+++ b/plugins/UserSettings/tests/System/processed/test___UserSettings.getLanguageCode_day.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>Polish (pl)</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>3</nb_visits>
+ <nb_actions>3</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>3</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>English - United States (en-us)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>2</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>French - Belgium (fr-be)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>2</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Arabic - Qatar (ar-qa)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Czech - Czech Republic (cs-cz)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>German (de)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Greek - Greece (el-gr)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Basque - Spain (eu-es)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>French (fr)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>French - Switzerland (fr-ch)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Serbian - Serbia Montenegro (sr-cs)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Thai (th)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Unknown - Liberia (xx-lr)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Chinese - Singapore (zh-sg)</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserSettings/tests/System/processed/test___UserSettings.getLanguage_day.xml b/plugins/UserSettings/tests/System/processed/test___UserSettings.getLanguage_day.xml
new file mode 100644
index 0000000000..6bb328c660
--- /dev/null
+++ b/plugins/UserSettings/tests/System/processed/test___UserSettings.getLanguage_day.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<result>
+ <row>
+ <label>Polish</label>
+ <nb_uniq_visitors>2</nb_uniq_visitors>
+ <nb_visits>3</nb_visits>
+ <nb_actions>3</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>3</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>English</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>2</nb_visits>
+ <nb_actions>2</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>2</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>French</label>
+ <nb_uniq_visitors>3</nb_uniq_visitors>
+ <nb_visits>4</nb_visits>
+ <nb_actions>4</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>4</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Arabic</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Czech</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>German</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Greek</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Basque</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Serbian</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Thai</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Unknown</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+ <row>
+ <label>Chinese</label>
+ <nb_uniq_visitors>1</nb_uniq_visitors>
+ <nb_visits>1</nb_visits>
+ <nb_actions>1</nb_actions>
+ <nb_users>0</nb_users>
+ <max_actions>1</max_actions>
+ <sum_visit_length>0</sum_visit_length>
+ <bounce_count>1</bounce_count>
+ <nb_visits_converted>0</nb_visits_converted>
+ </row>
+</result> \ No newline at end of file
diff --git a/plugins/UserSettings/tests/Unit/UserSettingsTest.php b/plugins/UserSettings/tests/Unit/UserSettingsTest.php
new file mode 100644
index 0000000000..408420ed6f
--- /dev/null
+++ b/plugins/UserSettings/tests/Unit/UserSettingsTest.php
@@ -0,0 +1,1036 @@
+<?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\Plugins\UserSettings\tests\Unit;
+
+use UserAgentParser;
+
+require_once PIWIK_INCLUDE_PATH . '/plugins/UserSettings/UserSettings.php';
+require_once PIWIK_INCLUDE_PATH . '/plugins/UserSettings/functions.php';
+
+class UserSettingsTest extends \PHPUnit_Framework_TestCase
+{
+ // User agent strings and expected parser results
+ public function getUserAgents()
+ {
+ return array(
+ // array('User Agent String', array(
+ // array( browser_id, name, short_name, version, major_number, minor_number, family ),
+ // array( os_id, name, short_name ))),
+
+ // Special: URL encoded IE8
+ array('Mozilla/4.0+(compatible;+MSIE+8.0;+Windows+NT+6.1;+WOW64;+Trident/4.0;+GTB7.4;+SLCC2;+.NET+CLR+2.0.50727;+.NET+CLR+3.5.30729;+.NET+CLR+3.0.30729;+Media+Center+PC+6.0;+.NET4.0C;+.NET4.0E;+MS-RTC+LM+8;+InfoPath.2)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+
+ // ABrowse
+ array('Mozilla/5.0 (compatible; U; ABrowse 0.6; Syllable) AppleWebKit/420+ (KHTML, like Gecko)', array(
+ array('AB', 'ABrowse', 'ABrowse', '0.6', '0', '6', 'webkit'),
+ array('SYL', 'Syllable', 'Syllable'))),
+ array('Mozilla/5.0 (compatible; ABrowse 0.4; Syllable)', array(
+ array('AB', 'ABrowse', 'ABrowse', '0.4', '0', '4', 'webkit'),
+ array('SYL', 'Syllable', 'Syllable'))),
+
+ // Acoo Browser (treat as IE)
+ array('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; Acoo Browser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Acoo Browser; .NET CLR 2.0.50727; .NET CLR 1.1.4322)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Acoo Browser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Amaya
+ array('amaya/9.52 libwww/5.4.0', array(
+ array('AM', 'Amaya', 'Amaya', '9.52', '9', '52', 'unknown'),
+ false)),
+
+ // AmigaVoyager
+ array('AmigaVoyager/3.2 (AmigaOS/MC680x0)', array(
+ array('AV', 'AmigaVoyager', 'AmigaVoyager', '3.2', '3', '2', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+ array('AmigaVoyager/2.95 (compatible; MC680x0; AmigaOS; SV1)', array(
+ array('AV', 'AmigaVoyager', 'AmigaVoyager', '2.95', '2', '95', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+ array('AmigaVoyager/2.95 (compatible; MC680x0; AmigaOS)', array(
+ array('AV', 'AmigaVoyager', 'AmigaVoyager', '2.95', '2', '95', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+
+ // Android
+ array('Mozilla/5.0 (Linux; U; Android 1.1; en-us; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2', array(
+ array('SF', 'Safari', 'Safari', '3.0', '3', '0', 'webkit'),
+ array('AND', 'Android', 'Android'))),
+ array('Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ array('AND', 'Android', 'Android'))),
+ array('Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; device Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Safari/533.1', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ array('AND', 'Android', 'Android'))),
+ array('Mozilla/5.0 (Linux; U; Android 4.0.1; en-us; Galaxy Nexus Build/ITL41D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ array('AND', 'Android', 'Android'))),
+
+ // Android - Mobile Chrome
+ /*
+ array('rray('Mozilla/5.0 (Linux; U; Android 4.1; en-us) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.16 Safari/534.24', array(
+ array('CH', 'Chrome', 'Chrome', '11.0', '11', '0', 'webkit'),
+ array('AND', 'Android', 'Android'))),
+ */
+ array('Mozilla/5.0 (Linux; U; Android 4.0.1; en-us; Galaxy Nexus Build/ITL41F) AppleWebKit/535.7 (KHTML, like Gecko) CrMo/16.0.912.75 Mobile Safari/535.7', array(
+ array('CH', 'Chrome', 'Chrome', '16.0', '16', '0', 'webkit'),
+ array('AND', 'Android', 'Android'))),
+
+ // AOL / America Online Browser (treat as IE)
+ array('Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.43; Windows NT 5.1; .NET CLR 1.1.4322)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.1; AOLBuild 4334.5009; Windows NT 5.1; GTB5; .NET CLR 1.1.4322)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.0; Windows NT 5.1; InfoPath.1)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; AOL 7.0; Windows NT 5.1)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 5.5; AOL 6.0; Windows 98; Win 9x 4.90)', array(
+ array('IE', 'Internet Explorer', 'IE', '5.5', '5', '5', 'ie'),
+ array('WME', 'Windows Me', 'Win Me'))),
+ array('Mozilla/4.0 (compatible; MSIE 5.5; AOL 5.0; Windows NT 5.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '5.5', '5', '5', 'ie'),
+ array('W2K', 'Windows 2000', 'Win 2000'))),
+ array('Mozilla/4.0 (compatible; MSIE 4.01; AOL 4.0; Windows 95)', array(
+ array('IE', 'Internet Explorer', 'IE', '4.01', '4', '01', 'ie'),
+ array('W95', 'Windows 95', 'Win 95'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; America Online Browser 1.1; Windows NT 5.1; (R1 1.5); .NET CLR 2.0.50727; InfoPath.1)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; America Online Browser 1.1; Windows 98)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('W98', 'Windows 98', 'Win 98'))),
+
+ // Arora
+ array('Mozilla/5.0 (X11; U; Linux; de-DE) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.8.0', array(
+ array('AR', 'Arora', 'Arora', '0.8', '0', '8', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6', array(
+ array('AR', 'Arora', 'Arora', '0.6', '0', '6', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.2; pt-BR) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.4 (Change: )', array(
+ array('AR', 'Arora', 'Arora', '0.4', '0', '4', 'webkit'),
+ array('WS3', 'Windows Server 2003 / XP x64', 'Win S2003'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)', array(
+ array('AR', 'Arora', 'Arora', '0.3', '0', '3', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.2 (Change: 189 35c14e0)', array(
+ array('AR', 'Arora', 'Arora', '0.2', '0', '2', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Avant (treat as IE)
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser; .NET CLR 2.0.50727; MAXTHON 2.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; Avant Browser; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+
+ // AWeb
+ array('Amiga-AWeb/3.5.07 beta', array(
+ array('AW', 'Amiga AWeb', 'AWeb', '3.5', '3', '5', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+ array('Mozilla/6.0; (Spoofed by Amiga-AWeb/3.5.07 beta)', array(
+ array('AW', 'Amiga AWeb', 'AWeb', '3.5', '3', '5', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+ array('MSIE/6.0; (Spoofed by Amiga-AWeb/3.4APL)', array(
+ array('AW', 'Amiga AWeb', 'AWeb', '3.4', '3', '4', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+
+ // Beonex
+ array('Mozilla/5.0 (Windows; U; WinNT; en; rv:1.0.2) Gecko/20030311 Beonex/0.8.2-stable', array(
+ array('BE', 'Beonex', 'Beonex', '0.8', '0', '8', 'unknown'),
+ array('WNT', 'Windows NT', 'Win NT'))),
+ array('Mozilla/5.0 (Windows; U; WinNT; en; Preview) Gecko/20020603 Beonex/0.8-stable', array(
+ array('BE', 'Beonex', 'Beonex', '0.8', '0', '8', 'unknown'),
+ array('WNT', 'Windows NT', 'Win NT'))),
+
+ // BlackBerry
+ array('BlackBerry8700/4.1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1', array(
+ array('BB', 'BlackBerry', 'BlackBerry', '4.1', '4', '1', 'webkit'),
+ array('BLB', 'BlackBerry', 'BlackBerry'))),
+
+ array('Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, Like Gecko) Version/6.0.0.141 Mobile Safari/534.1+', array(
+ array('BB', 'BlackBerry', 'BlackBerry', '6.0', '6', '0', 'webkit'),
+ array('BLB', 'BlackBerry', 'BlackBerry'))),
+
+ array('Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/0.0.1 Safari/534.11+', array(
+ array('BP', 'PlayBook', 'PlayBook', '0.0', '0', '0', 'webkit'),
+ array('QNX', 'QNX', 'QNX'))),
+
+ // BrowseX
+ array('Mozilla/4.61 [en] (X11; U; ) - BrowseX (2.0.0 Windows)', array(
+ array('BX', 'BrowseX', 'BrowseX', '2.0', '2', '0', 'unknown'),
+ false)),
+
+ // Camino (formerly known as Chimera; not to be confused with another browser also named Chimera)
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en; rv:1.9.0.8pre) Gecko/2009022800 Camino/2.0b3pre', array(
+ array('CA', 'Camino', 'Camino', '2.0', '2', '0', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en; rv:1.9.0.10pre) Gecko/2009041800 Camino/2.0b3pre (like Firefox/3.0.10pre)', array(
+ array('CA', 'Camino', 'Camino', '2.0', '2', '0', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.4pre) Gecko/20070511 Camino/1.6pre', array(
+ array('CA', 'Camino', 'Camino', '1.6', '1', '6', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.6) Gecko/20070809 Firefox/2.0.0.6 Camino/1.5.1', array(
+ array('CA', 'Camino', 'Camino', '1.5', '1', '5', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20030306 Camino/0.7', array(
+ array('CA', 'Camino', 'Camino', '0.7', '0', '7', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pl-PL; rv:1.0.1) Gecko/20021111 Chimera/0.6', array(
+ array('CA', 'Camino', 'Camino', '0.6', '0', '6', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+
+ // Cheshire
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.8 (KHTML, like Gecko, Safari) Cheshire/1.0.UNOFFICIAL', array(
+ array('CS', 'Cheshire', 'Cheshire', '1.0', '1', '0', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko, Safari/419.3) Cheshire/1.0.ALPHA', array(
+ array('CS', 'Cheshire', 'Cheshire', '1.0', '1', '0', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Safari) Cheshire/1.0.ALPHA', array(
+ array('CS', 'Cheshire', 'Cheshire', '1.0', '1', '0', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+
+ // Chrome / Chromium
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.310.0 Safari/532.9', array(
+ array('CH', 'Chrome', 'Chrome', '5.0', '5', '0', 'webkit'),
+ array('WS3', 'Windows Server 2003 / XP x64', 'Win S2003'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.48 Safari/525.19', array(
+ array('CH', 'Chrome', 'Chrome', '1.0', '1', '0', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Linux; U; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13', array(
+ array('CH', 'Chrome', 'Chrome', '0.2', '0', '2', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.16 Safari/534.24', array(
+ array('CH', 'Chrome', 'Chrome', '11.0', '11', '0', 'webkit'),
+ array('WVI', 'Windows Vista', 'Win Vista'))),
+ array('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.16 Safari/534.24', array(
+ array('CH', 'Chrome', 'Chrome', '11.0', '11', '0', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Chrome Frame
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; chromeframe/11.0.660.0)', array(
+ array('CF', 'Chrome Frame', 'Chrome Frame', '11.0', '11', '0', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) chromeframe/11.0.660.0', array(
+ array('CF', 'Chrome Frame', 'Chrome Frame', '11.0', '11', '0', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; chromeframe/11.0.660.0) AppleWebKit/534.18 (KHTML, like Gecko) Chrome/11.0.660.0 Safari/534.18', array(
+ array('CF', 'Chrome Frame', 'Chrome Frame', '11.0', '11', '0', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.18 (KHTML, like Gecko) Chrome/11.0.660.0 Safari/534.18', array(
+ array('CH', 'Chrome', 'Chrome', '11.0', '11', '0', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // ChromePlus (treat as Chrome)
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/532.2 (KHTML, like Gecko) ChromePlus/4.0.222.3 Chrome/4.0.222.3 Safari/532.2', array(
+ array('CH', 'Chrome', 'Chrome', '4.0', '4', '0', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 ChromePlus/4.0.222.3 Chrome/4.0.222.3 Safari/525.28.3', array(
+ array('CH', 'Chrome', 'Chrome', '3.2', '3', '2', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // CometBird
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.5) Gecko/2009011615 Firefox/3.0.5 CometBird/3.0.5', array(
+ array('CO', 'CometBird', 'CometBird', '3.0', '3', '0', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Crazy Browser (treat as IE)
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.2; .NET CLR 2.0.50727; .NET CLR 1.1.4322; Crazy Browser 3.0.0 Beta2)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser; .NET CLR 2.0.50727; .NET CLR 3.0.04506.590; .NET CLR 3.5.20706; Crazy Browser 2.0.1)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Dillo
+ array('Dillo/2.0', array(
+ array('DI', 'Dillo', 'Dillo', '2.0', '2', '0', 'unknown'),
+ false)),
+ array('Dillo/0.6.4', array(
+ array('DI', 'Dillo', 'Dillo', '0.6', '0', '6', 'unknown'),
+ false)),
+
+ // Dolfin (or Dolphin, depending on which Samsung documentation you read); and yes, it's "bada" (lower-case)
+ array('Mozilla/5.0 (SAMSUNG; SAMSUNG-GT-S5250/S5250AIJI3; U; Bada/1.0; it-it) AppleWebKit/533.1 (KHTML, like Gecko) Dolfin/2.0 Mobile WQVGA SMM-MMS/1.2.0 NexPlayer/3.0 profile/MIDP-2.1 configuration/CLDC-1.1 OPN-B', array(
+ array('DF', 'Dolfin', 'Dolfin', '2.0', '2', '0', 'webkit'),
+ array('SBA', 'bada', 'bada'))),
+ array('Mozilla/5.0 (SAMSUNG; SAMSUNG-GT-S8530/S8530XXJKA; U; Bada/1.2; en-us) AppleWebKit/533.1 (KHTML, like Gecko) Dolfin/2.2 Mobile WVGA SMM-MMS/1.2.0 OPN-B', array(
+ array('DF', 'Dolfin', 'Dolfin', '2.2', '2', '2', 'webkit'),
+ array('SBA', 'bada', 'bada'))),
+
+ // ELinks
+ array('ELinks/0.12~pre2.dfsg0-1ubuntu1-lite (textmode; Debian; Linux 2.6.32-4-jolicloud i686; 143x37-2)', array(
+ array('EL', 'ELinks', 'ELinks', '0.12', '0', '12', 'unknown'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('ELinks/0.12pre5.GIT (textmode; CYGWIN_NT-6.1 1.7.1(0.218/5/3) i686; 80x24-2)', array(
+ array('EL', 'ELinks', 'ELinks', '0.12', '0', '12', 'unknown'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+ array('ELinks (0.4.3; NetBSD 3.0.2_PATCH sparc64; 141x19)', array(
+ array('EL', 'ELinks', 'ELinks', '0.4', '0', '4', 'unknown'),
+ array('NBS', 'NetBSD', 'NetBSD'))),
+
+ // Epiphany
+ array('Mozilla/5.0 (X11; U; Linux i686; en-us) AppleWebKit/531.2+ (KHTML, like Gecko) Safari/531.2+ Epiphany/2.29.5', array(
+ array('EP', 'Epiphany', 'Epiphany', '2.29', '2', '29', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.11) Gecko/20080528 Epiphany/2.22 Firefox/3.0', array(
+ // technically, this should be 'gecko' but UserAgentParser only supports one browserType (family) per browser
+ array('EP', 'Epiphany', 'Epiphany', '2.22', '2', '22', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Fennec
+ array('Mozilla/5.0 (Android; Linux armv7l; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1', array(
+ array('FE', 'Fennec', 'Fennec', '2.0', '2', '0', 'gecko'),
+ array('AND', 'Android', 'Android'))),
+ array('Mozilla/5.0 (Maemo; Linux armv7l; rv2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1', array(
+ array('FE', 'Fennec', 'Fennec', '2.0', '2', '0', 'gecko'),
+ array('MAE', 'Maemo', 'Maemo'))),
+ array('Mozilla/5.0 (X11; Linux i686; rv2.0.1) Gecko/20100101 Firefox/4.0.1 Fennec/2.0.1', array(
+ array('FE', 'Fennec', 'Fennec', '2.0', '2', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2a1pre) Gecko/20090626 Fennec/1.0b2', array(
+ array('FE', 'Fennec', 'Fennec', '1.0', '1', '0', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (X11; U; Linux armv6l; en-US; rv:1.9.1b1pre) Gecko/20081005220218 Gecko/2008052201 Fennec/0.9pre', array(
+ array('FE', 'Fennec', 'Fennec', '0.9', '0', '9', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux armv6l; en-US; rv:1.9.1a1pre) Gecko/2008071707 Fennec/0.5', array(
+ array('FE', 'Fennec', 'Fennec', '0.5', '0', '5', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Firefox (formerly Firebird, formerly Phoenix; and rebranded versions)
+ array('Mozilla/5.0 (X11; Linux i686; rv:5.0a2) Gecko/20110413 Firefox/5.0a2', array(
+ array('FF', 'Firefox', 'Firefox', '5.0', '5', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1', array(
+ array('FF', 'Firefox', 'Firefox', '4.0', '4', '0', 'gecko'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:2.0a1pre) Gecko/2008060602 Minefield/4.0a1pre', array(
+ array('FF', 'Firefox', 'Firefox', '4.0', '4', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:2.0a1pre) Gecko/2008060602 Minefield/4.0a1p', array(
+ array('FF', 'Firefox', 'Firefox', '4.0', '4', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2a2pre) Gecko/20090826 Namoroka/3.6a2pre', array(
+ array('FF', 'Firefox', 'Firefox', '3.6', '3', '6', 'gecko'),
+ array('WVI', 'Windows Vista', 'Win Vista'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2) Gecko/20100119 Namoroka/3.6', array(
+ array('FF', 'Firefox', 'Firefox', '3.6', '3', '6', 'gecko'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b4pre) Gecko/20090420 Shiretoko/3.5b4pre (.NET CLR 3.5.30729)', array(
+ array('FF', 'Firefox', 'Firefox', '3.5', '3', '5', 'gecko'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.2) Gecko/20090803 Ubuntu/9.04 (jaunty) Shiretoko/3.5.2', array(
+ array('FF', 'Firefox', 'Firefox', '3.5', '3', '5', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6', array(
+ array('FF', 'Firefox', 'Firefox', '3.0', '3', '0', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9a7) Gecko/2007080210 GranParadiso/3.0a7', array(
+ array('FF', 'Firefox', 'Firefox', '3.0', '3', '0', 'gecko'),
+ array('WVI', 'Windows Vista', 'Win Vista'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008072716 IceCat/3.0.1-g1', array(
+ array('FF', 'Firefox', 'Firefox', '3.0', '3', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.1) Gecko/2008071420 Iceweasel/3.0.1 (Debian-3.0.1-1)', array(
+ array('FF', 'Firefox', 'Firefox', '3.0', '3', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1b2) Gecko/20060821 BonEcho/2.0b2', array(
+ array('FF', 'Firefox', 'Firefox', '2.0', '2', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Darwin Power Macintosh; en-US; rv:1.8.0.12) Gecko/20070803 Firefox/1.5.0.12 Fink Community Edition', array(
+ array('FF', 'Firefox', 'Firefox', '1.5', '1', '5', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.6b) Gecko/20031212 Firebird/0.7+', array(
+ array('FB', 'Firebird', 'Firebird', '0.7', '0', '7', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Windows; U; Win98; de-DE; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6', array(
+ array('FB', 'Firebird', 'Firebird', '0.6', '0', '6', 'gecko'),
+ array('W98', 'Windows 98', 'Win 98'))),
+ array('Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.3a) Gecko/20021207 Phoenix/0.5', array(
+ array('PX', 'Phoenix', 'Phoenix', '0.5', '0', '5', 'gecko'),
+ array('WNT', 'Windows NT', 'Win NT'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2b) Gecko/20020923 Phoenix/0.1', array(
+ array('PX', 'Phoenix', 'Phoenix', '0.1', '0', '1', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Nintendo DS v4; U; M3 Adapter CF + PassMe2; en-US; rv:1.8.0.6 ) Gecko/20060728 Firefox/1.5.0.6 (firefox.gba.ds)', array(
+ array('FF', 'Firefox', 'Firefox', '1.5', '1', '5', 'gecko'),
+ array('NDS', 'Nintendo DS', 'DS'))),
+ array('Mozilla/5.0 (Android; Mobile; rv:15.0) Gecko/15.0 Firefox/15.0a1', array(
+ array('FF', 'Firefox', 'Firefox', '15.0', '15', '0', 'gecko'),
+ array('AND', 'Android', 'Android'))),
+
+ // Flock
+ array('Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Flock/3.0.0.3737 Chrome/4.1.249.1071 Safari/532.5', array(
+ array('FL', 'Flock', 'Flock', '3.0', '3', '0', 'webkit'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+ // pre-3.0 is actually gecko
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 Flock/2.5.6 (.NET CLR 3.5.30729)', array(
+ array('FL', 'Flock', 'Flock', '2.5', '2', '5', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 AppleWebKit/531.21.8 KHTML/4.3.5 (like Gecko) Firefox/3.5.7 Flock/2.5.6 (.NET CLR 3.5.30729)', array(
+ array('FL', 'Flock', 'Flock', '2.5', '2', '5', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.7) Gecko/20091221 AppleWebKit/531.21.8 (KHTML, like Gecko) Firefox/3.5.7 Flock/2.5.6 (.NET CLR 3.5.30729)', array(
+ array('FL', 'Flock', 'Flock', '2.5', '2', '5', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.9) Gecko/20071106 Firefox/2.0.0.9 Flock/1.0.1', array(
+ array('FL', 'Flock', 'Flock', '1.0', '1', '0', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.8) Gecko/20071101 Firefox/2.0.0.8 Flock/1.0', array(
+ array('FL', 'Flock', 'Flock', '1.0', '1', '0', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8b5) Gecko/20051021 Flock/0.4 Firefox/1.0+', array(
+ array('FL', 'Flock', 'Flock', '0.4', '0', '4', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+
+ // Fluid
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; nl-nl) AppleWebKit/532.3+ (KHTML, like Gecko) Fluid/0.9.6 Safari/532.3+', array(
+ array('FD', 'Fluid', 'Fluid', '0.9', '0', '9', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Fluid/0.9.4 Safari/525.13', array(
+ array('FD', 'Fluid', 'Fluid', '0.9', '0', '9', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Galeon
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko/20090327 Galeon/2.0.7', array(
+ array('GA', 'Galeon', 'Galeon', '2.0', '2', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.1.19) Gecko/20090701 Galeon/2.0.7', array(
+ array('GA', 'Galeon', 'Galeon', '2.0', '2', '0', 'gecko'),
+ array('OBS', 'OpenBSD', 'OpenBSD'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081216 Galeon/2.0.4 Firefox/2.0.0.19', array(
+ array('GA', 'Galeon', 'Galeon', '2.0', '2', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.13pre) Gecko/20080207 Galeon/2.0.1 (Ubuntu package 2.0.1-1ubuntu2) Firefox/1.5.0.13pre', array(
+ array('GA', 'Galeon', 'Galeon', '2.0', '2', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.6) Gecko/20040406 Galeon/1.3.15', array(
+ array('GA', 'Galeon', 'Galeon', '1.3', '1', '3', 'gecko'),
+ array('BSD', 'FreeBSD', 'FreeBSD'))),
+ array('Mozilla/5.0 Galeon/1.2.9 (X11; Linux i686; U;) Gecko/20021213 Debian/1.2.9-0.bunk', array(
+ array('GA', 'Galeon', 'Galeon', '1.2', '1', '2', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 Galeon/1.0.3 (X11; Linux i686; U;) Gecko/0', array(
+ array('GA', 'Galeon', 'Galeon', '1.0', '1', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Google Earth embedded browser
+ array('Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/532.4 (KHTML, like Gecko) Google Earth/5.2.1.1329 Safari/532.4', array(
+ array('GE', 'Google Earth', 'Google Earth', '5.2', '5', '2', 'webkit'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+
+ // GreenBrowser (treat as IE)
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; Media Center PC 5.0; .NET CLR 3.5.21022; GreenBrowser)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.5.30729; InfoPath.2; .NET CLR 3.0.30729; GreenBrowser)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WVI', 'Windows Vista', 'Win Vista'))),
+
+ // Hana
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko) Hana/1.1', array(
+ array('HA', 'Hana', 'Hana', '1.1', '1', '1', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/417.9 (KHTML, like Gecko) Hana/1.0', array(
+ array('HA', 'Hana', 'Hana', '1.0', '1', '0', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+
+ // HotJava
+ array('HotJava/1.1.2 FCS', array(
+ array('HJ', 'HotJava', 'HotJava', '1.1', '1', '1', 'unknown'),
+ false)),
+ array('HotJava/1.0.1/JRE1.1.x', array(
+ array('HJ', 'HotJava', 'HotJava', '1.0', '1', '0', 'unknown'),
+ false)),
+
+ // iBrowse
+ array('Mozilla/5.0 (compatible; IBrowse 3.0; AmigaOS4.0)', array(
+ array('IB', 'IBrowse', 'IBrowse', '3.0', '3', '0', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+ array('Mozilla/4.0 (compatible; IBrowse 2.3; AmigaOS4.0)', array(
+ array('IB', 'IBrowse', 'IBrowse', '2.3', '2', '3', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+ array('IBrowse/2.4 (AmigaOS 3.9; 68K)', array(
+ array('IB', 'IBrowse', 'IBrowse', '2.4', '2', '4', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+ array('IBrowse/2.3 (AmigaOS V51)', array(
+ array('IB', 'IBrowse', 'IBrowse', '2.3', '2', '3', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+ array('IBrowse/2.3 (AmigaOS 4.0)', array(
+ array('IB', 'IBrowse', 'IBrowse', '2.3', '2', '3', 'unknown'),
+ array('AMI', 'AmigaOS', 'AmigaOS'))),
+
+ // iCab
+ array('iCab/4.5 (Macintosh; U; PPC Mac OS X)', array(
+ array('IC', 'iCab', 'iCab', '4.5', '4', '5', 'unknown'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('iCab/4.5 (Macintosh; U; Mac OS X Leopard 10.5.7)', array(
+ array('IC', 'iCab', 'iCab', '4.5', '4', '5', 'unknown'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (compatible; iCab 3.0.5; Macintosh; U; PPC Mac OS)', array(
+ array('IC', 'iCab', 'iCab', '3.0', '3', '0', 'unknown'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (compatible; iCab 3.0.5; Macintosh; U; PPC Mac OS X)', array(
+ array('IC', 'iCab', 'iCab', '3.0', '3', '0', 'unknown'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS; en) iCab 3', array(
+ array('IC', 'iCab', 'iCab', '3.0', '3', '0', 'unknown'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/4.5 (compatible; iCab 2.7.1; Macintosh; I; PPC)', array(
+ array('IC', 'iCab', 'iCab', '2.7', '2', '7', 'unknown'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('iCab/2.9.8 (Macintosh; U; 68K)', array(
+ array('IC', 'iCab', 'iCab', '2.9', '2', '9', 'unknown'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Lynx/2.8 (compatible; iCab 2.9.8; Macintosh; U; 68K)', array(
+ array('IC', 'iCab', 'iCab', '2.9', '2', '9', 'unknown'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/4/5 (compatible; iCab 2.9.8; Macintosh; U; 68K)', array(
+ array('IC', 'iCab', 'iCab', '2.9', '2', '9', 'unknown'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC)', array(
+ array('IE', 'Internet Explorer', 'IE', '5.0', '5', '0', 'ie'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/4.76 (Macintosh; I; PPC)', array(
+ array('NS', 'Netscape', 'Netscape', '4.76', '4', '76', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+
+ // Internet Explorer
+ array('Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)', array(
+ array('IE', 'Internet Explorer', 'IE', '9.0', '9', '0', 'ie'),
+ array('XBX', 'Xbox', 'Xbox'))),
+ array('Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; Xbox)', array(
+ array('IE', 'Internet Explorer', 'IE', '9.0', '9', '0', 'ie'),
+ array('XBX', 'Xbox', 'Xbox'))),
+ array('Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '10.0', '10', '0', 'ie'),
+ array('WI8', 'Windows 8', 'Win 8'))),
+ array('Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '10.0', '10', '0', 'ie'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/6.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '10.0', '10', '0', 'ie'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+ array('Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '9.0', '9', '0', 'ie'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/5.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '9.0', '9', '0', 'ie'),
+ array('WVI', 'Windows Vista', 'Win Vista'))),
+ array('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET CLR 3.0.04506; .NET CLR 3.5.21022; InfoPath.2; SLCC1; Zune 3.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+ array('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WVI', 'Windows Vista', 'Win Vista'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WVI', 'Windows Vista', 'Win Vista'))),
+ array('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('WS3', 'Windows Server 2003 / XP x64', 'Win S2003'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; WOW64; SV1; .NET CLR 2.0.50727)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('WS3', 'Windows Server 2003 / XP x64', 'Win S2003'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64; x64; SV1; .NET CLR 2.0.50727)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('WS3', 'Windows Server 2003 / XP x64', 'Win S2003'))),
+
+ // IE Mobile
+ array('Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; SAMSUNG; SGH-i917)', array(
+ array('IE', 'Internet Explorer', 'IE', '9.0', '9', '0', 'ie'),
+ array('WPH', 'Windows Phone OS', 'WinPhone'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; XBLWP7; ZuneWP7)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WPH', 'Windows Phone OS', 'WinPhone'))),
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; DeviceManufacturer; DeviceModel)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WPH', 'Windows Phone OS', 'WinPhone'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('WMO', 'Windows Mobile', 'WinMo'))),
+ array('Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320)', array(
+ array('IE', 'Internet Explorer', 'IE', '4.01', '4', '01', 'ie'),
+ array('WCE', 'Windows CE', 'Win CE'))),
+
+ // Internet Explorer with misbehaving Google Tool Bar
+ array('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6.5; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB0.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)', array(
+ array('IE', 'Internet Explorer', 'IE', '8.0', '8', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Iron
+ array('Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/531.0 (KHTML, like Gecko) Iron/3.0.189.0 Safari/531.0', array(
+ array('IR', 'Iron', 'Iron', '3.0', '3', '0', 'webkit'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+
+ // K-Meleon
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3', array(
+ array('KM', 'K-Meleon', 'K-Meleon', '1.5', '1', '5', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Darwin; FreeBSD 5.6; en-GB; rv:1.8.1.17pre) Gecko/20080716 K-Meleon/1.5.0', array(
+ array('KM', 'K-Meleon', 'K-Meleon', '1.5', '1', '5', 'gecko'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.2b) Gecko/20021016 K-Meleon 0.7', array(
+ array('KM', 'K-Meleon', 'K-Meleon', '0.7', '0', '7', 'gecko'),
+ array('WNT', 'Windows NT', 'Win NT'))),
+
+ // Kapiko
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.1) Gecko/20080722 Firefox/3.0.1 Kapiko/3.0', array(
+ array('KP', 'Kapiko', 'Kapiko', '3.0', '3', '0', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Kazehakase
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.11) Gecko Kazehakase/0.5.4 Debian/0.5.4-2.1ubuntu3', array(
+ array('KZ', 'Kazehakase', 'Kazehakase', '0.5', '0', '5', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.13) Gecko/20080311 (Debian-1.8.1.13+nobinonly-0ubuntu1) Kazehakase/0.5.2', array(
+ array('KZ', 'Kazehakase', 'Kazehakase', '0.5', '0', '5', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; Linux x86_64; U;) Gecko/20060207 Kazehakase/0.3.5 Debian/0.3.5-1', array(
+ array('KZ', 'Kazehakase', 'Kazehakase', '0.3', '0', '3', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // KKMAN (treat as IE)
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; KKMAN3.2)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Konqueror
+ array('Mozilla/5.0 (compatible; Konqueror/4.0; Linux) KHTML/4.0.5 (like Gecko)', array(
+ array('KO', 'Konqueror', 'Konqueror', '4.0', '4', '0', 'khtml'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (compatible; Konqueror/4.0; Microsoft Windows) KHTML/4.0.80 (like Gecko)', array(
+ array('KO', 'Konqueror', 'Konqueror', '4.0', '4', '0', 'khtml'),
+ false)),
+ array('Mozilla/5.0 (compatible; Konqueror/3.5; GNU/kFreeBSD) KHTML/3.5.9 (like Gecko) (Debian)', array(
+ array('KO', 'Konqueror', 'Konqueror', '3.5', '3', '5', 'khtml'),
+ array('BSD', 'FreeBSD', 'FreeBSD'))),
+ array('Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)', array(
+ array('KO', 'Konqueror', 'Konqueror', '2.1', '2', '1', 'khtml'),
+ false)),
+
+ // Links
+ array('Links', array(
+ false,
+ false)),
+ array('Links (2.1pre31; Linux 2.6.21-omap1 armv6l; x)', array(
+ array('LI', 'Links', 'Links', '2.1', '2', '1', 'unknown'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Links (0.99; OS/2 1 i386; 80x33)', array(
+ array('LI', 'Links', 'Links', '0.99', '0', '99', 'unknown'),
+ array('OS2', 'OS/2', 'OS/2'))),
+
+ // Lunascape (identity crisis)
+ array('Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1) Gecko/20090701 Firefox/3.5 Lunascape/5.1.2.3', array(
+ array('FF', 'Firefox', 'Firefox', '3.5', '3', '5', 'gecko'),
+ array('WVI', 'Windows Vista', 'Win Vista'))),
+ array('Mozilla/5.0 (Windows; U; ; cs-CZ) AppleWebKit/532+ (KHTML, like Gecko, Safari/532.0) Lunascape/5.1.2.3', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ false)),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; InfoPath.1; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Lunascape 5.1.2.3)', array(
+ array('IE', 'Internet Explorer', 'IE', '6.0', '6', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Lynx
+ array('Lynx (textmode)', array(
+ false,
+ false)),
+ array('Lynx/2.8.7dev.9 libwww-FM/2.14', array(
+ array('LX', 'Lynx', 'Lynx', '2.8', '2', '8', 'unknown'),
+ false)),
+
+ // Maxathon (treat as IE)
+ array('Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322)', array(
+ array('IE', 'Internet Explorer', 'IE', '7.0', '7', '0', 'ie'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Midori
+ array('Midori/0.1.9 (X11; Linux i686; U; fr-fr) WebKit/532+', array(
+ array('MI', 'Midori', 'Midori', '0.1', '0', '1', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux; pt-br) AppleWebKit/531+ (KHTML, like Gecko) Safari/531.2+ Midori/0.3', array(
+ array('MI', 'Midori', 'Midori', '0.3', '0', '3', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Mozilla Suite
+ array('Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.7) Gecko/20070606', array(
+ array('MO', 'Mozilla', 'Mozilla', '1.7', '1', '7', 'gecko'),
+ array('SOS', 'SunOS', 'SunOS'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050927 Debian/1.7.8-1sarge3', array(
+ array('MO', 'Mozilla', 'Mozilla', '1.7', '1', '7', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // NCSA Mosaic
+ array('PATHWORKS Mosaic/1.0 libwww/2.15_Spyglass', array(
+ array('MC', 'NCSA Mosaic', 'Mosaic', '1.0', '1', '0', 'unknown'),
+ false)),
+ array('WinMosaic/Version 2.0 (ALPHA 2)', array(
+ array('MC', 'NCSA Mosaic', 'Mosaic', '2.0', '2', '0', 'unknown'),
+ false)),
+ array('VMS_Mosaic/3.8-1 (Motif;OpenVMS V7.3-2 DEC 3000 - M700) libwww/2.12_Mosaic', array(
+ array('MC', 'NCSA Mosaic', 'Mosaic', '3.8', '3', '8', 'unknown'),
+ array('VMS', 'OpenVMS', 'OpenVMS'))),
+ array('Mosaic from Digital/1.02_Win32', array(
+ array('MC', 'NCSA Mosaic', 'Mosaic', '1.02', '1', '02', 'unknown'),
+ array('W95', 'Windows 95', 'Win 95'))),
+ array('NCSA Mosaic/2.0.0b4 (Windows AXP)', array(
+ array('MC', 'NCSA Mosaic', 'Mosaic', '2.0', '2', '0', 'unknown'),
+ false)),
+ array('NCSA_Mosaic/2.7b5 (X11;Linux 2.6.7 i686) libwww/2.12 modified', array(
+ array('MC', 'NCSA Mosaic', 'Mosaic', '2.7', '2', '7', 'unknown'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('mMosaic/3.6.6 (X11;SunOS 5.8 sun4m)', array(
+ array('MC', 'NCSA Mosaic', 'Mosaic', '3.6', '3', '6', 'unknown'),
+ array('SOS', 'SunOS', 'SunOS'))),
+
+ // Netscape Navigator (9.x)
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8pre) Gecko/20071015 Firefox/2.0.0.7 Navigator/9.0', array(
+ array('NS', 'Netscape', 'Netscape', '9.0', '9', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20070321 Netscape/9.0', array(
+ array('NS', 'Netscape', 'Netscape', '9.0', '9', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Netscape (6.x - 8.x)
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20070321 Netscape/8.1.3', array(
+ array('NS', 'Netscape', 'Netscape', '8.1', '8', '1', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax)', array(
+ array('NS', 'Netscape', 'Netscape', '7.2', '7', '2', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (X11; U; OSF1 alpha; en-US; rv:0.9.4.1) Gecko/20020517 Netscape6/6.2.3', array(
+ array('NS', 'Netscape', 'Netscape', '6.2', '6', '2', 'gecko'),
+ array('T64', 'Tru64', 'Tru64'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.2) Gecko/20010726 Netscape6/6.1', array(
+ array('NS', 'Netscape', 'Netscape', '6.1', '6', '1', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Netscape Communicator (4.x)
+ array('Mozilla/4.76C-SGI [en] (X11; I; IRIX64 6.5 IP30)', array(
+ array('NS', 'Netscape', 'Netscape', '4.76', '4', '76', 'gecko'),
+ array('IRI', 'IRIX', 'IRIX'))),
+ array('Mozilla/4.72 [en] (X11; I; HP-UX B.11.00 9000/800)', array(
+ array('NS', 'Netscape', 'Netscape', '4.72', '4', '72', 'gecko'),
+ array('HPX', 'HP-UX', 'HP-UX'))),
+ array('Mozilla/4.41 (BEOS; U ;Nav)', array(
+ array('NS', 'Netscape', 'Netscape', '4.41', '4', '41', 'gecko'),
+ array('BEO', 'BeOS', 'BeOS'))),
+ array('Mozilla/4.0 (compatible; Windows NT 5.1; U; en)', array(
+ array('NS', 'Netscape', 'Netscape', '4.0', '4', '0', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Netscape Navigator (up to 3.x)
+ array('Mozilla/3.0 (X11; I; AIX 2)', array(
+ array('NS', 'Netscape', 'Netscape', '3.0', '3', '0', 'gecko'),
+ array('AIX', 'AIX', 'AIX'))),
+ array('Mozilla/2.02 [fr] (WinNT; I)', array(
+ array('NS', 'Netscape', 'Netscape', '2.02', '2', '02', 'gecko'),
+ array('WNT', 'Windows NT', 'Win NT'))),
+
+ // NetFront NX
+ array('Mozilla/5.0 (Nintendo WiiU) AppleWebKit/534.52 (KHTML, like Gecko) NX/2.1.0.8.21 NintendoBrowser/1.0.0.7494.US', array(
+ array('NF', 'NetFront', 'NetFront', '2.1', '2', '1', 'webkit'),
+ array('WIU', 'Nintendo Wii U', 'Wii U'))),
+ array('Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7498.US', array(
+ array('NF', 'NetFront', 'NetFront', '1.7498', '1', '7498', 'webkit'),
+ array('3DS', 'Nintendo 3DS', '3DS'))),
+ array('Mozilla/5.0 (Playstation Vita 1.61) AppleWebKit/531.22.8 (KHTML, like Gecko) Silk/3.2', array(
+ array('NF', 'NetFront', 'NetFront', '3.2', '3', '2', 'webkit'),
+ array('PSV', 'PlayStation Vita', 'PS Vita'))),
+
+ // Kindle
+ array('Mozilla/4.0 (compatible; Linux 2.6.10) NetFront/3.3 Kindle/1.0 (screen 600x800)', array(
+ array('NF', 'NetFront', 'NetFront', '3.3', '3', '3', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Kindle Fire Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ array('AND', 'Android', 'Android'))),
+ array('Mozilla/5.0 (Linux; U; en-US) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) Version/4.0 Kindle/3.0 (screen 600×800; rotate)', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.1.0-80) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true', array(
+ array('SF', 'Safari', 'Safari', '5.0', '5', '0', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+
+ // Omniweb
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US) AppleWebKit/525.18 (KHTML, like Gecko, Safari/525.20) OmniWeb/v622.3.0.105198', array(
+ array('OW', 'OmniWeb', 'OmniWeb', '5.8', '5', '8', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/522+ (KHTML, like Gecko, Safari/522) OmniWeb/v613', array(
+ array('OW', 'OmniWeb', 'OmniWeb', '5.6', '5', '6', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/420+ (KHTML, like Gecko, Safari/420) OmniWeb/v607', array(
+ array('OW', 'OmniWeb', 'OmniWeb', '5.5', '5', '5', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/125.4 (KHTML, like Gecko, Safari) OmniWeb/v563.34', array(
+ array('OW', 'OmniWeb', 'OmniWeb', '5.1', '5', '1', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v558.36', array(
+ array('OW', 'OmniWeb', 'OmniWeb', '5.0', '5', '0', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/85 (KHTML, like Gecko) OmniWeb/v496', array(
+ array('OW', 'OmniWeb', 'OmniWeb', '4.5', '4', '5', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+
+ // Opera
+ array('Opera/9.63 (Windows NT 5.1; U; en) Presto/2.1.1', array(
+ array('OP', 'Opera', 'Opera', '9.63', '9', '63', 'opera'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Opera/9.30 (Nintendo Wii; U; ; 2047-7; en)', array(
+ array('OP', 'Opera', 'Opera', '9.30', '9', '30', 'opera'),
+ array('WII', 'Nintendo Wii', 'Wii'))),
+ array('Opera/9.64 (Windows ME; U; en) Presto/2.1.1', array(
+ array('OP', 'Opera', 'Opera', '9.64', '9', '64', 'opera'),
+ array('WME', 'Windows Me', 'Win Me'))),
+ array('Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.00', array(
+ array('OP', 'Opera', 'Opera', '10.00', '10', '0', 'opera'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/4.0 (compatible; MSIE 6.0; Nitro) Opera 8.50 [en Mozilla/4.0 (compatible; MSIE 6.0; Nitro) Opera 8.50 [ja]', array(
+ array('OP', 'Opera', 'Opera', '8.50', '8', '50', 'opera'),
+ array('NDS', 'Nintendo DS', 'DS'))),
+ array('Opera/9.00 (Nintendo DS U; ; 1309-9; de)', array(
+ array('OP', 'Opera', 'Opera', '9.00', '9', '00', 'opera'),
+ array('NDS', 'Nintendo DS', 'DS'))),
+ array('Opera/9.50 (Nintendo DSi; Opera/507; U; en-US) ', array(
+ array('OP', 'Opera', 'Opera', '9.50', '9', '50', 'opera'),
+ array('DSI', 'Nintendo DSi', 'DSi'))),
+
+ // PlayStation
+ array('Mozilla/5.0 (PLAYSTATION 3; 1.00)', array(
+ false,
+ array('PS3', 'PlayStation 3', 'PS3'))),
+
+ // PSP
+ array('PSP (PlayStation Portable); 2.00', array(
+ false,
+ array('PSP', 'PlayStation Portable', 'PSP'))),
+ array('Mozilla/4.0 (PSP (PlayStation Portable); 2.00)', array(
+ false,
+ array('PSP', 'PlayStation Portable', 'PSP'))),
+
+ // Rekonq 1.0+
+ array('Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.34 (KHTML, like Gecko) rekonq/1.0 Safari/534.34', array(
+ array('RK', 'Rekonq', 'Rekonq', '1.0', '1', '0', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Safari
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21', array(
+ array('SF', 'Safari', 'Safari', '3.1', '3', '1', 'webkit'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_2 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5G77 Safari/525.20', array(
+ array('SF', 'Safari', 'Safari', '3.1', '3', '1', 'webkit'),
+ array('IPH', 'iPhone', 'iPhone'))),
+ array('Mozilla/5.0 (iPod; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3A100a Safari/419.3', array(
+ array('SF', 'Safari', 'Safari', '3.0', '3', '0', 'webkit'),
+ array('IPD', 'iPod', 'iPod'))),
+ array('Mozilla/5.0 (iPod; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11a Safari/525.20', array(
+ array('SF', 'Safari', 'Safari', '3.1', '3', '1', 'webkit'),
+ array('IPD', 'iPod', 'iPod'))),
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/527.3+ (KHTML, like Gecko) Version/3.1.2 Safari/525.20.1', array(
+ array('SF', 'Safari', 'Safari', '3.1', '3', '1', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ array('IPA', 'iPad', 'iPad'))),
+ array('Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ array('IPA', 'iPad', 'iPad'))),
+ array('Mozilla/5.0 (iPod; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ array('IPD', 'iPod', 'iPod'))),
+ array('Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7', array(
+ array('SF', 'Safari', 'Safari', '4.0', '4', '0', 'webkit'),
+ array('IPH', 'iPhone', 'iPhone'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) ', array(
+ array('SF', 'Safari', 'Safari', '5.0', '5', '0', 'webkit'),
+ array('WVI', 'Windows Vista', 'Win Vista'))),
+ array('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50', array(
+ array('SF', 'Safari', 'Safari', '5.1', '5', '1', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Mobile/10B141', array(
+ array('SF', 'Safari', 'Safari', '6.0', '6', '0', 'webkit'),
+ array('IPH', 'iPhone', 'iPhone'))),
+ array('Mozilla/5.0 (iPhone; CPU iPhone OS 6_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B141 Safari/8536.25', array(
+ array('SF', 'Safari', 'Safari', '6.0', '6', '0', 'webkit'),
+ array('IPH', 'iPhone', 'iPhone'))),
+
+ // SeaMonkey (formerly Mozilla Suite and rebranded versions)
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071008 Iceape/1.1.5 (Ubuntu-1.1.5-1ubuntu0.7.10)', array(
+ array('SM', 'SeaMonkey', 'SeaMonkey', '1.1', '1', '1', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1b4pre) Gecko/20090405 SeaMonkey/2.0b1pre', array(
+ array('SM', 'SeaMonkey', 'SeaMonkey', '2.0', '2', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9) Gecko', array(
+ // this pre-2.0 UA is missing the SeaMonkey/X.Y
+ array('SM', 'SeaMonkey', 'SeaMonkey', '1.9', '1', '9', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+ array('Mozilla/5.0 (Windows; U; Windows NT 5.1; cs; rv:1.9) Gecko/2008052906', array(
+ // this pre-2.0 UA is missing the SeaMonkey/X.Y
+ array('SM', 'SeaMonkey', 'SeaMonkey', '1.9', '1', '9', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ // Palm webOS
+ array('Mozilla/5.0 (webOS/1.0; U; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0', array(
+ array('WO', 'Palm webOS', 'webOS', '1.0', '1', '0', 'webkit'),
+ array('WOS', 'Palm webOS', 'webOS'))),
+ array('Mozilla/5.0 (webOS/Palm webOS 1.2.9; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pixi/1.0', array(
+ array('WO', 'Palm webOS', 'webOS', '1.0', '1', '0', 'webkit'),
+ array('WOS', 'Palm webOS', 'webOS'))),
+ array('Mozilla/5.0 [en] (PalmOS; U; WebPro/3.5; Palm-Zi72)', array(
+ array('WP', 'WebPro', 'WebPro', '3.5', '3', '5', 'unknown'),
+ array('POS', 'Palm OS', 'Palm OS'))),
+
+ // Palm WebPro
+ array('Mozilla/4.76 [en] (PalmOS; U; WebPro/3.0.1a; Palm-Cct1)', array(
+ array('WP', 'WebPro', 'WebPro', '3.0', '3', '0', 'unknown'),
+ array('POS', 'Palm OS', 'Palm OS'))),
+ array('Mozilla/4.76 [en] (PalmOS; U; WebPro/3.0; Palm-Arz1)', array(
+ array('WP', 'WebPro', 'WebPro', '3.0', '3', '0', 'unknown'),
+ array('POS', 'Palm OS', 'Palm OS'))),
+
+ // Shiira 1.x - treat as Safari since it uses the installed version of Safari's WebKit
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/417.9 (KHTML, like Gecko, Safari) Shiira/1.1', array(
+ array('SF', 'Safari', 'Safari', '2.0', '2', '0', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+ array('Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pl-pl) AppleWebKit/312.8 (KHTML, like Gecko) Shiira/1.2.1 Safari/125', array(
+ array('SF', 'Safari', 'Safari', '1.3', '1', '3', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+
+ // Shiira 2.x - ditto
+ array('Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/525.28.3 (KHTML, like Gecko) Shiira Safari/125', array(
+ array('SF', 'Safari', 'Safari', '3.2', '3', '2', 'webkit'),
+ array('MAC', 'Mac OS', 'Mac OS'))),
+
+ // SymbianOS
+ array('Nokia3650/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0', array(
+ false,
+ array('SYM', 'SymbianOS', 'SymbianOS'))),
+ array('Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0 Nokia5800d-1b/20.2.014; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413', array(
+ array('SF', 'Safari', 'Safari', '2.0', '2', '0', 'webkit'),
+ array('SYM', 'SymbianOS', 'SymbianOS'))),
+ array('Opera/9.80 (S60; SymbOS; Opera Mobi/499; U; en-GB) Presto/2.4.18 Version/10.00', array(
+ array('OP', 'Opera', 'Opera', '10.00', '10', '00', 'opera'),
+ array('SYM', 'SymbianOS', 'SymbianOS'))),
+ array('SonyEricssonG700/R100 Mozilla/4.0 (compatible; MSIE 6.0; Symbian OS; 958) Opera 8.65 [ru]', array(
+ array('OP', 'Opera', 'Opera', '8.65', '8', '65', 'opera'),
+ array('SYM', 'SymbianOS', 'SymbianOS'))),
+
+ // Appcelerator Titanium
+ array('Appcelerator Titanium/1.8.0 (iPhone Simulator/4.3; iPhone OS; en_US;)', array(
+ array('TI', 'Titanium', 'Titanium', '1.8', '1', '8', 'webkit'),
+ array('IPH', 'iPhone', 'iPhone'))),
+
+ array('Appcelerator Titanium/1.8.0 (iPod touch/4.3.1; iPhone OS; de_DE;)', array(
+ array('TI', 'Titanium', 'Titanium', '1.8', '1', '8', 'webkit'),
+ array('IPD', 'iPod', 'iPod'))),
+
+ array('Appcelerator Titanium/1.8.0 (iPad/4.3.3; iPhone OS; de_DE;)', array(
+ array('TI', 'Titanium', 'Titanium', '1.8', '1', '8', 'webkit'),
+ array('IPA', 'iPad', 'iPad'))),
+
+ array('Dalvik/1.1.0 (Linux; U; Android 2.1; google_sdk Build/ERD79) Titanium/1.8.0', array(
+ array('TI', 'Titanium', 'Titanium', '1.8', '1', '8', 'webkit'),
+ array('AND', 'Android', 'Android'))),
+
+ array('Dalvik/1.4.0 (Linux; U; Android 2.3.3; GT-I9100 Build/GINGERBREAD) Titanium/1.8.0', array(
+ array('TI', 'Titanium', 'Titanium', '1.8', '1', '8', 'webkit'),
+ array('AND', 'Android', 'Android'))),
+
+ array('Mozilla/5.0 (X11; U; CrOS i686 9.10.0; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.253.0 Safari/532.5', array(
+ array('CH', 'Chrome', 'Chrome', '4.0', '4', '0', 'webkit'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ // Email Clients
+
+ // Thunderbird
+ array('Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20120713 Thunderbird/14.0 Lightning/1.6', array(
+ array('TB', 'Thunderbird', 'Thunderbird', '14.0', '14', '0', 'gecko'),
+ array('WXP', 'Windows XP', 'Win XP'))),
+
+ array('Mozilla/5.0 (X11; Linux i686; rv:16.0) Gecko/20121011 Thunderbird/16.0.1', array(
+ array('TB', 'Thunderbird', 'Thunderbird', '16.0', '16', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux'))),
+
+ array('Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20130107 Thunderbird/17.0.2 Lightning/1.9', array(
+ array('TB', 'Thunderbird', 'Thunderbird', '17.0', '17', '0', 'gecko'),
+ array('WI7', 'Windows 7', 'Win 7'))),
+
+ array('Mozilla/5.0 (X11; Linux i686 on x86_64; rv:15.0) Gecko/20120907 Thunderbird/15.0.1', array(
+ array('TB', 'Thunderbird', 'Thunderbird', '15.0', '15', '0', 'gecko'),
+ array('LIN', 'Linux', 'Linux')))
+
+ );
+ }
+
+ /**
+ * Test getBrowser()
+ *
+ * @dataProvider getUserAgents
+ * @group Plugins
+ */
+ public function testGetBrowser($userAgent, $expected)
+ {
+ $res = UserAgentParser::getBrowser($userAgent);
+ $family = false;
+
+ if ($res === false)
+ $this->assertFalse($expected[0]);
+ else {
+ $family = \Piwik\Plugins\UserSettings\getBrowserFamily($res['id']);
+ $this->assertEquals($expected[0][0], $res['id']);
+ $this->assertEquals($expected[0][1], $res['name']);
+ $this->assertEquals($expected[0][2], $res['short_name']);
+ $this->assertEquals($expected[0][3], $res['version']);
+ $this->assertEquals($expected[0][4], $res['major_number']);
+ $this->assertEquals($expected[0][5], $res['minor_number']);
+ $this->assertEquals($expected[0][6], $family);
+ }
+ }
+
+ /**
+ * Test getOperatingSystem()
+ *
+ * @dataProvider getUserAgents
+ * @group Plugins
+ */
+ public function testGetOperatingSystem($userAgent, $expected)
+ {
+ $res = UserAgentParser::getOperatingSystem($userAgent);
+
+ $this->assertEquals($expected[1][0], $res['id']);
+ $this->assertEquals($expected[1][1], $res['name']);
+ $this->assertEquals($expected[1][2], $res['short_name']);
+ }
+}
diff --git a/plugins/UsersManager/tests/APITest.php b/plugins/UsersManager/tests/Integration/APITest.php
index 60a53af07f..e84cd5b750 100644
--- a/plugins/UsersManager/tests/APITest.php
+++ b/plugins/UsersManager/tests/Integration/APITest.php
@@ -11,14 +11,15 @@ use Piwik\Access;
use FakeAccess;
use Piwik\Piwik;
use Piwik\Plugins\UsersManager\API;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group UsersManager
* @group APITest
- * @group Database
+ * @group Plugins
*/
-class APITest extends \DatabaseTestCase
+class APITest extends IntegrationTestCase
{
/**
* @var API
diff --git a/plugins/UsersManager/tests/UserPreferencesTest.php b/plugins/UsersManager/tests/Integration/UserPreferencesTest.php
index 7f27529b02..cd23e7baa3 100644
--- a/plugins/UsersManager/tests/UserPreferencesTest.php
+++ b/plugins/UsersManager/tests/Integration/UserPreferencesTest.php
@@ -7,20 +7,22 @@
*/
namespace Piwik\Plugins\UsersManager\tests;
+
use Piwik\Piwik;
use Piwik\Plugins\UsersManager\UserPreferences;
use Piwik\Plugins\UsersManager\API as APIUsersManager;
use FakeAccess;
use Piwik\Access;
-use Piwik\Tests\Fixture;
+use Piwik\Tests\Impl\Fixture;
+use Piwik\Tests\Impl\IntegrationTestCase;
/**
* @group UsersManager
* @group UserPreferencesTest
- * @group Database
+ * @group Plugins
* @group Plugins
*/
-class UserPreferencesTest extends \DatabaseTestCase
+class UserPreferencesTest extends IntegrationTestCase
{
/**
* @var UserPreferences
diff --git a/plugins/UsersManager/tests/Integration/UsersManagerTest.php b/plugins/UsersManager/tests/Integration/UsersManagerTest.php
new file mode 100644
index 0000000000..e813c2ac1b
--- /dev/null
+++ b/plugins/UsersManager/tests/Integration/UsersManagerTest.php
@@ -0,0 +1,919 @@
+<?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\Plugins\UsersManager\tests\Integration;
+
+use Piwik\Access;
+use Piwik\Plugins\SitesManager\API as APISitesManager;
+use Piwik\Plugins\UsersManager\API;
+use Piwik\Plugins\UsersManager\Model;
+use Piwik\Translate;
+use Piwik\Tests\Impl\IntegrationTestCase;
+use FakeAccess;
+use Exception;
+
+
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ * @group UsersManagerTest
+ * @group UsersManager
+ * @group Plugins
+ */
+class UsersManagerTest extends IntegrationTestCase
+{
+ /**
+ * @var API
+ */
+ private $api;
+
+ /**
+ * @var Model
+ */
+ private $model;
+
+ public function setUp()
+ {
+ parent::setUp();
+
+ \Piwik\Plugin\Manager::getInstance()->loadPlugin('UsersManager');
+ \Piwik\Plugin\Manager::getInstance()->installLoadedPlugins();
+
+ // setup the access layer
+ $pseudoMockAccess = new FakeAccess;
+ FakeAccess::setIdSitesView(array(1, 2));
+ FakeAccess::setIdSitesAdmin(array(3, 4));
+
+ //finally we set the user as a Super User by default
+ FakeAccess::$superUser = true;
+ FakeAccess::$superUserLogin = 'superusertest';
+ Access::setSingletonInstance($pseudoMockAccess);
+
+ $this->api = API::getInstance();
+ $this->model = new Model();
+ }
+
+ private function _flatten($sitesAccess)
+ {
+ $result = array();
+
+ foreach ($sitesAccess as $siteAccess) {
+ $result[$siteAccess['site']] = $siteAccess['access'];
+ }
+
+ return $result;
+ }
+
+ private function _checkUserHasNotChanged($user, $newPassword, $newEmail = null, $newAlias = null)
+ {
+ if (is_null($newEmail)) {
+ $newEmail = $user['email'];
+ }
+ if (is_null($newAlias)) {
+ $newAlias = $user['alias'];
+ }
+ $userAfter = $this->api->getUser($user["login"]);
+ unset($userAfter['date_registered']);
+
+ // we now compute what the token auth should be, it should always be a hash of the login and the current password
+ // if the password has changed then the token_auth has changed!
+ $user['token_auth'] = $this->api->getTokenAuth($user["login"], md5($newPassword));
+ $user['password'] = md5($newPassword);
+ $user['email'] = $newEmail;
+ $user['alias'] = $newAlias;
+ $user['superuser_access'] = 0;
+ $this->assertEquals($user, $userAfter);
+ }
+
+ /**
+ * bad password => exception#
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionInvalidPassword
+ */
+ public function testUpdateUserBadpasswd()
+ {
+ $login = "login";
+ $user = array('login' => $login,
+ 'password' => "geqgeagae",
+ 'email' => "test@test.com",
+ 'alias' => "alias");
+
+ $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']);
+
+ try {
+ $this->api->updateUser($login, "pas");
+ } catch (Exception $expected) {
+ $this->_checkUserHasNotChanged($user, $user['password']);
+ throw $expected;
+ }
+ }
+
+ /**
+ * Dataprovider
+ */
+ public function getAddUserInvalidLoginData()
+ {
+ return array(
+ array(12, "password", "email@email.com", "alias"), // wrong login / integer => exception
+ array("gegag'ggea'", "password", "email@email.com", "alias"), // wrong login / too short => exception
+ array("gegag11gge&", "password", "email@email.com", "alias"), // wrong login / too long => exception
+ array("geg'ag11gge@", "password", "email@email.com", "alias"), // wrong login / bad characters => exception
+ );
+ }
+
+ /**
+ * @dataProvider getAddUserInvalidLoginData
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionInvalidLogin
+ */
+ public function testAddUserWrongLogin($userLogin, $password, $email, $alias)
+ {
+ $this->api->addUser($userLogin, $password, $email, $alias);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionLoginExists
+ */
+ public function testAddUserExistingLogin()
+ {
+ $this->api->addUser("test", "password", "email@email.com", "alias");
+ $this->api->addUser("test", "password2", "em2ail@email.com", "al2ias");
+ }
+
+ /**
+ * Dataprovider for wrong password tests
+ */
+ public function getWrongPasswordTestData()
+ {
+ return array(
+ array("geggeqgeqag", "pas", "email@email.com", "alias"), // too short -> exception
+ array("ghqgeggg", "gegageqqqqqqqgeqgqeg84897897897897g122", "email@email.com", "alias"), // too long -> exception
+ array("geggeqgeqag", "", "email@email.com", "alias"), // empty -> exception
+ );
+ }
+
+ /**
+ * @dataProvider getWrongPasswordTestData
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionInvalidPassword
+ */
+ public function testAddUserWrongPassword($userLogin, $password, $email, $alias)
+ {
+ $this->api->addUser($userLogin, $password, $email, $alias);
+ }
+
+ /**
+ * Dataprovider for wrong email tests
+ */
+ public function getWrongEmailTestData()
+ {
+ return array(
+ array("geggeqgeqag", "geqgeagae", "ema'il@email.com", "alias"),
+ array("geggeqgeqag", "geqgeagae", "@email.com", "alias"),
+ array("geggeqgeqag", "geqgeagae", "email@.com", "alias"),
+ array("geggeqgeqag", "geqgeagae", "email@4.", "alias"),
+ array("geggeqgeqag", "geqgeagae", "", "alias"),
+ );
+ }
+
+ /**
+ * @dataProvider getWrongEmailTestData
+ * @expectedException \Exception
+ * @expectedExceptionMessage mail
+ */
+ public function testAddUserWrongEmail($userLogin, $password, $email, $alias)
+ {
+ $this->api->addUser($userLogin, $password, $email, $alias);
+ }
+
+ /**
+ * empty alias => use login
+ */
+ public function testAddUserEmptyAlias()
+ {
+ $login = "geggeqgeqag";
+ $this->api->addUser($login, "geqgeagae", "mgeagi@geq.com", "");
+ $user = $this->api->getUser($login);
+ $this->assertEquals($login, $user['alias']);
+ $this->assertEquals($login, $user['login']);
+ }
+
+ /**
+ * no alias => use login
+ */
+ public function testAddUserNoAliasSpecified()
+ {
+ $login = "geggeqg455eqag";
+ $this->api->addUser($login, "geqgeagae", "mgeagi@geq.com");
+ $user = $this->api->getUser($login);
+ $this->assertEquals($login, $user['alias']);
+ $this->assertEquals($login, $user['login']);
+ }
+
+ /**
+ * normal test case
+ */
+ public function testAddUser()
+ {
+ $login = "geggeq55eqag";
+ $password = "mypassword";
+ $email = "mgeag4544i@geq.com";
+ $alias = "her is my alias )(&|\" '£%*(&%+))";
+
+ $time = time();
+ $this->api->addUser($login, $password, $email, $alias);
+ $user = $this->api->getUser($login);
+
+ // check that the date registered is correct
+ $this->assertTrue($time <= strtotime($user['date_registered']) && strtotime($user['date_registered']) <= time(),
+ "the date_registered " . strtotime($user['date_registered']) . " is different from the time() " . time());
+ $this->assertTrue($user['date_registered'] <= time());
+
+ // check that token is 32 chars
+ $this->assertEquals(32, strlen($user['password']));
+
+ // that the password has been md5
+ $this->assertEquals(md5($login . md5($password)), $user['token_auth']);
+
+ // check that all fields are the same
+ $this->assertEquals($login, $user['login']);
+ $this->assertEquals(md5($password), $user['password']);
+ $this->assertEquals($email, $user['email']);
+ $this->assertEquals($alias, $user['alias']);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionDeleteDoesNotExist
+ */
+ public function testSeleteUserDoesntExist()
+ {
+ $this->api->addUser("geggeqgeqag", "geqgeagae", "test@test.com", "alias");
+ $this->api->deleteUser("geggeqggnew");
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionDeleteDoesNotExist
+ */
+ public function testDeleteUserEmptyUser()
+ {
+ $this->api->deleteUser("");
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionDeleteDoesNotExist
+ */
+ public function testDeleteUserNullUser()
+ {
+ $this->api->deleteUser(null);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionDeleteOnlyUserWithSuperUserAccess
+ */
+ public function testDeleteUser_ShouldFail_InCaseTheUserIsTheOnlyRemainingSuperUser()
+ {
+ //add user and set some rights
+ $this->api->addUser("regularuser", "geqgeagae1", "test1@test.com", "alias1");
+ $this->api->addUser("superuser", "geqgeagae2", "test2@test.com", "alias2");
+ $this->api->setSuperUserAccess('superuser', true);
+
+ // delete the user
+ $this->api->deleteUser("superuser");
+ }
+
+ /**
+ * normal case, user deleted
+ */
+ public function testDeleteUser()
+ {
+ $this->addSites(3);
+
+ //add user and set some rights
+ $this->api->addUser("geggeqgeqag", "geqgeagae", "test@test.com", "alias");
+ $this->api->setUserAccess("geggeqgeqag", "view", array(1, 2));
+ $this->api->setUserAccess("geggeqgeqag", "admin", array(1, 3));
+
+ // check rights are set
+ $this->assertNotEquals(array(), $this->api->getSitesAccessFromUser("geggeqgeqag"));
+
+ // delete the user
+ $this->api->deleteUser("geggeqgeqag");
+
+ // try to get it, it should raise an exception
+ try {
+ $this->api->getUser("geggeqgeqag");
+ $this->fail("Exception not raised.");
+ } catch (Exception $expected) {
+ $this->assertRegExp("(UsersManager_ExceptionUserDoesNotExist)", $expected->getMessage());
+ }
+
+ // add the same user
+ $this->api->addUser("geggeqgeqag", "geqgeagae", "test@test.com", "alias");
+
+ //checks access have been deleted
+ //to do so we recreate the same user login and check if the rights are still there
+ $this->assertEquals(array(), $this->api->getSitesAccessFromUser("geggeqgeqag"));
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionUserDoesNotExist
+ */
+ public function testGetUserNoUser()
+ {
+ // try to get it, it should raise an exception
+ $this->api->getUser("geggeqgeqag");
+ }
+
+ /**
+ * normal case
+ */
+ public function test_GetUser()
+ {
+ $login = "geggeq55eqag";
+ $password = "mypassword";
+ $email = "mgeag4544i@geq.com";
+ $alias = "";
+
+ $this->api->addUser($login, $password, $email, $alias);
+ $user = $this->api->getUser($login);
+
+ // check that all fields are the same
+ $this->assertEquals($login, $user['login']);
+ $this->assertInternalType('string', $user['password']);
+ $this->assertInternalType('string', $user['date_registered']);
+ $this->assertEquals($email, $user['email']);
+
+ //alias shouldnt be empty even if no alias specified
+ $this->assertGreaterThan(0, strlen($user['alias']));
+ }
+
+ /**
+ * no user => empty array
+ */
+ public function testGetUsersNoUser()
+ {
+ $this->assertEquals($this->api->getUsers(), array());
+ }
+
+ /**
+ * normal case
+ * as well as selecting specific user names, comma separated
+ */
+ public function testGetUsers()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+ $this->api->addUser("geggeqge632ge56a4qag", "geqgegeagae", "tesggt@tesgt.com", "alias");
+ $this->api->addUser("geggeqgeqagqegg", "geqgeaggggae", "tesgggt@tesgt.com");
+
+ $users = $this->api->getUsers();
+ $users = $this->_removeNonTestableFieldsFromUsers($users);
+ $user1 = array('login' => "gegg4564eqgeqag", 'password' => md5("geqgegagae"), 'alias' => "alias", 'email' => "tegst@tesgt.com", 'superuser_access' => 0);
+ $user2 = array('login' => "geggeqge632ge56a4qag", 'password' => md5("geqgegeagae"), 'alias' => "alias", 'email' => "tesggt@tesgt.com", 'superuser_access' => 0);
+ $user3 = array('login' => "geggeqgeqagqegg", 'password' => md5("geqgeaggggae"), 'alias' => 'geggeqgeqagqegg', 'email' => "tesgggt@tesgt.com", 'superuser_access' => 0);
+ $expectedUsers = array($user1, $user2, $user3);
+ $this->assertEquals($expectedUsers, $users);
+ $this->assertEquals(array($user1), $this->_removeNonTestableFieldsFromUsers($this->api->getUsers('gegg4564eqgeqag')));
+ $this->assertEquals(array($user1, $user2), $this->_removeNonTestableFieldsFromUsers($this->api->getUsers('gegg4564eqgeqag,geggeqge632ge56a4qag')));
+ }
+
+ protected function _removeNonTestableFieldsFromUsers($users)
+ {
+ foreach ($users as &$user) {
+ unset($user['token_auth']);
+ unset($user['date_registered']);
+ }
+ return $users;
+ }
+
+ /**
+ * normal case
+ */
+ public function testGetUsersLogin()
+ {
+ $this->api->addUser('gegg4564eqgeqag', 'geqgegagae', 'tegst@tesgt.com', 'alias');
+ $this->api->addUser("geggeqge632ge56a4qag", "geqgegeagae", "tesggt@tesgt.com", "alias");
+ $this->api->addUser("geggeqgeqagqegg", "geqgeaggggae", "tesgggt@tesgt.com");
+
+ $logins = $this->api->getUsersLogin();
+
+ $this->assertEquals(array("gegg4564eqgeqag", "geggeqge632ge56a4qag", "geggeqgeqagqegg"), $logins);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionUserDoesNotExist
+ */
+ public function testSetUserAccessNoLogin()
+ {
+ $this->api->setUserAccess("nologin", "view", 1);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionAccessValues
+ */
+ public function testSetUserAccessWrongAccessSpecified()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+ $this->api->setUserAccess("gegg4564eqgeqag", "viewnotknown", 1);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionAccessValues
+ */
+ public function testSetUserAccess_ShouldFail_SuperUserAccessIsNotAllowed()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+ $this->api->setUserAccess("gegg4564eqgeqag", "superuser", 1);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionUserDoesNotExist
+ */
+ public function testSetUserAccess_ShouldFail_IfLoginIsConfigSuperUserLogin()
+ {
+ $this->api->setUserAccess('superusertest', 'view', 1);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionSuperUserAccess
+ */
+ public function testSetUserAccess_ShouldFail_IfLoginIsUserWithSuperUserAccess()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+ $this->api->setSuperUserAccess('gegg4564eqgeqag', true);
+
+ $this->api->setUserAccess('gegg4564eqgeqag', 'view', 1);
+ }
+
+ /**
+ * idsites = all => apply access to all websites with admin access
+ */
+ public function testSetUserAccessIdsitesIsAll()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+
+ FakeAccess::$superUser = false;
+
+ $this->api->setUserAccess("gegg4564eqgeqag", "view", "all");
+
+ FakeAccess::$superUser = true;
+ $access = $this->api->getSitesAccessFromUser("gegg4564eqgeqag");
+ $access = $this->_flatten($access);
+
+ FakeAccess::$superUser = false;
+ $this->assertEquals(array_keys($access), FakeAccess::getSitesIdWithAdminAccess());
+
+ // we want to test the case for which we have actually set some rights
+ // if this is not OK then change the setUp method and add some admin rights for some websites
+ $this->assertGreaterThan(0, count(array_keys($access)));
+ }
+
+ /**
+ * idsites = all AND user is superuser=> apply access to all websites
+ */
+ public function testSetUserAccessIdsitesIsAllSuperuser()
+ {
+ FakeAccess::$superUser = true;
+
+ $idSites = $this->addSites(5);
+
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+ $this->api->setUserAccess("gegg4564eqgeqag", "view", "all");
+
+ $access = $this->api->getSitesAccessFromUser("gegg4564eqgeqag");
+ $access = $this->_flatten($access);
+ $this->assertEquals($idSites, array_keys($access));
+ }
+
+ /**
+ * @expectedException \Exception
+ */
+ public function testSetUserAccess_ShouldNotBeAbleToSetAnyAccess_IfIdSitesIsEmpty()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+
+ $this->api->setUserAccess("gegg4564eqgeqag", "view", array());
+ }
+
+ /**
+ * normal case, access set for only one site
+ */
+ public function testSetUserAccessIdsitesOneSite()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+ $idSites = $this->addSites(1);
+
+ $this->api->setUserAccess("gegg4564eqgeqag", "view", $idSites);
+
+ $access = $this->api->getSitesAccessFromUser("gegg4564eqgeqag");
+ $access = $this->_flatten($access);
+ $this->assertEquals($idSites, array_keys($access));
+ }
+
+ /**
+ * normal case, access set for multiple sites
+ */
+ public function testSetUserAccessIdsitesMultipleSites()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+ list($id1, $id2, $id3) = $this->addSites(3);
+
+ $this->api->setUserAccess("gegg4564eqgeqag", "view", array($id1, $id3));
+
+ $access = $this->api->getSitesAccessFromUser("gegg4564eqgeqag");
+ $access = $this->_flatten($access);
+ $this->assertEquals(array($id1, $id3), array_keys($access));
+ }
+
+ /**
+ * normal case, string idSites comma separated access set for multiple sites
+ */
+ public function testSetUserAccessWithIdSitesIsStringCommaSeparated()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+ list($id1, $id2, $id3) = $this->addSites(3);
+
+ $this->api->setUserAccess("gegg4564eqgeqag", "view", "1,3");
+
+ $access = $this->api->getSitesAccessFromUser("gegg4564eqgeqag");
+ $access = $this->_flatten($access);
+ $this->assertEquals(array($id1, $id3), array_keys($access));
+ }
+
+ /**
+ * normal case, set different acccess to different websites for one user
+ */
+ public function testSetUserAccessMultipleCallDistinctAccessSameUser()
+ {
+ $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias");
+
+ list($id1, $id2) = $this->addSites(2);
+
+ $this->api->setUserAccess("gegg4564eqgeqag", "view", array($id1));
+ $this->api->setUserAccess("gegg4564eqgeqag", "admin", array($id2));
+
+ $access = $this->api->getSitesAccessFromUser("gegg4564eqgeqag");
+ $access = $this->_flatten($access);
+ $this->assertEquals(array($id1 => 'view', $id2 => 'admin'), $access);
+ }
+
+ /**
+ * normal case, set different access to different websites for multiple users
+ */
+ public function testSetUserAccessMultipleCallDistinctAccessMultipleUser()
+ {
+ $this->api->addUser("user1", "geqgegagae", "tegst@tesgt.com", "alias");
+ $this->api->addUser("user2", "geqgegagae", "tegst2@tesgt.com", "alias");
+
+ list($id1, $id2, $id3) = $this->addSites(3);
+
+ $this->api->setUserAccess("user1", "view", array($id1, $id2));
+ $this->api->setUserAccess("user2", "admin", array($id1));
+ $this->api->setUserAccess("user2", "view", array($id3, $id2));
+
+ $access1 = $this->api->getSitesAccessFromUser("user1");
+ $access1 = $this->_flatten($access1);
+ $access2 = $this->api->getSitesAccessFromUser("user2");
+ $access2 = $this->_flatten($access2);
+ $wanted1 = array($id1 => 'view', $id2 => 'view',);
+ $wanted2 = array($id1 => 'admin', $id2 => 'view', $id3 => 'view');
+
+ $this->assertEquals($wanted1, $access1);
+ $this->assertEquals($wanted2, $access2);
+
+ $access1 = $this->api->getUsersAccessFromSite($id1);
+ $access2 = $this->api->getUsersAccessFromSite($id2);
+ $access3 = $this->api->getUsersAccessFromSite($id3);
+ $wanted1 = array('user1' => 'view', 'user2' => 'admin',);
+ $wanted2 = array('user1' => 'view', 'user2' => 'view');
+ $wanted3 = array('user2' => 'view');
+
+ $this->assertEquals($wanted1, $access1);
+ $this->assertEquals($wanted2, $access2);
+ $this->assertEquals($wanted3, $access3);
+
+ $access1 = $this->api->getUsersSitesFromAccess('view');
+ $access2 = $this->api->getUsersSitesFromAccess('admin');
+ $wanted1 = array('user1' => array($id1, $id2), 'user2' => array($id2, $id3));
+ $wanted2 = array('user2' => array($id1));
+
+ $this->assertEquals($wanted1, $access1);
+ $this->assertEquals($wanted2, $access2);
+
+ // Test getUsersWithSiteAccess
+ $users = $this->api->getUsersWithSiteAccess($id1, $access = 'view');
+ $this->assertEquals(1, count($users));
+ $this->assertEquals('user1', $users[0]['login']);
+ $users = $this->api->getUsersWithSiteAccess($id2, $access = 'view');
+ $this->assertEquals(2, count($users));
+ $users = $this->api->getUsersWithSiteAccess($id1, $access = 'admin');
+ $this->assertEquals(1, count($users));
+ $this->assertEquals('user2', $users[0]['login']);
+ $users = $this->api->getUsersWithSiteAccess($id3, $access = 'admin');
+ $this->assertEquals(0, count($users));
+ }
+
+ /**
+ * we set access for one user for one site several times and check that it is updated
+ */
+ public function testSetUserAccessMultipleCallOverwriteSingleUserOneSite()
+ {
+ $this->api->addUser("user1", "geqgegagae", "tegst@tesgt.com", "alias");
+
+ list($id1, $id2) = $this->addSites(2);
+
+ $this->api->setUserAccess("user1", "view", array($id1, $id2));
+ $this->api->setUserAccess("user1", "admin", array($id1));
+
+ $access1 = $this->api->getSitesAccessFromUser("user1");
+ $access1 = $this->_flatten($access1);
+ $wanted1 = array($id1 => 'admin', $id2 => 'view',);
+
+ $this->assertEquals($wanted1, $access1);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage checkUserHasSuperUserAccess Fake exception
+ */
+ public function testSetSuperUserAccess_ShouldFail_IfUserHasNotSuperUserPermission()
+ {
+ FakeAccess::setSuperUserAccess(false);
+ $this->api->setSuperUserAccess('nologin', false);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionUserDoesNotExist
+ */
+ public function testSetSuperUserAccess_ShouldFail_IfUserWithGivenLoginDoesNotExist()
+ {
+ $this->api->setSuperUserAccess('nologin', false);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionEditAnonymous
+ */
+ public function testSetSuperUserAccess_ShouldFail_IfUserIsAnonymous()
+ {
+ $this->api->setSuperUserAccess('anonymous', true);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionRemoveSuperUserAccessOnlySuperUser
+ */
+ public function testSetSuperUserAccess_ShouldFail_IfUserIsOnlyRemainingUserWithSuperUserAccess()
+ {
+ $this->api->addUser('login1', 'password1', 'test@example.com', false);
+ $this->api->setSuperUserAccess('login1', true);
+
+ $this->api->setSuperUserAccess('login1', false);
+ }
+
+ public function testSetSuperUserAccess_ShouldDeleteAllExistingAccessEntries()
+ {
+ list($id1, $id2) = $this->addSites(2);
+ $this->api->addUser('login1', 'password1', 'test@example.com', false);
+ $this->api->setUserAccess('login1', 'view', array($id1));
+ $this->api->setUserAccess('login1', 'admin', array($id2));
+
+ // verify user has access before setting Super User access
+ $access = $this->_flatten($this->api->getSitesAccessFromUser('login1'));
+ $this->assertEquals(array($id1 => 'view', $id2 => 'admin'), $access);
+
+ $this->api->setSuperUserAccess('login1', true);
+
+ // verify no longer any access
+ $this->assertEquals(array(), $this->model->getSitesAccessFromUser('login1'));
+ }
+
+ public function testSetSuperUserAccess_ShouldAddAndRemoveSuperUserAccessOnlyForGivenLogin()
+ {
+ $this->api->addUser('login1', 'password1', 'test1@example.com', false);
+ $this->api->addUser('login2', 'password2', 'test2@example.com', false);
+ $this->api->addUser('login3', 'password3', 'test3@example.com', false);
+
+ $this->api->setSuperUserAccess('login2', true);
+
+ // test add Super User access
+ $users = $this->api->getUsers();
+
+ $this->assertEquals(0, $users[0]['superuser_access']);
+ $this->assertEquals(1, $users[1]['superuser_access']);
+ $this->assertEquals('login2', $users[1]['login']);
+ $this->assertEquals(0, $users[2]['superuser_access']);
+
+ // should also accept string '1' to add Super User access
+ $this->api->setSuperUserAccess('login1', '1');
+ // test remove Super User access
+ $this->api->setSuperUserAccess('login2', false);
+
+ $users = $this->api->getUsers();
+ $this->assertEquals(1, $users[0]['superuser_access']);
+ $this->assertEquals('login1', $users[0]['login']);
+ $this->assertEquals(0, $users[1]['superuser_access']);
+ $this->assertEquals(0, $users[2]['superuser_access']);
+
+ $this->api->setSuperUserAccess('login3', true);
+ // should also accept string '0' to remove Super User access
+ $this->api->setSuperUserAccess('login1', '0');
+
+ $users = $this->api->getUsers();
+ $this->assertEquals(0, $users[0]['superuser_access']);
+ $this->assertEquals(0, $users[1]['superuser_access']);
+ $this->assertEquals('login3', $users[2]['login']);
+ $this->assertEquals(1, $users[2]['superuser_access']);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionUserDoesNotExist
+ */
+ public function testGetSitesAccessFromUserWrongUser()
+ {
+ $this->api->getSitesAccessFromUser("user1");
+ }
+
+ /**
+ * @expectedException \Exception
+ */
+ public function testGetUsersAccessFromSiteWrongIdSite()
+ {
+ $this->api->getUsersAccessFromSite(1);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionAccessValues
+ */
+ public function testGetUsersSitesFromAccessWrongSite()
+ {
+ $this->api->getUsersSitesFromAccess('unknown');
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionUserDoesNotExist
+ */
+ public function testUpdateUserNonExistingLogin()
+ {
+ $this->api->updateUser("lolgin", "password");
+ }
+
+ /**
+ * no email no alias => keep old ones
+ */
+ public function testUpdateUserNoEmailNoAlias()
+ {
+ $login = "login";
+ $user = array('login' => $login,
+ 'password' => "geqgeagae",
+ 'email' => "test@test.com",
+ 'alias' => "alias");
+
+ $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']);
+ $this->api->updateUser($login, "passowordOK");
+
+ $this->_checkUserHasNotChanged($user, "passowordOK");
+ }
+
+ /**
+ * no email => keep old ones
+ */
+ public function testUpdateUserNoEmail()
+ {
+ $login = "login";
+ $user = array('login' => $login,
+ 'password' => "geqgeagae",
+ 'email' => "test@test.com",
+ 'alias' => "alias");
+
+ $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']);
+ $this->api->updateUser($login, "passowordOK", null, "newalias");
+
+ $this->_checkUserHasNotChanged($user, "passowordOK", null, "newalias");
+ }
+
+ /**
+ * no alias => keep old ones
+ */
+ public function testUpdateUserNoAlias()
+ {
+ $login = "login";
+ $user = array('login' => $login,
+ 'password' => "geqgeagae",
+ 'email' => "test@test.com",
+ 'alias' => "alias");
+
+ $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']);
+ $this->api->updateUser($login, "passowordOK", "email@geaga.com");
+
+ $this->_checkUserHasNotChanged($user, "passowordOK", "email@geaga.com");
+ }
+
+ /**
+ * check to modify as the user
+ * @expectedException \Exception
+ * @expectedExceptionMessage UsersManager_ExceptionLoginExists
+ */
+ public function testAddUserIAmTheUser()
+ {
+ FakeAccess::$identity = 'login';
+ $this->testUpdateUserNoEmailNoAlias();
+ }
+
+ /**
+ * check to modify as being another user => exception
+ *
+ * @expectedException \Exception
+ */
+ public function testUpdateUserIAmNotTheUser()
+ {
+ FakeAccess::$identity = 'login2';
+ FakeAccess::$superUser = false;
+ $this->testUpdateUserNoEmailNoAlias();
+ }
+
+ /**
+ * normal case, reused in other tests
+ */
+ public function testUpdateUser()
+ {
+ $login = "login";
+ $user = array('login' => $login,
+ 'password' => "geqgeagae",
+ 'email' => "test@test.com",
+ 'alias' => "alias");
+
+ $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']);
+ $this->api->updateUser($login, "passowordOK", "email@geaga.com", "NEW ALIAS");
+
+ $this->_checkUserHasNotChanged($user, "passowordOK", "email@geaga.com", "NEW ALIAS");
+ }
+
+ /**
+ * @expectedException \Exception
+ */
+ public function testGetUserByEmailInvalidMail()
+ {
+ $this->api->getUserByEmail('email@test.com');
+ }
+
+ public function testGetUserByEmail()
+ {
+ $user = array('login' => "login",
+ 'password' => "geqgeagae",
+ 'email' => "test@test.com",
+ 'alias' => "alias");
+
+ $this->api->addUser($user['login'], $user['password'], $user['email'], $user['alias']);
+
+ $userByMail = $this->api->getUserByEmail($user['email']);
+
+ $this->assertEquals($user['login'], $userByMail['login']);
+ $this->assertEquals($user['email'], $userByMail['email']);
+ $this->assertEquals($user['alias'], $userByMail['alias']);
+ }
+
+ public function testGetUserPreferenceDefault()
+ {
+ $this->addSites(1);
+ $defaultReportPref = API::PREFERENCE_DEFAULT_REPORT;
+ $defaultReportDatePref = API::PREFERENCE_DEFAULT_REPORT_DATE;
+
+ $this->assertEquals(1, $this->api->getUserPreference('someUser', $defaultReportPref));
+ $this->assertEquals('yesterday', $this->api->getUserPreference('someUser', $defaultReportDatePref));
+ }
+
+ private function addSites($numberOfSites)
+ {
+ $idSites = array();
+
+ for ($index = 0; $index < $numberOfSites; $index++) {
+ $name = "test" . ($index + 1);
+ $idSites[] = APISitesManager::getInstance()->addSite($name, array("http://piwik.net", "http://piwik.com/test/"));
+ }
+
+ return $idSites;
+ }
+}