StreamTest.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <?php
  2. namespace GuzzleHttp\Tests\Psr7;
  3. use GuzzleHttp\Psr7\NoSeekStream;
  4. use GuzzleHttp\Psr7\Stream;
  5. /**
  6. * @covers GuzzleHttp\Psr7\Stream
  7. */
  8. class StreamTest extends BaseTest
  9. {
  10. public static $isFReadError = false;
  11. /**
  12. * @expectedException \InvalidArgumentException
  13. */
  14. public function testConstructorThrowsExceptionOnInvalidArgument()
  15. {
  16. new Stream(true);
  17. }
  18. public function testConstructorInitializesProperties()
  19. {
  20. $handle = fopen('php://temp', 'r+');
  21. fwrite($handle, 'data');
  22. $stream = new Stream($handle);
  23. $this->assertTrue($stream->isReadable());
  24. $this->assertTrue($stream->isWritable());
  25. $this->assertTrue($stream->isSeekable());
  26. $this->assertEquals('php://temp', $stream->getMetadata('uri'));
  27. $this->assertInternalType('array', $stream->getMetadata());
  28. $this->assertEquals(4, $stream->getSize());
  29. $this->assertFalse($stream->eof());
  30. $stream->close();
  31. }
  32. public function testConstructorInitializesPropertiesWithRbPlus()
  33. {
  34. $handle = fopen('php://temp', 'rb+');
  35. fwrite($handle, 'data');
  36. $stream = new Stream($handle);
  37. $this->assertTrue($stream->isReadable());
  38. $this->assertTrue($stream->isWritable());
  39. $this->assertTrue($stream->isSeekable());
  40. $this->assertEquals('php://temp', $stream->getMetadata('uri'));
  41. $this->assertInternalType('array', $stream->getMetadata());
  42. $this->assertEquals(4, $stream->getSize());
  43. $this->assertFalse($stream->eof());
  44. $stream->close();
  45. }
  46. public function testStreamClosesHandleOnDestruct()
  47. {
  48. $handle = fopen('php://temp', 'r');
  49. $stream = new Stream($handle);
  50. unset($stream);
  51. $this->assertFalse(is_resource($handle));
  52. }
  53. public function testConvertsToString()
  54. {
  55. $handle = fopen('php://temp', 'w+');
  56. fwrite($handle, 'data');
  57. $stream = new Stream($handle);
  58. $this->assertEquals('data', (string) $stream);
  59. $this->assertEquals('data', (string) $stream);
  60. $stream->close();
  61. }
  62. public function testGetsContents()
  63. {
  64. $handle = fopen('php://temp', 'w+');
  65. fwrite($handle, 'data');
  66. $stream = new Stream($handle);
  67. $this->assertEquals('', $stream->getContents());
  68. $stream->seek(0);
  69. $this->assertEquals('data', $stream->getContents());
  70. $this->assertEquals('', $stream->getContents());
  71. $stream->close();
  72. }
  73. public function testChecksEof()
  74. {
  75. $handle = fopen('php://temp', 'w+');
  76. fwrite($handle, 'data');
  77. $stream = new Stream($handle);
  78. $this->assertSame(4, $stream->tell(), 'Stream cursor already at the end');
  79. $this->assertFalse($stream->eof(), 'Stream still not eof');
  80. $this->assertSame('', $stream->read(1), 'Need to read one more byte to reach eof');
  81. $this->assertTrue($stream->eof());
  82. $stream->close();
  83. }
  84. public function testGetSize()
  85. {
  86. $size = filesize(__FILE__);
  87. $handle = fopen(__FILE__, 'r');
  88. $stream = new Stream($handle);
  89. $this->assertEquals($size, $stream->getSize());
  90. // Load from cache
  91. $this->assertEquals($size, $stream->getSize());
  92. $stream->close();
  93. }
  94. public function testEnsuresSizeIsConsistent()
  95. {
  96. $h = fopen('php://temp', 'w+');
  97. $this->assertEquals(3, fwrite($h, 'foo'));
  98. $stream = new Stream($h);
  99. $this->assertEquals(3, $stream->getSize());
  100. $this->assertEquals(4, $stream->write('test'));
  101. $this->assertEquals(7, $stream->getSize());
  102. $this->assertEquals(7, $stream->getSize());
  103. $stream->close();
  104. }
  105. public function testProvidesStreamPosition()
  106. {
  107. $handle = fopen('php://temp', 'w+');
  108. $stream = new Stream($handle);
  109. $this->assertEquals(0, $stream->tell());
  110. $stream->write('foo');
  111. $this->assertEquals(3, $stream->tell());
  112. $stream->seek(1);
  113. $this->assertEquals(1, $stream->tell());
  114. $this->assertSame(ftell($handle), $stream->tell());
  115. $stream->close();
  116. }
  117. public function testDetachStreamAndClearProperties()
  118. {
  119. $handle = fopen('php://temp', 'r');
  120. $stream = new Stream($handle);
  121. $this->assertSame($handle, $stream->detach());
  122. $this->assertInternalType('resource', $handle, 'Stream is not closed');
  123. $this->assertNull($stream->detach());
  124. $this->assertStreamStateAfterClosedOrDetached($stream);
  125. $stream->close();
  126. }
  127. public function testCloseResourceAndClearProperties()
  128. {
  129. $handle = fopen('php://temp', 'r');
  130. $stream = new Stream($handle);
  131. $stream->close();
  132. $this->assertFalse(is_resource($handle));
  133. $this->assertStreamStateAfterClosedOrDetached($stream);
  134. }
  135. private function assertStreamStateAfterClosedOrDetached(Stream $stream)
  136. {
  137. $this->assertFalse($stream->isReadable());
  138. $this->assertFalse($stream->isWritable());
  139. $this->assertFalse($stream->isSeekable());
  140. $this->assertNull($stream->getSize());
  141. $this->assertSame([], $stream->getMetadata());
  142. $this->assertNull($stream->getMetadata('foo'));
  143. $throws = function (callable $fn) {
  144. try {
  145. $fn();
  146. } catch (\Exception $e) {
  147. $this->assertContains('Stream is detached', $e->getMessage());
  148. return;
  149. }
  150. $this->fail('Exception should be thrown after the stream is detached.');
  151. };
  152. $throws(function () use ($stream) { $stream->read(10); });
  153. $throws(function () use ($stream) { $stream->write('bar'); });
  154. $throws(function () use ($stream) { $stream->seek(10); });
  155. $throws(function () use ($stream) { $stream->tell(); });
  156. $throws(function () use ($stream) { $stream->eof(); });
  157. $throws(function () use ($stream) { $stream->getContents(); });
  158. $this->assertSame('', (string) $stream);
  159. }
  160. public function testStreamReadingWithZeroLength()
  161. {
  162. $r = fopen('php://temp', 'r');
  163. $stream = new Stream($r);
  164. $this->assertSame('', $stream->read(0));
  165. $stream->close();
  166. }
  167. /**
  168. * @expectedException \RuntimeException
  169. * @expectedExceptionMessage Length parameter cannot be negative
  170. */
  171. public function testStreamReadingWithNegativeLength()
  172. {
  173. $r = fopen('php://temp', 'r');
  174. $stream = new Stream($r);
  175. try {
  176. $stream->read(-1);
  177. } catch (\Exception $e) {
  178. $stream->close();
  179. throw $e;
  180. }
  181. $stream->close();
  182. }
  183. /**
  184. * @expectedException \RuntimeException
  185. * @expectedExceptionMessage Unable to read from stream
  186. */
  187. public function testStreamReadingFreadError()
  188. {
  189. self::$isFReadError = true;
  190. $r = fopen('php://temp', 'r');
  191. $stream = new Stream($r);
  192. try {
  193. $stream->read(1);
  194. } catch (\Exception $e) {
  195. self::$isFReadError = false;
  196. $stream->close();
  197. throw $e;
  198. }
  199. self::$isFReadError = false;
  200. $stream->close();
  201. }
  202. }
  203. namespace GuzzleHttp\Psr7;
  204. use GuzzleHttp\Tests\Psr7\StreamTest;
  205. function fread($handle, $length)
  206. {
  207. return StreamTest::$isFReadError ? false : \fread($handle, $length);
  208. }