|
3 | 3 | namespace Tests\Unit; |
4 | 4 |
|
5 | 5 | use Laminas\Diactoros\ServerRequest; |
| 6 | +use Laminas\Diactoros\Response\HtmlResponse; |
| 7 | +use Monolog\Level; |
6 | 8 | use ownHackathon\App\Http\Exception\HttpDuplicateEntryException; |
| 9 | +use ownHackathon\App\Http\Exception\HttpHandledInvalidArgumentAsSuccessException; |
7 | 10 | use ownHackathon\App\Http\Exception\HttpInvalidArgumentException; |
8 | 11 | use ownHackathon\App\Http\Exception\HttpUnauthorizedException; |
9 | 12 | use ownHackathon\App\Http\Handler\PingHandler; |
|
26 | 29 | ->and((new HttpUnauthorizedException('a', 'b'))->getHttpStatusCode())->toBe(401); |
27 | 30 | }); |
28 | 31 |
|
| 32 | +test('duplicate entry exception preserves all constructor data and uses conflict status', function (): void { |
| 33 | + $previous = new \RuntimeException('database constraint'); |
| 34 | + $exception = new HttpDuplicateEntryException( |
| 35 | + 'Duplicate workspace', |
| 36 | + 'workspace name already in use', |
| 37 | + ['Workspace:' => 'existing-workspace'], |
| 38 | + Level::Error, |
| 39 | + $previous, |
| 40 | + ); |
| 41 | + |
| 42 | + expect($exception->getMessage())->toBe('Duplicate workspace') |
| 43 | + ->and($exception->getCode())->toBe(409) |
| 44 | + ->and($exception->getHttpStatusCode())->toBe(409) |
| 45 | + ->and($exception->getResponseMessage())->toBe('workspace name already in use') |
| 46 | + ->and($exception->getContext())->toBe(['Workspace:' => 'existing-workspace']) |
| 47 | + ->and($exception->getLogLevel())->toBe(Level::Error) |
| 48 | + ->and($exception->getPrevious())->toBe($previous); |
| 49 | +}); |
| 50 | + |
| 51 | +test('duplicate entry exception applies warning log level and empty context by default', function (): void { |
| 52 | + $exception = new HttpDuplicateEntryException('duplicate log', 'duplicate response'); |
| 53 | + |
| 54 | + expect($exception->getContext())->toBe([]) |
| 55 | + ->and($exception->getLogLevel())->toBe(Level::Warning) |
| 56 | + ->and($exception->getPrevious())->toBeNull(); |
| 57 | +}); |
| 58 | + |
| 59 | +test('handled invalid argument exception exposes a successful response status', function (): void { |
| 60 | + $previous = new \InvalidArgumentException('invalid input was handled'); |
| 61 | + $exception = new HttpHandledInvalidArgumentAsSuccessException( |
| 62 | + 'Invalid account state', |
| 63 | + 'account already activated', |
| 64 | + ['account' => 'user@example.test'], |
| 65 | + Level::Info, |
| 66 | + $previous, |
| 67 | + ); |
| 68 | + |
| 69 | + expect($exception->getMessage())->toBe('Invalid account state') |
| 70 | + ->and($exception->getCode())->toBe(200) |
| 71 | + ->and($exception->getHttpStatusCode())->toBe(200) |
| 72 | + ->and($exception->getResponseMessage())->toBe('account already activated') |
| 73 | + ->and($exception->getContext())->toBe(['account' => 'user@example.test']) |
| 74 | + ->and($exception->getLogLevel())->toBe(Level::Info) |
| 75 | + ->and($exception->getPrevious())->toBe($previous); |
| 76 | +}); |
| 77 | + |
| 78 | +test('handled invalid argument exception uses notice log level by default', function (): void { |
| 79 | + $exception = new HttpHandledInvalidArgumentAsSuccessException('handled log', 'handled response'); |
| 80 | + |
| 81 | + expect($exception->getLogLevel())->toBe(Level::Notice) |
| 82 | + ->and($exception->getContext())->toBe([]) |
| 83 | + ->and($exception->getPrevious())->toBeNull(); |
| 84 | +}); |
| 85 | + |
29 | 86 | test('ping handler returns runtime information', function (): void { |
30 | 87 | $response = (new PingHandler())->handle(new ServerRequest()); |
31 | 88 | $body = json_decode((string) $response->getBody(), true, 512, JSON_THROW_ON_ERROR); |
|
59 | 116 | define('ROOT_DIR', dirname(__DIR__, 2) . '/'); |
60 | 117 | } |
61 | 118 | $response = (new SwaggerUIHandler())->handle(new ServerRequest()); |
62 | | - expect($response->getStatusCode())->toBe(200)->and($response->getHeaderLine('content-type'))->toContain('text/html'); |
| 119 | + $body = (string) $response->getBody(); |
| 120 | + |
| 121 | + expect($response)->toBeInstanceOf(HtmlResponse::class) |
| 122 | + ->and($response->getStatusCode())->toBe(200) |
| 123 | + ->and($response->getHeaderLine('content-type'))->toContain('text/html') |
| 124 | + ->and($body)->toContain('<title>ownHackathon - SwaggerUI</title>') |
| 125 | + ->and($body)->toContain('<div id="swagger-ui"></div>') |
| 126 | + ->and($body)->toContain("url: 'swagger.json'") |
| 127 | + ->and($body)->toContain('SwaggerUIBundle'); |
| 128 | +}); |
| 129 | + |
| 130 | +test('swagger handler returns the same documentation for any request method', function (): void { |
| 131 | + if (!defined('ROOT_DIR')) { |
| 132 | + define('ROOT_DIR', dirname(__DIR__, 2) . '/'); |
| 133 | + } |
| 134 | + |
| 135 | + $handler = new SwaggerUIHandler(); |
| 136 | + $getResponse = $handler->handle((new ServerRequest())->withMethod('GET')); |
| 137 | + $headResponse = $handler->handle((new ServerRequest())->withMethod('HEAD')); |
| 138 | + |
| 139 | + expect((string) $getResponse->getBody())->toBe((string) $headResponse->getBody()) |
| 140 | + ->and($headResponse->getStatusCode())->toBe(200) |
| 141 | + ->and($headResponse->getHeaderLine('content-type'))->toContain('text/html'); |
63 | 142 | }); |
0 commit comments