From 65ccb6ca4a5a7bf7c244b8a28195fa188521b3d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20TAMARELLE?= Date: Fri, 21 Feb 2020 23:42:54 +0100 Subject: [PATCH] [HttpClient][DX] Add URL context to JsonException messages --- Response/ResponseTrait.php | 8 ++-- Tests/Response/MockResponseTest.php | 68 +++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 Tests/Response/MockResponseTest.php diff --git a/Response/ResponseTrait.php b/Response/ResponseTrait.php index 000da53..595ac97 100644 --- a/Response/ResponseTrait.php +++ b/Response/ResponseTrait.php @@ -147,21 +147,21 @@ public function toArray(bool $throw = true): array $contentType = $this->headers['content-type'][0] ?? 'application/json'; if (!preg_match('/\bjson\b/i', $contentType)) { - throw new JsonException(sprintf('Response content-type is "%s" while a JSON-compatible one was expected.', $contentType)); + throw new JsonException(sprintf('Response content-type is "%s" while a JSON-compatible one was expected for "%s".', $contentType, $this->getInfo('url'))); } try { $content = json_decode($content, true, 512, JSON_BIGINT_AS_STRING | (\PHP_VERSION_ID >= 70300 ? JSON_THROW_ON_ERROR : 0)); } catch (\JsonException $e) { - throw new JsonException($e->getMessage(), $e->getCode()); + throw new JsonException(sprintf('%s for "%s".', $e->getMessage(), $this->getInfo('url')), $e->getCode()); } if (\PHP_VERSION_ID < 70300 && JSON_ERROR_NONE !== json_last_error()) { - throw new JsonException(json_last_error_msg(), json_last_error()); + throw new JsonException(sprintf('%s for "%s".', json_last_error_msg(), $this->getInfo('url')), json_last_error()); } if (!\is_array($content)) { - throw new JsonException(sprintf('JSON content was expected to decode to an array, %s returned.', \gettype($content))); + throw new JsonException(sprintf('JSON content was expected to decode to an array, %s returned for "%s".', \gettype($content), $this->getInfo('url'))); } if (null !== $this->content) { diff --git a/Tests/Response/MockResponseTest.php b/Tests/Response/MockResponseTest.php new file mode 100644 index 0000000..61ceb91 --- /dev/null +++ b/Tests/Response/MockResponseTest.php @@ -0,0 +1,68 @@ + 'orange', 'size' => 42]; + $response = new MockResponse(json_encode($data)); + $response = MockResponse::fromRequest('GET', 'https://example.com/file.json', [], $response); + + $this->assertSame($data, $response->toArray()); + } + + /** + * @dataProvider toArrayErrors + */ + public function testToArrayError($content, $responseHeaders, $message) + { + $this->expectException(JsonException::class); + $this->expectExceptionMessage($message); + + $response = new MockResponse($content, ['response_headers' => $responseHeaders]); + $response = MockResponse::fromRequest('GET', 'https://example.com/file.json', [], $response); + $response->toArray(); + } + + public function toArrayErrors() + { + yield [ + 'content' => '{}', + 'responseHeaders' => ['content-type' => 'plain/text'], + 'message' => 'Response content-type is "plain/text" while a JSON-compatible one was expected for "https://example.com/file.json".', + ]; + + yield [ + 'content' => 'not json', + 'responseHeaders' => [], + 'message' => 'Syntax error for "https://example.com/file.json".', + ]; + + yield [ + 'content' => '[1,2}', + 'responseHeaders' => [], + 'message' => 'State mismatch (invalid or malformed JSON) for "https://example.com/file.json".', + ]; + + yield [ + 'content' => '"not an array"', + 'responseHeaders' => [], + 'message' => 'JSON content was expected to decode to an array, string returned for "https://example.com/file.json".', + ]; + + yield [ + 'content' => '8', + 'responseHeaders' => [], + 'message' => 'JSON content was expected to decode to an array, integer returned for "https://example.com/file.json".', + ]; + } +}