From be6f6bf027e92cc19c661ee7bb37b1d9b5d4f162 Mon Sep 17 00:00:00 2001 From: Gustavo Freze de Araujo Santos Date: Mon, 11 Mar 2024 11:20:09 -0300 Subject: [PATCH] feat: Adds wrapper for HTTP code 422. --- composer.json | 2 +- infection.json.dist | 27 ++++-------- src/HttpHeaders.php | 5 +-- src/HttpResponse.php | 5 +++ src/Internal/Stream/StreamMetaData.php | 6 +-- tests/HttpResponseTest.php | 14 ++++++ tests/Internal/HeadersTest.php | 28 ------------ tests/Internal/HttpHeadersTest.php | 61 ++++++++++++++++++++++++++ tests/Internal/Stream/StreamTest.php | 24 ++++++++-- 9 files changed, 115 insertions(+), 57 deletions(-) delete mode 100644 tests/Internal/HeadersTest.php create mode 100644 tests/Internal/HttpHeadersTest.php diff --git a/composer.json b/composer.json index 526f5ba..a8a1df1 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ "require-dev": { "infection/infection": "^0.27", "phpmd/phpmd": "^2.15", - "phpunit/phpunit": "^10", + "phpunit/phpunit": "^10.5", "squizlabs/php_codesniffer": "^3.8" }, "suggest": { diff --git a/infection.json.dist b/infection.json.dist index 13361a2..dcff8e5 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -1,31 +1,22 @@ { - "timeout": 10, - "testFramework": "phpunit", + "$schema": "vendor/infection/infection/resources/schema.json", "tmpDir": "report/", + "logs": { + "text": "report/logs/infection-text.log", + "summary": "report/logs/infection-summary.log" + }, "source": { "directories": [ "src" ] }, - "logs": { - "text": "report/logs/infection-text.log", - "summary": "report/logs/infection-summary.log" - }, + "timeout": 10, "mutators": { "@default": true, - "ArrayItem": false, "LogicalOr": false, - "IfNegation": false, "InstanceOf_": false, "UnwrapArrayMap": false, - "ArrayItemRemoval": false, - "UnwrapArrayUnique": false, - "MethodCallRemoval": false, - "LogicalOrAllSubExprNegation": false, - "LogicalOrSingleSubExprNegation": false + "MethodCallRemoval": false }, - "phpUnit": { - "configDir": "", - "customPath": "./vendor/bin/phpunit" - } -} \ No newline at end of file + "testFramework": "phpunit" +} diff --git a/src/HttpHeaders.php b/src/HttpHeaders.php index b6fe26d..f5b0b86 100644 --- a/src/HttpHeaders.php +++ b/src/HttpHeaders.php @@ -63,9 +63,6 @@ public function hasHeader(string $key): bool public function toArray(): array { - return array_map( - fn(array $values): array => [end($values)], - array_map(fn(array $values): array => array_unique($values), $this->values) - ); + return array_map(fn(array $values): array => array_unique($values), $this->values); } } diff --git a/src/HttpResponse.php b/src/HttpResponse.php index 4b4d157..e4d404f 100644 --- a/src/HttpResponse.php +++ b/src/HttpResponse.php @@ -51,6 +51,11 @@ public static function conflict(mixed $data, ?HttpHeaders $headers = null): Resp return Response::from(code: HttpCode::CONFLICT, data: $data, headers: $headers); } + public static function unprocessableEntity(mixed $data, ?HttpHeaders $headers = null): ResponseInterface + { + return Response::from(code: HttpCode::UNPROCESSABLE_ENTITY, data: $data, headers: $headers); + } + # Server error (500 – 599) public static function internalServerError(mixed $data, ?HttpHeaders $headers = null): ResponseInterface diff --git a/src/Internal/Stream/StreamMetaData.php b/src/Internal/Stream/StreamMetaData.php index c25bfff..40b5e97 100644 --- a/src/Internal/Stream/StreamMetaData.php +++ b/src/Internal/Stream/StreamMetaData.php @@ -4,7 +4,7 @@ final readonly class StreamMetaData { - public function __construct( + private function __construct( private string $uri, private string $mode, private bool $seekable, @@ -36,8 +36,8 @@ public function toArray(): array { return [ 'uri' => $this->uri, - 'mode' => $this->getMode(), - 'seekable' => $this->isSeekable(), + 'mode' => $this->mode, + 'seekable' => $this->seekable, 'streamType' => $this->streamType ]; } diff --git a/tests/HttpResponseTest.php b/tests/HttpResponseTest.php index 780756a..c5fbdc4 100644 --- a/tests/HttpResponseTest.php +++ b/tests/HttpResponseTest.php @@ -103,6 +103,20 @@ public function testResponseConflict(mixed $data, mixed $expected): void self::assertEquals($this->defaultHeaderFrom(code: HttpCode::CONFLICT), $response->getHeaders()); } + /** + * @dataProvider providerData + */ + public function testResponseUnprocessableEntity(mixed $data, mixed $expected): void + { + $response = HttpResponse::unprocessableEntity(data: $data); + + self::assertEquals($expected, $response->getBody()->__toString()); + self::assertEquals($expected, $response->getBody()->getContents()); + self::assertEquals(HttpCode::UNPROCESSABLE_ENTITY->value, $response->getStatusCode()); + self::assertEquals(HttpCode::UNPROCESSABLE_ENTITY->message(), $response->getReasonPhrase()); + self::assertEquals($this->defaultHeaderFrom(code: HttpCode::UNPROCESSABLE_ENTITY), $response->getHeaders()); + } + /** * @dataProvider providerData */ diff --git a/tests/Internal/HeadersTest.php b/tests/Internal/HeadersTest.php deleted file mode 100644 index 2094cfd..0000000 --- a/tests/Internal/HeadersTest.php +++ /dev/null @@ -1,28 +0,0 @@ -addFromContentType(header: HttpContentType::APPLICATION_JSON); - $expected = ['Content-Type' => [HttpContentType::APPLICATION_JSON->value]]; - - self::assertEquals($expected, $headers->toArray()); - } - - public function testAddAndGetUniqueValues(): void - { - $headers = HttpHeaders::build() - ->addFromContentType(header: HttpContentType::TEXT_HTML) - ->addFromContentType(header: HttpContentType::APPLICATION_PDF); - $expected = ['Content-Type' => [HttpContentType::APPLICATION_PDF->value]]; - - self::assertEquals($expected, $headers->toArray()); - } -} diff --git a/tests/Internal/HttpHeadersTest.php b/tests/Internal/HttpHeadersTest.php new file mode 100644 index 0000000..5988c72 --- /dev/null +++ b/tests/Internal/HttpHeadersTest.php @@ -0,0 +1,61 @@ +addFrom(key: 'X-Custom-Header', value: 'value1') + ->addFrom(key: 'X-Custom-Header', value: 'value2') + ->removeFrom(key: 'X-Custom-Header'); + + self::assertTrue($actual->hasNoHeaders()); + self::assertFalse($actual->hasHeader(key: 'X-Custom-Header')); + } + + public function testAddFromCode(): void + { + $actual = HttpHeaders::build()->addFromCode(code: HttpCode::OK); + $expected = ['Status' => [HttpCode::OK->message()]]; + + self::assertEquals($expected, $actual->toArray()); + } + + public function testAddFromContentType(): void + { + $headers = HttpHeaders::build()->addFromContentType(header: HttpContentType::APPLICATION_JSON); + $actual = $headers->toArray(); + $expected = ['Content-Type' => [HttpContentType::APPLICATION_JSON->value]]; + + self::assertEquals($expected, $actual); + } + + public function testGetHeader(): void + { + $headers = HttpHeaders::build() + ->addFrom(key: 'X-Custom-Header', value: 'value1') + ->addFrom(key: 'X-Custom-Header', value: 'value2'); + $actual = $headers->getHeader(key: 'X-Custom-Header'); + $expected = ['value1', 'value2']; + + self::assertEquals($expected, $actual); + } + + public function testToArrayWithNonUniqueValues(): void + { + $headers = HttpHeaders::build() + ->addFrom(key: 'X-Custom-Header', value: 'value1') + ->addFrom(key: 'X-Custom-Header', value: 'value1'); + $actual = $headers->toArray(); + $expected = ['X-Custom-Header' => ['value1']]; + + self::assertEquals($expected, $actual); + } +} diff --git a/tests/Internal/Stream/StreamTest.php b/tests/Internal/Stream/StreamTest.php index f6e6174..fbdbbda 100644 --- a/tests/Internal/Stream/StreamTest.php +++ b/tests/Internal/Stream/StreamTest.php @@ -67,9 +67,18 @@ public function testGetMetadata(): void $actual = $stream->getMetadata(); $expected = StreamMetaData::from(data: stream_get_meta_data($this->resource))->toArray(); - self::assertNull($stream->getMetadata(key: '')); - self::assertEquals($expected, $actual); - self::assertEquals($expected['mode'], $stream->getMetadata(key: 'mode')); + self::assertEquals($expected['uri'], $actual['uri']); + self::assertEquals($expected['mode'], $actual['mode']); + self::assertEquals($expected['seekable'], $actual['seekable']); + self::assertEquals($expected['streamType'], $actual['streamType']); + } + + public function testGetMetadataWhenKeyIsUnknown(): void + { + $stream = Stream::from(resource: $this->resource); + $actual = $stream->getMetadata(key: 'UNKNOWN'); + + self::assertNull($actual); } public function testSeekMovesCursorPosition(): void @@ -125,6 +134,15 @@ public function testExceptionWhenMissingResourceStreamOnTell(): void $stream->tell(); } + public function testToStringRewindsStreamIfNotSeekable(): void + { + $stream = Stream::from(resource: $this->resource); + $stream->write(string: 'Hello, world!'); + $actual = (string)$stream; + + self::assertEquals('Hello, world!', $actual); + } + public function testExceptionWhenNonSeekableStream(): void { $stream = Stream::from(resource: $this->resource);