From 33410eae1d1c76f16e5aad57dddc5553c82adf3a Mon Sep 17 00:00:00 2001 From: sgiehl <stefangiehl@gmail.com> Date: Sat, 23 Jun 2012 21:18:56 +0000 Subject: [PATCH] refs #3227 more and more tests completely converted :) git-svn-id: http://dev.piwik.org/svn/trunk@6495 59fd770c-687e-43c8-a1e3-f5a4ff64c105 --- tests/PHPUnit/Core/IPTest.php | 812 +++++++++++++++++++ tests/PHPUnit/Core/ScheduledTaskTest.php | 45 + tests/PHPUnit/Core/ScheduledTimeTest.php | 560 +++++++++++++ tests/PHPUnit/Core/SegmentExpressionTest.php | 128 +++ tests/PHPUnit/Core/SegmentTest.php | 465 +++++++++++ 5 files changed, 2010 insertions(+) create mode 100644 tests/PHPUnit/Core/IPTest.php create mode 100644 tests/PHPUnit/Core/ScheduledTaskTest.php create mode 100644 tests/PHPUnit/Core/ScheduledTimeTest.php create mode 100644 tests/PHPUnit/Core/SegmentExpressionTest.php create mode 100644 tests/PHPUnit/Core/SegmentTest.php diff --git a/tests/PHPUnit/Core/IPTest.php b/tests/PHPUnit/Core/IPTest.php new file mode 100644 index 0000000000..bd9321543c --- /dev/null +++ b/tests/PHPUnit/Core/IPTest.php @@ -0,0 +1,812 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * @version $Id$ + */ +class IPTest extends PHPUnit_Framework_TestCase +{ + /** + * Dataprovider for testSanitizeIp + */ + public function getIPData() { + return array( // input, output + // single IPv4 address + array('127.0.0.1', '127.0.0.1'), + + // single IPv6 address (ambiguous) + array('::1', '::1'), + array('::ffff:127.0.0.1', '::ffff:127.0.0.1'), + array('2001:5c0:1000:b::90f8', '2001:5c0:1000:b::90f8'), + + // single IPv6 address + array('[::1]', '::1'), + array('[2001:5c0:1000:b::90f8]', '2001:5c0:1000:b::90f8'), + array('[::ffff:127.0.0.1]', '::ffff:127.0.0.1'), + + // single IPv4 address (CIDR notation) + array('192.168.1.1/32', '192.168.1.1'), + + // single IPv6 address (CIDR notation) + array('::1/128', '::1'), + array('::ffff:127.0.0.1/128', '::ffff:127.0.0.1'), + array('2001:5c0:1000:b::90f8/128', '2001:5c0:1000:b::90f8'), + + // IPv4 address with port + array('192.168.1.2:80', '192.168.1.2'), + + // IPv6 address with port + array('[::1]:80', '::1'), + array('[::ffff:127.0.0.1]:80', '::ffff:127.0.0.1'), + array('[2001:5c0:1000:b::90f8]:80', '2001:5c0:1000:b::90f8'), + + // hostnames with port? + array('localhost', 'localhost'), + array('localhost:80', 'localhost'), + array('www.example.com', 'www.example.com'), + array('example.com:80', 'example.com'), + ); + } + + /** + * @dataProvider getIPData + * @group Core + * @group IP + */ + public function testSanitizeIp($ip, $expected) + { + $this->assertEquals($expected, Piwik_IP::sanitizeIp($ip)); + } + + /** + * Dataprovider for testSanitizeIpRange + */ + public function getIPRangeData() + { + return array( + array('', false), + array(' 127.0.0.1 ', '127.0.0.1/32'), + array('192.168.1.0', '192.168.1.0/32'), + array('192.168.1.1/24', '192.168.1.1/24'), + array('192.168.1.2/16', '192.168.1.2/16'), + array('192.168.1.3/8', '192.168.1.3/8'), + array('192.168.2.*', '192.168.2.0/24'), + array('192.169.*.*', '192.169.0.0/16'), + array('193.*.*.*', '193.0.0.0/8'), + array('*.*.*.*', '0.0.0.0/0'), + array('*.*.*.1', false), + array('*.*.1.1', false), + array('*.1.1.1', false), + array('1.*.1.1', false), + array('1.1.*.1', false), + array('1.*.*.1', false), + array('::1', '::1/128'), + array('::ffff:127.0.0.1', '::ffff:127.0.0.1/128'), + array('2001:5c0:1000:b::90f8', '2001:5c0:1000:b::90f8/128'), + array('::1/64', '::1/64'), + array('::ffff:127.0.0.1/64', '::ffff:127.0.0.1/64'), + array('2001:5c0:1000:b::90f8/64', '2001:5c0:1000:b::90f8/64'), + ); + } + + /** + * @dataProvider getIPRangeData + * @group Core + * @group IP + */ + public function testSanitizeIpRange($ip, $expected) + { + $this->assertEquals($expected, Piwik_IP::sanitizeIpRange($ip)); + } + + /** + * Dataprovider for testP2N + */ + public function getP2NTestData() + { + return array( + // IPv4 + array('0.0.0.0', "\x00\x00\x00\x00"), + array('127.0.0.1', "\x7F\x00\x00\x01"), + array('192.168.1.12', "\xc0\xa8\x01\x0c"), + array('255.255.255.255', "\xff\xff\xff\xff"), + + // IPv6 + array('::', "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), + array('::1', "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), + array('::fffe:7f00:1', "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x7f\x00\x00\x01"), + array('::ffff:127.0.0.1', "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x7f\x00\x00\x01"), + array('2001:5c0:1000:b::90f8', "\x20\x01\x05\xc0\x10\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x90\xf8"), + ); + } + + /** + * @dataProvider getP2NTestData + * @group Core + * @group IP + */ + public function testP2N($P, $N) + { + $this->assertEquals($N, Piwik_IP::P2N($P)); + } + + /** + * Dataprovider for testP2NInvalidInput + */ + public function getP2NInvalidInputData() + { + return array( + // not a series of dotted numbers + array(null), + array(''), + array('alpha'), + array('...'), + + // missing an octet + array('.0.0.0'), + array('0..0.0'), + array('0.0..0'), + array('0.0.0.'), + + // octets must be 0-255 + array('-1.0.0.0'), + array('1.1.1.256'), + + // leading zeros not supported (i.e., can be ambiguous, e.g., octal) + array('07.07.07.07'), + ); + } + + /** + * @group Core + * @group IP + * @dataProvider getP2NInvalidInputData + */ + public function testP2NInvalidInput($P) + { + $this->assertEquals( "\x00\x00\x00\x00", Piwik_IP::P2N($P) ); + } + + /** + * @group Core + * @group IP + */ + public function getN2PTestData() + { + // a valid network address is either 4 or 16 bytes; those lines are intentionally left blank ;) + return array( + array(null), + array(''), + array("\x01"), + array("\x01\x00"), + array("\x01\x00\x00"), + + array("\x01\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), + + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"), + ); + } + + /** + * @dataProvider getP2NTestData + * @group Core + * @group IP + */ + public function testN2P($P, $N) + { + $this->assertEquals($P, Piwik_IP::N2P($N), "$P vs" . Piwik_IP::N2P($N)); + } + + /** + * @dataProvider getN2PTestData + * @group Core + * @group IP + */ + public function testN2PinvalidInput($N) + { + $this->assertEquals("0.0.0.0", Piwik_IP::N2P($N), bin2hex($N)); + } + + /** + * @dataProvider getP2NTestData + * @group Core + * @group IP + */ + public function testPrettyPrint($P, $N) + { + $this->assertEquals($P, Piwik_IP::prettyPrint($N), "$P vs" . Piwik_IP::N2P($N)); + } + + /** + * @dataProvider getN2PTestData + * @group Core + * @group IP + */ + public function testPrettyPrintInvalidInput($N) + { + $this->assertEquals("0.0.0.0", Piwik_IP::prettyPrint($N), bin2hex($N)); + } + + /** + * Dataprovider for IP4 test data + */ + public function getIPv4Data() + { + // a valid network address is either 4 or 16 bytes; those lines are intentionally left blank ;) + return array( + // invalid + array(null, false), + array("", false), + + // IPv4 + array("\x00\x00\x00\x00", true), + array("\x7f\x00\x00\x01", true), + + // IPv4-compatible (this transitional format is deprecated in RFC 4291, section 2.5.5.1) + array("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\xa8\x01\x01", true), + + // IPv4-mapped (RFC 4291, 2.5.5.2) + array("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\xa8\x01\x02", true), + + // other IPv6 address + array("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\xc0\xa8\x01\x03", false), + array("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\xa8\x01\x04", false), + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\xa8\x01\x05", false), + + /* + * We assume all stored IP addresses (pre-Piwik 1.4) were converted from UNSIGNED INT to VARBINARY. + * The following is just for informational purposes. + */ + + // 192.168.1.0 + array('-1062731520', false), + array('3232235776', false), + + // 10.10.10.10 + array('168430090', false), + + // 0.0.39.15 - this is the ambiguous case (i.e., 4 char string) + array('9999', true), + array("\x39\x39\x39\x39", true), + + // 0.0.3.231 + array('999', false), + array("\x39\x39\x39", false), + ); + + } + + /** + * @dataProvider getIPv4Data + * @group Core + * @group IP + */ + public function testIsIPv4($ip, $bool) + { + $this->assertEquals($bool, Piwik_IP::isIPv4($ip), bin2hex($ip)); + } + + /** + * Dataprovider for long2ip test + */ + public function getLong2IPTestData() + { + // a valid network address is either 4 or 16 bytes; those lines are intentionally left blank ;) + return array( + // invalid + array(null, '0.0.0.0'), + array("", '0.0.0.0'), + + // IPv4 + array("\x7f\x00\x00\x01", '127.0.0.1'), + + // IPv4-compatible (this transitional format is deprecated in RFC 4291, section 2.5.5.1) + array("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\xa8\x01\x01", '192.168.1.1'), + + // IPv4-mapped (RFC 4291, 2.5.5.2) + array("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\xa8\x01\x02", '192.168.1.2'), + + // other IPv6 address + array("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\xc0\xa8\x01\x03", '0.0.0.0'), + array("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xc0\xa8\x01\x04", '0.0.0.0'), + array("\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\xa8\x01\x05", '0.0.0.0'), + + /* + * We assume all stored IP addresses (pre-Piwik 1.4) were converted from UNSIGNED INT to VARBINARY. + * The following is just for informational purposes. + */ + + // 192.168.1.0 + array('-1062731520', '0.0.0.0'), + array('3232235776', '0.0.0.0'), + + // 10.10.10.10 + array('168430090', '0.0.0.0'), + + // 0.0.39.15 - this is the ambiguous case (i.e., 4 char string) + array('9999', '57.57.57.57'), + array("\x39\x39\x39\x39", '57.57.57.57'), + + // 0.0.3.231 + array('999', '0.0.0.0'), + array("\x39\x39\x39", '0.0.0.0'), + ); + } + + /** + * @dataProvider getLong2IPTestData + * @group Core + * @group IP + */ + public function testLong2ip($N, $P) + { + $this->assertEquals($P, Piwik_IP::long2ip($N), bin2hex($N)); + // this is our compatibility function + $this->assertEquals($P, Piwik_Common::long2ip($N), bin2hex($N)); + } + + /** + * Dataprovider for ip range test + */ + public function getIPsForRangeTest() + { + return array( + + // invalid ranges + array(null, false), + array('', false), + array('0', false), + + // single IPv4 + array('127.0.0.1', array( "\x7f\x00\x00\x01", "\x7f\x00\x00\x01" )), + + // IPv4 with wildcards + array('192.168.1.*', array( "\xc0\xa8\x01\x00", "\xc0\xa8\x01\xff" )), + array('192.168.*.*', array( "\xc0\xa8\x00\x00", "\xc0\xa8\xff\xff" )), + array('192.*.*.*', array( "\xc0\x00\x00\x00", "\xc0\xff\xff\xff" )), + array('*.*.*.*', array( "\x00\x00\x00\x00", "\xff\xff\xff\xff" )), + + // single IPv4 in expected CIDR notation + array('192.168.1.1/24', array( "\xc0\xa8\x01\x00", "\xc0\xa8\x01\xff" )), + + array('192.168.1.127/32', array( "\xc0\xa8\x01\x7f", "\xc0\xa8\x01\x7f" )), + array('192.168.1.127/31', array( "\xc0\xa8\x01\x7e", "\xc0\xa8\x01\x7f" )), + array('192.168.1.127/30', array( "\xc0\xa8\x01\x7c", "\xc0\xa8\x01\x7f" )), + array('192.168.1.127/29', array( "\xc0\xa8\x01\x78", "\xc0\xa8\x01\x7f" )), + array('192.168.1.127/28', array( "\xc0\xa8\x01\x70", "\xc0\xa8\x01\x7f" )), + array('192.168.1.127/27', array( "\xc0\xa8\x01\x60", "\xc0\xa8\x01\x7f" )), + array('192.168.1.127/26', array( "\xc0\xa8\x01\x40", "\xc0\xa8\x01\x7f" )), + array('192.168.1.127/25', array( "\xc0\xa8\x01\x00", "\xc0\xa8\x01\x7f" )), + + array('192.168.1.255/32', array( "\xc0\xa8\x01\xff", "\xc0\xa8\x01\xff" )), + array('192.168.1.255/31', array( "\xc0\xa8\x01\xfe", "\xc0\xa8\x01\xff" )), + array('192.168.1.255/30', array( "\xc0\xa8\x01\xfc", "\xc0\xa8\x01\xff" )), + array('192.168.1.255/29', array( "\xc0\xa8\x01\xf8", "\xc0\xa8\x01\xff" )), + array('192.168.1.255/28', array( "\xc0\xa8\x01\xf0", "\xc0\xa8\x01\xff" )), + array('192.168.1.255/27', array( "\xc0\xa8\x01\xe0", "\xc0\xa8\x01\xff" )), + array('192.168.1.255/26', array( "\xc0\xa8\x01\xc0", "\xc0\xa8\x01\xff" )), + array('192.168.1.255/25', array( "\xc0\xa8\x01\x80", "\xc0\xa8\x01\xff" )), + + array('192.168.255.255/24', array( "\xc0\xa8\xff\x00", "\xc0\xa8\xff\xff" )), + array('192.168.255.255/23', array( "\xc0\xa8\xfe\x00", "\xc0\xa8\xff\xff" )), + array('192.168.255.255/22', array( "\xc0\xa8\xfc\x00", "\xc0\xa8\xff\xff" )), + array('192.168.255.255/21', array( "\xc0\xa8\xf8\x00", "\xc0\xa8\xff\xff" )), + array('192.168.255.255/20', array( "\xc0\xa8\xf0\x00", "\xc0\xa8\xff\xff" )), + array('192.168.255.255/19', array( "\xc0\xa8\xe0\x00", "\xc0\xa8\xff\xff" )), + array('192.168.255.255/18', array( "\xc0\xa8\xc0\x00", "\xc0\xa8\xff\xff" )), + array('192.168.255.255/17', array( "\xc0\xa8\x80\x00", "\xc0\xa8\xff\xff" )), + + // single IPv6 + array('::1', array( "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" )), + + // single IPv6 in expected CIDR notation + array('::1/128', array( "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" )), + array('::1/127', array( "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" )), + array('::fffe:7f00:1/120', array( "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x7f\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x7f\x00\x00\xff" )), + array('::ffff:127.0.0.1/120', array( "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x7f\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x7f\x00\x00\xff" )), + + array('2001:ca11:911::b0b:15:dead/128', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xad", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xad" )), + array('2001:ca11:911::b0b:15:dead/127', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xac", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xad" )), + array('2001:ca11:911::b0b:15:dead/126', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xac", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xaf" )), + array('2001:ca11:911::b0b:15:dead/125', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xa8", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xaf" )), + array('2001:ca11:911::b0b:15:dead/124', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xa0", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xaf" )), + array('2001:ca11:911::b0b:15:dead/123', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xa0", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xbf" )), + array('2001:ca11:911::b0b:15:dead/122', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\x80", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xbf" )), + array('2001:ca11:911::b0b:15:dead/121', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\x80", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xff" )), + array('2001:ca11:911::b0b:15:dead/120', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\x00", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\xff" )), + array('2001:ca11:911::b0b:15:dead/119', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xde\x00", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xdf\xff" )), + array('2001:ca11:911::b0b:15:dead/118', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xdc\x00", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xdf\xff" )), + array('2001:ca11:911::b0b:15:dead/117', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xd8\x00", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xdf\xff" )), + array('2001:ca11:911::b0b:15:dead/116', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xd0\x00", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xdf\xff" )), + array('2001:ca11:911::b0b:15:dead/115', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xc0\x00", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xdf\xff" )), + array('2001:ca11:911::b0b:15:dead/114', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xc0\x00", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xff\xff" )), + array('2001:ca11:911::b0b:15:dead/113', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\x80\x00", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xff\xff" )), + array('2001:ca11:911::b0b:15:dead/112', array( "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\x00\x00", "\x20\x01\xca\x11\x09\x11\x00\x00\x00\x00\x0b\x0b\x00\x15\xff\xff" )), + ); + } + + /** + * @dataProvider getIPsForRangeTest + * @group Core + * @group IP + */ + public function testGetIpsForRange($range, $expected) + { + $this->assertEquals($expected, Piwik_IP::getIpsForRange($range)); + } + + /** + * Dataprovider for testIsIpInRange + */ + public function getIpsInRangeData() + { + return array( + array('192.168.1.10', array( + '192.168.1.9' => false, + '192.168.1.10' => true, + '192.168.1.11' => false, + + // IPv6 addresses (including IPv4 mapped) have to be compared against IPv6 address ranges + '::ffff:192.168.1.10' => false, + )), + + array('::ffff:192.168.1.10', array( + '::ffff:192.168.1.9' => false, + '::ffff:192.168.1.10' => true, + '::ffff:c0a8:010a' => true, + '0000:0000:0000:0000:0000:ffff:c0a8:010a' => true, + '::ffff:192.168.1.11' => false, + + // conversely, IPv4 addresses have to be compared against IPv4 address ranges + '192.168.1.10' => false, + )), + + array('192.168.1.10/32', array( + '192.168.1.9' => false, + '192.168.1.10' => true, + '192.168.1.11' => false, + )), + + array('192.168.1.10/31', array( + '192.168.1.9' => false, + '192.168.1.10' => true, + '192.168.1.11' => true, + '192.168.1.12' => false, + )), + + array('192.168.1.128/25', array( + '192.168.1.127' => false, + '192.168.1.128' => true, + '192.168.1.255' => true, + '192.168.2.0' => false, + )), + + array('192.168.1.10/24', array( + '192.168.0.255' => false, + '192.168.1.0' => true, + '192.168.1.1' => true, + '192.168.1.2' => true, + '192.168.1.3' => true, + '192.168.1.4' => true, + '192.168.1.7' => true, + '192.168.1.8' => true, + '192.168.1.15' => true, + '192.168.1.16' => true, + '192.168.1.31' => true, + '192.168.1.32' => true, + '192.168.1.63' => true, + '192.168.1.64' => true, + '192.168.1.127' => true, + '192.168.1.128' => true, + '192.168.1.255' => true, + '192.168.2.0' => false, + )), + + array('192.168.1.*', array( + '192.168.0.255' => false, + '192.168.1.0' => true, + '192.168.1.1' => true, + '192.168.1.2' => true, + '192.168.1.3' => true, + '192.168.1.4' => true, + '192.168.1.7' => true, + '192.168.1.8' => true, + '192.168.1.15' => true, + '192.168.1.16' => true, + '192.168.1.31' => true, + '192.168.1.32' => true, + '192.168.1.63' => true, + '192.168.1.64' => true, + '192.168.1.127' => true, + '192.168.1.128' => true, + '192.168.1.255' => true, + '192.168.2.0' => false, + )), + ); + } + + /** + * @group Core + * @group IP + * @dataProvider getIpsInRangeData + */ + public function testIsIpInRange($range, $test) + { + foreach($test as $ip => $expected) + { + // range as a string + $this->assertEquals( $expected, Piwik_IP::isIpInRange(Piwik_IP::P2N($ip), array($range)), "$ip in $range" ); + + // range as an array(low, high) + $aRange = Piwik_IP::getIpsForRange($range); + $aRange[0] = Piwik_IP::N2P($aRange[0]); + $aRange[1] = Piwik_IP::N2P($aRange[1]); + $this->assertEquals( $expected, Piwik_IP::isIpInRange(Piwik_IP::P2N($ip), array($aRange)), "$ip in $range" ); + } + } + + /** + * Dataprovider for ip from header tests + */ + public function getIpFromHeaderTestData() + { + return array( + array('localhost inside LAN', array('127.0.0.1', '', null, null, '127.0.0.1')), + array('outside LAN, no proxy', array('128.252.135.4', '', null, null, '128.252.135.4')), + array('outside LAN, no (trusted) proxy', array('128.252.135.4', '137.18.2.13, 128.252.135.4', '', null, '128.252.135.4')), + array('outside LAN, one trusted proxy', array('192.168.1.10', '137.18.2.13, 128.252.135.4, 192.168.1.10', 'HTTP_X_FORWARDED_FOR', null, '128.252.135.4')), + array('outside LAN, proxy', array('192.168.1.10', '128.252.135.4, 192.168.1.10', 'HTTP_X_FORWARDED_FOR', null, '128.252.135.4')), + array('outside LAN, misconfigured proxy', array('192.168.1.10', '128.252.135.4, 192.168.1.10, 192.168.1.10', 'HTTP_X_FORWARDED_FOR', null, '128.252.135.4')), + array('outside LAN, multiple proxies', array('192.168.1.10', '128.252.135.4, 192.168.1.20, 192.168.1.10', 'HTTP_X_FORWARDED_FOR', '192.168.1.*', '128.252.135.4')), + array('outside LAN, multiple proxies', array('[::ffff:7f00:10]', '128.252.135.4, [::ffff:7f00:20], [::ffff:7f00:10]', 'HTTP_X_FORWARDED_FOR', '::ffff:7f00:0/120', '128.252.135.4')), + ); + } + + /** + * @dataProvider getIpFromHeaderTestData + * @group Core + * @group IP + */ + public function testGetIpFromHeader($description, $test) + { + Piwik::createConfigObject(); + Piwik_Config::getInstance()->setTestEnvironment(); + + $_SERVER['REMOTE_ADDR'] = $test[0]; + $_SERVER['HTTP_X_FORWARDED_FOR'] = $test[1]; + Piwik_Config::getInstance()->General['proxy_client_headers'] = array($test[2]); + Piwik_Config::getInstance()->General['proxy_ips'] = array($test[3]); + $this->assertEquals($test[4], Piwik_IP::getIpFromHeader(), $description); + } + + /** + * Dataprovider + * @return array + */ + public function getIpTestData() + { + return array( + array('0.0.0.0'), + array('72.14.204.99'), + array('127.0.0.1'), + array('169.254.0.1'), + array('208.80.152.2'), + array('224.0.0.1'), + ); + } + + + /** + * @group Core + * @group IP + * @dataProvider getIpTestData + */ + public function testGetNonProxyIpFromHeader($ip) + { + $this->assertEquals($ip, Piwik_IP::getNonProxyIpFromHeader($ip, array())); + } + + /** + * @group Core + * @group IP + * @dataProvider getIpTestData + */ + public function testGetNonProxyIpFromHeader2($ip) + { + // 1.1.1.1 is not a trusted proxy + $_SERVER['REMOTE_ADDR'] = '1.1.1.1'; + $_SERVER['HTTP_X_FORWARDED_FOR'] = ''; + $this->assertEquals('1.1.1.1', Piwik_IP::getNonProxyIpFromHeader('1.1.1.1', array('HTTP_X_FORWARDED_FOR'))); + } + + /** + * @group Core + * @group IP + * @dataProvider getIpTestData + */ + public function testGetNonProxyIpFromHeader3($ip) + { + // 1.1.1.1 is a trusted proxy + $_SERVER['REMOTE_ADDR'] = '1.1.1.1'; + + $_SERVER['HTTP_X_FORWARDED_FOR'] = $ip; + $this->assertEquals($ip, Piwik_IP::getNonProxyIpFromHeader('1.1.1.1', array('HTTP_X_FORWARDED_FOR'))); + + $_SERVER['HTTP_X_FORWARDED_FOR'] = '1.2.3.4, ' . $ip; + $this->assertEquals($ip, Piwik_IP::getNonProxyIpFromHeader('1.1.1.1', array('HTTP_X_FORWARDED_FOR'))); + + // misconfiguration + $_SERVER['HTTP_X_FORWARDED_FOR'] = $ip . ', 1.1.1.1'; + $this->assertEquals($ip, Piwik_IP::getNonProxyIpFromHeader('1.1.1.1', array('HTTP_X_FORWARDED_FOR'))); + } + + /** + * Dataprovider for testGetLastIpFromList + */ + public function getLastIpFromListTestData() + { + return array( + array('', ''), + array('127.0.0.1', '127.0.0.1'), + array(' 127.0.0.1 ', '127.0.0.1'), + array(' 192.168.1.1, 127.0.0.1', '127.0.0.1'), + array('192.168.1.1 ,127.0.0.1 ', '127.0.0.1'), + array('192.168.1.1,', ''), + ); + } + + /** + * @group Core + * @group IP + * @dataProvider getLastIpFromListTestData + */ + public function testGetLastIpFromList($csv, $expected) + { + // without excluded IPs + $this->assertEquals($expected, Piwik_IP::getLastIpFromList($csv)); + + // with excluded Ips + $this->assertEquals($expected, Piwik_IP::getLastIpFromList($csv . ', 10.10.10.10', array('10.10.10.10'))); + } + + /** + * @group Core + * @group IP + */ + public function testGetHostByAddr() + { + $hosts = array( 'localhost', strtolower(@php_uname('n')), '127.0.0.1' ); + $this->assertTrue( in_array(strtolower(Piwik_IP::getHostByAddr('127.0.0.1')), $hosts), '127.0.0.1 -> localhost' ); + + if (!Piwik_Common::isWindows() || PHP_VERSION >= '5.3') + { + $hosts = array( 'ip6-localhost', strtolower(@php_uname('n')), '::1' ); + $this->assertTrue( in_array(strtolower(Piwik_IP::getHostByAddr('::1')), $hosts), '::1 -> ip6-localhost' ); + } + } + + /** + * Dataprovider for testPhpCompatInetNtop + */ + public function getInetNtopData() + { + return array( + array('127.0.0.1', '7f000001'), + array('192.232.131.222', 'c0e883de'), + array('255.0.0.0', 'ff000000'), + array('255.255.255.255', 'ffffffff'), + array('::1', '00000000000000000000000000000001'), + array('::101', '00000000000000000000000000000101'), + array('::0.1.1.1', '00000000000000000000000000010101'), + array('2001:260:0:10::1', '20010260000000100000000000000001'), + array('2001:0:0:260::1', '20010000000002600000000000000001'), + array('2001::260:0:0:10:1', '20010000000002600000000000100001'), + array('2001:5c0:1000:b::90f8', '200105c01000000b00000000000090f8'), + array('fe80::200:4cff:fe43:172f', 'fe8000000000000002004cfffe43172f'), + array('::ffff:127.0.0.1', '00000000000000000000ffff7f000001'), + array('::127.0.0.1', '0000000000000000000000007f000001'), + array('::fff0:7f00:1', '00000000000000000000fff07f000001'), + ); + } + + /** + * @group Core + * @group IP + * @dataProvider getInetNtopData + */ + public function testPhpCompatInetNtop($k, $v) + { + $this->assertEquals($k, php_compat_inet_ntop(pack('H*', $v))); + if(!Piwik_Common::isWindows()) { + $this->assertEquals($k, @inet_ntop(pack('H*', $v))); + } + } + + /** + * Dataprovider for testPhpCompatInetPton + * @return array + */ + public function getInetPtonTestData() + { + return array( + array('127.0.0.1', '7f000001'), + array('192.232.131.222', 'c0e883de'), + array('255.0.0.0', 'ff000000'), + array('255.255.255.255', 'ffffffff'), + array('::', '00000000000000000000000000000000'), + array('::0', '00000000000000000000000000000000'), + array('0::', '00000000000000000000000000000000'), + array('0::0', '00000000000000000000000000000000'), + array('::1', '00000000000000000000000000000001'), + array('2001:260:0:10::1', '20010260000000100000000000000001'), + array('2001:5c0:1000:b::90f8', '200105c01000000b00000000000090f8'), + array('fe80::200:4cff:fe43:172f', 'fe8000000000000002004cfffe43172f'), + array('::ffff:127.0.0.1', '00000000000000000000ffff7f000001'), + array('::127.0.0.1', '0000000000000000000000007f000001'), + + // relaxed rules + array('00000::', '00000000000000000000000000000000'), + array('1:2:3:4:5:ffff:127.0.0.1', '00010002000300040005ffff7f000001'), + + // invalid input + array(null, false), + array(false, false), + array(true, false), + array('', false), + array('0', false), + array('07.07.07.07', false), + array('1.', false), + array('.1', false), + array('1.1', false), + array('.1.1.', false), + array('1.1.1.', false), + array('.1.1.1', false), + array('1.2.3.4.', false), + array('.1.2.3.4', false), + array('1.2.3.256', false), + array('a.b.c.d', false), + array('::1::', false), + array('1:2:3:4:::5:6', false), + array('1:2:3:4:5:6:', false), + array(':1:2:3:4:5:6', false), + array('1:2:3:4:5:6:7:', false), + array(':1:2:3:4:5:6:7', false), + array('::11111:0', false), + array('::g', false), + array('::ffff:127.00.0.1', false), + array('::ffff:127.0.0.01', false), + array('::ffff:256.0.0.1', false), + array('::ffff:1.256.0.1', false), + array('::ffff:65536.0.0.1', false), + array('::ffff:256.65536.0.1', false), + array('::ffff:65536.65536.0.1', false), + array('::ffff:7f01:0.1', false), + array('ffff:127.0.0.1:ffff::', false), + ); + } + + /** + * @group Core + * @group IP + * @dataProvider getInetPtonTestData + */ + public function testPhpCompatInetPton($k, $v) + { + $this->assertEquals($v, bin2hex(php_compat_inet_pton($k))); + if(!Piwik_Common::isWindows()) { + $this->assertEquals($v, bin2hex(@inet_pton($k))); + } + } +} diff --git a/tests/PHPUnit/Core/ScheduledTaskTest.php b/tests/PHPUnit/Core/ScheduledTaskTest.php new file mode 100644 index 0000000000..2eba437c66 --- /dev/null +++ b/tests/PHPUnit/Core/ScheduledTaskTest.php @@ -0,0 +1,45 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * @version $Id$ + */ +class ScheduledTaskTest extends PHPUnit_Framework_TestCase +{ + /** + * @group Core + * @group ScheduledTask + */ + public function testGetClassName() + { + $scheduledTask = new Piwik_ScheduledTask ( "className", null, null ); + $className = $scheduledTask->getClassName(); + $this->assertInternalType('string', $className); + $this->assertNotEmpty($className); + } + + /** + * @group Core + * @group ScheduledTask + */ + public function testGetMethodName() + { + $scheduledTask = new Piwik_ScheduledTask ( null, "methodname", null ); + $methodName = $scheduledTask->getMethodName(); + $this->assertInternalType('string', $methodName); + $this->assertNotEmpty($methodName); + } + + /** + * @group Core + * @group ScheduledTask + */ + public function testGetScheduledTime() + { + $scheduledTask = new Piwik_ScheduledTask ( null, null, new Piwik_ScheduledTime_Hourly() ); + $scheduledTime = $scheduledTask->getScheduledTime(); + $this->assertInstanceOf("Piwik_ScheduledTime_Hourly", $scheduledTime); + } +} diff --git a/tests/PHPUnit/Core/ScheduledTimeTest.php b/tests/PHPUnit/Core/ScheduledTimeTest.php new file mode 100644 index 0000000000..d7ecca515a --- /dev/null +++ b/tests/PHPUnit/Core/ScheduledTimeTest.php @@ -0,0 +1,560 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * @version $Id$ + */ +class ScheduledTimeTest extends PHPUnit_Framework_TestCase +{ + private $_JANUARY_01_1971_09_00_00; + private $_JANUARY_01_1971_09_10_00; + private $_JANUARY_01_1971_10_00_00; + private $_JANUARY_01_1971_12_10_00; + private $_JANUARY_02_1971_00_00_00; + private $_JANUARY_02_1971_09_00_00; + private $_JANUARY_04_1971_00_00_00; + private $_JANUARY_04_1971_09_00_00; + private $_JANUARY_05_1971_09_00_00; + private $_JANUARY_11_1971_00_00_00; + private $_JANUARY_15_1971_00_00_00; + private $_JANUARY_15_1971_09_00_00; + private $_FEBRUARY_01_1971_00_00_00; + private $_FEBRUARY_02_1971_00_00_00; + private $_FEBRUARY_28_1971_00_00_00; + + public function setUp() + { + parent::setUp(); + $this->_JANUARY_01_1971_09_00_00 = mktime(9,00,00,1,1,1971); + $this->_JANUARY_01_1971_09_10_00 = mktime(9,10,00,1,1,1971); + $this->_JANUARY_01_1971_10_00_00 = mktime(10,00,00,1,1,1971); + $this->_JANUARY_01_1971_12_10_00 = mktime(12,10,00,1,1,1971); + $this->_JANUARY_02_1971_00_00_00 = mktime(0,00,00,1,2,1971); + $this->_JANUARY_02_1971_09_00_00 = mktime(9,00,00,1,2,1971); + $this->_JANUARY_04_1971_00_00_00 = mktime(0,00,00,1,4,1971); + $this->_JANUARY_04_1971_09_00_00 = mktime(9,00,00,1,4,1971); + $this->_JANUARY_05_1971_09_00_00 = mktime(9,00,00,1,5,1971); + $this->_JANUARY_11_1971_00_00_00 = mktime(0,00,00,1,11,1971); + $this->_JANUARY_15_1971_00_00_00 = mktime(0,00,00,1,15,1971); + $this->_JANUARY_15_1971_09_00_00 = mktime(9,00,00,1,15,1971); + $this->_FEBRUARY_01_1971_00_00_00 = mktime(0,00,00,2,1,1971); + $this->_FEBRUARY_02_1971_00_00_00 = mktime(0,00,00,2,2,1971); + $this->_FEBRUARY_28_1971_00_00_00 = mktime(0,00,00,2,28,1971); + } + + /** + * Tests forbidden call to setHour on Piwik_ScheduledTime_Hourly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetHourScheduledTimeHourly() + { + $hourlySchedule = new Piwik_ScheduledTime_Hourly(); + $hourlySchedule->setHour(0); + } + + /** + * Tests invalid call to setHour on Piwik_ScheduledTime_Daily + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetHourScheduledTimeDailyNegative() + { + $dailySchedule = new Piwik_ScheduledTime_Daily(); + $dailySchedule->setHour(-1); + } + + /** + * Tests invalid call to setHour on Piwik_ScheduledTime_Daily + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetHourScheduledTimeDailyOver24() + { + $dailySchedule = new Piwik_ScheduledTime_Daily(); + $dailySchedule->setHour(25); + } + + /** + * Tests invalid call to setHour on Piwik_ScheduledTime_Weekly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetHourScheduledTimeWeeklyNegative() + { + $weeklySchedule = new Piwik_ScheduledTime_Weekly(); + $weeklySchedule->setHour(-1); + } + + /** + * Tests invalid call to setHour on Piwik_ScheduledTime_Weekly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetHourScheduledTimeWeeklyOver24() + { + $weeklySchedule = new Piwik_ScheduledTime_Weekly(); + $weeklySchedule->setHour(25); + } + + /** + * Tests invalid call to setHour on Piwik_ScheduledTime_Monthly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetHourScheduledTimeMonthlyNegative() + { + $monthlySchedule = new Piwik_ScheduledTime_Monthly(); + $monthlySchedule->setHour(-1); + } + + /** + * Tests invalid call to setHour on Piwik_ScheduledTime_Monthly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetHourScheduledTimMonthlyOver24() + { + $monthlySchedule = new Piwik_ScheduledTime_Monthly(); + $monthlySchedule->setHour(25); + } + + /** + * Tests forbidden call to setDay on Piwik_ScheduledTime_Hourly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetDayScheduledTimeHourly() + { + $hourlySchedule = new Piwik_ScheduledTime_Hourly(); + $hourlySchedule->setDay(1); + } + + /** + * Tests forbidden call to setDay on Piwik_ScheduledTime_Daily + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetDayScheduledTimeDaily() + { + $dailySchedule = new Piwik_ScheduledTime_Daily(); + $dailySchedule->setDay(1); + } + + /** + * Tests invalid call to setDay on Piwik_ScheduledTime_Weekly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetDayScheduledTimeWeeklyDay0() + { + $weeklySchedule = new Piwik_ScheduledTime_Weekly(); + $weeklySchedule->setDay(0); + } + + /** + * Tests invalid call to setDay on Piwik_ScheduledTime_Weekly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetDayScheduledTimeWeeklyOver7() + { + $weeklySchedule = new Piwik_ScheduledTime_Weekly(); + $weeklySchedule->setDay(8); + } + + /** + * Tests invalid call to setDay on Piwik_ScheduledTime_Monthly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetDayScheduledTimeMonthlyDay0() + { + $monthlySchedule = new Piwik_ScheduledTime_Monthly(); + $monthlySchedule->setDay(0); + } + + /** + * Tests invalid call to setDay on Piwik_ScheduledTime_Monthly + * @group Core + * @group ScheduledTime + * @expectedException Exception + */ + public function testSetDayScheduledTimeMonthlyOver31() + { + $monthlySchedule = new Piwik_ScheduledTime_Monthly(); + $monthlySchedule->setDay(32); + } + + + /** + * Tests getRescheduledTime on Piwik_ScheduledTime_Hourly + * @group Core + * @group ScheduledTime + */ + public function testGetRescheduledTimeHourly() + { + /* + * Test 1 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 09:00:00 GMT + * + * Expected : + * getRescheduledTime returns Friday January 1 1971 10:00:00 GMT + */ + $mock = $this->getMock('Piwik_ScheduledTime_Hourly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_09_00_00)); + $this->assertEquals($this->_JANUARY_01_1971_10_00_00, $mock->getRescheduledTime()); + + /* + * Test 2 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 09:10:00 GMT + * + * Expected : + * getRescheduledTime returns Friday January 1 1971 10:00:00 GMT + */ + $mock = $this->getMock('Piwik_ScheduledTime_Hourly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_09_10_00)); + $this->assertEquals($this->_JANUARY_01_1971_10_00_00, $mock->getRescheduledTime()); + } + + /** + * Tests getRescheduledTime on Piwik_ScheduledTime_Daily with unspecified hour + * @group Core + * @group ScheduledTime + */ + public function testGetRescheduledTimeDailyUnspecifiedHour() + { + /* + * Test 1 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 09:10:00 UTC + * - setHour is not called, defaulting to midnight + * + * Expected : + * getRescheduledTime returns Saturday January 2 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Daily', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_09_10_00)); + $this->assertEquals($this->_JANUARY_02_1971_00_00_00, $mock->getRescheduledTime()); + } + + /** + * Tests getRescheduledTime on Piwik_ScheduledTime_Daily with specified hour + * @group Core + * @group ScheduledTime + */ + public function testGetRescheduledTimeDailySpecifiedHour() + { + /* + * Test 1 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 09:00:00 UTC + * - setHour is set to 9 + * + * Expected : + * getRescheduledTime returns Saturday January 2 1971 09:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Daily', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_09_00_00)); + $mock->setHour(9); + $this->assertEquals($this->_JANUARY_02_1971_09_00_00, $mock->getRescheduledTime()); + + /* + * Test 2 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 12:10:00 UTC + * - setHour is set to 9 + * + * Expected : + * getRescheduledTime returns Saturday January 2 1971 09:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Daily', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_12_10_00)); + $mock->setHour(9); + $this->assertEquals($this->_JANUARY_02_1971_09_00_00, $mock->getRescheduledTime()); + + /* + * Test 3 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 12:10:00 UTC + * - setHour is set to 0 + * + * Expected : + * getRescheduledTime returns Saturday January 2 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Daily', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_12_10_00)); + $mock->setHour(0); + $this->assertEquals($this->_JANUARY_02_1971_00_00_00, $mock->getRescheduledTime()); + } + + /** + * Tests getRescheduledTime on Piwik_ScheduledTime_Weekly with unspecified hour and unspecified day + * @group Core + * @group ScheduledTime + */ + public function testGetRescheduledTimeWeeklyUnspecifiedHourUnspecifiedDay() + { + /* + * Test 1 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 09:10:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is not called, defaulting to monday + * + * Expected : + * getRescheduledTime returns Monday January 4 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Weekly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_09_10_00)); + $this->assertEquals($this->_JANUARY_04_1971_00_00_00, $mock->getRescheduledTime()); + } + + /** + * Tests getRescheduledTime on Piwik_ScheduledTime_Weekly with specified hour and unspecified day + * @group Core + * @group ScheduledTime + */ + public function testGetRescheduledTimeWeeklySpecifiedHourUnspecifiedDay() + { + /* + * Test 1 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 09:10:00 UTC + * - setHour is set to 9 + * - setDay is not called, defaulting to monday + * + * Expected : + * getRescheduledTime returns Monday January 4 1971 09:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Weekly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_09_10_00)); + $mock->setHour(9); + $this->assertEquals($this->_JANUARY_04_1971_09_00_00, $mock->getRescheduledTime()); + } + + /** + * Tests getRescheduledTime on Piwik_ScheduledTime_Weekly with unspecified hour and specified day + * @group Core + * @group ScheduledTime + */ + public function testGetRescheduledTimeWeeklyUnspecifiedHourSpecifiedDay() + { + /* + * Test 1 + * + * Context : + * - getRescheduledTime called Monday January 4 1971 09:00:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is set to 1, Monday + * + * Expected : + * getRescheduledTime returns Monday January 11 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Weekly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_04_1971_09_00_00)); + $mock->setDay(1); + $this->assertEquals($this->_JANUARY_11_1971_00_00_00, $mock->getRescheduledTime()); + + /* + * Test 2 + * + * Context : + * - getRescheduledTime called Tuesday 5 1971 09:00:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is set to 1, Monday + * + * Expected : + * getRescheduledTime returns Monday January 11 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Weekly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_05_1971_09_00_00)); + $mock->setDay(1); + $this->assertEquals($this->_JANUARY_11_1971_00_00_00, $mock->getRescheduledTime()); + + /* + * Test 3 + * + * Context : + * - getRescheduledTime called Monday January 4 1971 09:00:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is set to 1, Friday + * + * Expected : + * getRescheduledTime returns Friday January 15 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Weekly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_04_1971_09_00_00)); + $mock->setDay(5); + $this->assertEquals($this->_JANUARY_15_1971_00_00_00, $mock->getRescheduledTime()); + } + + /** + * Tests getRescheduledTime on Piwik_ScheduledTime_Monthly with unspecified hour and unspecified day + * @group Core + * @group ScheduledTime + */ + public function testGetRescheduledTimeMonthlyUnspecifiedHourUnspecifiedDay() + { + /* + * Test 1 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 09:00:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is not called, defaulting to first day of the month + * + * Expected : + * getRescheduledTime returns Monday February 1 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Monthly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_09_00_00)); + $this->assertEquals($this->_FEBRUARY_01_1971_00_00_00, $mock->getRescheduledTime()); + + /* + * Test 2 + * + * Context : + * - getRescheduledTime called Tuesday January 5 1971 09:00:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is not called, defaulting to first day of the month + * + * Expected : + * getRescheduledTime returns Monday February 1 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Monthly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_05_1971_09_00_00)); + $this->assertEquals($this->_FEBRUARY_01_1971_00_00_00, $mock->getRescheduledTime()); + } + + + /** + * Tests getRescheduledTime on Piwik_ScheduledTime_Monthly with unspecified hour and specified day + * @group Core + * @group ScheduledTime + */ + public function testGetRescheduledTimeMonthlyUnspecifiedHourSpecifiedDay() + { + /* + * Test 1 + * + * Context : + * - getRescheduledTime called Friday January 1 1971 09:00:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is set to 1 + * + * Expected : + * getRescheduledTime returns Monday February 1 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Monthly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_01_1971_09_00_00)); + $mock->setDay(1); + $this->assertEquals($this->_FEBRUARY_01_1971_00_00_00, $mock->getRescheduledTime()); + + /* + * Test 2 + * + * Context : + * - getRescheduledTime called Saturday January 2 1971 09:00:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is set to 2 + * + * Expected : + * getRescheduledTime returns Tuesday February 2 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Monthly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_02_1971_09_00_00)); + $mock->setDay(2); + $this->assertEquals($this->_FEBRUARY_02_1971_00_00_00, $mock->getRescheduledTime()); + + /* + * Test 3 + * + * Context : + * - getRescheduledTime called Friday January 15 1971 09:00:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is set to 2 + * + * Expected : + * getRescheduledTime returns Tuesday February 1 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Monthly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_15_1971_09_00_00)); + $mock->setDay(2); + $this->assertEquals($this->_FEBRUARY_02_1971_00_00_00, $mock->getRescheduledTime()); + + /* + * Test 4 + * + * Context : + * - getRescheduledTime called Friday January 15 1971 09:00:00 UTC + * - setHour is not called, defaulting to midnight + * - setDay is set to 31 + * + * Expected : + * getRescheduledTime returns Sunday February 28 1971 00:00:00 UTC + */ + $mock = $this->getMock('Piwik_ScheduledTime_Monthly', array('getTime')); + $mock->expects($this->any()) + ->method('getTime') + ->will($this->returnValue($this->_JANUARY_15_1971_09_00_00)); + $mock->setDay(31); + $this->assertEquals($this->_FEBRUARY_28_1971_00_00_00, $mock->getRescheduledTime()); + } +} diff --git a/tests/PHPUnit/Core/SegmentExpressionTest.php b/tests/PHPUnit/Core/SegmentExpressionTest.php new file mode 100644 index 0000000000..9c3a88f65b --- /dev/null +++ b/tests/PHPUnit/Core/SegmentExpressionTest.php @@ -0,0 +1,128 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * @version $Id$ + */ +class SegmentExpressionTest extends PHPUnit_Framework_TestCase +{ + /** + * Dataprovider for testSegmentSqlSimpleNoOperation + * @return array + */ + public function getSimpleSegmentExpressions() + { + return array( + // classic expressions + array('A', " A "), + array('A,B', " (A OR B )"), + array('A;B', " A AND B "), + array('A;B;C', " A AND B AND C "), + array('A,B;C,D;E,F,G', " (A OR B) AND (C OR D) AND (E OR F OR G )"), + + // unescape the backslash + array('A\,B\,C,D', " (A,B,C OR D )"), + array('\,A', ' ,A '), + // unescape only when it was escaping a known delimiter + array('\\\A', ' \\\A '), + // unescape at the end + array('\,\;\A\B,\,C,D\;E\,', ' (,;\A\B OR ,C OR D;E, )'), + + // only replace when a following expression is detected + array('A,', ' A, '), + array('A;', ' A; '), + array('A;B;', ' A AND B; '), + array('A,B,', ' (A OR B, )'), + ); + } + + /** + * @dataProvider getSimpleSegmentExpressions + * @group Core + * @group SegmentExpression + */ + public function testSegmentSqlSimpleNoOperation($expression, $expectedSql) + { + $segment = new Piwik_SegmentExpression($expression); + $expected = array('where' => $expectedSql, 'bind' => array(), 'join' => ''); + $processed = $segment->getSql(); + $this->assertEquals($expected, $processed); + } + + /** + * Dataprovider for testSegmentSqlWithOperations + * @return array + */ + public function getOperationSegmentExpressions() + { + // Filter expression => SQL string + Bind values + return array( + array('A==B%', array('where' => " A = ? ", 'bind' => array('B%'))), + array('ABCDEF====B===', array('where' => " ABCDEF = ? ", 'bind' => array('==B==='))), + array('A===B;CDEF!=C!=', array('where' => " A = ? AND CDEF <> ? ", 'bind' => array('=B', 'C!=' ))), + array('A==B,C==D', array('where' => " (A = ? OR C = ? )", 'bind' => array('B', 'D'))), + array('A!=B;C==D', array('where' => " A <> ? AND C = ? ", 'bind' => array('B', 'D'))), + array('A!=B;C==D,E!=Hello World!=', array('where' => " A <> ? AND (C = ? OR E <> ? )", 'bind' => array('B', 'D', 'Hello World!='))), + + array('A>B', array('where' => " A > ? ", 'bind' => array('B'))), + array('A<B', array('where' => " A < ? ", 'bind' => array('B'))), + array('A<=B', array('where' => " A <= ? ", 'bind' => array('B'))), + array('A>=B', array('where' => " A >= ? ", 'bind' => array('B'))), + array('ABCDEF>=>=>=B===', array('where' => " ABCDEF >= ? ", 'bind' => array('>=>=B==='))), + array('A>=<=B;CDEF>G;H>=I;J<K;L<=M', array('where' => " A >= ? AND CDEF > ? AND H >= ? AND J < ? AND L <= ? ", 'bind' => array('<=B', 'G','I','K','M' ))), + array('A>=B;C>=D,E<w_ow great!', array('where' => " A >= ? AND (C >= ? OR E < ? )", 'bind' => array('B', 'D', 'w_ow great!'))), + + array('A=@B_', array('where' => " A LIKE ? ", 'bind' => array('%B\_%'))), + array('A!@B%', array('where' => " A NOT LIKE ? ", 'bind' => array('%B\%%'))), + ); + } + + /** + * @dataProvider getOperationSegmentExpressions + * @group Core + * @group SegmentExpression + */ + public function testSegmentSqlWithOperations($expression, $expectedSql) + { + $segment = new Piwik_SegmentExpression($expression); + $segment->parseSubExpressions(); + $segment->parseSubExpressionsIntoSqlExpressions(); + $processed = $segment->getSql(); + $expectedSql['join'] = ''; + $this->assertEquals($expectedSql, $processed); + } + + /** + * Dataprovider for testBogusFiltersExpectExceptionThrown + * @return array + */ + public function getBogusFilters() + { + return array( + array('A=B'), + array('C!D'), + array(''), + array(' '), + array(',;,'), + array(','), + array(',,'), + array('==='), + array('!=') + ); + } + + /** + * @dataProvider getBogusFilters + * @group Core + * @group SegmentExpression + * @expectedException Exception + */ + public function testBogusFiltersExpectExceptionThrown($bogus) + { + $segment = new Piwik_SegmentExpression($bogus); + $segment->parseSubExpressions(); + $segment->getSql(); + } +} diff --git a/tests/PHPUnit/Core/SegmentTest.php b/tests/PHPUnit/Core/SegmentTest.php new file mode 100644 index 0000000000..7117bcc2d1 --- /dev/null +++ b/tests/PHPUnit/Core/SegmentTest.php @@ -0,0 +1,465 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * @version $Id$ + */ +class SegmentTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + parent::setUp(); + + // setup the access layer (required in Segment contrustor testing if anonymous is allowed to use segments) + $pseudoMockAccess = new FakeAccess; + FakeAccess::$superUser = true; + Zend_Registry::set('access', $pseudoMockAccess); + + // Load and install plugins + $pluginsManager = Piwik_PluginsManager::getInstance(); + $pluginsManager->loadPlugins( Piwik_Config::getInstance()->Plugins['Plugins'] ); + } + + public function tearDown() + { + parent::tearDown(); + Piwik_PluginsManager::getInstance()->unloadPlugins(); + } + + protected function _filterWhitsSpaces($valueToFilter) + { + if(is_array($valueToFilter)) { + foreach($valueToFilter AS $key => $value) { + $valueToFilter[$key] = $this->_filterWhitsSpaces($value); + } + return $valueToFilter; + } else { + return preg_replace('/[\s]+/', ' ', $valueToFilter); + } + } + + + public function getCommonTestData() + { + return array( + // Normal segment + array('country==France', array( + 'where' => ' log_visit.location_country = ? ', + 'bind' => array('France'))), + + // unescape the comma please + array('country==a\,==', array( + 'where' => ' log_visit.location_country = ? ', + 'bind' => array('a,=='))), + + // AND, with 2 values rewrites + array('country==a;visitorType!=returning;visitorType==new', array( + 'where' => ' log_visit.location_country = ? AND log_visit.visitor_returning <> ? AND log_visit.visitor_returning = ? ', + 'bind' => array('a', '1', '0'))), + + // OR, with 2 value rewrites + array('referrerType==search,referrerType==direct', array( + 'where'=>' (log_visit.referer_type = ? OR log_visit.referer_type = ? )', + 'bind' => array(Piwik_Common::REFERER_TYPE_SEARCH_ENGINE, + Piwik_Common::REFERER_TYPE_DIRECT_ENTRY))), + ); + } + + /** + * @dataProvider getCommonTestData + * @group Core + * @group Segment + */ + public function testCommon($segment, $expected) + { + $select = 'log_visit.idvisit'; + $from = 'log_visit'; + + $expected = array( + 'sql' => ' + SELECT + log_visit.idvisit + FROM + '.Piwik_Common::prefixTable('log_visit').' AS log_visit + WHERE + '.$expected['where'], + 'bind' => $expected['bind'] + ); + + $segment = new Piwik_Segment($segment, $idSites = array()); + $sql = $segment->getSelectQuery($select, $from, false); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($sql)); + + // calling twice should give same results + $sql = $segment->getSelectQuery($select, array($from)); + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($sql)); + + $this->assertEquals(32, strlen($segment->getHash())); + } + + /** + * @group Core + * @group Segment + */ + public function testGetSelectQueryNoJoin() + { + $select = '*'; + $from = 'log_visit'; + $where = 'idsite = ?'; + $bind = array(1); + + $segment = 'customVariableName1==Test;visitorType==new'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + * + FROM + ".Piwik_Common::prefixTable('log_visit')." AS log_visit + WHERE + ( idsite = ? ) + AND + ( log_visit.custom_var_k1 = ? AND log_visit.visitor_returning = ? )", + "bind" => array(1, 'Test', 0)); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * @group Core + * @group Segment + */ + public function testGetSelectQueryJoinVisitOnAction() + { + $select = '*'; + $from = 'log_link_visit_action'; + $where = 'log_link_visit_action.idvisit = ?'; + $bind = array(1); + + $segment = 'customVariablePageName1==Test;visitorType==new'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + * + FROM + ".Piwik_Common::prefixTable('log_link_visit_action')." AS log_link_visit_action + LEFT JOIN ".Piwik_Common::prefixTable('log_visit')." AS log_visit ON log_visit.idvisit = log_link_visit_action.idvisit + WHERE + ( log_link_visit_action.idvisit = ? ) + AND + ( log_link_visit_action.custom_var_k1 = ? AND log_visit.visitor_returning = ? )", + "bind" => array(1, 'Test', 0)); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * @group Core + * @group Segment + */ + public function testGetSelectQueryJoinActionOnVisit() + { + $select = 'sum(log_visit.visit_total_actions) as nb_actions, max(log_visit.visit_total_actions) as max_actions, sum(log_visit.visit_total_time) as sum_visit_length'; + $from = 'log_visit'; + $where = 'log_visit.idvisit = ?'; + $bind = array(1); + + $segment = 'customVariablePageName1==Test;visitorType==new'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + sum(log_inner.visit_total_actions) as nb_actions, max(log_inner.visit_total_actions) as max_actions, sum(log_inner.visit_total_time) as sum_visit_length + FROM + ( + SELECT + log_visit.visit_total_actions, + log_visit.visit_total_time + FROM + ".Piwik_Common::prefixTable('log_visit')." AS log_visit + LEFT JOIN ".Piwik_Common::prefixTable('log_link_visit_action')." AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit + WHERE + ( log_visit.idvisit = ? ) + AND + ( log_link_visit_action.custom_var_k1 = ? AND log_visit.visitor_returning = ? ) + GROUP BY log_visit.idvisit + ) AS log_inner", + "bind" => array(1, 'Test', 0)); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * @group Core + * @group Segment + */ + public function testGetSelectQueryJoinConversionOnAction() + { + $select = '*'; + $from = 'log_link_visit_action'; + $where = 'log_link_visit_action.idvisit = ?'; + $bind = array(1); + + $segment = 'customVariablePageName1==Test;visitConvertedGoalId==1;customVariablePageName2==Test2'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + * + FROM + ".Piwik_Common::prefixTable('log_link_visit_action')." AS log_link_visit_action + LEFT JOIN ".Piwik_Common::prefixTable('log_conversion')." AS log_conversion ON log_conversion.idlink_va = log_link_visit_action.idlink_va AND log_conversion.idsite = log_link_visit_action.idsite + WHERE + ( log_link_visit_action.idvisit = ? ) + AND + ( log_link_visit_action.custom_var_k1 = ? AND log_conversion.idgoal = ? AND log_link_visit_action.custom_var_k2 = ? )", + "bind" => array(1, 'Test', 1, 'Test2')); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * @group Core + * @group Segment + */ + public function testGetSelectQueryJoinActionOnConversion() + { + $select = '*'; + $from = 'log_conversion'; + $where = 'log_conversion.idvisit = ?'; + $bind = array(1); + + $segment = 'visitConvertedGoalId!=2;customVariablePageName1==Test;visitConvertedGoalId==1'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + * + FROM + ".Piwik_Common::prefixTable('log_conversion')." AS log_conversion + LEFT JOIN ".Piwik_Common::prefixTable('log_link_visit_action')." AS log_link_visit_action ON log_conversion.idlink_va = log_link_visit_action.idlink_va + WHERE + ( log_conversion.idvisit = ? ) + AND + ( log_conversion.idgoal <> ? AND log_link_visit_action.custom_var_k1 = ? AND log_conversion.idgoal = ? )", + "bind" => array(1, 2, 'Test', 1)); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * @group Core + * @group Segment + */ + public function testGetSelectQueryJoinConversionOnVisit() + { + $select = 'log_visit.*'; + $from = 'log_visit'; + $where = 'log_visit.idvisit = ?'; + $bind = array(1); + + $segment = 'visitConvertedGoalId==1'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + log_inner.* + FROM + ( + SELECT + log_visit.* + FROM + ".Piwik_Common::prefixTable('log_visit')." AS log_visit + LEFT JOIN ".Piwik_Common::prefixTable('log_conversion')." AS log_conversion ON log_conversion.idvisit = log_visit.idvisit + WHERE + ( log_visit.idvisit = ? ) + AND + ( log_conversion.idgoal = ? ) + GROUP BY log_visit.idvisit + ) AS log_inner", + "bind" => array(1, 1)); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * @group Core + * @group Segemnt + */ + public function testGetSelectQueryConversionOnly() + { + $select = 'log_conversion.*'; + $from = 'log_conversion'; + $where = 'log_conversion.idvisit = ?'; + $bind = array(1); + + $segment = 'visitConvertedGoalId==1'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + log_conversion.* + FROM + ".Piwik_Common::prefixTable('log_conversion')." AS log_conversion + WHERE + ( log_conversion.idvisit = ? ) + AND + ( log_conversion.idgoal = ? )", + "bind" => array(1, 1)); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * @group Core + * @group Segment + */ + public function testGetSelectQueryJoinVisitOnConversion() + { + $select = '*'; + $from = 'log_conversion'; + $where = 'log_conversion.idvisit = ?'; + $bind = array(1); + + $segment = 'visitConvertedGoalId==1,visitServerHour==12'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + * + FROM + ".Piwik_Common::prefixTable('log_conversion')." AS log_conversion + LEFT JOIN ".Piwik_Common::prefixTable('log_visit')." AS log_visit ON log_conversion.idvisit = log_visit.idvisit + WHERE + ( log_conversion.idvisit = ? ) + AND + ( (log_conversion.idgoal = ? OR HOUR(log_visit.visit_last_action_time) = ? ))", + "bind" => array(1, 1, 12)); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * visit is joined on action, then conversion is joined + * make sure that conversion is joined on action not visit + * + * @group Core + * @group Segment + */ + public function testGetSelectQueryJoinVisitAndConversionOnAction() + { + $select = '*'; + $from = 'log_link_visit_action'; + $where = false; + $bind = array(); + + $segment = 'visitServerHour==12;visitConvertedGoalId==1'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + * + FROM + ".Piwik_Common::prefixTable('log_link_visit_action')." AS log_link_visit_action + LEFT JOIN ".Piwik_Common::prefixTable('log_visit')." AS log_visit ON log_visit.idvisit = log_link_visit_action.idvisit + LEFT JOIN ".Piwik_Common::prefixTable('log_conversion')." AS log_conversion ON log_conversion.idlink_va = log_link_visit_action.idlink_va AND log_conversion.idsite = log_link_visit_action.idsite + WHERE + HOUR(log_visit.visit_last_action_time) = ? AND log_conversion.idgoal = ? ", + "bind" => array(12, 1)); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * join conversion on visit, then actions + * make sure actions are joined before conversions + * + * @group Core + * @group Segment + */ + public function testGetSelectQueryJoinConversionAndActionOnVisit() + { + $select = 'log_visit.*'; + $from = 'log_visit'; + $where = false; + $bind = array(); + + $segment = 'visitConvertedGoalId==1;visitServerHour==12;customVariablePageName1==Test'; + $segment = new Piwik_Segment($segment, $idSites = array()); + + $query = $segment->getSelectQuery($select, $from, $where, $bind); + + $expected = array( + "sql" => " + SELECT + log_inner.* + FROM + ( + SELECT + log_visit.* + FROM + ".Piwik_Common::prefixTable('log_visit')." AS log_visit + LEFT JOIN ".Piwik_Common::prefixTable('log_link_visit_action')." AS log_link_visit_action ON log_link_visit_action.idvisit = log_visit.idvisit + LEFT JOIN ".Piwik_Common::prefixTable('log_conversion')." AS log_conversion ON log_conversion.idlink_va = log_link_visit_action.idlink_va AND log_conversion.idsite = log_link_visit_action.idsite + WHERE + log_conversion.idgoal = ? AND HOUR(log_visit.visit_last_action_time) = ? AND log_link_visit_action.custom_var_k1 = ? + GROUP BY log_visit.idvisit + ) AS log_inner", + "bind" => array(1, 12, 'Test')); + + $this->assertEquals($this->_filterWhitsSpaces($expected), $this->_filterWhitsSpaces($query)); + } + + /** + * Dataprovider for testBogusSegmentThrowsException + */ + public function getBogusSegments() + { + return array( + array('referrerType==not'), + array('someRandomSegment==not'), + array('A=B') + ); + } + /** + * @group Core + * @group Segment + * @dataProvider getBogusSegments + * @expectedException Exception + */ + public function testBogusSegmentThrowsException($segment) + { + $segment = new Piwik_Segment($segment, $idSites = array()); + } +} -- GitLab