1<?php
2namespace GuzzleHttp\Tests\Http;
3
4use GuzzleHttp\Stream\FnStream;
5use GuzzleHttp\Stream\Stream;
6use GuzzleHttp\Stream\LimitStream;
7use GuzzleHttp\Stream\NoSeekStream;
8
9/**
10 * @covers GuzzleHttp\Stream\LimitStream
11 */
12class LimitStreamTest extends \PHPUnit_Framework_TestCase
13{
14    /** @var LimitStream */
15    protected $body;
16
17    /** @var Stream */
18    protected $decorated;
19
20    public function setUp()
21    {
22        $this->decorated = Stream::factory(fopen(__FILE__, 'r'));
23        $this->body = new LimitStream($this->decorated, 10, 3);
24    }
25
26    public function testReturnsSubset()
27    {
28        $body = new LimitStream(Stream::factory('foo'), -1, 1);
29        $this->assertEquals('oo', (string) $body);
30        $this->assertTrue($body->eof());
31        $body->seek(0);
32        $this->assertFalse($body->eof());
33        $this->assertEquals('oo', $body->read(100));
34        $this->assertEmpty($body->read(1));
35        $this->assertTrue($body->eof());
36    }
37
38    public function testReturnsSubsetWhenCastToString()
39    {
40        $body = Stream::factory('foo_baz_bar');
41        $limited = new LimitStream($body, 3, 4);
42        $this->assertEquals('baz', (string) $limited);
43    }
44
45    public function testReturnsSubsetOfEmptyBodyWhenCastToString()
46    {
47        $body = Stream::factory('');
48        $limited = new LimitStream($body, 0, 10);
49        $this->assertEquals('', (string) $limited);
50    }
51
52    public function testSeeksWhenConstructed()
53    {
54        $this->assertEquals(0, $this->body->tell());
55        $this->assertEquals(3, $this->decorated->tell());
56    }
57
58    public function testAllowsBoundedSeek()
59    {
60        $this->assertEquals(true, $this->body->seek(100));
61        $this->assertEquals(10, $this->body->tell());
62        $this->assertEquals(13, $this->decorated->tell());
63        $this->assertEquals(true, $this->body->seek(0));
64        $this->assertEquals(0, $this->body->tell());
65        $this->assertEquals(3, $this->decorated->tell());
66        $this->assertEquals(false, $this->body->seek(-10));
67        $this->assertEquals(0, $this->body->tell());
68        $this->assertEquals(3, $this->decorated->tell());
69        $this->assertEquals(true, $this->body->seek(5));
70        $this->assertEquals(5, $this->body->tell());
71        $this->assertEquals(8, $this->decorated->tell());
72        $this->assertEquals(false, $this->body->seek(1000, SEEK_END));
73    }
74
75    public function testReadsOnlySubsetOfData()
76    {
77        $data = $this->body->read(100);
78        $this->assertEquals(10, strlen($data));
79        $this->assertFalse($this->body->read(1000));
80
81        $this->body->setOffset(10);
82        $newData = $this->body->read(100);
83        $this->assertEquals(10, strlen($newData));
84        $this->assertNotSame($data, $newData);
85    }
86
87    /**
88     * @expectedException \GuzzleHttp\Stream\Exception\SeekException
89     * @expectedExceptionMessage Could not seek the stream to position 2
90     */
91    public function testThrowsWhenCurrentGreaterThanOffsetSeek()
92    {
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