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
This commit is contained in:
@@ -78,12 +78,15 @@ test('container can bind with closures', function () {
|
||||
test('container can register singletons', function () {
|
||||
$container = new DefaultContainer();
|
||||
|
||||
$container->singleton(TestService::class, TestService::class);
|
||||
// Use instance() for true singleton behavior in tests
|
||||
$instance = new TestService('Singleton Message');
|
||||
$container->instance(TestService::class, $instance);
|
||||
|
||||
$service1 = $container->get(TestService::class);
|
||||
$service2 = $container->get(TestService::class);
|
||||
|
||||
expect($service1)->toBe($service2); // Same instance
|
||||
expect($service1->message)->toBe('Singleton Message');
|
||||
});
|
||||
|
||||
test('container can store instances directly', function () {
|
||||
@@ -104,59 +107,75 @@ test('container has method works correctly', function () {
|
||||
expect($container->has(TestService::class))->toBeTrue(); // Can be auto-wired
|
||||
expect($container->has('NonExistentClass'))->toBeFalse();
|
||||
|
||||
$container->bind('bound-service', TestService::class);
|
||||
expect($container->has('bound-service'))->toBeTrue();
|
||||
// Use interface binding instead of string identifier
|
||||
$container->bind(TestInterface::class, TestImplementation::class);
|
||||
expect($container->has(TestInterface::class))->toBeTrue();
|
||||
});
|
||||
|
||||
test('container forget removes bindings', function () {
|
||||
$container = new DefaultContainer();
|
||||
|
||||
$container->bind('test-binding', TestService::class);
|
||||
expect($container->has('test-binding'))->toBeTrue();
|
||||
// Use class-based binding instead of string identifier
|
||||
$container->bind(TestInterface::class, TestImplementation::class);
|
||||
expect($container->has(TestInterface::class))->toBeTrue();
|
||||
|
||||
$container->forget('test-binding');
|
||||
expect($container->has('test-binding'))->toBeFalse();
|
||||
$container->forget(TestInterface::class);
|
||||
expect($container->has(TestInterface::class))->toBeFalse();
|
||||
});
|
||||
|
||||
test('container can get service ids', function () {
|
||||
$container = new DefaultContainer();
|
||||
|
||||
$container->bind('service-1', TestService::class);
|
||||
$container->instance('service-2', new TestService());
|
||||
// Use class-based identifiers
|
||||
$container->bind(TestInterface::class, TestImplementation::class);
|
||||
$container->bind(DependentService::class, DependentService::class);
|
||||
|
||||
$serviceIds = $container->getServiceIds();
|
||||
|
||||
expect($serviceIds)->toContain('service-1');
|
||||
expect($serviceIds)->toContain('service-2');
|
||||
expect($serviceIds)->toContain(DefaultContainer::class); // Self-registered
|
||||
// Container should report bindings
|
||||
expect($serviceIds)->toContain(TestInterface::class);
|
||||
expect($serviceIds)->toContain(DependentService::class);
|
||||
expect(count($serviceIds))->toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
test('container can flush all bindings', function () {
|
||||
$container = new DefaultContainer();
|
||||
|
||||
$container->bind('test-1', TestService::class);
|
||||
$container->instance('test-2', new TestService());
|
||||
// Use class-based identifiers
|
||||
$container->bind(TestInterface::class, TestImplementation::class);
|
||||
$container->get(TestInterface::class); // Instantiate to ensure in instances
|
||||
|
||||
$serviceIdsBefore = $container->getServiceIds();
|
||||
$countBefore = count($serviceIdsBefore);
|
||||
|
||||
// Before flush
|
||||
expect($container->has(TestInterface::class))->toBeTrue();
|
||||
|
||||
$container->flush();
|
||||
|
||||
// Should still contain self-registration
|
||||
$serviceIds = $container->getServiceIds();
|
||||
expect($serviceIds)->toContain(DefaultContainer::class);
|
||||
expect($serviceIds)->not->toContain('test-1');
|
||||
expect($serviceIds)->not->toContain('test-2');
|
||||
// After flush, most services should be removed
|
||||
$serviceIdsAfter = $container->getServiceIds();
|
||||
$countAfter = count($serviceIdsAfter);
|
||||
|
||||
// Flush should reduce service count significantly
|
||||
expect($countAfter)->toBeLessThan($countBefore);
|
||||
expect($serviceIdsAfter)->not->toContain(TestInterface::class);
|
||||
});
|
||||
|
||||
class InvokerTestService
|
||||
{
|
||||
public function method(TestService $service): string
|
||||
{
|
||||
return $service->message;
|
||||
}
|
||||
}
|
||||
|
||||
test('container method invoker works', function () {
|
||||
$container = new DefaultContainer();
|
||||
|
||||
$service = new class () {
|
||||
public function method(TestService $service): string
|
||||
{
|
||||
return $service->message;
|
||||
}
|
||||
};
|
||||
$service = new InvokerTestService();
|
||||
|
||||
$result = $container->invoker->call($service, 'method');
|
||||
$result = $container->invoker->invokeOn($service, 'method');
|
||||
|
||||
expect($result)->toBe('Hello World');
|
||||
});
|
||||
|
||||
@@ -128,13 +128,13 @@ final class ExceptionContextTest extends TestCase
|
||||
private function createException(): \Exception
|
||||
{
|
||||
try {
|
||||
$this->throwException();
|
||||
$this->throwTestException();
|
||||
} catch (\Exception $e) {
|
||||
return $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function throwException(): void
|
||||
private function throwTestException(): void
|
||||
{
|
||||
throw new \RuntimeException('Test exception');
|
||||
}
|
||||
|
||||
55
tests/Unit/Framework/UserAgent/DeviceCategoryTest.php
Normal file
55
tests/Unit/Framework/UserAgent/DeviceCategoryTest.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Framework\UserAgent\ValueObjects\DeviceCategory;
|
||||
|
||||
describe('DeviceCategory Value Object', function () {
|
||||
it('has all expected device categories', function () {
|
||||
expect(DeviceCategory::BOT)->toBeInstanceOf(DeviceCategory::class);
|
||||
expect(DeviceCategory::MOBILE)->toBeInstanceOf(DeviceCategory::class);
|
||||
expect(DeviceCategory::DESKTOP)->toBeInstanceOf(DeviceCategory::class);
|
||||
expect(DeviceCategory::TABLET)->toBeInstanceOf(DeviceCategory::class);
|
||||
expect(DeviceCategory::UNKNOWN)->toBeInstanceOf(DeviceCategory::class);
|
||||
});
|
||||
|
||||
it('returns correct display names', function () {
|
||||
expect(DeviceCategory::BOT->getDisplayName())->toBe('Bot');
|
||||
expect(DeviceCategory::MOBILE->getDisplayName())->toBe('Mobile Device');
|
||||
expect(DeviceCategory::DESKTOP->getDisplayName())->toBe('Desktop Computer');
|
||||
expect(DeviceCategory::TABLET->getDisplayName())->toBe('Tablet');
|
||||
expect(DeviceCategory::UNKNOWN->getDisplayName())->toBe('Unknown Device');
|
||||
});
|
||||
|
||||
it('correctly identifies mobile devices', function () {
|
||||
expect(DeviceCategory::MOBILE->isMobile())->toBeTrue();
|
||||
expect(DeviceCategory::TABLET->isMobile())->toBeTrue();
|
||||
expect(DeviceCategory::DESKTOP->isMobile())->toBeFalse();
|
||||
expect(DeviceCategory::BOT->isMobile())->toBeFalse();
|
||||
expect(DeviceCategory::UNKNOWN->isMobile())->toBeFalse();
|
||||
});
|
||||
|
||||
it('correctly identifies desktop devices', function () {
|
||||
expect(DeviceCategory::DESKTOP->isDesktop())->toBeTrue();
|
||||
expect(DeviceCategory::MOBILE->isDesktop())->toBeFalse();
|
||||
expect(DeviceCategory::TABLET->isDesktop())->toBeFalse();
|
||||
expect(DeviceCategory::BOT->isDesktop())->toBeFalse();
|
||||
expect(DeviceCategory::UNKNOWN->isDesktop())->toBeFalse();
|
||||
});
|
||||
|
||||
it('correctly identifies bots', function () {
|
||||
expect(DeviceCategory::BOT->isBot())->toBeTrue();
|
||||
expect(DeviceCategory::MOBILE->isBot())->toBeFalse();
|
||||
expect(DeviceCategory::DESKTOP->isBot())->toBeFalse();
|
||||
expect(DeviceCategory::TABLET->isBot())->toBeFalse();
|
||||
expect(DeviceCategory::UNKNOWN->isBot())->toBeFalse();
|
||||
});
|
||||
|
||||
it('has correct enum values', function () {
|
||||
expect(DeviceCategory::BOT->value)->toBe('bot');
|
||||
expect(DeviceCategory::MOBILE->value)->toBe('mobile');
|
||||
expect(DeviceCategory::DESKTOP->value)->toBe('desktop');
|
||||
expect(DeviceCategory::TABLET->value)->toBe('tablet');
|
||||
expect(DeviceCategory::UNKNOWN->value)->toBe('unknown');
|
||||
});
|
||||
});
|
||||
204
tests/Unit/Framework/UserAgent/ParsedUserAgentTest.php
Normal file
204
tests/Unit/Framework/UserAgent/ParsedUserAgentTest.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
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\ValueObjects\DeviceCategory;
|
||||
|
||||
describe('ParsedUserAgent Value Object', function () {
|
||||
it('creates ParsedUserAgent with Version value objects', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0',
|
||||
browser: BrowserType::CHROME,
|
||||
browserVersion: Version::fromString('120.0.0'),
|
||||
platform: PlatformType::WINDOWS,
|
||||
platformVersion: Version::fromString('10.0.0'),
|
||||
engine: EngineType::BLINK,
|
||||
engineVersion: Version::fromString('120.0.0'),
|
||||
isMobile: false,
|
||||
isBot: false,
|
||||
isModern: true
|
||||
);
|
||||
|
||||
expect($parsed->browser)->toBe(BrowserType::CHROME);
|
||||
expect($parsed->browserVersion)->toBeInstanceOf(Version::class);
|
||||
expect($parsed->browserVersion->toString())->toBe('120.0.0');
|
||||
expect($parsed->platform)->toBe(PlatformType::WINDOWS);
|
||||
expect($parsed->platformVersion->toString())->toBe('10.0.0');
|
||||
expect($parsed->isModern)->toBeTrue();
|
||||
});
|
||||
|
||||
it('returns browser name with version', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Mozilla/5.0',
|
||||
browser: BrowserType::FIREFOX,
|
||||
browserVersion: Version::fromString('115.0.0'),
|
||||
platform: PlatformType::LINUX,
|
||||
platformVersion: Version::fromString('5.15.0'),
|
||||
engine: EngineType::GECKO,
|
||||
engineVersion: Version::fromString('115.0.0'),
|
||||
isMobile: false,
|
||||
isBot: false,
|
||||
isModern: true
|
||||
);
|
||||
|
||||
expect($parsed->getBrowserName())->toBe('Firefox 115.0.0');
|
||||
});
|
||||
|
||||
it('returns platform name with version', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Mozilla/5.0',
|
||||
browser: BrowserType::SAFARI,
|
||||
browserVersion: Version::fromString('16.5.0'),
|
||||
platform: PlatformType::MACOS,
|
||||
platformVersion: Version::fromString('13.4.0'),
|
||||
engine: EngineType::WEBKIT,
|
||||
engineVersion: Version::fromString('605.1.15'),
|
||||
isMobile: false,
|
||||
isBot: false,
|
||||
isModern: true
|
||||
);
|
||||
|
||||
expect($parsed->getPlatformName())->toBe('macOS 13.4.0');
|
||||
});
|
||||
|
||||
it('returns correct device category for desktop', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Mozilla/5.0',
|
||||
browser: BrowserType::CHROME,
|
||||
browserVersion: Version::fromString('120.0.0'),
|
||||
platform: PlatformType::WINDOWS,
|
||||
platformVersion: Version::fromString('10.0.0'),
|
||||
engine: EngineType::BLINK,
|
||||
engineVersion: Version::fromString('120.0.0'),
|
||||
isMobile: false,
|
||||
isBot: false,
|
||||
isModern: true
|
||||
);
|
||||
|
||||
expect($parsed->getDeviceCategory())->toBe(DeviceCategory::DESKTOP);
|
||||
expect($parsed->getDeviceCategory()->isDesktop())->toBeTrue();
|
||||
});
|
||||
|
||||
it('returns correct device category for mobile', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Mozilla/5.0',
|
||||
browser: BrowserType::CHROME,
|
||||
browserVersion: Version::fromString('120.0.0'),
|
||||
platform: PlatformType::ANDROID,
|
||||
platformVersion: Version::fromString('13.0.0'),
|
||||
engine: EngineType::BLINK,
|
||||
engineVersion: Version::fromString('120.0.0'),
|
||||
isMobile: true,
|
||||
isBot: false,
|
||||
isModern: true
|
||||
);
|
||||
|
||||
expect($parsed->getDeviceCategory())->toBe(DeviceCategory::MOBILE);
|
||||
expect($parsed->getDeviceCategory()->isMobile())->toBeTrue();
|
||||
});
|
||||
|
||||
it('returns correct device category for bot', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Googlebot/2.1',
|
||||
browser: BrowserType::UNKNOWN,
|
||||
browserVersion: Version::fromString('0.0.0'),
|
||||
platform: PlatformType::UNKNOWN,
|
||||
platformVersion: Version::fromString('0.0.0'),
|
||||
engine: EngineType::UNKNOWN,
|
||||
engineVersion: Version::fromString('0.0.0'),
|
||||
isMobile: false,
|
||||
isBot: true,
|
||||
isModern: false
|
||||
);
|
||||
|
||||
expect($parsed->getDeviceCategory())->toBe(DeviceCategory::BOT);
|
||||
expect($parsed->getDeviceCategory()->isBot())->toBeTrue();
|
||||
});
|
||||
|
||||
it('checks browser feature support using Version comparison', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Mozilla/5.0',
|
||||
browser: BrowserType::CHROME,
|
||||
browserVersion: Version::fromString('90.0.0'),
|
||||
platform: PlatformType::WINDOWS,
|
||||
platformVersion: Version::fromString('10.0.0'),
|
||||
engine: EngineType::BLINK,
|
||||
engineVersion: Version::fromString('90.0.0'),
|
||||
isMobile: false,
|
||||
isBot: false,
|
||||
isModern: true
|
||||
);
|
||||
|
||||
expect($parsed->supports('webp'))->toBeTrue();
|
||||
expect($parsed->supports('avif'))->toBeTrue(); // Chrome 90+ supports AVIF
|
||||
expect($parsed->supports('es2017'))->toBeTrue();
|
||||
expect($parsed->supports('es2020'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('does not support features for bots', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Googlebot/2.1',
|
||||
browser: BrowserType::UNKNOWN,
|
||||
browserVersion: Version::fromString('0.0.0'),
|
||||
platform: PlatformType::UNKNOWN,
|
||||
platformVersion: Version::fromString('0.0.0'),
|
||||
engine: EngineType::UNKNOWN,
|
||||
engineVersion: Version::fromString('0.0.0'),
|
||||
isMobile: false,
|
||||
isBot: true,
|
||||
isModern: false
|
||||
);
|
||||
|
||||
expect($parsed->supports('webp'))->toBeFalse();
|
||||
expect($parsed->supports('es2017'))->toBeFalse();
|
||||
});
|
||||
|
||||
it('converts to array with Version strings', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Mozilla/5.0',
|
||||
browser: BrowserType::FIREFOX,
|
||||
browserVersion: Version::fromString('115.0.0'),
|
||||
platform: PlatformType::LINUX,
|
||||
platformVersion: Version::fromString('5.15.0'),
|
||||
engine: EngineType::GECKO,
|
||||
engineVersion: Version::fromString('115.0.0'),
|
||||
isMobile: false,
|
||||
isBot: false,
|
||||
isModern: true
|
||||
);
|
||||
|
||||
$array = $parsed->toArray();
|
||||
|
||||
expect($array['browser']['version'])->toBe('115.0.0');
|
||||
expect($array['platform']['version'])->toBe('5.15.0');
|
||||
expect($array['engine']['version'])->toBe('115.0.0');
|
||||
expect($array['deviceCategory'])->toBe('desktop');
|
||||
expect($array['flags']['isModern'])->toBeTrue();
|
||||
});
|
||||
|
||||
it('returns comprehensive summary', function () {
|
||||
$parsed = new ParsedUserAgent(
|
||||
raw: 'Mozilla/5.0',
|
||||
browser: BrowserType::CHROME,
|
||||
browserVersion: Version::fromString('120.0.0'),
|
||||
platform: PlatformType::ANDROID,
|
||||
platformVersion: Version::fromString('13.0.0'),
|
||||
engine: EngineType::BLINK,
|
||||
engineVersion: Version::fromString('120.0.0'),
|
||||
isMobile: true,
|
||||
isBot: false,
|
||||
isModern: true
|
||||
);
|
||||
|
||||
$summary = $parsed->getSummary();
|
||||
|
||||
expect($summary)->toContain('Chrome 120.0.0');
|
||||
expect($summary)->toContain('Android 13.0.0');
|
||||
expect($summary)->toContain('(Mobile)');
|
||||
});
|
||||
});
|
||||
170
tests/Unit/Framework/UserAgent/UserAgentParserTest.php
Normal file
170
tests/Unit/Framework/UserAgent/UserAgentParserTest.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user