Files
michaelschiemer/tests/Unit/Framework/Http/Url/WhatwgUrlTest.php
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

264 lines
9.5 KiB
PHP

<?php
declare(strict_types=1);
use App\Framework\Http\Url\UrlSpec;
use App\Framework\Http\Url\WhatwgUrl;
describe('WhatwgUrl', function () {
describe('parsing', function () {
it('parses basic HTTP URLs', function () {
$url = WhatwgUrl::parse('https://example.com/path');
expect($url->getScheme())->toBe('https');
expect($url->getHost())->toBe('example.com');
expect($url->getPath())->toBe('/path');
});
it('parses URLs with all components', function () {
$url = WhatwgUrl::parse('https://user:pass@example.com:8080/path?query=1#fragment');
expect($url->getScheme())->toBe('https');
expect($url->getUserInfo())->toBe('user:pass');
expect($url->getHost())->toBe('example.com');
expect($url->getPort())->toBe(8080);
expect($url->getPath())->toBe('/path');
expect($url->getQuery())->toBe('query=1');
expect($url->getFragment())->toBe('fragment');
});
it('handles default ports correctly', function () {
$url = WhatwgUrl::parse('https://example.com/path');
expect($url->getPort())->toBeNull();
});
it('parses relative URLs with base', function () {
$base = WhatwgUrl::parse('https://example.com/base/path');
$url = WhatwgUrl::parse('../other', $base);
expect($url->getPath())->toContain('other');
});
it('normalizes URLs according to WHATWG spec', function () {
$url = WhatwgUrl::parse('https://example.com/./path/../other');
// WHATWG normalizes . and .. in paths
expect($url->getPath())->toBe('/other');
});
});
describe('spec compliance', function () {
it('reports WHATWG spec', function () {
$url = WhatwgUrl::parse('https://example.com');
expect($url->getSpec())->toBe(UrlSpec::WHATWG);
expect($url->getSpec()->isWhatwg())->toBeTrue();
expect($url->getSpec()->isRfc3986())->toBeFalse();
});
});
describe('immutable withers', function () {
it('returns new instance with different scheme', function () {
$original = WhatwgUrl::parse('https://example.com');
$modified = $original->withScheme('http');
expect($original->getScheme())->toBe('https');
expect($modified->getScheme())->toBe('http');
expect(spl_object_id($original))->notToBe(spl_object_id($modified));
});
it('returns new instance with different host', function () {
$original = WhatwgUrl::parse('https://example.com');
$modified = $original->withHost('app.example.com');
expect($original->getHost())->toBe('example.com');
expect($modified->getHost())->toBe('app.example.com');
});
it('returns new instance with different port', function () {
$original = WhatwgUrl::parse('https://example.com');
$modified = $original->withPort(8080);
expect($original->getPort())->toBeNull();
expect($modified->getPort())->toBe(8080);
});
it('returns new instance with different path', function () {
$original = WhatwgUrl::parse('https://example.com/old');
$modified = $original->withPath('/new');
expect($original->getPath())->toBe('/old');
expect($modified->getPath())->toBe('/new');
});
it('returns new instance with different query', function () {
$original = WhatwgUrl::parse('https://example.com?old=1');
$modified = $original->withQuery('new=2');
expect($original->getQuery())->toBe('old=1');
expect($modified->getQuery())->toBe('new=2');
});
it('returns new instance with different fragment', function () {
$original = WhatwgUrl::parse('https://example.com#old');
$modified = $original->withFragment('new');
expect($original->getFragment())->toBe('old');
expect($modified->getFragment())->toBe('new');
});
it('returns new instance with user info', function () {
$original = WhatwgUrl::parse('https://example.com');
$modified = $original->withUserInfo('user', 'pass');
expect($original->getUserInfo())->toBe('');
expect($modified->getUserInfo())->toBe('user:pass');
});
it('handles user info without password', function () {
$url = WhatwgUrl::parse('https://example.com');
$modified = $url->withUserInfo('user');
expect($modified->getUserInfo())->toBe('user');
});
});
describe('serialization', function () {
it('converts to string', function () {
$url = WhatwgUrl::parse('https://example.com/path?query=1#fragment');
expect($url->toString())->toBe('https://example.com/path?query=1#fragment');
expect((string) $url)->toBe('https://example.com/path?query=1#fragment');
});
it('handles IDNA domains (Punycode)', function () {
$url = WhatwgUrl::parse('https://例え.jp/path');
$str = $url->toString();
// WHATWG automatically Punycode-encodes
expect($str)->toContain('xn--');
});
it('toAsciiString returns same as toString for WHATWG', function () {
$url = WhatwgUrl::parse('https://example.com/path');
expect($url->toAsciiString())->toBe($url->toString());
});
});
describe('URL resolution', function () {
it('resolves relative URLs', function () {
$base = WhatwgUrl::parse('https://example.com/base/path');
$resolved = $base->resolve('relative');
expect($resolved->getHost())->toBe('example.com');
expect($resolved->getPath())->toContain('relative');
});
it('resolves absolute URLs', function () {
$base = WhatwgUrl::parse('https://example.com/base');
$resolved = $base->resolve('https://other.com/path');
expect($resolved->getHost())->toBe('other.com');
expect($resolved->getPath())->toBe('/path');
});
it('resolves with path normalization', function () {
$base = WhatwgUrl::parse('https://example.com/base');
$resolved = $base->resolve('./path/../other');
expect($resolved->getPath())->toBe('/other');
});
});
describe('URL comparison', function () {
it('compares URLs for equality', function () {
$url1 = WhatwgUrl::parse('https://example.com/path');
$url2 = WhatwgUrl::parse('https://example.com/path');
expect($url1->equals($url2))->toBeTrue();
});
it('compares URLs ignoring fragments by default', function () {
$url1 = WhatwgUrl::parse('https://example.com/path#frag1');
$url2 = WhatwgUrl::parse('https://example.com/path#frag2');
expect($url1->equals($url2))->toBeTrue();
expect($url1->equals($url2, includeFragment: true))->toBeFalse();
});
it('detects different URLs', function () {
$url1 = WhatwgUrl::parse('https://example.com/path1');
$url2 = WhatwgUrl::parse('https://example.com/path2');
expect($url1->equals($url2))->toBeFalse();
});
});
describe('edge cases', function () {
it('handles trailing slashes', function () {
$url = WhatwgUrl::parse('https://example.com/path/');
expect($url->getPath())->toBe('/path/');
});
it('handles empty path', function () {
$url = WhatwgUrl::parse('https://example.com');
expect($url->getPath())->toBe('/');
});
it('handles empty query', function () {
$url = WhatwgUrl::parse('https://example.com/path');
expect($url->getQuery())->toBe('');
});
it('handles empty fragment', function () {
$url = WhatwgUrl::parse('https://example.com/path');
expect($url->getFragment())->toBe('');
});
it('removes port with null', function () {
$url = WhatwgUrl::parse('https://example.com:8080/path');
$modified = $url->withPort(null);
expect($modified->getPort())->toBeNull();
});
});
describe('browser redirect use cases', function () {
it('handles query parameters for redirects', function () {
$url = WhatwgUrl::parse('https://example.com/redirect');
$withParams = $url->withQuery('return_url=https://other.com&status=success');
expect($withParams->getQuery())->toContain('return_url');
expect($withParams->getQuery())->toContain('status=success');
});
it('handles fragment identifiers', function () {
$url = WhatwgUrl::parse('https://example.com/page#section');
expect($url->getFragment())->toBe('section');
});
it('normalizes paths for browser compatibility', function () {
$url = WhatwgUrl::parse('https://example.com/./path/../other');
expect($url->getPath())->toBe('/other');
});
});
describe('deep link use cases', function () {
it('handles custom schemes', function () {
$url = WhatwgUrl::parse('myapp://open/profile?user_id=123');
expect($url->getScheme())->toBe('myapp');
expect($url->getPath())->toContain('profile');
expect($url->getQuery())->toContain('user_id=123');
});
});
});