init
This commit is contained in:
10
vendor/react/stream/tests/CallableStub.php
vendored
Executable file
10
vendor/react/stream/tests/CallableStub.php
vendored
Executable file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
class CallableStub
|
||||
{
|
||||
public function __invoke()
|
||||
{
|
||||
}
|
||||
}
|
||||
267
vendor/react/stream/tests/CompositeStreamTest.php
vendored
Executable file
267
vendor/react/stream/tests/CompositeStreamTest.php
vendored
Executable file
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
use React\Stream\CompositeStream;
|
||||
use React\Stream\ThroughStream;
|
||||
|
||||
/**
|
||||
* @covers React\Stream\CompositeStream
|
||||
*/
|
||||
class CompositeStreamTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function itShouldCloseReadableIfNotWritable()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('isReadable')
|
||||
->willReturn(true);
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('close');
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('isWritable')
|
||||
->willReturn(false);
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
|
||||
$composite->on('close', $this->expectCallableNever());
|
||||
$composite->close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldCloseWritableIfNotReadable()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('isReadable')
|
||||
->willReturn(false);
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('close');
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
|
||||
$composite->on('close', $this->expectCallableNever());
|
||||
$composite->close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldForwardWritableCallsToWritableStream()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('isReadable')
|
||||
->willReturn(true);
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('write')
|
||||
->with('foo');
|
||||
$writable
|
||||
->expects($this->exactly(2))
|
||||
->method('isWritable')
|
||||
->willReturn(true);
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
$composite->write('foo');
|
||||
$composite->isWritable();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldForwardReadableCallsToReadableStream()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->exactly(2))
|
||||
->method('isReadable')
|
||||
->willReturn(true);
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('pause');
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('resume');
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->any())
|
||||
->method('isWritable')
|
||||
->willReturn(true);
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
$composite->isReadable();
|
||||
$composite->pause();
|
||||
$composite->resume();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldNotForwardResumeIfStreamIsNotWritable()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('isReadable')
|
||||
->willReturn(true);
|
||||
$readable
|
||||
->expects($this->never())
|
||||
->method('resume');
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->exactly(2))
|
||||
->method('isWritable')
|
||||
->willReturnOnConsecutiveCalls(true, false);
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
$composite->resume();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function endShouldDelegateToWritableWithData()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('isReadable')
|
||||
->willReturn(true);
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('isWritable')
|
||||
->willReturn(true);
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('end')
|
||||
->with('foo');
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
$composite->end('foo');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function closeShouldCloseBothStreams()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('isReadable')
|
||||
->willReturn(true);
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('close');
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('isWritable')
|
||||
->willReturn(true);
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('close');
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
$composite->close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldForwardCloseOnlyOnce()
|
||||
{
|
||||
$readable = new ThroughStream();
|
||||
$writable = new ThroughStream();
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
$composite->on('close', $this->expectCallableOnce());
|
||||
|
||||
$readable->close();
|
||||
$writable->close();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldForwardCloseAndRemoveAllListeners()
|
||||
{
|
||||
$in = new ThroughStream();
|
||||
|
||||
$composite = new CompositeStream($in, $in);
|
||||
$composite->on('close', $this->expectCallableOnce());
|
||||
|
||||
$this->assertTrue($composite->isReadable());
|
||||
$this->assertTrue($composite->isWritable());
|
||||
$this->assertCount(1, $composite->listeners('close'));
|
||||
|
||||
$composite->close();
|
||||
|
||||
$this->assertFalse($composite->isReadable());
|
||||
$this->assertFalse($composite->isWritable());
|
||||
$this->assertCount(0, $composite->listeners('close'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldReceiveForwardedEvents()
|
||||
{
|
||||
$readable = new ThroughStream();
|
||||
$writable = new ThroughStream();
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
$composite->on('data', $this->expectCallableOnce());
|
||||
$composite->on('drain', $this->expectCallableOnce());
|
||||
|
||||
$readable->emit('data', array('foo'));
|
||||
$writable->emit('drain');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldHandlePipingCorrectly()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('isReadable')
|
||||
->willReturn(true);
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable->expects($this->any())->method('isWritable')->willReturn(True);
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('write')
|
||||
->with('foo');
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
|
||||
$input = new ThroughStream();
|
||||
$input->pipe($composite);
|
||||
$input->emit('data', array('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldForwardPipeCallsToReadableStream()
|
||||
{
|
||||
$readable = new ThroughStream();
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable->expects($this->any())->method('isWritable')->willReturn(True);
|
||||
|
||||
$composite = new CompositeStream($readable, $writable);
|
||||
|
||||
$output = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$output->expects($this->any())->method('isWritable')->willReturn(True);
|
||||
$output
|
||||
->expects($this->once())
|
||||
->method('write')
|
||||
->with('foo');
|
||||
|
||||
$composite->pipe($output);
|
||||
$readable->emit('data', array('foo'));
|
||||
}
|
||||
}
|
||||
390
vendor/react/stream/tests/DuplexResourceStreamIntegrationTest.php
vendored
Executable file
390
vendor/react/stream/tests/DuplexResourceStreamIntegrationTest.php
vendored
Executable file
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
use Clue\StreamFilter as Filter;
|
||||
use React\Stream\DuplexResourceStream;
|
||||
use React\Stream\ReadableResourceStream;
|
||||
use React\EventLoop\ExtEventLoop;
|
||||
use React\EventLoop\ExtLibeventLoop;
|
||||
use React\EventLoop\ExtLibevLoop;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\EventLoop\LibEventLoop;
|
||||
use React\EventLoop\LibEvLoop;
|
||||
use React\EventLoop\StreamSelectLoop;
|
||||
|
||||
class DuplexResourceStreamIntegrationTest extends TestCase
|
||||
{
|
||||
public function loopProvider()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
function() {
|
||||
return true;
|
||||
},
|
||||
function () {
|
||||
return new StreamSelectLoop();
|
||||
}
|
||||
),
|
||||
array(
|
||||
function () {
|
||||
return function_exists('event_base_new');
|
||||
},
|
||||
function () {
|
||||
return class_exists('React\EventLoop\ExtLibeventLoop') ? new ExtLibeventLoop() : new LibEventLoop();
|
||||
}
|
||||
),
|
||||
array(
|
||||
function () {
|
||||
return class_exists('libev\EventLoop');
|
||||
},
|
||||
function () {
|
||||
return class_exists('React\EventLoop\ExtLibevLoop') ? new ExtLibevLoop() : new LibEvLoop();
|
||||
}
|
||||
),
|
||||
array(
|
||||
function () {
|
||||
return class_exists('EventBase') && class_exists('React\EventLoop\ExtEventLoop');
|
||||
},
|
||||
function () {
|
||||
return new ExtEventLoop();
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testBufferReadsLargeChunks($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
list($sockA, $sockB) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
|
||||
|
||||
$bufferSize = 4096;
|
||||
$streamA = new DuplexResourceStream($sockA, $loop, $bufferSize);
|
||||
$streamB = new DuplexResourceStream($sockB, $loop, $bufferSize);
|
||||
|
||||
$testString = str_repeat("*", $bufferSize + 1);
|
||||
|
||||
$buffer = "";
|
||||
$streamB->on('data', function ($data) use (&$buffer) {
|
||||
$buffer .= $data;
|
||||
});
|
||||
|
||||
$streamA->write($testString);
|
||||
|
||||
$this->loopTick($loop);
|
||||
$this->loopTick($loop);
|
||||
$this->loopTick($loop);
|
||||
|
||||
$streamA->close();
|
||||
$streamB->close();
|
||||
|
||||
$this->assertEquals($testString, $buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testWriteLargeChunk($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
list($sockA, $sockB) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
|
||||
|
||||
$streamA = new DuplexResourceStream($sockA, $loop);
|
||||
$streamB = new DuplexResourceStream($sockB, $loop);
|
||||
|
||||
// limit seems to be 192 KiB
|
||||
$size = 256 * 1024;
|
||||
|
||||
// sending side sends and expects clean close with no errors
|
||||
$streamA->end(str_repeat('*', $size));
|
||||
$streamA->on('close', $this->expectCallableOnce());
|
||||
$streamA->on('error', $this->expectCallableNever());
|
||||
|
||||
// receiving side counts bytes and expects clean close with no errors
|
||||
$received = 0;
|
||||
$streamB->on('data', function ($chunk) use (&$received) {
|
||||
$received += strlen($chunk);
|
||||
});
|
||||
$streamB->on('close', $this->expectCallableOnce());
|
||||
$streamB->on('error', $this->expectCallableNever());
|
||||
|
||||
$loop->run();
|
||||
|
||||
$streamA->close();
|
||||
$streamB->close();
|
||||
|
||||
$this->assertEquals($size, $received);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testDoesNotEmitDataIfNothingHasBeenWritten($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
list($sockA, $sockB) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
|
||||
|
||||
$streamA = new DuplexResourceStream($sockA, $loop);
|
||||
$streamB = new DuplexResourceStream($sockB, $loop);
|
||||
|
||||
// end streamA without writing any data
|
||||
$streamA->end();
|
||||
|
||||
// streamB should not emit any data
|
||||
$streamB->on('data', $this->expectCallableNever());
|
||||
|
||||
$loop->run();
|
||||
|
||||
$streamA->close();
|
||||
$streamB->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testDoesNotWriteDataIfRemoteSideFromPairHasBeenClosed($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
list($sockA, $sockB) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
|
||||
|
||||
$streamA = new DuplexResourceStream($sockA, $loop);
|
||||
$streamB = new DuplexResourceStream($sockB, $loop);
|
||||
|
||||
// end streamA without writing any data
|
||||
$streamA->pause();
|
||||
$streamA->write('hello');
|
||||
$streamA->on('close', $this->expectCallableOnce());
|
||||
|
||||
$streamB->on('data', $this->expectCallableNever());
|
||||
$streamB->close();
|
||||
|
||||
$loop->run();
|
||||
|
||||
$streamA->close();
|
||||
$streamB->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testDoesNotWriteDataIfServerSideHasBeenClosed($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
$server = stream_socket_server('tcp://127.0.0.1:0');
|
||||
|
||||
$client = stream_socket_client(stream_socket_get_name($server, false));
|
||||
$peer = stream_socket_accept($server);
|
||||
|
||||
$streamA = new DuplexResourceStream($client, $loop);
|
||||
$streamB = new DuplexResourceStream($peer, $loop);
|
||||
|
||||
// end streamA without writing any data
|
||||
$streamA->pause();
|
||||
$streamA->write('hello');
|
||||
$streamA->on('close', $this->expectCallableOnce());
|
||||
|
||||
$streamB->on('data', $this->expectCallableNever());
|
||||
$streamB->close();
|
||||
|
||||
$loop->run();
|
||||
|
||||
$streamA->close();
|
||||
$streamB->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testDoesNotWriteDataIfClientSideHasBeenClosed($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
$server = stream_socket_server('tcp://127.0.0.1:0');
|
||||
|
||||
$client = stream_socket_client(stream_socket_get_name($server, false));
|
||||
$peer = stream_socket_accept($server);
|
||||
|
||||
$streamA = new DuplexResourceStream($peer, $loop);
|
||||
$streamB = new DuplexResourceStream($client, $loop);
|
||||
|
||||
// end streamA without writing any data
|
||||
$streamA->pause();
|
||||
$streamA->write('hello');
|
||||
$streamA->on('close', $this->expectCallableOnce());
|
||||
|
||||
$streamB->on('data', $this->expectCallableNever());
|
||||
$streamB->close();
|
||||
|
||||
$loop->run();
|
||||
|
||||
$streamA->close();
|
||||
$streamB->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testReadsSingleChunkFromProcessPipe($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
$stream = new ReadableResourceStream(popen('echo test', 'r'), $loop);
|
||||
$stream->on('data', $this->expectCallableOnceWith("test\n"));
|
||||
$stream->on('end', $this->expectCallableOnce());
|
||||
$stream->on('error', $this->expectCallableNever());
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testReadsMultipleChunksFromProcessPipe($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
$stream = new ReadableResourceStream(popen('echo a;sleep 0.1;echo b;sleep 0.1;echo c', 'r'), $loop);
|
||||
|
||||
$buffer = '';
|
||||
$stream->on('data', function ($chunk) use (&$buffer) {
|
||||
$buffer .= $chunk;
|
||||
});
|
||||
|
||||
$stream->on('end', $this->expectCallableOnce());
|
||||
$stream->on('error', $this->expectCallableNever());
|
||||
|
||||
$loop->run();
|
||||
|
||||
$this->assertEquals("a\n" . "b\n" . "c\n", $buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testReadsLongChunksFromProcessPipe($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
$stream = new ReadableResourceStream(popen('dd if=/dev/zero bs=12345 count=1234 2>&-', 'r'), $loop);
|
||||
|
||||
$bytes = 0;
|
||||
$stream->on('data', function ($chunk) use (&$bytes) {
|
||||
$bytes += strlen($chunk);
|
||||
});
|
||||
|
||||
$stream->on('end', $this->expectCallableOnce());
|
||||
$stream->on('error', $this->expectCallableNever());
|
||||
|
||||
$loop->run();
|
||||
|
||||
$this->assertEquals(12345 * 1234, $bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testReadsNothingFromProcessPipeWithNoOutput($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
$stream = new ReadableResourceStream(popen('true', 'r'), $loop);
|
||||
$stream->on('data', $this->expectCallableNever());
|
||||
$stream->on('end', $this->expectCallableOnce());
|
||||
$stream->on('error', $this->expectCallableNever());
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::handleData
|
||||
* @dataProvider loopProvider
|
||||
*/
|
||||
public function testEmptyReadShouldntFcloseStream($condition, $loopFactory)
|
||||
{
|
||||
if (true !== $condition()) {
|
||||
return $this->markTestSkipped('Loop implementation not available');
|
||||
}
|
||||
|
||||
$server = stream_socket_server('tcp://127.0.0.1:0');
|
||||
|
||||
$client = stream_socket_client(stream_socket_get_name($server, false));
|
||||
$stream = stream_socket_accept($server);
|
||||
|
||||
|
||||
// add a filter which returns an error when encountering an 'a' when reading
|
||||
Filter\append($stream, function ($chunk) {
|
||||
return '';
|
||||
}, STREAM_FILTER_READ);
|
||||
|
||||
$loop = $loopFactory();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->on('error', $this->expectCallableNever());
|
||||
$conn->on('data', $this->expectCallableNever());
|
||||
$conn->on('end', $this->expectCallableNever());
|
||||
|
||||
fwrite($client, "foobar\n");
|
||||
|
||||
$conn->handleData($stream);
|
||||
|
||||
fclose($stream);
|
||||
fclose($client);
|
||||
fclose($server);
|
||||
}
|
||||
|
||||
private function loopTick(LoopInterface $loop)
|
||||
{
|
||||
$loop->addTimer(0, function () use ($loop) {
|
||||
$loop->stop();
|
||||
});
|
||||
$loop->run();
|
||||
}
|
||||
}
|
||||
495
vendor/react/stream/tests/DuplexResourceStreamTest.php
vendored
Executable file
495
vendor/react/stream/tests/DuplexResourceStreamTest.php
vendored
Executable file
@@ -0,0 +1,495 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
use React\Stream\DuplexResourceStream;
|
||||
use Clue\StreamFilter as Filter;
|
||||
use React\Stream\WritableResourceStream;
|
||||
|
||||
class DuplexResourceStreamTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testConstructor()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new DuplexResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testConstructorWithExcessiveMode()
|
||||
{
|
||||
// excessive flags are ignored for temp streams, so we have to use a file stream
|
||||
$name = tempnam(sys_get_temp_dir(), 'test');
|
||||
$stream = @fopen($name, 'r+eANYTHING');
|
||||
unlink($name);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
$buffer = new DuplexResourceStream($stream, $loop);
|
||||
$buffer->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionOnInvalidStream()
|
||||
{
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new DuplexResourceStream('breakme', $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionOnWriteOnlyStream()
|
||||
{
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$this->markTestSkipped('HHVM does not report fopen mode for STDOUT');
|
||||
}
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new DuplexResourceStream(STDOUT, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionOnWriteOnlyStreamWithExcessiveMode()
|
||||
{
|
||||
// excessive flags are ignored for temp streams, so we have to use a file stream
|
||||
$name = tempnam(sys_get_temp_dir(), 'test');
|
||||
$stream = fopen($name, 'weANYTHING');
|
||||
unlink($name);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
new DuplexResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @expectedException RunTimeException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionIfStreamDoesNotSupportNonBlocking()
|
||||
{
|
||||
if (!in_array('blocking', stream_get_wrappers())) {
|
||||
stream_wrapper_register('blocking', 'React\Tests\Stream\EnforceBlockingWrapper');
|
||||
}
|
||||
|
||||
$stream = fopen('blocking://test', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new DuplexResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testConstructorAcceptsBuffer()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop, null, $buffer);
|
||||
}
|
||||
|
||||
public function testCloseShouldEmitCloseEvent()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->on('close', $this->expectCallableOnce());
|
||||
$conn->on('end', $this->expectCallableNever());
|
||||
|
||||
$conn->close();
|
||||
|
||||
$this->assertFalse($conn->isReadable());
|
||||
}
|
||||
|
||||
public function testEndShouldEndBuffer()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$buffer->expects($this->once())->method('end')->with('foo');
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop, null, $buffer);
|
||||
$conn->end('foo');
|
||||
}
|
||||
|
||||
|
||||
public function testEndAfterCloseIsNoOp()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$buffer->expects($this->never())->method('end');
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->close();
|
||||
$conn->end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @covers React\Stream\DuplexResourceStream::handleData
|
||||
*/
|
||||
public function testDataEvent()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$capturedData = null;
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->on('data', function ($data) use (&$capturedData) {
|
||||
$capturedData = $data;
|
||||
});
|
||||
|
||||
fwrite($stream, "foobar\n");
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
$this->assertSame("foobar\n", $capturedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @covers React\Stream\DuplexResourceStream::handleData
|
||||
*/
|
||||
public function testDataEventDoesEmitOneChunkMatchingBufferSize()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$capturedData = null;
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop, 4321);
|
||||
$conn->on('data', function ($data) use (&$capturedData) {
|
||||
$capturedData = $data;
|
||||
});
|
||||
|
||||
fwrite($stream, str_repeat("a", 100000));
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
|
||||
$this->assertTrue($conn->isReadable());
|
||||
$this->assertEquals(4321, strlen($capturedData));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::__construct
|
||||
* @covers React\Stream\DuplexResourceStream::handleData
|
||||
*/
|
||||
public function testDataEventDoesEmitOneChunkUntilStreamEndsWhenBufferSizeIsInfinite()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$capturedData = null;
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop, -1);
|
||||
|
||||
$conn->on('data', function ($data) use (&$capturedData) {
|
||||
$capturedData = $data;
|
||||
});
|
||||
|
||||
fwrite($stream, str_repeat("a", 100000));
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
|
||||
$this->assertTrue($conn->isReadable());
|
||||
$this->assertEquals(100000, strlen($capturedData));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::handleData
|
||||
*/
|
||||
public function testEmptyStreamShouldNotEmitData()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->on('data', $this->expectCallableNever());
|
||||
|
||||
$conn->handleData($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::write
|
||||
*/
|
||||
public function testWrite()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createWriteableLoopMock();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->write("foo\n");
|
||||
|
||||
rewind($stream);
|
||||
$this->assertSame("foo\n", fgets($stream));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::end
|
||||
* @covers React\Stream\DuplexResourceStream::isReadable
|
||||
* @covers React\Stream\DuplexResourceStream::isWritable
|
||||
*/
|
||||
public function testEnd()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->end();
|
||||
|
||||
$this->assertFalse(is_resource($stream));
|
||||
$this->assertFalse($conn->isReadable());
|
||||
$this->assertFalse($conn->isWritable());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::end
|
||||
*/
|
||||
public function testEndRemovesReadStreamFromLoop()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
$loop->expects($this->once())->method('removeReadStream')->with($stream);
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->end('bye');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::pause
|
||||
*/
|
||||
public function testPauseRemovesReadStreamFromLoop()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
$loop->expects($this->once())->method('removeReadStream')->with($stream);
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->pause();
|
||||
$conn->pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::pause
|
||||
*/
|
||||
public function testResumeDoesAddStreamToLoopOnlyOnce()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->resume();
|
||||
$conn->resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::close
|
||||
*/
|
||||
public function testCloseRemovesReadStreamFromLoop()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
$loop->expects($this->once())->method('removeReadStream')->with($stream);
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::close
|
||||
*/
|
||||
public function testCloseAfterPauseRemovesReadStreamFromLoopOnlyOnce()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
$loop->expects($this->once())->method('removeReadStream')->with($stream);
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->pause();
|
||||
$conn->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::close
|
||||
*/
|
||||
public function testResumeAfterCloseDoesAddReadStreamToLoopOnlyOnce()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->close();
|
||||
$conn->resume();
|
||||
}
|
||||
|
||||
public function testEndedStreamsShouldNotWrite()
|
||||
{
|
||||
$file = tempnam(sys_get_temp_dir(), 'reactphptest_');
|
||||
$stream = fopen($file, 'r+');
|
||||
$loop = $this->createWriteableLoopMock();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->write("foo\n");
|
||||
$conn->end();
|
||||
|
||||
$res = $conn->write("bar\n");
|
||||
$stream = fopen($file, 'r');
|
||||
|
||||
$this->assertSame("foo\n", fgets($stream));
|
||||
$this->assertFalse($res);
|
||||
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
public function testPipeShouldReturnDestination()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$dest = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
|
||||
$this->assertSame($dest, $conn->pipe($dest));
|
||||
}
|
||||
|
||||
public function testBufferEventsShouldBubbleUp()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$conn = new DuplexResourceStream($stream, $loop, null, $buffer);
|
||||
|
||||
$conn->on('drain', $this->expectCallableOnce());
|
||||
$conn->on('error', $this->expectCallableOnce());
|
||||
|
||||
$buffer->emit('drain');
|
||||
$buffer->emit('error', array(new \RuntimeException('Whoops')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::handleData
|
||||
*/
|
||||
public function testClosingStreamInDataEventShouldNotTriggerError()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->on('error', $this->expectCallableNever());
|
||||
$conn->on('data', function ($data) use ($conn) {
|
||||
$conn->close();
|
||||
});
|
||||
|
||||
fwrite($stream, "foobar\n");
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::handleData
|
||||
*/
|
||||
public function testDataFiltered()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
|
||||
// add a filter which removes every 'a' when reading
|
||||
Filter\append($stream, function ($chunk) {
|
||||
return str_replace('a', '', $chunk);
|
||||
}, STREAM_FILTER_READ);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$capturedData = null;
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->on('data', function ($data) use (&$capturedData) {
|
||||
$capturedData = $data;
|
||||
});
|
||||
|
||||
fwrite($stream, "foobar\n");
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
$this->assertSame("foobr\n", $capturedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\DuplexResourceStream::handleData
|
||||
*/
|
||||
public function testDataErrorShouldEmitErrorAndClose()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
|
||||
// add a filter which returns an error when encountering an 'a' when reading
|
||||
Filter\append($stream, function ($chunk) {
|
||||
if (strpos($chunk, 'a') !== false) {
|
||||
throw new \Exception('Invalid');
|
||||
}
|
||||
return $chunk;
|
||||
}, STREAM_FILTER_READ);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new DuplexResourceStream($stream, $loop);
|
||||
$conn->on('data', $this->expectCallableNever());
|
||||
$conn->on('error', $this->expectCallableOnce());
|
||||
$conn->on('close', $this->expectCallableOnce());
|
||||
|
||||
fwrite($stream, "foobar\n");
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
}
|
||||
|
||||
private function createWriteableLoopMock()
|
||||
{
|
||||
$loop = $this->createLoopMock();
|
||||
$loop
|
||||
->expects($this->once())
|
||||
->method('addWriteStream')
|
||||
->will($this->returnCallback(function ($stream, $listener) {
|
||||
call_user_func($listener, $stream);
|
||||
}));
|
||||
|
||||
return $loop;
|
||||
}
|
||||
|
||||
private function createLoopMock()
|
||||
{
|
||||
return $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
}
|
||||
}
|
||||
35
vendor/react/stream/tests/EnforceBlockingWrapper.php
vendored
Executable file
35
vendor/react/stream/tests/EnforceBlockingWrapper.php
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
/**
|
||||
* Used to test dummy stream resources that do not support setting non-blocking mode
|
||||
*
|
||||
* @link http://php.net/manual/de/class.streamwrapper.php
|
||||
*/
|
||||
class EnforceBlockingWrapper
|
||||
{
|
||||
public function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_cast($cast_as)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_eof()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function stream_set_option($option, $arg1, $arg2)
|
||||
{
|
||||
if ($option === STREAM_OPTION_BLOCKING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
122
vendor/react/stream/tests/FunctionalInternetTest.php
vendored
Executable file
122
vendor/react/stream/tests/FunctionalInternetTest.php
vendored
Executable file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
use React\EventLoop\Factory;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Stream\DuplexResourceStream;
|
||||
use React\Stream\WritableResourceStream;
|
||||
|
||||
/**
|
||||
* @group internet
|
||||
*/
|
||||
class FunctionalInternetTest extends TestCase
|
||||
{
|
||||
public function testUploadKilobytePlain()
|
||||
{
|
||||
$size = 1000;
|
||||
$stream = stream_socket_client('tcp://httpbin.org:80');
|
||||
|
||||
$loop = Factory::create();
|
||||
$stream = new DuplexResourceStream($stream, $loop);
|
||||
|
||||
$buffer = '';
|
||||
$stream->on('data', function ($chunk) use (&$buffer) {
|
||||
$buffer .= $chunk;
|
||||
});
|
||||
|
||||
$stream->on('error', $this->expectCallableNever());
|
||||
|
||||
$stream->write("POST /post HTTP/1.0\r\nHost: httpbin.org\r\nContent-Length: $size\r\n\r\n" . str_repeat('.', $size));
|
||||
|
||||
$this->awaitStreamClose($stream, $loop);
|
||||
|
||||
$this->assertNotEquals('', $buffer);
|
||||
}
|
||||
|
||||
public function testUploadBiggerBlockPlain()
|
||||
{
|
||||
$size = 50 * 1000;
|
||||
$stream = stream_socket_client('tcp://httpbin.org:80');
|
||||
|
||||
$loop = Factory::create();
|
||||
$stream = new DuplexResourceStream($stream, $loop);
|
||||
|
||||
$buffer = '';
|
||||
$stream->on('data', function ($chunk) use (&$buffer) {
|
||||
$buffer .= $chunk;
|
||||
});
|
||||
|
||||
$stream->on('error', $this->expectCallableNever());
|
||||
|
||||
$stream->write("POST /post HTTP/1.0\r\nHost: httpbin.org\r\nContent-Length: $size\r\n\r\n" . str_repeat('.', $size));
|
||||
|
||||
$this->awaitStreamClose($stream, $loop);
|
||||
|
||||
$this->assertNotEquals('', $buffer);
|
||||
}
|
||||
|
||||
public function testUploadKilobyteSecure()
|
||||
{
|
||||
$size = 1000;
|
||||
$stream = stream_socket_client('tls://httpbin.org:443');
|
||||
|
||||
$loop = Factory::create();
|
||||
$stream = new DuplexResourceStream($stream, $loop);
|
||||
|
||||
$buffer = '';
|
||||
$stream->on('data', function ($chunk) use (&$buffer) {
|
||||
$buffer .= $chunk;
|
||||
});
|
||||
|
||||
$stream->on('error', $this->expectCallableNever());
|
||||
|
||||
$stream->write("POST /post HTTP/1.0\r\nHost: httpbin.org\r\nContent-Length: $size\r\n\r\n" . str_repeat('.', $size));
|
||||
|
||||
$this->awaitStreamClose($stream, $loop);
|
||||
|
||||
$this->assertNotEquals('', $buffer);
|
||||
}
|
||||
|
||||
public function testUploadBiggerBlockSecureRequiresSmallerChunkSize()
|
||||
{
|
||||
$size = 50 * 1000;
|
||||
$stream = stream_socket_client('tls://httpbin.org:443');
|
||||
|
||||
$loop = Factory::create();
|
||||
$stream = new DuplexResourceStream(
|
||||
$stream,
|
||||
$loop,
|
||||
null,
|
||||
new WritableResourceStream($stream, $loop, null, 8192)
|
||||
);
|
||||
|
||||
$buffer = '';
|
||||
$stream->on('data', function ($chunk) use (&$buffer) {
|
||||
$buffer .= $chunk;
|
||||
});
|
||||
|
||||
$stream->on('error', $this->expectCallableNever());
|
||||
|
||||
$stream->write("POST /post HTTP/1.0\r\nHost: httpbin.org\r\nContent-Length: $size\r\n\r\n" . str_repeat('.', $size));
|
||||
|
||||
$this->awaitStreamClose($stream, $loop);
|
||||
|
||||
$this->assertNotEquals('', $buffer);
|
||||
}
|
||||
|
||||
private function awaitStreamClose(DuplexResourceStream $stream, LoopInterface $loop, $timeout = 10.0)
|
||||
{
|
||||
$stream->on('close', function () use ($loop) {
|
||||
$loop->stop();
|
||||
});
|
||||
|
||||
$that = $this;
|
||||
$loop->addTimer($timeout, function () use ($loop, $that) {
|
||||
$loop->stop();
|
||||
$that->fail('Timed out while waiting for stream to close');
|
||||
});
|
||||
|
||||
$loop->run();
|
||||
}
|
||||
}
|
||||
391
vendor/react/stream/tests/ReadableResourceStreamTest.php
vendored
Executable file
391
vendor/react/stream/tests/ReadableResourceStreamTest.php
vendored
Executable file
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
use React\Stream\ReadableResourceStream;
|
||||
use Clue\StreamFilter as Filter;
|
||||
|
||||
class ReadableResourceStreamTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::__construct
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testConstructor()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new ReadableResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::__construct
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testConstructorWithExcessiveMode()
|
||||
{
|
||||
// excessive flags are ignored for temp streams, so we have to use a file stream
|
||||
$name = tempnam(sys_get_temp_dir(), 'test');
|
||||
$stream = @fopen($name, 'r+eANYTHING');
|
||||
unlink($name);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
$buffer = new ReadableResourceStream($stream, $loop);
|
||||
$buffer->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionOnInvalidStream()
|
||||
{
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new ReadableResourceStream(false, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionOnWriteOnlyStream()
|
||||
{
|
||||
if (defined('HHVM_VERSION')) {
|
||||
$this->markTestSkipped('HHVM does not report fopen mode for STDOUT');
|
||||
}
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new ReadableResourceStream(STDOUT, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionOnWriteOnlyStreamWithExcessiveMode()
|
||||
{
|
||||
// excessive flags are ignored for temp streams, so we have to use a file stream
|
||||
$name = tempnam(sys_get_temp_dir(), 'test');
|
||||
$stream = fopen($name, 'weANYTHING');
|
||||
unlink($name);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
new ReadableResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::__construct
|
||||
* @expectedException RuntimeException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionIfStreamDoesNotSupportNonBlocking()
|
||||
{
|
||||
if (!in_array('blocking', stream_get_wrappers())) {
|
||||
stream_wrapper_register('blocking', 'React\Tests\Stream\EnforceBlockingWrapper');
|
||||
}
|
||||
|
||||
$stream = fopen('blocking://test', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new ReadableResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
|
||||
public function testCloseShouldEmitCloseEvent()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->on('close', $this->expectCallableOnce());
|
||||
|
||||
$conn->close();
|
||||
|
||||
$this->assertFalse($conn->isReadable());
|
||||
}
|
||||
|
||||
public function testCloseTwiceShouldEmitCloseEventOnce()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->on('close', $this->expectCallableOnce());
|
||||
|
||||
$conn->close();
|
||||
$conn->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::__construct
|
||||
* @covers React\Stream\ReadableResourceStream::handleData
|
||||
*/
|
||||
public function testDataEvent()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$capturedData = null;
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->on('data', function ($data) use (&$capturedData) {
|
||||
$capturedData = $data;
|
||||
});
|
||||
|
||||
fwrite($stream, "foobar\n");
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
$this->assertSame("foobar\n", $capturedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::__construct
|
||||
* @covers React\Stream\ReadableResourceStream::handleData
|
||||
*/
|
||||
public function testDataEventDoesEmitOneChunkMatchingBufferSize()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$capturedData = null;
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop, 4321);
|
||||
$conn->on('data', function ($data) use (&$capturedData) {
|
||||
$capturedData = $data;
|
||||
});
|
||||
|
||||
fwrite($stream, str_repeat("a", 100000));
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
|
||||
$this->assertTrue($conn->isReadable());
|
||||
$this->assertEquals(4321, strlen($capturedData));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::__construct
|
||||
* @covers React\Stream\ReadableResourceStream::handleData
|
||||
*/
|
||||
public function testDataEventDoesEmitOneChunkUntilStreamEndsWhenBufferSizeIsInfinite()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$capturedData = null;
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop, -1);
|
||||
|
||||
$conn->on('data', function ($data) use (&$capturedData) {
|
||||
$capturedData = $data;
|
||||
});
|
||||
|
||||
fwrite($stream, str_repeat("a", 100000));
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
|
||||
$this->assertTrue($conn->isReadable());
|
||||
$this->assertEquals(100000, strlen($capturedData));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::handleData
|
||||
*/
|
||||
public function testEmptyStreamShouldNotEmitData()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->on('data', $this->expectCallableNever());
|
||||
|
||||
$conn->handleData($stream);
|
||||
}
|
||||
|
||||
public function testPipeShouldReturnDestination()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$dest = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
|
||||
$this->assertSame($dest, $conn->pipe($dest));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::handleData
|
||||
*/
|
||||
public function testClosingStreamInDataEventShouldNotTriggerError()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->on('error', $this->expectCallableNever());
|
||||
$conn->on('data', function ($data) use ($conn) {
|
||||
$conn->close();
|
||||
});
|
||||
|
||||
fwrite($stream, "foobar\n");
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::pause
|
||||
*/
|
||||
public function testPauseRemovesReadStreamFromLoop()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
$loop->expects($this->once())->method('removeReadStream')->with($stream);
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->pause();
|
||||
$conn->pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::pause
|
||||
*/
|
||||
public function testResumeDoesAddStreamToLoopOnlyOnce()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->resume();
|
||||
$conn->resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::close
|
||||
*/
|
||||
public function testCloseRemovesReadStreamFromLoop()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
$loop->expects($this->once())->method('removeReadStream')->with($stream);
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::close
|
||||
*/
|
||||
public function testCloseAfterPauseRemovesReadStreamFromLoopOnce()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
$loop->expects($this->once())->method('removeReadStream')->with($stream);
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->pause();
|
||||
$conn->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::close
|
||||
*/
|
||||
public function testResumeAfterCloseDoesAddReadStreamToLoopOnlyOnce()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addReadStream')->with($stream);
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->close();
|
||||
$conn->resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::handleData
|
||||
*/
|
||||
public function testDataFiltered()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
|
||||
// add a filter which removes every 'a' when reading
|
||||
Filter\append($stream, function ($chunk) {
|
||||
return str_replace('a', '', $chunk);
|
||||
}, STREAM_FILTER_READ);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$capturedData = null;
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->on('data', function ($data) use (&$capturedData) {
|
||||
$capturedData = $data;
|
||||
});
|
||||
|
||||
fwrite($stream, "foobar\n");
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
$this->assertSame("foobr\n", $capturedData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::handleData
|
||||
*/
|
||||
public function testDataErrorShouldEmitErrorAndClose()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
|
||||
// add a filter which returns an error when encountering an 'a' when reading
|
||||
Filter\append($stream, function ($chunk) {
|
||||
if (strpos($chunk, 'a') !== false) {
|
||||
throw new \Exception('Invalid');
|
||||
}
|
||||
return $chunk;
|
||||
}, STREAM_FILTER_READ);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->on('data', $this->expectCallableNever());
|
||||
$conn->on('error', $this->expectCallableOnce());
|
||||
$conn->on('close', $this->expectCallableOnce());
|
||||
|
||||
fwrite($stream, "foobar\n");
|
||||
rewind($stream);
|
||||
|
||||
$conn->handleData($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ReadableResourceStream::handleData
|
||||
*/
|
||||
public function testEmptyReadShouldntFcloseStream()
|
||||
{
|
||||
list($stream, $_) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$conn = new ReadableResourceStream($stream, $loop);
|
||||
$conn->on('error', $this->expectCallableNever());
|
||||
$conn->on('data', $this->expectCallableNever());
|
||||
$conn->on('end', $this->expectCallableNever());
|
||||
|
||||
$conn->handleData();
|
||||
|
||||
fclose($stream);
|
||||
fclose($_);
|
||||
}
|
||||
|
||||
private function createLoopMock()
|
||||
{
|
||||
return $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
}
|
||||
}
|
||||
61
vendor/react/stream/tests/Stub/ReadableStreamStub.php
vendored
Executable file
61
vendor/react/stream/tests/Stub/ReadableStreamStub.php
vendored
Executable file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream\Stub;
|
||||
|
||||
use Evenement\EventEmitter;
|
||||
use React\Stream\ReadableStreamInterface;
|
||||
use React\Stream\WritableStreamInterface;
|
||||
use React\Stream\Util;
|
||||
|
||||
class ReadableStreamStub extends EventEmitter implements ReadableStreamInterface
|
||||
{
|
||||
public $readable = true;
|
||||
public $paused = false;
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// trigger data event
|
||||
public function write($data)
|
||||
{
|
||||
$this->emit('data', array($data));
|
||||
}
|
||||
|
||||
// trigger error event
|
||||
public function error($error)
|
||||
{
|
||||
$this->emit('error', array($error));
|
||||
}
|
||||
|
||||
// trigger end event
|
||||
public function end()
|
||||
{
|
||||
$this->emit('end', array());
|
||||
}
|
||||
|
||||
public function pause()
|
||||
{
|
||||
$this->paused = true;
|
||||
}
|
||||
|
||||
public function resume()
|
||||
{
|
||||
$this->paused = false;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->readable = false;
|
||||
|
||||
$this->emit('close');
|
||||
}
|
||||
|
||||
public function pipe(WritableStreamInterface $dest, array $options = array())
|
||||
{
|
||||
Util::pipe($this, $dest, $options);
|
||||
|
||||
return $dest;
|
||||
}
|
||||
}
|
||||
54
vendor/react/stream/tests/TestCase.php
vendored
Executable file
54
vendor/react/stream/tests/TestCase.php
vendored
Executable file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
use PHPUnit\Framework\TestCase as BaseTestCase;
|
||||
|
||||
class TestCase extends BaseTestCase
|
||||
{
|
||||
protected function expectCallableExactly($amount)
|
||||
{
|
||||
$mock = $this->createCallableMock();
|
||||
$mock
|
||||
->expects($this->exactly($amount))
|
||||
->method('__invoke');
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
protected function expectCallableOnce()
|
||||
{
|
||||
$mock = $this->createCallableMock();
|
||||
$mock
|
||||
->expects($this->once())
|
||||
->method('__invoke');
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
protected function expectCallableOnceWith($value)
|
||||
{
|
||||
$callback = $this->createCallableMock();
|
||||
$callback
|
||||
->expects($this->once())
|
||||
->method('__invoke')
|
||||
->with($value);
|
||||
|
||||
return $callback;
|
||||
}
|
||||
|
||||
protected function expectCallableNever()
|
||||
{
|
||||
$mock = $this->createCallableMock();
|
||||
$mock
|
||||
->expects($this->never())
|
||||
->method('__invoke');
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
protected function createCallableMock()
|
||||
{
|
||||
return $this->getMockBuilder('React\Tests\Stream\CallableStub')->getMock();
|
||||
}
|
||||
}
|
||||
267
vendor/react/stream/tests/ThroughStreamTest.php
vendored
Executable file
267
vendor/react/stream/tests/ThroughStreamTest.php
vendored
Executable file
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
use React\Stream\ThroughStream;
|
||||
|
||||
/**
|
||||
* @covers React\Stream\ThroughStream
|
||||
*/
|
||||
class ThroughStreamTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function itShouldRejectInvalidCallback()
|
||||
{
|
||||
new ThroughStream(123);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldReturnTrueForAnyDataWrittenToIt()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$ret = $through->write('foo');
|
||||
|
||||
$this->assertTrue($ret);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldEmitAnyDataWrittenToIt()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->on('data', $this->expectCallableOnceWith('foo'));
|
||||
$through->write('foo');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldEmitAnyDataWrittenToItPassedThruFunction()
|
||||
{
|
||||
$through = new ThroughStream('strtoupper');
|
||||
$through->on('data', $this->expectCallableOnceWith('FOO'));
|
||||
$through->write('foo');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldEmitAnyDataWrittenToItPassedThruCallback()
|
||||
{
|
||||
$through = new ThroughStream('strtoupper');
|
||||
$through->on('data', $this->expectCallableOnceWith('FOO'));
|
||||
$through->write('foo');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldEmitErrorAndCloseIfCallbackThrowsException()
|
||||
{
|
||||
$through = new ThroughStream(function () {
|
||||
throw new \RuntimeException();
|
||||
});
|
||||
$through->on('error', $this->expectCallableOnce());
|
||||
$through->on('close', $this->expectCallableOnce());
|
||||
$through->on('data', $this->expectCallableNever());
|
||||
$through->on('end', $this->expectCallableNever());
|
||||
|
||||
$through->write('foo');
|
||||
|
||||
$this->assertFalse($through->isReadable());
|
||||
$this->assertFalse($through->isWritable());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldEmitErrorAndCloseIfCallbackThrowsExceptionOnEnd()
|
||||
{
|
||||
$through = new ThroughStream(function () {
|
||||
throw new \RuntimeException();
|
||||
});
|
||||
$through->on('error', $this->expectCallableOnce());
|
||||
$through->on('close', $this->expectCallableOnce());
|
||||
$through->on('data', $this->expectCallableNever());
|
||||
$through->on('end', $this->expectCallableNever());
|
||||
|
||||
$through->end('foo');
|
||||
|
||||
$this->assertFalse($through->isReadable());
|
||||
$this->assertFalse($through->isWritable());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldReturnFalseForAnyDataWrittenToItWhenPaused()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->pause();
|
||||
$ret = $through->write('foo');
|
||||
|
||||
$this->assertFalse($ret);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldEmitDrainOnResumeAfterReturnFalseForAnyDataWrittenToItWhenPaused()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->pause();
|
||||
$through->write('foo');
|
||||
|
||||
$through->on('drain', $this->expectCallableOnce());
|
||||
$through->resume();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldReturnTrueForAnyDataWrittenToItWhenResumedAfterPause()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->on('drain', $this->expectCallableNever());
|
||||
$through->pause();
|
||||
$through->resume();
|
||||
$ret = $through->write('foo');
|
||||
|
||||
$this->assertTrue($ret);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function pipingStuffIntoItShouldWork()
|
||||
{
|
||||
$readable = new ThroughStream();
|
||||
|
||||
$through = new ThroughStream();
|
||||
$through->on('data', $this->expectCallableOnceWith('foo'));
|
||||
|
||||
$readable->pipe($through);
|
||||
$readable->emit('data', array('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function endShouldEmitEndAndClose()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->on('data', $this->expectCallableNever());
|
||||
$through->on('end', $this->expectCallableOnce());
|
||||
$through->on('close', $this->expectCallableOnce());
|
||||
$through->end();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function endShouldCloseTheStream()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->on('data', $this->expectCallableNever());
|
||||
$through->end();
|
||||
|
||||
$this->assertFalse($through->isReadable());
|
||||
$this->assertFalse($through->isWritable());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function endShouldWriteDataBeforeClosing()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->on('data', $this->expectCallableOnceWith('foo'));
|
||||
$through->end('foo');
|
||||
|
||||
$this->assertFalse($through->isReadable());
|
||||
$this->assertFalse($through->isWritable());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function endTwiceShouldOnlyEmitOnce()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->on('data', $this->expectCallableOnce('first'));
|
||||
$through->end('first');
|
||||
$through->end('ignored');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function writeAfterEndShouldReturnFalse()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->on('data', $this->expectCallableNever());
|
||||
$through->end();
|
||||
|
||||
$this->assertFalse($through->write('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function writeDataWillCloseStreamShouldReturnFalse()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->on('data', array($through, 'close'));
|
||||
|
||||
$this->assertFalse($through->write('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function writeDataToPausedShouldReturnFalse()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->pause();
|
||||
|
||||
$this->assertFalse($through->write('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function writeDataToResumedShouldReturnTrue()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$through->pause();
|
||||
$through->resume();
|
||||
|
||||
$this->assertTrue($through->write('foo'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldBeReadableByDefault()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$this->assertTrue($through->isReadable());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function itShouldBeWritableByDefault()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
$this->assertTrue($through->isWritable());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function closeShouldCloseOnce()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
|
||||
$through->on('close', $this->expectCallableOnce());
|
||||
|
||||
$through->close();
|
||||
|
||||
$this->assertFalse($through->isReadable());
|
||||
$this->assertFalse($through->isWritable());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function doubleCloseShouldCloseOnce()
|
||||
{
|
||||
$through = new ThroughStream();
|
||||
|
||||
$through->on('close', $this->expectCallableOnce());
|
||||
|
||||
$through->close();
|
||||
$through->close();
|
||||
|
||||
$this->assertFalse($through->isReadable());
|
||||
$this->assertFalse($through->isWritable());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function pipeShouldPipeCorrectly()
|
||||
{
|
||||
$output = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$output->expects($this->any())->method('isWritable')->willReturn(True);
|
||||
$output
|
||||
->expects($this->once())
|
||||
->method('write')
|
||||
->with('foo');
|
||||
|
||||
$through = new ThroughStream();
|
||||
$through->pipe($output);
|
||||
$through->write('foo');
|
||||
}
|
||||
}
|
||||
273
vendor/react/stream/tests/UtilTest.php
vendored
Executable file
273
vendor/react/stream/tests/UtilTest.php
vendored
Executable file
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
use React\Stream\WritableResourceStream;
|
||||
use React\Stream\Util;
|
||||
use React\Stream\CompositeStream;
|
||||
use React\Stream\ThroughStream;
|
||||
|
||||
/**
|
||||
* @covers React\Stream\Util
|
||||
*/
|
||||
class UtilTest extends TestCase
|
||||
{
|
||||
public function testPipeReturnsDestinationStream()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
|
||||
$ret = Util::pipe($readable, $writable);
|
||||
|
||||
$this->assertSame($writable, $ret);
|
||||
}
|
||||
|
||||
public function testPipeNonReadableSourceShouldDoNothing()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->any())
|
||||
->method('isReadable')
|
||||
->willReturn(false);
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->never())
|
||||
->method('isWritable');
|
||||
$writable
|
||||
->expects($this->never())
|
||||
->method('end');
|
||||
|
||||
Util::pipe($readable, $writable);
|
||||
}
|
||||
|
||||
public function testPipeIntoNonWritableDestinationShouldPauseSource()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->any())
|
||||
->method('isReadable')
|
||||
->willReturn(true);
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('pause');
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->any())
|
||||
->method('isWritable')
|
||||
->willReturn(false);
|
||||
$writable
|
||||
->expects($this->never())
|
||||
->method('end');
|
||||
|
||||
Util::pipe($readable, $writable);
|
||||
}
|
||||
|
||||
public function testPipeClosingDestPausesSource()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable
|
||||
->expects($this->any())
|
||||
->method('isReadable')
|
||||
->willReturn(true);
|
||||
$readable
|
||||
->expects($this->once())
|
||||
->method('pause');
|
||||
|
||||
$writable = new ThroughStream();
|
||||
|
||||
Util::pipe($readable, $writable);
|
||||
|
||||
$writable->close();
|
||||
}
|
||||
|
||||
public function testPipeWithEnd()
|
||||
{
|
||||
$readable = new Stub\ReadableStreamStub();
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->any())
|
||||
->method('isWritable')
|
||||
->willReturn(true);
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('end');
|
||||
|
||||
Util::pipe($readable, $writable);
|
||||
|
||||
$readable->end();
|
||||
}
|
||||
|
||||
public function testPipeWithoutEnd()
|
||||
{
|
||||
$readable = new Stub\ReadableStreamStub();
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->any())
|
||||
->method('isWritable')
|
||||
->willReturn(true);
|
||||
$writable
|
||||
->expects($this->never())
|
||||
->method('end');
|
||||
|
||||
Util::pipe($readable, $writable, array('end' => false));
|
||||
|
||||
$readable->end();
|
||||
}
|
||||
|
||||
public function testPipeWithTooSlowWritableShouldPauseReadable()
|
||||
{
|
||||
$readable = new Stub\ReadableStreamStub();
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->any())
|
||||
->method('isWritable')
|
||||
->willReturn(true);
|
||||
$writable
|
||||
->expects($this->once())
|
||||
->method('write')
|
||||
->with('some data')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$readable->pipe($writable);
|
||||
|
||||
$this->assertFalse($readable->paused);
|
||||
$readable->write('some data');
|
||||
$this->assertTrue($readable->paused);
|
||||
}
|
||||
|
||||
public function testPipeWithTooSlowWritableShouldResumeOnDrain()
|
||||
{
|
||||
$readable = new Stub\ReadableStreamStub();
|
||||
|
||||
$onDrain = null;
|
||||
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable
|
||||
->expects($this->any())
|
||||
->method('isWritable')
|
||||
->willReturn(true);
|
||||
$writable
|
||||
->expects($this->any())
|
||||
->method('on')
|
||||
->will($this->returnCallback(function ($name, $callback) use (&$onDrain) {
|
||||
if ($name === 'drain') {
|
||||
$onDrain = $callback;
|
||||
}
|
||||
}));
|
||||
|
||||
$readable->pipe($writable);
|
||||
$readable->pause();
|
||||
|
||||
$this->assertTrue($readable->paused);
|
||||
$this->assertNotNull($onDrain);
|
||||
$onDrain();
|
||||
$this->assertFalse($readable->paused);
|
||||
}
|
||||
|
||||
public function testPipeWithWritableResourceStream()
|
||||
{
|
||||
$readable = new Stub\ReadableStreamStub();
|
||||
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
|
||||
$readable->pipe($buffer);
|
||||
|
||||
$readable->write('hello, I am some ');
|
||||
$readable->write('random data');
|
||||
|
||||
$buffer->handleWrite();
|
||||
rewind($stream);
|
||||
$this->assertSame('hello, I am some random data', stream_get_contents($stream));
|
||||
}
|
||||
|
||||
public function testPipeSetsUpListeners()
|
||||
{
|
||||
$source = new ThroughStream();
|
||||
$dest = new ThroughStream();
|
||||
|
||||
$this->assertCount(0, $source->listeners('data'));
|
||||
$this->assertCount(0, $source->listeners('end'));
|
||||
$this->assertCount(0, $dest->listeners('drain'));
|
||||
|
||||
Util::pipe($source, $dest);
|
||||
|
||||
$this->assertCount(1, $source->listeners('data'));
|
||||
$this->assertCount(1, $source->listeners('end'));
|
||||
$this->assertCount(1, $dest->listeners('drain'));
|
||||
}
|
||||
|
||||
public function testPipeClosingSourceRemovesListeners()
|
||||
{
|
||||
$source = new ThroughStream();
|
||||
$dest = new ThroughStream();
|
||||
|
||||
Util::pipe($source, $dest);
|
||||
|
||||
$source->close();
|
||||
|
||||
$this->assertCount(0, $source->listeners('data'));
|
||||
$this->assertCount(0, $source->listeners('end'));
|
||||
$this->assertCount(0, $dest->listeners('drain'));
|
||||
}
|
||||
|
||||
public function testPipeClosingDestRemovesListeners()
|
||||
{
|
||||
$source = new ThroughStream();
|
||||
$dest = new ThroughStream();
|
||||
|
||||
Util::pipe($source, $dest);
|
||||
|
||||
$dest->close();
|
||||
|
||||
$this->assertCount(0, $source->listeners('data'));
|
||||
$this->assertCount(0, $source->listeners('end'));
|
||||
$this->assertCount(0, $dest->listeners('drain'));
|
||||
}
|
||||
|
||||
public function testPipeDuplexIntoSelfEndsOnEnd()
|
||||
{
|
||||
$readable = $this->getMockBuilder('React\Stream\ReadableStreamInterface')->getMock();
|
||||
$readable->expects($this->any())->method('isReadable')->willReturn(true);
|
||||
$writable = $this->getMockBuilder('React\Stream\WritableStreamInterface')->getMock();
|
||||
$writable->expects($this->any())->method('isWritable')->willReturn(true);
|
||||
$duplex = new CompositeStream($readable, $writable);
|
||||
|
||||
Util::pipe($duplex, $duplex);
|
||||
|
||||
$writable->expects($this->once())->method('end');
|
||||
|
||||
$duplex->emit('end');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function forwardEventsShouldSetupForwards()
|
||||
{
|
||||
$source = new ThroughStream();
|
||||
$target = new ThroughStream();
|
||||
|
||||
Util::forwardEvents($source, $target, array('data'));
|
||||
$target->on('data', $this->expectCallableOnce());
|
||||
$target->on('foo', $this->expectCallableNever());
|
||||
|
||||
$source->emit('data', array('hello'));
|
||||
$source->emit('foo', array('bar'));
|
||||
}
|
||||
|
||||
private function createLoopMock()
|
||||
{
|
||||
return $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
}
|
||||
|
||||
private function notEqualTo($value)
|
||||
{
|
||||
return new \PHPUnit_Framework_Constraint_Not($value);
|
||||
}
|
||||
}
|
||||
534
vendor/react/stream/tests/WritableStreamResourceTest.php
vendored
Executable file
534
vendor/react/stream/tests/WritableStreamResourceTest.php
vendored
Executable file
@@ -0,0 +1,534 @@
|
||||
<?php
|
||||
|
||||
namespace React\Tests\Stream;
|
||||
|
||||
use Clue\StreamFilter as Filter;
|
||||
use React\Stream\WritableResourceStream;
|
||||
|
||||
class WritableResourceStreamTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::__construct
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testConstructor()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new WritableResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::__construct
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testConstructorWithExcessiveMode()
|
||||
{
|
||||
// excessive flags are ignored for temp streams, so we have to use a file stream
|
||||
$name = tempnam(sys_get_temp_dir(), 'test');
|
||||
$stream = @fopen($name, 'w+eANYTHING');
|
||||
unlink($name);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$buffer->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsIfNotAValidStreamResource()
|
||||
{
|
||||
$stream = null;
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new WritableResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionOnReadOnlyStream()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new WritableResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::__construct
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionOnReadOnlyStreamWithExcessiveMode()
|
||||
{
|
||||
// excessive flags are ignored for temp streams, so we have to use a file stream
|
||||
$name = tempnam(sys_get_temp_dir(), 'test');
|
||||
$stream = fopen($name, 'reANYTHING');
|
||||
unlink($name);
|
||||
|
||||
$loop = $this->createLoopMock();
|
||||
new WritableResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::__construct
|
||||
* @expectedException RuntimeException
|
||||
*/
|
||||
public function testConstructorThrowsExceptionIfStreamDoesNotSupportNonBlocking()
|
||||
{
|
||||
if (!in_array('blocking', stream_get_wrappers())) {
|
||||
stream_wrapper_register('blocking', 'React\Tests\Stream\EnforceBlockingWrapper');
|
||||
}
|
||||
|
||||
$stream = fopen('blocking://test', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
new WritableResourceStream($stream, $loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testWrite()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createWriteableLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$buffer->on('error', $this->expectCallableNever());
|
||||
|
||||
$buffer->write("foobar\n");
|
||||
rewind($stream);
|
||||
$this->assertSame("foobar\n", fread($stream, 1024));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
*/
|
||||
public function testWriteWithDataDoesAddResourceToLoop()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('addWriteStream')->with($this->equalTo($stream));
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
|
||||
$buffer->write("foobar\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testEmptyWriteDoesNotAddToLoop()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->never())->method('addWriteStream');
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
|
||||
$buffer->write("");
|
||||
$buffer->write(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testWriteReturnsFalseWhenWritableResourceStreamIsFull()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createWriteableLoopMock();
|
||||
$loop->preventWrites = true;
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop, 4);
|
||||
$buffer->on('error', $this->expectCallableNever());
|
||||
|
||||
$this->assertTrue($buffer->write("foo"));
|
||||
$loop->preventWrites = false;
|
||||
$this->assertFalse($buffer->write("bar\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
*/
|
||||
public function testWriteReturnsFalseWhenWritableResourceStreamIsExactlyFull()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop, 3);
|
||||
|
||||
$this->assertFalse($buffer->write("foo"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testWriteDetectsWhenOtherSideIsClosed()
|
||||
{
|
||||
list($a, $b) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
|
||||
|
||||
$loop = $this->createWriteableLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($a, $loop, 4);
|
||||
$buffer->on('error', $this->expectCallableOnce());
|
||||
|
||||
fclose($b);
|
||||
|
||||
$buffer->write("foo");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testEmitsDrainAfterWriteWhichExceedsBuffer()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop, 2);
|
||||
$buffer->on('error', $this->expectCallableNever());
|
||||
$buffer->on('drain', $this->expectCallableOnce());
|
||||
|
||||
$buffer->write("foo");
|
||||
$buffer->handleWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testWriteInDrain()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop, 2);
|
||||
$buffer->on('error', $this->expectCallableNever());
|
||||
|
||||
$buffer->once('drain', function () use ($buffer) {
|
||||
$buffer->write("bar\n");
|
||||
$buffer->handleWrite();
|
||||
});
|
||||
|
||||
$this->assertFalse($buffer->write("foo\n"));
|
||||
$buffer->handleWrite();
|
||||
|
||||
fseek($stream, 0);
|
||||
$this->assertSame("foo\nbar\n", stream_get_contents($stream));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testDrainAfterWrite()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop, 2);
|
||||
|
||||
$buffer->on('drain', $this->expectCallableOnce());
|
||||
|
||||
$buffer->write("foo");
|
||||
$buffer->handleWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testDrainAfterWriteWillRemoveResourceFromLoopWithoutClosing()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('removeWriteStream')->with($stream);
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop, 2);
|
||||
|
||||
$buffer->on('drain', $this->expectCallableOnce());
|
||||
|
||||
$buffer->on('close', $this->expectCallableNever());
|
||||
|
||||
$buffer->write("foo");
|
||||
$buffer->handleWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testClosingDuringDrainAfterWriteWillRemoveResourceFromLoopOnceAndClose()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->expects($this->once())->method('removeWriteStream')->with($stream);
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop, 2);
|
||||
|
||||
$buffer->on('drain', function () use ($buffer) {
|
||||
$buffer->close();
|
||||
});
|
||||
|
||||
$buffer->on('close', $this->expectCallableOnce());
|
||||
|
||||
$buffer->write("foo");
|
||||
$buffer->handleWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::end
|
||||
*/
|
||||
public function testEndWithoutDataClosesImmediatelyIfWritableResourceStreamIsEmpty()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$buffer->on('error', $this->expectCallableNever());
|
||||
$buffer->on('close', $this->expectCallableOnce());
|
||||
|
||||
$this->assertTrue($buffer->isWritable());
|
||||
$buffer->end();
|
||||
$this->assertFalse($buffer->isWritable());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::end
|
||||
*/
|
||||
public function testEndWithoutDataDoesNotCloseIfWritableResourceStreamIsFull()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$buffer->on('error', $this->expectCallableNever());
|
||||
$buffer->on('close', $this->expectCallableNever());
|
||||
|
||||
$buffer->write('foo');
|
||||
|
||||
$this->assertTrue($buffer->isWritable());
|
||||
$buffer->end();
|
||||
$this->assertFalse($buffer->isWritable());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::end
|
||||
*/
|
||||
public function testEndWithDataClosesImmediatelyIfWritableResourceStreamFlushes()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$filterBuffer = '';
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$buffer->on('error', $this->expectCallableNever());
|
||||
$buffer->on('close', $this->expectCallableOnce());
|
||||
|
||||
Filter\append($stream, function ($chunk) use (&$filterBuffer) {
|
||||
$filterBuffer .= $chunk;
|
||||
return $chunk;
|
||||
});
|
||||
|
||||
$this->assertTrue($buffer->isWritable());
|
||||
$buffer->end('final words');
|
||||
$this->assertFalse($buffer->isWritable());
|
||||
|
||||
$buffer->handleWrite();
|
||||
$this->assertSame('final words', $filterBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::end
|
||||
*/
|
||||
public function testEndWithDataDoesNotCloseImmediatelyIfWritableResourceStreamIsFull()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$buffer->on('error', $this->expectCallableNever());
|
||||
$buffer->on('close', $this->expectCallableNever());
|
||||
|
||||
$buffer->write('foo');
|
||||
|
||||
$this->assertTrue($buffer->isWritable());
|
||||
$buffer->end('final words');
|
||||
$this->assertFalse($buffer->isWritable());
|
||||
|
||||
rewind($stream);
|
||||
$this->assertSame('', stream_get_contents($stream));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::isWritable
|
||||
* @covers React\Stream\WritableResourceStream::close
|
||||
*/
|
||||
public function testClose()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$buffer->on('error', $this->expectCallableNever());
|
||||
$buffer->on('close', $this->expectCallableOnce());
|
||||
|
||||
$this->assertTrue($buffer->isWritable());
|
||||
$buffer->close();
|
||||
$this->assertFalse($buffer->isWritable());
|
||||
|
||||
$this->assertEquals(array(), $buffer->listeners('close'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::close
|
||||
*/
|
||||
public function testClosingAfterWriteRemovesStreamFromLoop()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
|
||||
$loop->expects($this->once())->method('removeWriteStream')->with($stream);
|
||||
|
||||
$buffer->write('foo');
|
||||
$buffer->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::close
|
||||
*/
|
||||
public function testClosingWithoutWritingDoesNotRemoveStreamFromLoop()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
|
||||
$loop->expects($this->never())->method('removeWriteStream');
|
||||
|
||||
$buffer->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::close
|
||||
*/
|
||||
public function testDoubleCloseWillEmitOnlyOnce()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$buffer->on('close', $this->expectCallableOnce());
|
||||
|
||||
$buffer->close();
|
||||
$buffer->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::write
|
||||
* @covers React\Stream\WritableResourceStream::close
|
||||
*/
|
||||
public function testWritingToClosedWritableResourceStreamShouldNotWriteToStream()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$filterBuffer = '';
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
|
||||
Filter\append($stream, function ($chunk) use (&$filterBuffer) {
|
||||
$filterBuffer .= $chunk;
|
||||
return $chunk;
|
||||
});
|
||||
|
||||
$buffer->close();
|
||||
|
||||
$buffer->write('foo');
|
||||
|
||||
$buffer->handleWrite();
|
||||
$this->assertSame('', $filterBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers React\Stream\WritableResourceStream::handleWrite
|
||||
*/
|
||||
public function testErrorWhenStreamResourceIsInvalid()
|
||||
{
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
$loop = $this->createWriteableLoopMock();
|
||||
|
||||
$error = null;
|
||||
|
||||
$buffer = new WritableResourceStream($stream, $loop);
|
||||
$buffer->on('error', function ($message) use (&$error) {
|
||||
$error = $message;
|
||||
});
|
||||
|
||||
// invalidate stream resource
|
||||
fclose($stream);
|
||||
|
||||
$buffer->write('Attempting to write to bad stream');
|
||||
|
||||
$this->assertInstanceOf('Exception', $error);
|
||||
|
||||
// the error messages differ between PHP versions, let's just check substrings
|
||||
$this->assertContains('Unable to write to stream: ', $error->getMessage());
|
||||
$this->assertContains(' not a valid stream resource', $error->getMessage(), '', true);
|
||||
}
|
||||
|
||||
public function testWritingToClosedStream()
|
||||
{
|
||||
if ('Darwin' === PHP_OS) {
|
||||
$this->markTestSkipped('OS X issue with shutting down pair for writing');
|
||||
}
|
||||
|
||||
list($a, $b) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
|
||||
$loop = $this->createLoopMock();
|
||||
|
||||
$error = null;
|
||||
|
||||
$buffer = new WritableResourceStream($a, $loop);
|
||||
$buffer->on('error', function($message) use (&$error) {
|
||||
$error = $message;
|
||||
});
|
||||
|
||||
$buffer->write('foo');
|
||||
$buffer->handleWrite();
|
||||
stream_socket_shutdown($b, STREAM_SHUT_RD);
|
||||
stream_socket_shutdown($a, STREAM_SHUT_RD);
|
||||
$buffer->write('bar');
|
||||
$buffer->handleWrite();
|
||||
|
||||
$this->assertInstanceOf('Exception', $error);
|
||||
$this->assertSame('Unable to write to stream: fwrite(): send of 3 bytes failed with errno=32 Broken pipe', $error->getMessage());
|
||||
}
|
||||
|
||||
private function createWriteableLoopMock()
|
||||
{
|
||||
$loop = $this->createLoopMock();
|
||||
$loop->preventWrites = false;
|
||||
$loop
|
||||
->expects($this->any())
|
||||
->method('addWriteStream')
|
||||
->will($this->returnCallback(function ($stream, $listener) use ($loop) {
|
||||
if (!$loop->preventWrites) {
|
||||
call_user_func($listener, $stream);
|
||||
}
|
||||
}));
|
||||
|
||||
return $loop;
|
||||
}
|
||||
|
||||
private function createLoopMock()
|
||||
{
|
||||
return $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user