Fixed: basePath self→static binding, namespace detection, event wiring,
SQLite cache, file cache driver. All Mod Boot classes converted to
$listens pattern for lifecycle event discovery.
Working endpoints:
- /v1/explorer/info — live chain height, difficulty, aliases
- /v1/explorer/stats — formatted chain statistics
- /v1/names/directory — alias directory grouped by type
- /v1/names/available/{name} — name availability check
- /v1/names/lookup/{name} — name details
Co-Authored-By: Charon <charon@lethean.io>
270 lines
12 KiB
PHP
270 lines
12 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Core PHP Framework
|
|
*
|
|
* Licensed under the European Union Public Licence (EUPL) v1.2.
|
|
* See LICENSE file for details.
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Core\Front\Tests\Unit;
|
|
|
|
use Core\Front\Services\DeviceDetectionService;
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use Tests\TestCase;
|
|
|
|
class DeviceDetectionServiceTest extends TestCase
|
|
{
|
|
private DeviceDetectionService $service;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->service = new DeviceDetectionService;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// In-App Browser Detection
|
|
// -------------------------------------------------------------------------
|
|
|
|
#[Test]
|
|
#[DataProvider('inAppBrowserUserAgents')]
|
|
public function it_detects_in_app_browsers(string $userAgent, string $expectedPlatform): void
|
|
{
|
|
$this->assertSame($expectedPlatform, $this->service->detectInAppBrowser($userAgent));
|
|
$this->assertTrue($this->service->isInAppBrowser($userAgent));
|
|
}
|
|
|
|
public static function inAppBrowserUserAgents(): array
|
|
{
|
|
return [
|
|
'Instagram iOS' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Instagram 275.0.0.20.98',
|
|
'instagram',
|
|
],
|
|
'Instagram Android' => [
|
|
'Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36 Instagram 290.0.0.30.115',
|
|
'instagram',
|
|
],
|
|
'Facebook iOS' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20A362 [FBAN/FBIOS;FBAV/420.0.0.42.70]',
|
|
'facebook',
|
|
],
|
|
'Facebook Android' => [
|
|
'Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/420.0.0.42.70]',
|
|
'facebook',
|
|
],
|
|
'TikTok iOS' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20A362 BytedanceWebview/d8a21c6',
|
|
'tiktok',
|
|
],
|
|
'TikTok Android' => [
|
|
'Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36 musical_ly/27.7.4',
|
|
'tiktok',
|
|
],
|
|
'Twitter iOS' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20A362 Twitter for iPhone',
|
|
'twitter',
|
|
],
|
|
'LinkedIn iOS' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20A362 LinkedInApp',
|
|
'linkedin',
|
|
],
|
|
'Snapchat iOS' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20A362 Snapchat/12.0.0',
|
|
'snapchat',
|
|
],
|
|
'Threads (Barcelona)' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20A362 Barcelona',
|
|
'threads',
|
|
],
|
|
'Pinterest iOS' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20A362 Pinterest for iOS',
|
|
'pinterest',
|
|
],
|
|
'Reddit iOS' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20A362 Reddit/2023.30.0',
|
|
'reddit',
|
|
],
|
|
'WeChat' => [
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/20A362 MicroMessenger/8.0.38',
|
|
'wechat',
|
|
],
|
|
'WhatsApp' => [
|
|
'WhatsApp/2.23.17.76 A',
|
|
'whatsapp',
|
|
],
|
|
];
|
|
}
|
|
|
|
#[Test]
|
|
public function it_returns_null_for_standard_browsers(): void
|
|
{
|
|
$standardBrowsers = [
|
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
|
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
|
|
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
|
|
];
|
|
|
|
foreach ($standardBrowsers as $ua) {
|
|
$this->assertNull($this->service->detectInAppBrowser($ua));
|
|
$this->assertFalse($this->service->isInAppBrowser($ua));
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Platform-Specific Methods
|
|
// -------------------------------------------------------------------------
|
|
|
|
#[Test]
|
|
public function it_has_platform_specific_methods(): void
|
|
{
|
|
$instagramUa = 'Mozilla/5.0 (iPhone) Instagram 275.0.0.20.98';
|
|
$facebookUa = 'Mozilla/5.0 (iPhone) [FBAN/FBIOS]';
|
|
$tiktokUa = 'Mozilla/5.0 (iPhone) BytedanceWebview';
|
|
$twitterUa = 'Mozilla/5.0 (iPhone) Twitter for iPhone';
|
|
|
|
$this->assertTrue($this->service->isInstagram($instagramUa));
|
|
$this->assertFalse($this->service->isInstagram($facebookUa));
|
|
|
|
$this->assertTrue($this->service->isFacebook($facebookUa));
|
|
$this->assertFalse($this->service->isFacebook($instagramUa));
|
|
|
|
$this->assertTrue($this->service->isTikTok($tiktokUa));
|
|
$this->assertTrue($this->service->isTwitter($twitterUa));
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Strict Content Platforms
|
|
// -------------------------------------------------------------------------
|
|
|
|
#[Test]
|
|
public function it_identifies_strict_content_platforms(): void
|
|
{
|
|
// Strict platforms
|
|
$this->assertTrue($this->service->isStrictContentPlatform('Instagram'));
|
|
$this->assertTrue($this->service->isStrictContentPlatform('[FBAN/FBIOS]'));
|
|
$this->assertTrue($this->service->isStrictContentPlatform('TikTok'));
|
|
$this->assertTrue($this->service->isStrictContentPlatform('Twitter'));
|
|
$this->assertTrue($this->service->isStrictContentPlatform('Snapchat'));
|
|
$this->assertTrue($this->service->isStrictContentPlatform('LinkedInApp'));
|
|
$this->assertTrue($this->service->isStrictContentPlatform('Barcelona')); // Threads
|
|
|
|
// Non-strict platforms
|
|
$this->assertFalse($this->service->isStrictContentPlatform('Pinterest'));
|
|
$this->assertFalse($this->service->isStrictContentPlatform('Reddit'));
|
|
$this->assertFalse($this->service->isStrictContentPlatform('Chrome'));
|
|
}
|
|
|
|
#[Test]
|
|
public function it_identifies_meta_platforms(): void
|
|
{
|
|
$this->assertTrue($this->service->isMetaPlatform('Instagram'));
|
|
$this->assertTrue($this->service->isMetaPlatform('[FBAN/FBIOS]'));
|
|
$this->assertTrue($this->service->isMetaPlatform('Barcelona')); // Threads
|
|
|
|
$this->assertFalse($this->service->isMetaPlatform('TikTok'));
|
|
$this->assertFalse($this->service->isMetaPlatform('Twitter'));
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Display Names
|
|
// -------------------------------------------------------------------------
|
|
|
|
#[Test]
|
|
public function it_returns_platform_display_names(): void
|
|
{
|
|
$this->assertSame('Instagram', $this->service->getPlatformDisplayName('Instagram'));
|
|
$this->assertSame('TikTok', $this->service->getPlatformDisplayName('TikTok'));
|
|
$this->assertSame('X (Twitter)', $this->service->getPlatformDisplayName('Twitter'));
|
|
$this->assertNull($this->service->getPlatformDisplayName('Chrome'));
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Device Detection
|
|
// -------------------------------------------------------------------------
|
|
|
|
#[Test]
|
|
public function it_detects_device_types(): void
|
|
{
|
|
$this->assertSame('mobile', $this->service->detectDeviceType('iPhone'));
|
|
$this->assertSame('mobile', $this->service->detectDeviceType('Android Mobile'));
|
|
$this->assertSame('tablet', $this->service->detectDeviceType('iPad'));
|
|
$this->assertSame('tablet', $this->service->detectDeviceType('Android Tablet'));
|
|
$this->assertSame('desktop', $this->service->detectDeviceType('Windows NT 10.0'));
|
|
$this->assertSame('desktop', $this->service->detectDeviceType('Macintosh'));
|
|
}
|
|
|
|
#[Test]
|
|
public function it_detects_operating_systems(): void
|
|
{
|
|
$this->assertSame('iOS', $this->service->detectOS('iPhone'));
|
|
$this->assertSame('iOS', $this->service->detectOS('iPad'));
|
|
$this->assertSame('Android', $this->service->detectOS('Android'));
|
|
$this->assertSame('Windows', $this->service->detectOS('Windows NT 10.0'));
|
|
$this->assertSame('macOS', $this->service->detectOS('Macintosh'));
|
|
$this->assertSame('Linux', $this->service->detectOS('Linux x86_64'));
|
|
}
|
|
|
|
#[Test]
|
|
public function it_detects_browsers(): void
|
|
{
|
|
$this->assertSame('Chrome', $this->service->detectBrowser('Chrome/114.0.0.0'));
|
|
$this->assertSame('Firefox', $this->service->detectBrowser('Firefox/115.0'));
|
|
$this->assertSame('Safari', $this->service->detectBrowser('Safari/604.1'));
|
|
$this->assertSame('Edge', $this->service->detectBrowser('Edg/114.0'));
|
|
}
|
|
|
|
#[Test]
|
|
public function it_returns_null_browser_for_in_app(): void
|
|
{
|
|
$this->assertNull($this->service->detectBrowser('Instagram 275.0'));
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Bot Detection
|
|
// -------------------------------------------------------------------------
|
|
|
|
#[Test]
|
|
public function it_detects_bots(): void
|
|
{
|
|
$this->assertTrue($this->service->isBot('Googlebot/2.1'));
|
|
$this->assertTrue($this->service->isBot('Bingbot/2.0'));
|
|
$this->assertTrue($this->service->isBot('facebookexternalhit/1.1'));
|
|
$this->assertTrue($this->service->isBot('Twitterbot/1.0'));
|
|
$this->assertTrue($this->service->isBot('AhrefsBot/7.0'));
|
|
|
|
$this->assertFalse($this->service->isBot('Chrome/114.0.0.0'));
|
|
$this->assertFalse($this->service->isBot('Instagram 275.0'));
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Full Parse
|
|
// -------------------------------------------------------------------------
|
|
|
|
#[Test]
|
|
public function it_parses_full_device_info(): void
|
|
{
|
|
$ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 Mobile Instagram 275.0.0.20.98';
|
|
|
|
$result = $this->service->parse($ua);
|
|
|
|
$this->assertSame('mobile', $result['device_type']);
|
|
$this->assertSame('iOS', $result['os_name']);
|
|
$this->assertNull($result['browser_name']); // In-app
|
|
$this->assertSame('instagram', $result['in_app_browser']);
|
|
$this->assertTrue($result['is_in_app']);
|
|
}
|
|
|
|
#[Test]
|
|
public function it_handles_null_and_empty_user_agents(): void
|
|
{
|
|
$this->assertNull($this->service->detectInAppBrowser(null));
|
|
$this->assertNull($this->service->detectInAppBrowser(''));
|
|
$this->assertFalse($this->service->isInAppBrowser(null));
|
|
$this->assertSame('desktop', $this->service->detectDeviceType(null));
|
|
}
|
|
}
|