1<?php 2namespace GuzzleHttp\Tests\Http; 3 4use GuzzleHttp\Stream\Exception\SeekException; 5use GuzzleHttp\Stream\FnStream; 6use GuzzleHttp\Stream\Stream; 7use GuzzleHttp\Stream\LimitStream; 8use GuzzleHttp\Stream\NoSeekStream; 9use PHPUnit\Framework\TestCase; 10 11/** 12 * @covers GuzzleHttp\Stream\LimitStream 13 */ 14class LimitStreamTest extends TestCase 15{ 16 /** @var LimitStream */ 17 protected $body; 18 19 /** @var Stream */ 20 protected $decorated; 21 22 public function setUp(): void 23 { 24 $this->decorated = Stream::factory(fopen(__FILE__, 'r')); 25 $this->body = new LimitStream($this->decorated, 10, 3); 26 } 27 28 public function testReturnsSubset() 29 { 30 $body = new LimitStream(Stream::factory('foo'), -1, 1); 31 $this->assertEquals('oo', (string) $body); 32 $this->assertTrue($body->eof()); 33 $body->seek(0); 34 $this->assertFalse($body->eof()); 35 $this->assertEquals('oo', $body->read(100)); 36 $this->assertEmpty($body->read(1)); 37 $this->assertTrue($body->eof()); 38 } 39 40 public function testReturnsSubsetWhenCastToString() 41 { 42 $body = Stream::factory('foo_baz_bar'); 43 $limited = new LimitStream($body, 3, 4); 44 $this->assertEquals('baz', (string) $limited); 45 } 46 47 public function testReturnsSubsetOfEmptyBodyWhenCastToString() 48 { 49 $body = Stream::factory(''); 50 $limited = new LimitStream($body, 0, 10); 51 $this->assertEquals('', (string) $limited); 52 } 53 54 public function testSeeksWhenConstructed() 55 { 56 $this->assertEquals(0, $this->body->tell()); 57 $this->assertEquals(3, $this->decorated->tell()); 58 } 59 60 public function testAllowsBoundedSeek() 61 { 62 $this->assertEquals(true, $this->body->seek(100)); 63 $this->assertEquals(10, $this->body->tell()); 64 $this->assertEquals(13, $this->decorated->tell()); 65 $this->assertEquals(true, $this->body->seek(0)); 66 $this->assertEquals(0, $this->body->tell()); 67 $this->assertEquals(3, $this->decorated->tell()); 68 $this->assertEquals(false, $this->body->seek(-10)); 69 $this->assertEquals(0, $this->body->tell()); 70 $this->assertEquals(3, $this->decorated->tell()); 71 $this->assertEquals(true, $this->body->seek(5)); 72 $this->assertEquals(5, $this->body->tell()); 73 $this->assertEquals(8, $this->decorated->tell()); 74 $this->assertEquals(false, $this->body->seek(1000, SEEK_END)); 75 } 76 77 public function testReadsOnlySubsetOfData() 78 { 79 $data = $this->body->read(100); 80 $this->assertEquals(10, strlen($data)); 81 $this->assertFalse($this->body->read(1000)); 82 83 $this->body->setOffset(10); 84 $newData = $this->body->read(100); 85 $this->assertEquals(10, strlen($newData)); 86 $this->assertNotSame($data, $newData); 87 } 88 89 public function testThrowsWhenCurrentGreaterThanOffsetSeek() 90 { 91 $this->expectException(SeekException::class); 92 $this->expectExceptionMessage('Could not seek the stream to position 2'); 93 $a = Stream::factory('foo_bar'); 94 $b = new NoSeekStream($a); 95 $c = new LimitStream($b); 96 $a->getContents(); 97 $c->setOffset(2); 98 } 99 100 public function testClaimsConsumedWhenReadLimitIsReached() 101 { 102 $this->assertFalse($this->body->eof()); 103 $this->body->read(1000); 104 $this->assertTrue($this->body->eof()); 105 } 106 107 public function testContentLengthIsBounded() 108 { 109 $this->assertEquals(10, $this->body->getSize()); 110 } 111 112 public function testGetContentsIsBasedOnSubset() 113 { 114 $body = new LimitStream(Stream::factory('foobazbar'), 3, 3); 115 $this->assertEquals('baz', $body->getContents()); 116 } 117 118 public function testReturnsNullIfSizeCannotBeDetermined() 119 { 120 $a = new FnStream([ 121 'getSize' => function () { return null; }, 122 'tell' => function () { return 0; }, 123 ]); 124 $b = new LimitStream($a); 125 $this->assertNull($b->getSize()); 126 } 127 128 public function testLengthLessOffsetWhenNoLimitSize() 129 { 130 $a = Stream::factory('foo_bar'); 131 $b = new LimitStream($a, -1, 4); 132 $this->assertEquals(3, $b->getSize()); 133 } 134} 135