diff --git a/src/Parsers/ResponseParser.php b/src/Parsers/ResponseParser.php index be0e960..0c2ac59 100644 --- a/src/Parsers/ResponseParser.php +++ b/src/Parsers/ResponseParser.php @@ -46,7 +46,25 @@ public function parse(ResponseInterface $response): DocumentInterface private function responseHasBody(ResponseInterface $response): bool { - return (bool) $response->getBody()->getSize(); + $body = $response->getBody(); + $size = $body->getSize(); + + if ($size === 0) { + return false; + } + if (is_int($size) && $size > 0) { + return true; + } + + if ($body->isSeekable()) { + $pos = $body->tell(); + $chunk = $body->read(1); + $body->seek($pos); + } else { + $chunk = $body->read(1); + } + + return $chunk !== ''; } private function responseHasSuccessfulStatusCode(ResponseInterface $response): bool diff --git a/tests/Parsers/ResponseParserTest.php b/tests/Parsers/ResponseParserTest.php index e7e24cb..dc8022f 100644 --- a/tests/Parsers/ResponseParserTest.php +++ b/tests/Parsers/ResponseParserTest.php @@ -4,8 +4,10 @@ namespace Swis\JsonApi\Client\Tests\Parsers; +use GuzzleHttp\Psr7\PumpStream; use GuzzleHttp\Psr7\Response; use PHPUnit\Framework\TestCase; +use Psr\Http\Message\StreamInterface; use Swis\JsonApi\Client\CollectionDocument; use Swis\JsonApi\Client\Document; use Swis\JsonApi\Client\InvalidResponseDocument; @@ -59,6 +61,95 @@ public function it_parses_a_response_with_an_empty_body() $this->assertSame($response, $document->getResponse()); } + /** + * @test + */ + public function it_parses_a_response_with_an_empty_body_and_unknown_size() + { + $documentParser = $this->createMock(DocumentParser::class); + $documentParser->expects($this->never()) + ->method('parse'); + + $parser = new ResponseParser($documentParser); + + $stream = new PumpStream(function () { + return false; + }); + + $response = new Response(204, [], $stream); + + $document = $parser->parse($response); + + $this->assertInstanceOf(Document::class, $document); + $this->assertSame($response, $document->getResponse()); + } + + /** + * @test + */ + public function it_parses_a_response_with_a_body_and_unknown_size() + { + $json = json_encode(['meta' => ['ok' => true]]); + + $stream = new PumpStream(function () use ($json) { + static $done = false; + if ($done) { + return false; + } + $done = true; + + return $json; + }); + + $parsedDocument = new Document; + + $documentParser = $this->createMock(DocumentParser::class); + $documentParser + ->expects($this->once()) + ->method('parse') + ->with($this->isType('string')) + ->willReturn($parsedDocument); + + $parser = new ResponseParser($documentParser); + + $response = new Response(200, [], $stream); + + $document = $parser->parse($response); + + $this->assertSame($parsedDocument, $document); + $this->assertSame($response, $document->getResponse()); + } + + /** + * @test + */ + public function it_parses_a_response_with_a_seekable_stream_and_unknown_size() + { + $stream = $this->createMock(StreamInterface::class); + $stream->method('getSize')->willReturn(-1); + $stream->method('isSeekable')->willReturn(true); + $stream->method('tell')->willReturn(0); + $stream->expects($this->once())->method('read')->with(1)->willReturn('x'); + $stream->expects($this->once())->method('seek')->with(0); + + $parsedDocument = new Document; + + $documentParser = $this->createMock(DocumentParser::class); + $documentParser + ->expects($this->once()) + ->method('parse') + ->with($this->isType('string')) + ->willReturn($parsedDocument); + + $parser = new ResponseParser($documentParser); + $response = new Response(200, [], $stream); + + $document = $parser->parse($response); + + $this->assertSame($parsedDocument, $document); + $this->assertSame($response, $document->getResponse()); + } + /** * @test */