You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

370 lines
10 KiB

<?php
namespace GuzzleHttp\Tests\Psr7;
use GuzzleHttp\Psr7\NoSeekStream;
use GuzzleHttp\Psr7\Stream;
/**
* @covers GuzzleHttp\Psr7\Stream
*/
class StreamTest extends BaseTest
{
public static $isFReadError = false;
/**
* @expectedException \InvalidArgumentException
*/
public function testConstructorThrowsExceptionOnInvalidArgument()
{
new Stream(true);
}
public function testConstructorInitializesProperties()
{
$handle = fopen('php://temp', 'r+');
fwrite($handle, 'data');
$stream = new Stream($handle);
$this->assertTrue($stream->isReadable());
$this->assertTrue($stream->isWritable());
$this->assertTrue($stream->isSeekable());
$this->assertEquals('php://temp', $stream->getMetadata('uri'));
$this->assertInternalType('array', $stream->getMetadata());
$this->assertEquals(4, $stream->getSize());
$this->assertFalse($stream->eof());
$stream->close();
}
public function testConstructorInitializesPropertiesWithRbPlus()
{
$handle = fopen('php://temp', 'rb+');
fwrite($handle, 'data');
$stream = new Stream($handle);
$this->assertTrue($stream->isReadable());
$this->assertTrue($stream->isWritable());
$this->assertTrue($stream->isSeekable());
$this->assertEquals('php://temp', $stream->getMetadata('uri'));
$this->assertInternalType('array', $stream->getMetadata());
$this->assertEquals(4, $stream->getSize());
$this->assertFalse($stream->eof());
$stream->close();
}
public function testStreamClosesHandleOnDestruct()
{
$handle = fopen('php://temp', 'r');
$stream = new Stream($handle);
unset($stream);
$this->assertFalse(is_resource($handle));
}
public function testConvertsToString()
{
$handle = fopen('php://temp', 'w+');
fwrite($handle, 'data');
$stream = new Stream($handle);
$this->assertEquals('data', (string) $stream);
$this->assertEquals('data', (string) $stream);
$stream->close();
}
public function testGetsContents()
{
$handle = fopen('php://temp', 'w+');
fwrite($handle, 'data');
$stream = new Stream($handle);
$this->assertEquals('', $stream->getContents());
$stream->seek(0);
$this->assertEquals('data', $stream->getContents());
$this->assertEquals('', $stream->getContents());
$stream->close();
}
public function testChecksEof()
{
$handle = fopen('php://temp', 'w+');
fwrite($handle, 'data');
$stream = new Stream($handle);
$this->assertSame(4, $stream->tell(), 'Stream cursor already at the end');
$this->assertFalse($stream->eof(), 'Stream still not eof');
$this->assertSame('', $stream->read(1), 'Need to read one more byte to reach eof');
$this->assertTrue($stream->eof());
$stream->close();
}
public function testGetSize()
{
$size = filesize(__FILE__);
$handle = fopen(__FILE__, 'r');
$stream = new Stream($handle);
$this->assertEquals($size, $stream->getSize());
// Load from cache
$this->assertEquals($size, $stream->getSize());
$stream->close();
}
public function testEnsuresSizeIsConsistent()
{
$h = fopen('php://temp', 'w+');
$this->assertEquals(3, fwrite($h, 'foo'));
$stream = new Stream($h);
$this->assertEquals(3, $stream->getSize());
$this->assertEquals(4, $stream->write('test'));
$this->assertEquals(7, $stream->getSize());
$this->assertEquals(7, $stream->getSize());
$stream->close();
}
public function testProvidesStreamPosition()
{
$handle = fopen('php://temp', 'w+');
$stream = new Stream($handle);
$this->assertEquals(0, $stream->tell());
$stream->write('foo');
$this->assertEquals(3, $stream->tell());
$stream->seek(1);
$this->assertEquals(1, $stream->tell());
$this->assertSame(ftell($handle), $stream->tell());
$stream->close();
}
public function testDetachStreamAndClearProperties()
{
$handle = fopen('php://temp', 'r');
$stream = new Stream($handle);
$this->assertSame($handle, $stream->detach());
$this->assertInternalType('resource', $handle, 'Stream is not closed');
$this->assertNull($stream->detach());
$this->assertStreamStateAfterClosedOrDetached($stream);
$stream->close();
}
public function testCloseResourceAndClearProperties()
{
$handle = fopen('php://temp', 'r');
$stream = new Stream($handle);
$stream->close();
$this->assertFalse(is_resource($handle));
$this->assertStreamStateAfterClosedOrDetached($stream);
}
private function assertStreamStateAfterClosedOrDetached(Stream $stream)
{
$this->assertFalse($stream->isReadable());
$this->assertFalse($stream->isWritable());
$this->assertFalse($stream->isSeekable());
$this->assertNull($stream->getSize());
$this->assertSame([], $stream->getMetadata());
$this->assertNull($stream->getMetadata('foo'));
$throws = function (callable $fn) {
try {
$fn();
} catch (\Exception $e) {
$this->assertContains('Stream is detached', $e->getMessage());
return;
}
$this->fail('Exception should be thrown after the stream is detached.');
};
$throws(function () use ($stream) { $stream->read(10); });
$throws(function () use ($stream) { $stream->write('bar'); });
$throws(function () use ($stream) { $stream->seek(10); });
$throws(function () use ($stream) { $stream->tell(); });
$throws(function () use ($stream) { $stream->eof(); });
$throws(function () use ($stream) { $stream->getContents(); });
$this->assertSame('', (string) $stream);
}
public function testStreamReadingWithZeroLength()
{
$r = fopen('php://temp', 'r');
$stream = new Stream($r);
$this->assertSame('', $stream->read(0));
$stream->close();
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Length parameter cannot be negative
*/
public function testStreamReadingWithNegativeLength()
{
$r = fopen('php://temp', 'r');
$stream = new Stream($r);
try {
$stream->read(-1);
} catch (\Exception $e) {
$stream->close();
throw $e;
}
$stream->close();
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Unable to read from stream
*/
public function testStreamReadingFreadError()
{
self::$isFReadError = true;
$r = fopen('php://temp', 'r');
$stream = new Stream($r);
try {
$stream->read(1);
} catch (\Exception $e) {
self::$isFReadError = false;
$stream->close();
throw $e;
}
self::$isFReadError = false;
$stream->close();
}
/**
* @dataProvider gzipModeProvider
*
* @param string $mode
* @param bool $readable
* @param bool $writable
*/
public function testGzipStreamModes($mode, $readable, $writable)
{
if (defined('HHVM_VERSION')) {
$this->markTestSkipped('This does not work on HHVM.');
}
$r = gzopen('php://temp', $mode);
$stream = new Stream($r);
$this->assertSame($readable, $stream->isReadable());
$this->assertSame($writable, $stream->isWritable());
$stream->close();
}
public function gzipModeProvider()
{
return [
['mode' => 'rb9', 'readable' => true, 'writable' => false],
['mode' => 'wb2', 'readable' => false, 'writable' => true],
];
}
/**
* @dataProvider readableModeProvider
*
* @param string $mode
*/
public function testReadableStream($mode)
{
$r = fopen('php://temp', $mode);
$stream = new Stream($r);
$this->assertTrue($stream->isReadable());
$stream->close();
}
public function readableModeProvider()
{
return [
['r'],
['w+'],
['r+'],
['x+'],
['c+'],
['rb'],
['w+b'],
['r+b'],
['x+b'],
['c+b'],
['rt'],
['w+t'],
['r+t'],
['x+t'],
['c+t'],
['a+'],
['rb+'],
];
}
public function testWriteOnlyStreamIsNotReadable()
{
$r = fopen('php://output', 'w');
$stream = new Stream($r);
$this->assertFalse($stream->isReadable());
$stream->close();
}
/**
* @dataProvider writableModeProvider
*
* @param string $mode
*/
public function testWritableStream($mode)
{
$r = fopen('php://temp', $mode);
$stream = new Stream($r);
$this->assertTrue($stream->isWritable());
$stream->close();
}
public function writableModeProvider()
{
return [
['w'],
['w+'],
['rw'],
['r+'],
['x+'],
['c+'],
['wb'],
['w+b'],
['r+b'],
['rb+'],
['x+b'],
['c+b'],
['w+t'],
['r+t'],
['x+t'],
['c+t'],
['a'],
['a+'],
];
}
public function testReadOnlyStreamIsNotWritable()
{
$r = fopen('php://input', 'r');
$stream = new Stream($r);
$this->assertFalse($stream->isWritable());
$stream->close();
}
}
namespace GuzzleHttp\Psr7;
use GuzzleHttp\Tests\Psr7\StreamTest;
function fread($handle, $length)
{
return StreamTest::$isFReadError ? false : \fread($handle, $length);
}