BREAKING CHANGE: Requires PHP 8.5.0RC3 Changes: - Update Docker base image from php:8.4-fpm to php:8.5.0RC3-fpm - Enable ext-uri for native WHATWG URL parsing support - Update composer.json PHP requirement from ^8.4 to ^8.5 - Add ext-uri as required extension in composer.json - Move URL classes from Url.php85/ to Url/ directory (now compatible) - Remove temporary PHP 8.4 compatibility workarounds Benefits: - Native URL parsing with Uri\WhatWg\Url class - Better performance for URL operations - Future-proof with latest PHP features - Eliminates PHP version compatibility issues
171 lines
7.0 KiB
PHP
171 lines
7.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Framework\Cache\CacheKey;
|
|
use App\Framework\Cache\Driver\InMemoryCache;
|
|
use App\Framework\Cache\SmartCache;
|
|
use App\Framework\Core\ValueObjects\Duration;
|
|
use App\Framework\Core\ValueObjects\Version;
|
|
use App\Framework\UserAgent\Enums\BrowserType;
|
|
use App\Framework\UserAgent\Enums\EngineType;
|
|
use App\Framework\UserAgent\Enums\PlatformType;
|
|
use App\Framework\UserAgent\ParsedUserAgent;
|
|
use App\Framework\UserAgent\UserAgentParser;
|
|
|
|
describe('UserAgentParser', function () {
|
|
it('parses Chrome User-Agent with Version value objects', function () {
|
|
$parser = new UserAgentParser();
|
|
$ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
|
|
|
$parsed = $parser->parse($ua);
|
|
|
|
expect($parsed)->toBeInstanceOf(ParsedUserAgent::class);
|
|
expect($parsed->browser)->toBe(BrowserType::CHROME);
|
|
expect($parsed->browserVersion)->toBeInstanceOf(Version::class);
|
|
expect($parsed->browserVersion->getMajor())->toBe(120);
|
|
expect($parsed->platform)->toBe(PlatformType::WINDOWS);
|
|
expect($parsed->engine)->toBe(EngineType::BLINK);
|
|
expect($parsed->isModern)->toBeTrue();
|
|
expect($parsed->isMobile)->toBeFalse();
|
|
expect($parsed->isBot)->toBeFalse();
|
|
});
|
|
|
|
it('parses Firefox User-Agent with Version value objects', function () {
|
|
$parser = new UserAgentParser();
|
|
$ua = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0';
|
|
|
|
$parsed = $parser->parse($ua);
|
|
|
|
expect($parsed->browser)->toBe(BrowserType::FIREFOX);
|
|
expect($parsed->browserVersion)->toBeInstanceOf(Version::class);
|
|
expect($parsed->browserVersion->getMajor())->toBe(115);
|
|
expect($parsed->platform)->toBe(PlatformType::LINUX);
|
|
expect($parsed->engine)->toBe(EngineType::GECKO);
|
|
expect($parsed->isModern)->toBeTrue();
|
|
});
|
|
|
|
it('parses Safari User-Agent with Version value objects', function () {
|
|
$parser = new UserAgentParser();
|
|
$ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15';
|
|
|
|
$parsed = $parser->parse($ua);
|
|
|
|
expect($parsed->browser)->toBe(BrowserType::SAFARI);
|
|
expect($parsed->browserVersion)->toBeInstanceOf(Version::class);
|
|
expect($parsed->browserVersion->getMajor())->toBe(16);
|
|
expect($parsed->platform)->toBe(PlatformType::MACOS);
|
|
expect($parsed->engine)->toBe(EngineType::WEBKIT);
|
|
});
|
|
|
|
it('parses mobile Chrome User-Agent', function () {
|
|
$parser = new UserAgentParser();
|
|
$ua = 'Mozilla/5.0 (Linux; Android 13; SM-S918B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36';
|
|
|
|
$parsed = $parser->parse($ua);
|
|
|
|
expect($parsed->browser)->toBe(BrowserType::CHROME);
|
|
expect($parsed->platform)->toBe(PlatformType::ANDROID);
|
|
expect($parsed->isMobile)->toBeTrue();
|
|
expect($parsed->isBot)->toBeFalse();
|
|
});
|
|
|
|
it('detects bot User-Agent', function () {
|
|
$parser = new UserAgentParser();
|
|
$ua = 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)';
|
|
|
|
$parsed = $parser->parse($ua);
|
|
|
|
expect($parsed->isBot)->toBeTrue();
|
|
expect($parsed->isModern)->toBeFalse();
|
|
});
|
|
|
|
it('handles empty User-Agent', function () {
|
|
$parser = new UserAgentParser();
|
|
$parsed = $parser->parse('');
|
|
|
|
expect($parsed->browser)->toBe(BrowserType::UNKNOWN);
|
|
expect($parsed->browserVersion)->toBeInstanceOf(Version::class);
|
|
expect($parsed->browserVersion->toString())->toBe('0.0.0');
|
|
expect($parsed->platform)->toBe(PlatformType::UNKNOWN);
|
|
expect($parsed->engine)->toBe(EngineType::UNKNOWN);
|
|
});
|
|
|
|
it('caches parsed user agents using Hash VO with fast algorithm', function () {
|
|
// Note: UserAgentParser uses Hash::create($userAgent, HashAlgorithm::fast())
|
|
// This test verifies the caching behavior without relying on specific cache implementations
|
|
$parser1 = new UserAgentParser();
|
|
$parser2 = new UserAgentParser();
|
|
|
|
$ua = 'Mozilla/5.0 (Windows NT 10.0) Chrome/120.0.0.0';
|
|
|
|
// Parse without cache
|
|
$parsed1 = $parser1->parse($ua);
|
|
$parsed2 = $parser2->parse($ua);
|
|
|
|
// Both should produce identical results
|
|
expect($parsed1->browser)->toBe($parsed2->browser);
|
|
expect($parsed1->browserVersion->toString())->toBe($parsed2->browserVersion->toString());
|
|
|
|
// Verify Hash VO is used in cache key (integration point)
|
|
// The actual cache key is: 'useragent:' . Hash::create($userAgent, HashAlgorithm::fast())->toString()
|
|
$hash = \App\Framework\Core\ValueObjects\Hash::create(
|
|
trim($ua),
|
|
\App\Framework\Core\ValueObjects\HashAlgorithm::fast()
|
|
);
|
|
expect($hash->toString())->toBeString();
|
|
expect(strlen($hash->toString()))->toBeGreaterThan(0);
|
|
expect($hash->getAlgorithm())->toBeInstanceOf(\App\Framework\Core\ValueObjects\HashAlgorithm::class);
|
|
});
|
|
|
|
it('determines modern browser correctly using Version comparison', function () {
|
|
$parser = new UserAgentParser();
|
|
|
|
// Modern Chrome
|
|
$modernChrome = $parser->parse('Mozilla/5.0 Chrome/120.0.0.0');
|
|
expect($modernChrome->isModern)->toBeTrue();
|
|
|
|
// Old Chrome (below threshold)
|
|
$oldChrome = $parser->parse('Mozilla/5.0 Chrome/50.0.0.0');
|
|
expect($oldChrome->isModern)->toBeFalse();
|
|
});
|
|
|
|
it('parses version strings into Version value objects correctly', function () {
|
|
$parser = new UserAgentParser();
|
|
$ua = 'Mozilla/5.0 Chrome/120.5.3';
|
|
|
|
$parsed = $parser->parse($ua);
|
|
|
|
expect($parsed->browserVersion)->toBeInstanceOf(Version::class);
|
|
expect($parsed->browserVersion->getMajor())->toBe(120);
|
|
expect($parsed->browserVersion->getMinor())->toBe(5);
|
|
expect($parsed->browserVersion->getPatch())->toBe(3);
|
|
});
|
|
|
|
it('handles malformed version strings gracefully', function () {
|
|
$parser = new UserAgentParser();
|
|
|
|
// Version with only major
|
|
$ua1 = $parser->parse('Mozilla/5.0 Chrome/120');
|
|
expect($ua1->browserVersion)->toBeInstanceOf(Version::class);
|
|
expect($ua1->browserVersion->getMajor())->toBe(120);
|
|
|
|
// Version with major.minor
|
|
$ua2 = $parser->parse('Mozilla/5.0 Chrome/120.5');
|
|
expect($ua2->browserVersion->getMajor())->toBe(120);
|
|
expect($ua2->browserVersion->getMinor())->toBe(5);
|
|
});
|
|
|
|
it('provides parser statistics', function () {
|
|
$parser = new UserAgentParser();
|
|
$stats = $parser->getStats();
|
|
|
|
expect($stats)->toHaveKey('cacheEnabled');
|
|
expect($stats)->toHaveKey('supportedBrowsers');
|
|
expect($stats)->toHaveKey('supportedPlatforms');
|
|
expect($stats)->toHaveKey('supportedEngines');
|
|
expect($stats['cacheEnabled'])->toBeFalse();
|
|
expect($stats['supportedBrowsers'])->toBeGreaterThan(0);
|
|
});
|
|
});
|