1<?php
2namespace GuzzleHttp\Tests\Stream;
3
4use BadMethodCallException;
5use GuzzleHttp\Stream\Exception\CannotAttachException;
6use GuzzleHttp\Stream\StreamInterface;
7use GuzzleHttp\Stream\Stream;
8use GuzzleHttp\Stream\StreamDecoratorTrait;
9use PHPUnit\Framework\TestCase;
10use UnexpectedValueException;
11
12class Str implements StreamInterface
13{
14    use StreamDecoratorTrait;
15}
16
17/**
18 * @covers GuzzleHttp\Stream\StreamDecoratorTrait
19 */
20class StreamDecoratorTraitTest extends TestCase
21{
22    private $a;
23    private $b;
24    private $c;
25
26    public function setUp(): void
27    {
28        $this->c = fopen('php://temp', 'r+');
29        fwrite($this->c, 'foo');
30        fseek($this->c, 0);
31        $this->a = Stream::factory($this->c);
32        $this->b = new Str($this->a);
33    }
34
35    public function testCatchesExceptionsWhenCastingToString()
36    {
37        $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface')
38            ->getMockForAbstractClass();
39        $s->expects($this->once())
40            ->method('read')
41            ->will($this->throwException(new \Exception('foo')));
42        $msg = '';
43        set_error_handler(function ($errNo, $str) use (&$msg) { $msg = $str; });
44        echo new Str($s);
45        restore_error_handler();
46        $this->assertStringContainsString('foo', $msg);
47    }
48
49    public function testToString()
50    {
51        $this->assertEquals('foo', (string) $this->b);
52    }
53
54    public function testHasSize()
55    {
56        $this->assertEquals(3, $this->b->getSize());
57        $this->assertSame($this->b, $this->b->setSize(2));
58        $this->assertEquals(2, $this->b->getSize());
59    }
60
61    public function testReads()
62    {
63        $this->assertEquals('foo', $this->b->read(10));
64    }
65
66    public function testCheckMethods()
67    {
68        $this->assertEquals($this->a->isReadable(), $this->b->isReadable());
69        $this->assertEquals($this->a->isWritable(), $this->b->isWritable());
70        $this->assertEquals($this->a->isSeekable(), $this->b->isSeekable());
71    }
72
73    public function testSeeksAndTells()
74    {
75        $this->assertTrue($this->b->seek(1));
76        $this->assertEquals(1, $this->a->tell());
77        $this->assertEquals(1, $this->b->tell());
78        $this->assertTrue($this->b->seek(0));
79        $this->assertEquals(0, $this->a->tell());
80        $this->assertEquals(0, $this->b->tell());
81        $this->assertTrue($this->b->seek(0, SEEK_END));
82        $this->assertEquals(3, $this->a->tell());
83        $this->assertEquals(3, $this->b->tell());
84    }
85
86    public function testGetsContents()
87    {
88        $this->assertEquals('foo', $this->b->getContents());
89        $this->assertEquals('', $this->b->getContents());
90        $this->b->seek(1);
91        $this->assertEquals('oo', $this->b->getContents(1));
92    }
93
94    public function testCloses()
95    {
96        $this->b->close();
97        $this->assertFalse(is_resource($this->c));
98    }
99
100    public function testDetaches()
101    {
102        $this->b->detach();
103        $this->assertFalse($this->b->isReadable());
104    }
105
106    public function testCannotAttachByDefault()
107    {
108        $this->expectException(CannotAttachException::class);
109        $this->b->attach('a');
110    }
111
112    public function testWrapsMetadata()
113    {
114        $this->assertSame($this->b->getMetadata(), $this->a->getMetadata());
115        $this->assertSame($this->b->getMetadata('uri'), $this->a->getMetadata('uri'));
116    }
117
118    public function testWrapsWrites()
119    {
120        $this->b->seek(0, SEEK_END);
121        $this->b->write('foo');
122        $this->assertEquals('foofoo', (string) $this->a);
123    }
124
125    public function testThrowsWithInvalidGetter()
126    {
127        $this->expectException(UnexpectedValueException::class);
128        $this->b->foo;
129    }
130
131    public function testThrowsWhenGetterNotImplemented()
132    {
133        $this->expectException(BadMethodCallException::class);
134        $s = new BadStream();
135        $s->stream;
136    }
137}
138
139class BadStream
140{
141    use StreamDecoratorTrait;
142
143    public function __construct() {}
144}
145