1<?php
2namespace GuzzleHttp\Tests\Stream;
3
4use GuzzleHttp\Stream\Exception\SeekException;
5use GuzzleHttp\Stream\FnStream;
6use GuzzleHttp\Stream\NoSeekStream;
7use GuzzleHttp\Stream\Stream;
8use GuzzleHttp\Stream\Utils;
9use PHPUnit\Framework\TestCase;
10use RuntimeException;
11
12class UtilsTest extends TestCase
13{
14    public function testCopiesToString()
15    {
16        $s = Stream::factory('foobaz');
17        $this->assertEquals('foobaz', Utils::copyToString($s));
18        $s->seek(0);
19        $this->assertEquals('foo', Utils::copyToString($s, 3));
20        $this->assertEquals('baz', Utils::copyToString($s, 3));
21        $this->assertEquals('', Utils::copyToString($s));
22    }
23
24    public function testCopiesToStringStopsWhenReadFails()
25    {
26        $s1 = Stream::factory('foobaz');
27        $s1 = FnStream::decorate($s1, [
28            'read' => function () {
29                return false;
30            }
31        ]);
32        $result = Utils::copyToString($s1);
33        $this->assertEquals('', $result);
34    }
35
36    public function testCopiesToStream()
37    {
38        $s1 = Stream::factory('foobaz');
39        $s2 = Stream::factory('');
40        Utils::copyToStream($s1, $s2);
41        $this->assertEquals('foobaz', (string) $s2);
42        $s2 = Stream::factory('');
43        $s1->seek(0);
44        Utils::copyToStream($s1, $s2, 3);
45        $this->assertEquals('foo', (string) $s2);
46        Utils::copyToStream($s1, $s2, 3);
47        $this->assertEquals('foobaz', (string) $s2);
48    }
49
50    public function testStopsCopyToStreamWhenWriteFails()
51    {
52        $s1 = Stream::factory('foobaz');
53        $s2 = Stream::factory('');
54        $s2 = FnStream::decorate($s2, ['write' => function () { return 0; }]);
55        Utils::copyToStream($s1, $s2);
56        $this->assertEquals('', (string) $s2);
57    }
58
59    public function testStopsCopyToSteamWhenWriteFailsWithMaxLen()
60    {
61        $s1 = Stream::factory('foobaz');
62        $s2 = Stream::factory('');
63        $s2 = FnStream::decorate($s2, ['write' => function () { return 0; }]);
64        Utils::copyToStream($s1, $s2, 10);
65        $this->assertEquals('', (string) $s2);
66    }
67
68    public function testStopsCopyToSteamWhenReadFailsWithMaxLen()
69    {
70        $s1 = Stream::factory('foobaz');
71        $s1 = FnStream::decorate($s1, ['read' => function () { return ''; }]);
72        $s2 = Stream::factory('');
73        Utils::copyToStream($s1, $s2, 10);
74        $this->assertEquals('', (string) $s2);
75    }
76
77    public function testReadsLines()
78    {
79        $s = Stream::factory("foo" . PHP_EOL . "baz" . PHP_EOL . "bar");
80        $this->assertEquals("foo" . PHP_EOL, Utils::readline($s));
81        $this->assertEquals("baz" . PHP_EOL, Utils::readline($s));
82        $this->assertEquals("bar", Utils::readline($s));
83    }
84
85    public function testReadsLinesUpToMaxLength()
86    {
87        $s = Stream::factory("12345" . PHP_EOL);
88        $this->assertEquals("123", Utils::readline($s, 3));
89        $this->assertEquals("45" . PHP_EOL, Utils::readline($s));
90    }
91
92    public function testReadsLinesWithCustomEol()
93    {
94        $s = Stream::factory("foo\tbaz\t\tbar");
95        $this->assertEquals("foo\tbaz\t\t", Utils::readline($s, null, "\t\t"));
96        $this->assertEquals("bar", Utils::readline($s));
97    }
98
99    public function testReadsLineUntilFalseReturnedFromRead()
100    {
101        $s = $this->getMockBuilder('GuzzleHttp\Stream\Stream')
102            ->setMethods(['read', 'eof'])
103            ->disableOriginalConstructor()
104            ->getMock();
105        $s->expects($this->exactly(2))
106            ->method('read')
107            ->will($this->returnCallback(function () {
108                static $c = false;
109                if ($c) {
110                    return false;
111                }
112                $c = true;
113                return 'h';
114            }));
115        $s->expects($this->exactly(2))
116            ->method('eof')
117            ->will($this->returnValue(false));
118        $this->assertEquals("h", Utils::readline($s));
119    }
120
121    public function testCalculatesHash()
122    {
123        $s = Stream::factory('foobazbar');
124        $this->assertEquals(md5('foobazbar'), Utils::hash($s, 'md5'));
125    }
126
127    public function testCalculatesHashThrowsWhenSeekFails()
128    {
129        $this->expectException(SeekException::class);
130        $s = new NoSeekStream(Stream::factory('foobazbar'));
131        $s->read(2);
132        Utils::hash($s, 'md5');
133    }
134
135    public function testCalculatesHashSeeksToOriginalPosition()
136    {
137        $s = Stream::factory('foobazbar');
138        $s->seek(4);
139        $this->assertEquals(md5('foobazbar'), Utils::hash($s, 'md5'));
140        $this->assertEquals(4, $s->tell());
141    }
142
143    public function testOpensFilesSuccessfully()
144    {
145        $r = Utils::open(__FILE__, 'r');
146        $this->assertIsResource($r);
147        fclose($r);
148    }
149
150    public function testThrowsExceptionNotWarning()
151    {
152        $this->expectException(RuntimeException::class);
153        $this->expectErrorMessage('Unable to open /path/to/does/not/exist using mode r');
154        Utils::open('/path/to/does/not/exist', 'r');
155    }
156
157    public function testProxiesToFactory()
158    {
159        $this->assertEquals('foo', (string) Utils::create('foo'));
160    }
161}
162