assertTrue(class_exists('Mobile_Detect')); } public function setUp() { $this->detect = new Mobile_Detect; } public function testBasicMethods() { $this->assertNotEmpty( $this->detect->getScriptVersion() ); $this->detect->setHttpHeaders(array( 'SERVER_SOFTWARE' => 'Apache/2.2.15 (Linux) Whatever/4.0 PHP/5.2.13', 'REQUEST_METHOD' => 'POST', 'HTTP_HOST' => 'home.ghita.org', 'HTTP_X_REAL_IP' => '1.2.3.4', 'HTTP_X_FORWARDED_FOR' => '1.2.3.5', 'HTTP_CONNECTION' => 'close', 'HTTP_USER_AGENT' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25', 'HTTP_ACCEPT' => 'text/vnd.wap.wml, application/json, text/javascript, */*; q=0.01', 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5', 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest', 'HTTP_REFERER' => 'http://mobiledetect.net', 'HTTP_PRAGMA' => 'no-cache', 'HTTP_CACHE_CONTROL' => 'no-cache', 'REMOTE_ADDR' => '11.22.33.44', 'REQUEST_TIME' => '01-10-2012 07:57' )); //12 because only 12 start with HTTP_ $this->assertCount( 12, $this->detect->getHttpHeaders() ); $this->assertTrue( $this->detect->checkHttpHeadersForMobile() ); $this->detect->setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25'); $this->assertNotEmpty( $this->detect->getUserAgent() ); $this->assertTrue( $this->detect->isMobile() ); $this->assertFalse( $this->detect->isTablet() ); $this->assertTrue( $this->detect->isIphone() ); $this->assertTrue( $this->detect->isiphone() ); $this->assertTrue( $this->detect->isiOS() ); $this->assertTrue( $this->detect->isios() ); $this->assertTrue( $this->detect->is('iphone') ); $this->assertTrue( $this->detect->is('ios') ); } public function headersProvider() { return array( array(array( 'SERVER_SOFTWARE' => 'Apache/2.2.15 (Linux) Whatever/4.0 PHP/5.2.13', 'REQUEST_METHOD' => 'POST', 'HTTP_HOST' => 'home.ghita.org', 'HTTP_X_REAL_IP' => '1.2.3.4', 'HTTP_X_FORWARDED_FOR' => '1.2.3.5', 'HTTP_CONNECTION' => 'close', 'HTTP_USER_AGENT' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0_1 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A523 Safari/8536.25', 'HTTP_ACCEPT' => 'text/vnd.wap.wml, application/json, text/javascript, */*; q=0.01', 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5', 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate', 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest', 'HTTP_REFERER' => 'http://mobiledetect.net', 'HTTP_PRAGMA' => 'no-cache', 'HTTP_CACHE_CONTROL' => 'no-cache', 'REMOTE_ADDR' => '11.22.33.44', 'REQUEST_TIME' => '01-10-2012 07:57' )), array(array( 'SERVER_SOFTWARE' => 'Rogue software', 'REQUEST_METHOD' => 'GET', 'REMOTE_ADDR' => '8.8.8.8', 'REQUEST_TIME' => '07-10-2013 23:56', 'HTTP_USER_AGENT' => "garbage/1.0" )), array(array( 'SERVER_SOFTWARE' => 'Apache/1.3.17 (Linux) PHP/5.5.2', 'REQUEST_METHOD' => 'HEAD', 'HTTP_USER_AGENT' => 'Mozilla/5.0 (Linux; U; Android 1.5; en-us; ADR6200 Build/CUPCAKE) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1', 'REMOTE_ADDR' => '1.250.250.0', 'REQUEST_TIME' => '06-12-2006 11:06' )), ); } /** * @dataProvider headersProvider * @covers Mobile_Detect::getHttpHeader */ public function testConstructorInjection(array $headers) { $md = new Mobile_Detect($headers); foreach ($headers as $header => $value) { if (substr($header, 0, 5) !== 'HTTP_') { //make sure it wasn't set $this->assertNull($md->getHttpHeader($value)); } else { //make sure it's equal $this->assertEquals($value, $md->getHttpHeader($header)); } } //verify some of the headers work with the translated getter $this->assertNull($md->getHttpHeader('Remote-Addr')); $this->assertNull($md->getHttpHeader('Server-Software')); $this->assertEquals($headers['HTTP_USER_AGENT'], $md->getHttpHeader('User-Agent')); } /** * @dataProvider headersProvider * @covers Mobile_Detect::getHttpHeader */ public function testInvalidHeader($headers) { $md = new Mobile_Detect($headers); $this->assertNull($md->getHttpHeader('garbage_is_Garbage')); } public function userAgentProvider() { return array( array(array( 'HTTP_USER_AGENT' => 'blah' ), 'blah'), array(array( 'HTTP_USER_AGENT' => 'iphone', 'HTTP_X_OPERAMINI_PHONE_UA' => 'some other stuff' ), 'iphone some other stuff'), array(array( 'HTTP_X_DEVICE_USER_AGENT' => 'hello world' ), 'hello world'), array(array(), null) ); } /** * @dataProvider userAgentProvider * @covers Mobile_Detect::setUserAgent * @covers Mobile_Detect::getUserAgent */ public function testGetUserAgent($headers, $expectedUserAgent) { $md = new Mobile_Detect($headers); $md->setUserAgent(); $this->assertSame($expectedUserAgent, $md->getUserAgent()); } /** * Headers should be reset when you use setHttpHeaders. * @covers Mobile_Detect::setHttpHeaders * @issue #144 */ public function testSetHttpHeaders() { $header1 = array('HTTP_PINK_PONY' => 'I secretly love ponies >_>'); $md = new Mobile_Detect($header1); $this->assertSame($md->getHttpHeaders(), $header1); $header2 = array('HTTP_FIRE_BREATHING_DRAGON' => 'yeah!'); $md->setHttpHeaders($header2); $this->assertSame($md->getHttpHeaders(), $header2); } /** * Read response from cloudfront, if the cloudfront headers are detected * @covers Mobile_Detect::setCfHeaders */ public function testSetCfHeaders() { // Test mobile detected $header1 = array( 'HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER' => 'false', 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER' => 'true', 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER' => 'false' ); $md = new Mobile_Detect($header1); $this->assertSame($md->getCfHeaders(), $header1); $this->assertSame($md->getUserAgent(), 'Amazon CloudFront'); $this->assertSame($md->isTablet(), false); $this->assertSame($md->isMobile(), true); // Test neither mobile nor tablet (desktop) $header2 = array( 'HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER' => 'true', 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER' => 'false', 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER' => 'false' ); $md->setHttpHeaders($header2); $this->assertSame($md->getCfHeaders(), $header2); $this->assertSame($md->getUserAgent(), 'Amazon CloudFront'); $this->assertSame($md->isTablet(), false); $this->assertSame($md->isMobile(), false); // Test tablet detected $header3 = array( 'HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER' => 'false', 'HTTP_CLOUDFRONT_IS_MOBILE_VIEWER' => 'false', 'HTTP_CLOUDFRONT_IS_TABLET_VIEWER' => 'true' ); $md->setCfHeaders($header3); $this->assertSame($md->getCfHeaders(), $header3); $this->assertSame($md->getUserAgent(), 'Amazon CloudFront'); $this->assertSame($md->isTablet(), true); $this->assertSame($md->isMobile(), false); // Check if the headers are cleared $header4 = array(); $md->setHttpHeaders($header4); $this->assertSame($md->getCfHeaders(), $header4); } /** * @covers Mobile_Detect::setUserAgent * @covers Mobile_Detect::getUserAgent */ public function testSetUserAgent() { $md = new Mobile_Detect(array()); $md->setUserAgent('hello world'); $this->assertSame('hello world', $md->getUserAgent()); } /** * @covers Mobile_Detect::setDetectionType */ public function testSetDetectionType() { $md = new Mobile_Detect(array()); $md->setDetectionType('bskdfjhs'); $this->assertAttributeEquals( Mobile_Detect::DETECTION_TYPE_MOBILE, 'detectionType', $md ); $md->setDetectionType(); $this->assertAttributeEquals( Mobile_Detect::DETECTION_TYPE_MOBILE, 'detectionType', $md ); $md->setDetectionType(Mobile_Detect::DETECTION_TYPE_MOBILE); $this->assertAttributeEquals( Mobile_Detect::DETECTION_TYPE_MOBILE, 'detectionType', $md ); $md->setDetectionType(Mobile_Detect::DETECTION_TYPE_EXTENDED); $this->assertAttributeEquals( Mobile_Detect::DETECTION_TYPE_EXTENDED, 'detectionType', $md ); } //special headers that give 'quick' indication that a device is mobile public function quickHeadersData() { return array( array(array( 'HTTP_ACCEPT' => 'application/json; q=0.2, application/x-obml2d; q=0.8, image/gif; q=0.99, */*' )), array(array( 'HTTP_ACCEPT' => 'text/*; q=0.1, application/vnd.rim.html' )), array(array( 'HTTP_ACCEPT' => 'text/vnd.wap.wml', )), array(array( 'HTTP_ACCEPT' => 'application/vnd.wap.xhtml+xml', )), array(array( 'HTTP_X_WAP_PROFILE' => 'hello', )), array(array( 'HTTP_X_WAP_CLIENTID' => '' )), array(array( 'HTTP_WAP_CONNECTION' => '' )), array(array( 'HTTP_PROFILE' => '' )), array(array( 'HTTP_X_OPERAMINI_PHONE_UA' => '' )), array(array( 'HTTP_X_NOKIA_GATEWAY_ID' => '' )), array(array( 'HTTP_X_ORANGE_ID' => '' )), array(array( 'HTTP_X_VODAFONE_3GPDPCONTEXT' => '' )), array(array( 'HTTP_X_HUAWEI_USERID' => '' )), array(array( 'HTTP_UA_OS' => '' )), array(array( 'HTTP_X_MOBILE_GATEWAY' => '' )), array(array( 'HTTP_X_ATT_DEVICEID' => '' )), array(array( 'HTTP_UA_CPU' => 'ARM' )) ); } /** * @dataProvider quickHeadersData * @covers Mobile_Detect::checkHttpHeadersForMobile */ public function testQuickHeaders($headers) { $md = new Mobile_Detect($headers); $this->assertTrue($md->checkHttpHeadersForMobile()); } // Headers that are not mobile. public function quickNonMobileHeadersData() { return array( array(array( 'HTTP_UA_CPU' => 'AMD64' )), array(array( 'HTTP_UA_CPU' => 'X86' )), array(array( 'HTTP_ACCEPT' => 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01' )), array(array( 'HTTP_REQUEST_METHOD' => 'DELETE' )), array(array( 'HTTP_VIA' => '1.1 ws-proxy.stuff.co.il C0A800FA' )), ); } /** * @dataProvider quickNonMobileHeadersData * @covers Mobile_Detect::checkHttpHeadersForMobile */ public function testNonMobileQuickHeaders($headers) { $md = new Mobile_Detect($headers); $this->assertFalse($md->checkHttpHeadersForMobile()); } /** * @expectedException BadMethodCallException * @coversNothing */ public function testBadMethodCall() { $md = new Mobile_Detect(array()); $md->badmethodthatdoesntexistatall(); } public function versionDataProvider() { return array( array( 'Mozilla/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19', 'Android', '4.0.4', 4.04 ), array( 'Mozilla/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19', 'Webkit', '535.19', 535.19 ), array( 'Mozilla/5.0 (Linux; Android 4.0.4; ARCHOS 80G9 Build/IMM76D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19', 'Chrome', '18.0.1025.166', 18.01025166 ), array( 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9700; en-US) AppleWebKit/534.8 (KHTML, like Gecko) Version/6.0.0.448 Mobile Safari/534.8', 'BlackBerry', '6.0.0.448', 6.00448 ), array( 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9700; en-US) AppleWebKit/534.8 (KHTML, like Gecko) Version/6.0.0.448 Mobile Safari/534.8', 'Webkit', '534.8', 534.8 ), array( 'Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en-GB) AppleWebKit/534.8+ (KHTML, like Gecko) Version/6.0.0.546 Mobile Safari/534.8+', 'BlackBerry', '6.0.0.546', 6.00546 ) ); } /** * @dataProvider versionDataProvider * @covers Mobile_Detect::version */ public function testVersionExtraction($userAgent, $property, $stringVersion, $floatVersion) { $md = new Mobile_Detect(array('HTTP_USER_AGENT' => $userAgent)); $prop = $md->version($property); $this->assertSame($stringVersion, $prop); $prop = $md->version($property, 'float'); $this->assertSame($floatVersion, $prop); //assert that garbage data is always === false $prop = $md->version('garbage input is always garbage'); $this->assertFalse($prop); } /** * @covers Mobile_Detect::getMobileDetectionRules */ public function testRules() { $md = new Mobile_Detect; $count = array_sum(array( count(Mobile_Detect::getPhoneDevices()), count(Mobile_Detect::getTabletDevices()), count(Mobile_Detect::getOperatingSystems()), count(Mobile_Detect::getBrowsers()) )); $rules = $md->getRules(); $this->assertEquals($count, count($rules)); } /** * @covers Mobile_Detect::getMobileDetectionRulesExtended */ public function testRulesExtended() { $md = new Mobile_Detect; $count = array_sum(array( count(Mobile_Detect::getPhoneDevices()), count(Mobile_Detect::getTabletDevices()), count(Mobile_Detect::getOperatingSystems()), count(Mobile_Detect::getBrowsers()), count(Mobile_Detect::getUtilities()) )); $md->setDetectionType(Mobile_Detect::DETECTION_TYPE_EXTENDED); $rules = $md->getRules(); $this->assertEquals($count, count($rules)); } /** * @covers Mobile_Detect::getScriptVersion */ public function testScriptVersion() { $v = Mobile_Detect::getScriptVersion(); $formatCheck = (bool)preg_match('/^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9])?$/', $v); $this->assertTrue($formatCheck, "Fails the semantic version test. The version " . var_export($v, true) . ' does not match X.Y.Z pattern'); } public function crazyVersionNumbers() { return array( array('2.5.6', 2.56), array('12142.2142.412521.24.152', 12142.214241252124152), array('6_3', 6.3), array('4_7 /7 7 12_9', 4.777129), array('49', 49.0), array('2.6.x', 2.6), array('45.6.1.x.12', 45.61) ); } /** * @dataProvider crazyVersionNumbers * @covers Mobile_Detect::prepareVersionNo */ public function testPrepareVersionNo($raw, $expected) { $md = new Mobile_Detect; $actual = $md->prepareVersionNo($raw); $this->assertSame($expected, $actual, "We expected " . var_export($raw, true) . " to convert to " . var_export($expected, true) . ', but got ' . var_export($actual, true) . ' instead'); } }