aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Enderlin <ivan.enderlin@hoa-project.net>2016-06-15 13:38:09 +0200
committerIvan Enderlin <ivan.enderlin@hoa-project.net>2016-06-17 17:04:44 +0200
commit45f8fd3e82668f671dc13e00f13ae36ca5baf8bc (patch)
tree176f8ede34d99fb1a284667d935221d4303e5e11
parent866dba25862b1aea27cff322b9294b156ffc6b48 (diff)
downloadWebsocket-45f8fd3e82668f671dc13e00f13ae36ca5baf8bc.zip
Websocket-45f8fd3e82668f671dc13e00f13ae36ca5baf8bc.tar.gz
Websocket-45f8fd3e82668f671dc13e00f13ae36ca5baf8bc.tar.bz2
Test: Write test suite of `…Websocket\Connection`.
-rw-r--r--Test/Unit/Connection.php1236
1 files changed, 1235 insertions, 1 deletions
diff --git a/Test/Unit/Connection.php b/Test/Unit/Connection.php
index d8c64e3..0d687be 100644
--- a/Test/Unit/Connection.php
+++ b/Test/Unit/Connection.php
@@ -36,8 +36,11 @@
namespace Hoa\Webocket\Test\Unit;
+use Hoa\Event;
+use Hoa\Socket;
use Hoa\Test;
-use Hoa\Websocket\Connection as SUT;
+use Hoa\Websocket;
+use Mock\Hoa\Websocket\Connection as SUT;
/**
* Class \Hoa\Websocket\Test\Unit\Connection.
@@ -96,4 +99,1235 @@ class Connection extends Test\Unit\Suite
->integer(SUT::CLOSE_TLS)
->isEqualTo(1015);
}
+
+ public function case_constructor()
+ {
+ $this
+ ->given($socket = new Socket\Client('tcp://*:1234'))
+ ->when($result = new SUT($socket))
+ ->then
+ ->object($result->getConnection())
+ ->isIdenticalTo($socket)
+ ->string($socket->getNodeName())
+ ->isEqualTo(Websocket\Node::class)
+ ->let($listener = $this->invoke($result)->getListener())
+ ->object($listener)
+ ->isInstanceOf(Event\Listener::class)
+ ->boolean($listener->listenerExists('open'))
+ ->isTrue()
+ ->boolean($listener->listenerExists('message'))
+ ->isTrue()
+ ->boolean($listener->listenerExists('binary-message'))
+ ->isTrue()
+ ->boolean($listener->listenerExists('ping'))
+ ->isTrue()
+ ->boolean($listener->listenerExists('close'))
+ ->isTrue()
+ ->boolean($listener->listenerExists('error'))
+ ->isTrue();
+ }
+
+ public function case_run_do_handshake()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+
+ $connection->on(
+ 'open',
+ function (Event\Bucket $bucket) use (&$calledA, $self) {
+ $calledA = true;
+
+ $self
+ ->variable($bucket->getData())
+ ->isNull();
+
+ return;
+ }
+ ),
+
+ $this->calling($node)->getHandshake = FAILED,
+ $this->calling($connection)->doHandshake = function () use (&$calledB) {
+ $calledB = true;
+
+ return;
+ }
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->boolean($calledA)
+ ->isTrue()
+ ->boolean($calledB)
+ ->isTrue();
+ }
+
+ public function case_run_cannot_read_the_frame()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation(new Websocket\Protocol\Rfc6455($socket)),
+
+ $this->calling($socket)->read[1] =
+ chr(
+ (0x1 << 7)
+ | (0x1 << 6)
+ | (0x0 << 5)
+ | (0x0 << 4)
+ | Websocket\Connection::OPCODE_TEXT_FRAME
+ ),
+ $this->calling($socket)->read[2] =
+ chr(
+ (0x1 << 7)
+ | 42
+ ),
+ $this->calling($socket)->getCurrentNode = $node,
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$called, $self) {
+ $called = true;
+
+ $self
+ ->integer($_code)
+ ->isEqualTo(SUT::CLOSE_PROTOCOL_ERROR)
+ ->string($_reason)
+ ->isNotEmpty();
+
+ return;
+ }
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->boolean($called)
+ ->isTrue();
+ }
+
+ public function case_run_client_messages_must_be_masked()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Server('tcp://*:1234'),
+ $connection = new \Mock\Hoa\Websocket\Server($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_TEXT_FRAME,
+ 'mask' => 0x0,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ],
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$called, $self) {
+ $called = true;
+
+ $self
+ ->integer($_code)
+ ->isEqualTo(SUT::CLOSE_MESSAGE_ERROR)
+ ->string($_reason)
+ ->isEqualTo('All messages from the client must be masked.');
+
+ return;
+ }
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->boolean($called)
+ ->isTrue();
+ }
+
+ public function case_run_ping_opcode()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_PING,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ],
+ $this->calling($protocol)->writeFrame = function ($_message, $_opcode, $_mask) use (&$calledA, $self) {
+ $calledA = true;
+
+ $self
+ ->string($_message)
+ ->isEqualTo('foobar')
+ ->integer($_opcode)
+ ->isEqualTo(SUT::OPCODE_PONG)
+ ->boolean($_mask)
+ ->isTrue();
+
+ return;
+ },
+
+ $connection->on(
+ 'ping',
+ function (Event\Bucket $bucket) use (&$calledB, $self) {
+ $calledB = true;
+
+ $self
+ ->array($bucket->getData())
+ ->isEqualTo([
+ 'message' => 'foobar'
+ ]);
+
+ return;
+ }
+ )
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->boolean($calledA)
+ ->isTrue()
+ ->boolean($calledB)
+ ->isTrue();
+ }
+
+ public function case_run_ping_opcode_not_fin()
+ {
+ return $this->_case_run_ping_opcode_with_invalid_frame([
+ 'fin' => 0x0,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_PING,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ]);
+ }
+
+ public function case_run_ping_opcode_with_length_too_big()
+ {
+ return $this->_case_run_ping_opcode_with_invalid_frame([
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_PING,
+ 'mask' => 0x1,
+ 'length' => 0x7e,
+ 'message' => 'foobar…'
+ ]);
+ }
+
+ protected function _case_run_ping_opcode_with_invalid_frame(array $frame)
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame = $frame,
+ $this->calling($protocol)->writeFrame = function ($_message, $_opcode, $_mask) use (&$calledA) {
+ $calledA = true;
+
+ return;
+ },
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$calledB, $self) {
+ $calledB = true;
+
+ $self
+ ->integer($_code)
+ ->isEqualTo(SUT::CLOSE_PROTOCOL_ERROR)
+ ->variable($_reason)
+ ->isNull();
+
+ return;
+ },
+
+ $connection->on(
+ 'ping',
+ function (Event\Bucket $bucket) use (&$calledC) {
+ $calledC = true;
+
+ return;
+ }
+ )
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($calledA)
+ ->isNull()
+ ->boolean($calledB)
+ ->isTrue()
+ ->variable($calledC)
+ ->isNull();
+ }
+
+ public function case_run_pong_opcode()
+ {
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_PONG,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ],
+ $this->calling($protocol)->writeFrame = function ($_message, $_opcode, $_mask) use (&$called) {
+ $called = true;
+
+ return;
+ }
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($called)
+ ->isNull();
+ }
+
+ public function case_run_pong_opcode_not_fin()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x0,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_PONG,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ],
+ $this->calling($protocol)->writeFrame = function ($_message, $_opcode, $_mask) use (&$calledA) {
+ $calledA = true;
+
+ return;
+ },
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$calledB, $self) {
+ $calledB = true;
+
+ $self
+ ->integer($_code)
+ ->isEqualTo(SUT::CLOSE_PROTOCOL_ERROR)
+ ->variable($_reason)
+ ->isNull();
+
+ return;
+ }
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($calledA)
+ ->isNull()
+ ->boolean($calledB)
+ ->isTrue();
+ }
+
+ public function case_run_text_frame_opcode_with_fragments()
+ {
+ return $this->_case_run_x_frame_opcode_with_fragments(SUT::OPCODE_TEXT_FRAME);
+ }
+
+ public function case_run_binary_frame_opcode_with_fragments()
+ {
+ return $this->_case_run_x_frame_opcode_with_fragments(SUT::OPCODE_BINARY_FRAME);
+ }
+
+ protected function _case_run_x_frame_opcode_with_fragments($opcode)
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($node)->getNumberOfFragments = 42,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => $opcode,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ],
+ $this->calling($protocol)->writeFrame = function ($_message, $_opcode, $_mask) use (&$calledA) {
+ $calledA = true;
+
+ return;
+ },
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$calledB, $self) {
+ $calledB = true;
+
+ $self
+ ->integer($_code)
+ ->isEqualTo(SUT::CLOSE_PROTOCOL_ERROR)
+ ->variable($_reason)
+ ->isNull();
+
+ return;
+ }
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($calledA)
+ ->isNull()
+ ->boolean($calledB)
+ ->isTrue();
+ }
+
+ public function case_run_text_frame_opcode_with_invalid_message_encoding()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_TEXT_FRAME,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => iconv('UTF-8', 'UTF-16', '😄')
+ ],
+ $this->calling($protocol)->writeFrame = function ($_message, $_opcode, $_mask) use (&$calledA) {
+ $calledA = true;
+
+ return;
+ },
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$calledB, $self) {
+ $calledB = true;
+
+ $self
+ ->integer($_code)
+ ->isEqualTo(SUT::CLOSE_MESSAGE_ERROR)
+ ->variable($_reason)
+ ->isNull();
+
+ return;
+ }
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($calledA)
+ ->isNull()
+ ->boolean($calledB)
+ ->isTrue();
+ }
+
+ public function case_run_text_frame_opcode()
+ {
+ return $this->_case_run_x_frame_opcode(SUT::OPCODE_TEXT_FRAME);
+ }
+
+ public function case_run_binary_frame_opcode()
+ {
+ return $this->_case_run_x_frame_opcode(SUT::OPCODE_BINARY_FRAME);
+ }
+
+ protected function _case_run_x_frame_opcode($opcode)
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => $opcode,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ],
+ $this->calling($protocol)->writeFrame = function ($_message, $_opcode, $_mask) use (&$calledA) {
+ $calledA = true;
+
+ return;
+ },
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$calledB) {
+ $calledB = true;
+
+ return;
+ },
+
+ $connection->on(
+ SUT::OPCODE_TEXT_FRAME === $opcode ? 'message' : 'binary-message',
+ function (Event\Bucket $bucket) use (&$calledC, $self) {
+ $calledC = true;
+
+ $self
+ ->array($bucket->getData())
+ ->isEqualTo([
+ 'message' => 'foobar'
+ ]);
+
+ return;
+ }
+ )
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($calledA)
+ ->isNull()
+ ->variable($calledB)
+ ->isNull()
+ ->boolean($calledC)
+ ->isTrue();
+ }
+
+ public function case_run_text_frame_opcode_with_an_exception_from_the_listener()
+ {
+ return $this->_case_run_x_frame_opcode_with_an_exception_from_the_listener(SUT::OPCODE_TEXT_FRAME);
+ }
+
+ public function case_run_binary_frame_opcode_with_an_exception_from_the_listener()
+ {
+ return $this->_case_run_x_frame_opcode_with_an_exception_from_the_listener(SUT::OPCODE_BINARY_FRAME);
+ }
+
+ protected function _case_run_x_frame_opcode_with_an_exception_from_the_listener($opcode)
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => $opcode,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ],
+ $this->calling($protocol)->writeFrame = function ($_message, $_opcode, $_mask) use (&$calledA) {
+ $calledA = true;
+
+ return;
+ },
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$calledB) {
+ $calledB = true;
+
+ return;
+ },
+
+ $connection->on(
+ SUT::OPCODE_TEXT_FRAME === $opcode ? 'message' : 'binary-message',
+ function (Event\Bucket $bucket) use (&$calledC, $self) {
+ $calledC = true;
+
+ $self
+ ->array($bucket->getData())
+ ->isEqualTo([
+ 'message' => 'foobar'
+ ]);
+
+ throw new \RuntimeException('bang');
+ }
+ ),
+ $connection->on(
+ 'error',
+ function (Event\Bucket $bucket) use (&$calledD, $self) {
+ $calledD = true;
+
+ $self
+ ->let($data = $bucket->getData())
+ ->array($data)
+ ->hasSize(1)
+ ->hasKey('exception')
+ ->exception($data['exception'])
+ ->isInstanceOf(\RuntimeException::class)
+ ->hasMessage('bang');
+
+ return;
+ }
+ )
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($calledA)
+ ->isNull()
+ ->variable($calledB)
+ ->isNull()
+ ->boolean($calledC)
+ ->isTrue()
+ ->boolean($calledD)
+ ->isTrue();
+ }
+
+ public function case_run_incomplete_text_frame_opcode()
+ {
+ return $this->_case_run_incomplete_x_frame_opcode(SUT::OPCODE_TEXT_FRAME);
+ }
+
+ public function case_run_incomplete_binary_frame_opcode()
+ {
+ return $this->_case_run_incomplete_x_frame_opcode(SUT::OPCODE_BINARY_FRAME);
+ }
+
+ protected function _case_run_incomplete_x_frame_opcode($opcode)
+ {
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x0,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => $opcode,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ],
+ $this->calling($protocol)->writeFrame = function ($_message, $_opcode, $_mask) use (&$calledA) {
+ $calledA = true;
+
+ return;
+ },
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$calledB) {
+ $calledB = true;
+
+ return;
+ },
+
+ $connection->on(
+ 'message',
+ function (Event\Bucket $bucket) use (&$calledC) {
+ $calledC = true;
+
+ return;
+ }
+ )
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($calledA)
+ ->isNull()
+ ->variable($calledB)
+ ->isNull()
+ ->variable($calledC)
+ ->isNull()
+ ->boolean($node->isMessageComplete())
+ ->isFalse()
+ ->integer($node->getNumberOfFragments())
+ ->isEqualTo(1)
+ ->string($node->getFragmentedMessage())
+ ->isEqualTo('foobar')
+ ->boolean($node->isBinary())
+ ->isEqualTo(SUT::OPCODE_BINARY_FRAME === $opcode);
+ }
+
+ public function case_run_continuation_frame_opcode_with_fragments()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($node)->getNumberOfFragments = 42,
+ $this->calling($protocol)->readFrame = [
+ 'fin' => 0x0,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_CONTINUATION_FRAME,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => 'foobar'
+ ],
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$called) {
+ $called = true;
+
+ $self
+ ->integer($_code)
+ ->isEqualTo(SUT::CLOSE_PROTOCOL_ERROR)
+ ->variable($_reason)
+ ->isNull();
+
+ return;
+ }
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($called)
+ ->isNull();
+ }
+
+ public function case_run_text_frame_and_continuation_frame_opcodes()
+ {
+ return $this->_case_run_x_frame_and_continuation_frame_opcodes(SUT::OPCODE_TEXT_FRAME);
+ }
+
+ public function case_run_binary_frame_and_continuation_frame_opcodes()
+ {
+ return $this->_case_run_x_frame_and_continuation_frame_opcodes(SUT::OPCODE_BINARY_FRAME);
+ }
+
+ protected function _case_run_x_frame_and_continuation_frame_opcodes($opcode)
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame[1] = [
+ 'fin' => 0x0,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => $opcode,
+ 'mask' => 0x1,
+ 'length' => 3,
+ 'message' => 'foo'
+ ],
+ $this->calling($protocol)->readFrame[2] = [
+ 'fin' => 0x0,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_CONTINUATION_FRAME,
+ 'mask' => 0x1,
+ 'length' => 3,
+ 'message' => 'bar'
+ ],
+ $this->calling($protocol)->readFrame[3] = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_CONTINUATION_FRAME,
+ 'mask' => 0x1,
+ 'length' => 3,
+ 'message' => 'baz'
+ ],
+ $this->calling($socket)->getCurrentNode = $node,
+
+ $connection->on(
+ SUT::OPCODE_TEXT_FRAME === $opcode ? 'message' : 'binary-message',
+ function (Event\Bucket $bucket) use (&$called, $self) {
+ $called = true;
+
+ $self
+ ->array($bucket->getData())
+ ->isEqualTo([
+ 'message' => 'foobarbaz'
+ ]);
+
+ return;
+ }
+ )
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->integer($node->getNumberOfFragments())
+ ->isEqualTo(1)
+ ->string($node->getFragmentedMessage())
+ ->isEqualTo('foo')
+ ->boolean($node->isMessageComplete())
+ ->isFalse()
+ ->variable($called)
+ ->isNull()
+
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->integer($node->getNumberOfFragments())
+ ->isEqualTo(2)
+ ->string($node->getFragmentedMessage())
+ ->isEqualTo('foobar')
+ ->boolean($node->isMessageComplete())
+ ->isFalse()
+ ->variable($called)
+ ->isNull()
+
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->integer($node->getNumberOfFragments())
+ ->isEqualTo(0)
+ ->variable($node->getFragmentedMessage())
+ ->isNull()
+ ->boolean($node->isMessageComplete())
+ ->isTrue()
+ ->boolean($called)
+ ->isTrue();
+ }
+
+ public function case_run_text_frame_and_continuation_frame_opcodes_with_an_exception_from_the_listener()
+ {
+ return $this->_case_run_x_frame_and_continuation_frame_opcodes_with_an_exception_from_the_listener(SUT::OPCODE_TEXT_FRAME);
+ }
+
+ public function case_run_binary_frame_and_continuation_frame_opcodes_with_an_exception_from_the_listener()
+ {
+ return $this->_case_run_x_frame_and_continuation_frame_opcodes_with_an_exception_from_the_listener(SUT::OPCODE_BINARY_FRAME);
+ }
+
+ protected function _case_run_x_frame_and_continuation_frame_opcodes_with_an_exception_from_the_listener($opcode)
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame[1] = [
+ 'fin' => 0x0,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => $opcode,
+ 'mask' => 0x1,
+ 'length' => 3,
+ 'message' => 'foo'
+ ],
+ $this->calling($protocol)->readFrame[2] = [
+ 'fin' => 0x0,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_CONTINUATION_FRAME,
+ 'mask' => 0x1,
+ 'length' => 3,
+ 'message' => 'bar'
+ ],
+ $this->calling($protocol)->readFrame[3] = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_CONTINUATION_FRAME,
+ 'mask' => 0x1,
+ 'length' => 3,
+ 'message' => 'baz'
+ ],
+ $this->calling($socket)->getCurrentNode = $node,
+
+ $connection->on(
+ SUT::OPCODE_TEXT_FRAME === $opcode ? 'message' : 'binary-message',
+ function (Event\Bucket $bucket) use (&$calledA, $self) {
+ $calledA = true;
+
+ $self
+ ->array($bucket->getData())
+ ->isEqualTo([
+ 'message' => 'foobarbaz'
+ ]);
+
+ throw new \RuntimeException('bang');
+ }
+ ),
+ $connection->on(
+ 'error',
+ function (Event\Bucket $bucket) use (&$calledB, $self) {
+ $calledB = true;
+
+ $self
+ ->let($data = $bucket->getData())
+ ->array($data)
+ ->hasSize(1)
+ ->hasKey('exception')
+ ->exception($data['exception'])
+ ->isInstanceOf(\RuntimeException::class)
+ ->hasMessage('bang');
+
+ return;
+ }
+ )
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->integer($node->getNumberOfFragments())
+ ->isEqualTo(1)
+ ->string($node->getFragmentedMessage())
+ ->isEqualTo('foo')
+ ->boolean($node->isMessageComplete())
+ ->isFalse()
+ ->variable($calledA)
+ ->isNull()
+ ->variable($calledB)
+ ->isNull()
+
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->integer($node->getNumberOfFragments())
+ ->isEqualTo(2)
+ ->string($node->getFragmentedMessage())
+ ->isEqualTo('foobar')
+ ->boolean($node->isMessageComplete())
+ ->isFalse()
+ ->variable($calledA)
+ ->isNull()
+ ->variable($calledB)
+ ->isNull()
+
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->integer($node->getNumberOfFragments())
+ ->isEqualTo(0)
+ ->variable($node->getFragmentedMessage())
+ ->isNull()
+ ->boolean($node->isMessageComplete())
+ ->isTrue()
+ ->boolean($calledA)
+ ->isTrue()
+ ->boolean($calledB)
+ ->isTrue();
+ }
+
+ public function case_run_text_frame_and_continuation_frame_opcodes_with_invalid_message_encoding()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $this->calling($node)->getHandshake = SUCCEED,
+ $this->calling($protocol)->readFrame[1] = [
+ 'fin' => 0x0,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_TEXT_FRAME,
+ 'mask' => 0x1,
+ 'length' => 3,
+ 'message' => 'foo'
+ ],
+ $this->calling($protocol)->readFrame[2] = [
+ 'fin' => 0x1,
+ 'rsv1' => 0x0,
+ 'rsv2' => 0x0,
+ 'rsv3' => 0x0,
+ 'opcode' => SUT::OPCODE_CONTINUATION_FRAME,
+ 'mask' => 0x1,
+ 'length' => 6,
+ 'message' => iconv('UTF-8', 'UTF-16', '😄')
+ ],
+ $this->calling($socket)->getCurrentNode = $node,
+
+ $this->calling($connection)->close = function ($_code, $_reason) use (&$called, $self) {
+ $called = true;
+
+ $self
+ ->integer($_code)
+ ->isEqualTo(SUT::CLOSE_MESSAGE_ERROR)
+ ->variable($_reason)
+ ->isNull();
+
+ return;
+ }
+ )
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->integer($node->getNumberOfFragments())
+ ->isEqualTo(1)
+ ->string($node->getFragmentedMessage())
+ ->isEqualTo('foo')
+ ->boolean($node->isMessageComplete())
+ ->isFalse()
+ ->variable($called)
+ ->isNull()
+
+ ->when($result = $this->invoke($connection)->_run($node))
+ ->then
+ ->integer($node->getNumberOfFragments())
+ ->isEqualTo(0)
+ ->variable($node->getFragmentedMessage())
+ ->isNull()
+ ->boolean($node->isMessageComplete())
+ ->isTrue()
+ ->boolean($called)
+ ->isTrue();
+ }
+
+ public function case__send()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $message = 'foobar',
+ $opcode = SUT::OPCODE_TEXT_FRAME,
+ $end = true,
+
+ $this->calling($node)->getHandshake = true,
+ $this->calling($protocol)->send = function ($_message, $_opcode, $_end, $_mask) use (&$called, $self, $message, $opcode, $end) {
+ $called = true;
+
+ $self
+ ->string($_message)
+ ->isEqualTo($message)
+ ->integer($_opcode)
+ ->isEqualTo($opcode)
+ ->boolean($_end)
+ ->isEqualTo($end)
+ ->boolean($_mask)
+ ->isFalse();
+
+ return 42;
+ },
+
+ $closure = $this->invoke($connection)->_send($message, $node)
+ )
+ ->when($result = new \ReflectionFunction($closure))
+ ->then
+ ->integer($result->getNumberOfRequiredParameters())
+ ->isEqualTo(2)
+
+ ->when($result = $closure($opcode, $end))
+ ->then
+ ->integer($result)
+ ->isEqualTo(42)
+ ->boolean($called)
+ ->isTrue();
+ }
+
+ public function case__send_with_no_handshake()
+ {
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $message = 'foobar',
+ $opcode = SUT::OPCODE_TEXT_FRAME,
+ $end = true,
+
+ $this->calling($protocol)->send = function ($_message, $_opcode, $_end, $_mask) use (&$called) {
+ $called = true;
+
+ return 42;
+ },
+
+ $closure = $this->invoke($connection)->_send($message, $node)
+ )
+ ->when($result = new \ReflectionFunction($closure))
+ ->then
+ ->integer($result->getNumberOfRequiredParameters())
+ ->isEqualTo(2)
+
+ ->when($result = $closure($opcode, $end))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->variable($called)
+ ->isNull();
+ }
+
+ public function case_close_with_no_protocol()
+ {
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+
+ $this->calling($socket)->getCurrentNode = $node
+ )
+ ->when($result = $connection->close(SUT::CLOSE_DATA_ERROR, 'foo'))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->boolean($socket->isDisconnected())
+ ->isTrue();
+ }
+
+ public function case_close()
+ {
+ $self = $this;
+
+ $this
+ ->given(
+ $socket = new \Mock\Hoa\Socket\Client('tcp://*:1234'),
+ $connection = new SUT($socket),
+ $protocol = new \Mock\Hoa\Websocket\Protocol\Rfc6455($socket),
+ $this->mockGenerator->orphanize('__construct'),
+ $node = new \Mock\Hoa\Websocket\Node(),
+ $node->setProtocolImplementation($protocol),
+
+ $code = SUT::CLOSE_DATA_ERROR,
+ $reason = 'foo',
+
+ $this->calling($protocol)->close = function ($_code, $_reason) use (&$called, $self, $code, $reason) {
+ $called = true;
+
+ $self
+ ->integer($_code)
+ ->isEqualTo($code)
+ ->string($_reason)
+ ->isEqualTo($reason);
+
+ return;
+ },
+ $this->calling($socket)->getCurrentNode = $node
+ )
+ ->when($result = $connection->close($code, $reason))
+ ->then
+ ->variable($result)
+ ->isNull()
+ ->boolean($socket->isDisconnected())
+ ->isTrue()
+ ->boolean($called)
+ ->isTrue();
+ }
}