Streams throw exceptions instead of returning false.

This commit is contained in:
PJ Dietz 2015-04-26 20:49:59 -04:00
parent dce4bdf572
commit 4f667f1dda
4 changed files with 125 additions and 29 deletions

View File

@ -14,6 +14,10 @@ class NullStream implements StreamInterface
*
* Warning: This could attempt to load a large amount of data into memory.
*
* This method MUST NOT raise an exception in order to conform with PHP's
* string casting operations.
*
* @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
* @return string
*/
public function __toString()
@ -58,7 +62,7 @@ class NullStream implements StreamInterface
*/
public function tell()
{
return false;
return 0;
}
/**
@ -91,27 +95,26 @@ class NullStream implements StreamInterface
* PHP $whence values for `fseek()`. SEEK_SET: Set position equal to
* offset bytes SEEK_CUR: Set position to current location plus offset
* SEEK_END: Set position to end-of-stream plus offset.
* @return bool Returns TRUE on success or FALSE on failure.
* @throws \RuntimeException on failure.
*/
public function seek($offset, $whence = SEEK_SET)
{
return false;
throw new \RuntimeException("Unable to seek to position.");
}
/**
* Seek to the beginning of the stream.
*
* If the stream is not seekable, this method will return FALSE, indicating
* failure; otherwise, it will perform a seek(0), and return the status of
* that operation.
* If the stream is not seekable, this method will raise an exception;
* otherwise, it will perform a seek(0).
*
* @see seek()
* @link http://www.php.net/manual/en/function.fseek.php
* @return bool Returns TRUE on success or FALSE on failure.
* @throws \RuntimeException on failure.
*/
public function rewind()
{
return false;
throw new \RuntimeException("Unable to rewind srream.");
}
/**
@ -128,12 +131,12 @@ class NullStream implements StreamInterface
* Write data to the stream.
*
* @param string $string The string that is to be written.
* @return int|bool Returns the number of bytes written to the stream on
* success or FALSE on failure.
* @return int Returns the number of bytes written to the stream.
* @throws \RuntimeException on failure.
*/
public function write($string)
{
return false;
throw new \RuntimeException("Unable to write to stream.");
}
/**
@ -152,8 +155,9 @@ class NullStream implements StreamInterface
* @param int $length Read up to $length bytes from the object and return
* them. Fewer than $length bytes may be returned if underlying stream
* call returns fewer bytes.
* @return string|false Returns the data read from the stream, false if
* unable to read or if an error occurs.
* @return string Returns the data read from the stream, or an empty string
* if no bytes are available.
* @throws \RuntimeException if an error occurs.
*/
public function read($length)
{
@ -164,6 +168,8 @@ class NullStream implements StreamInterface
* Returns the remaining contents in a string
*
* @return string
* @throws \RuntimeException if unable to read or an error occurs while
* reading.
*/
public function getContents()
{

View File

@ -41,6 +41,10 @@ class Stream implements StreamInterface
*
* Warning: This could attempt to load a large amount of data into memory.
*
* This method MUST NOT raise an exception in order to conform with PHP's
* string casting operations.
*
* @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
* @return string
*/
public function __toString()
@ -87,11 +91,18 @@ class Stream implements StreamInterface
/**
* Returns the current position of the file read/write pointer
*
* @return int|bool Position of the file pointer or false on error.
* @return int Position of the file pointer
* @throws \RuntimeException on error.
*/
public function tell()
{
return ftell($this->resource);
$position = ftell($this->resource);
if ($position === false) {
// @codeCoverageIgnoreStart
throw new \RuntimeException("Unable to retrieve current position of file pointer.");
// @codeCoverageIgnoreEnd
}
return $position;
}
/**
@ -124,11 +135,19 @@ class Stream implements StreamInterface
* PHP $whence values for `fseek()`. SEEK_SET: Set position equal to
* offset bytes SEEK_CUR: Set position to current location plus offset
* SEEK_END: Set position to end-of-stream plus offset.
* @return bool Returns TRUE on success or FALSE on failure.
* @throws \RuntimeException on failure.
*/
public function seek($offset, $whence = SEEK_SET)
{
fseek($this->resource, $offset, $whence);
$result = -1;
if ($this->isSeekable()) {
$result = fseek($this->resource, $offset, $whence);
}
if ($result === -1) {
// @codeCoverageIgnoreStart
throw new \RuntimeException("Unable to seek to position.");
// @codeCoverageIgnoreEnd
}
}
/**
@ -144,7 +163,15 @@ class Stream implements StreamInterface
*/
public function rewind()
{
rewind($this->resource);
$result = false;
if ($this->isSeekable()) {
$result = rewind($this->resource);
}
if ($result === false) {
// @codeCoverageIgnoreStart
throw new \RuntimeException("Unable to seek to position.");
// @codeCoverageIgnoreEnd
}
}
/**
@ -162,12 +189,19 @@ class Stream implements StreamInterface
* Write data to the stream.
*
* @param string $string The string that is to be written.
* @return int|bool Returns the number of bytes written to the stream on
* success or FALSE on failure.
* @return int Returns the number of bytes written to the stream.
* @throws \RuntimeException on failure.
*/
public function write($string)
{
return fwrite($this->resource, $string);
$result = false;
if ($this->isWritable()) {
$result = fwrite($this->resource, $string);
}
if ($result === false) {
throw new \RuntimeException("Unable to write to stream.");
}
return $result;
}
/**
@ -192,17 +226,33 @@ class Stream implements StreamInterface
*/
public function read($length)
{
return fread($this->resource, $length);
$result = false;
if ($this->isReadable()) {
$result = fread($this->resource, $length);
}
if ($result === false) {
throw new \RuntimeException("Unable to read from stream.");
}
return $result;
}
/**
* Returns the remaining contents in a string
*
* @return string
* @throws \RuntimeException if unable to read or an error occurs while
* reading.
*/
public function getContents()
{
return stream_get_contents($this->resource);
$result = false;
if ($this->isReadable()) {
$result = stream_get_contents($this->resource);
}
if ($result === false) {
throw new \RuntimeException("Unable to read from stream.");
}
return $result;
}
/**

View File

@ -20,6 +20,7 @@ class NullStreamTest extends \PHPUnit_Framework_TestCase
$stream = new \WellRESTed\Message\NullStream();
$this->assertNull($stream->close());
}
/**
* @covers WellRESTed\Message\NullStream::detach()
* @uses WellRESTed\Message\Stream
@ -43,10 +44,10 @@ class NullStreamTest extends \PHPUnit_Framework_TestCase
/**
* @covers WellRESTed\Message\NullStream::tell
*/
public function testTellReturnsFalse()
public function testTellReturnsZero()
{
$stream = new \WellRESTed\Message\NullStream();
$this->assertFalse($stream->tell());
$this->assertEquals(0, $stream->tell());
}
/**
@ -70,20 +71,22 @@ class NullStreamTest extends \PHPUnit_Framework_TestCase
/**
* @covers WellRESTed\Message\NullStream::seek
* @expectedException \RuntimeException
*/
public function testSeekReturnsFalse()
{
$stream = new NullStream();
$this->assertFalse($stream->seek(10));
$stream->seek(10);
}
/**
* @covers WellRESTed\Message\NullStream::rewind
* @expectedException \RuntimeException
*/
public function testRewindReturnsFalse()
{
$stream = new \WellRESTed\Message\NullStream();
$this->assertFalse($stream->rewind());
$stream->rewind();
}
/**
@ -97,11 +100,12 @@ class NullStreamTest extends \PHPUnit_Framework_TestCase
/**
* @covers WellRESTed\Message\NullStream::write
* @expectedException \RuntimeException
*/
public function testWriteReturnsFalse()
public function testWriteThrowsException()
{
$stream = new \WellRESTed\Message\NullStream();
$this->assertFalse($stream->write(""));
$stream->write("");
}
/**

View File

@ -172,6 +172,30 @@ class StreamTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($this->content . $message, (string) $stream);
}
/**
* @covers WellRESTed\Message\Stream::write
* @expectedException \RuntimeException
*/
public function testThrowsExceptionOnErrorWriting()
{
$filename = tempnam(sys_get_temp_dir(), "php");
$handle = fopen($filename, "r");
$stream = new \WellRESTed\Message\Stream($handle);
$stream->write("Hello, world!");
}
/**
* @covers WellRESTed\Message\Stream::read
* @expectedException \RuntimeException
*/
public function testThrowsExceptionOnErrorReading()
{
$filename = tempnam(sys_get_temp_dir(), "php");
$handle = fopen($filename, "w");
$stream = new \WellRESTed\Message\Stream($handle);
$stream->read(10);
}
/**
* @covers WellRESTed\Message\Stream::read
*/
@ -183,6 +207,18 @@ class StreamTest extends \PHPUnit_Framework_TestCase
$this->assertEquals("world", $string);
}
/**
* @covers WellRESTed\Message\Stream::getContents
* @expectedException \RuntimeException
*/
public function testThrowsExceptionOnErrorReadingToEnd()
{
$filename = tempnam(sys_get_temp_dir(), "php");
$handle = fopen($filename, "w");
$stream = new \WellRESTed\Message\Stream($handle);
$stream->getContents();
}
/**
* @covers WellRESTed\Message\Stream::getContents
*/