Files
michaelschiemer/tests/Unit/Framework/UserAgent/UserAgentParserTest.php
Michael Schiemer c8b47e647d feat(Docker): Upgrade to PHP 8.5.0RC3 with native ext-uri support
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
2025-10-27 09:31:28 +01:00

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);
});
});