summaryrefslogtreecommitdiffstats
path: root/vendor/clue/redis-protocol
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clue/redis-protocol')
-rw-r--r--vendor/clue/redis-protocol/.travis.yml8
-rw-r--r--vendor/clue/redis-protocol/CHANGELOG.md50
-rw-r--r--vendor/clue/redis-protocol/README.md139
-rw-r--r--vendor/clue/redis-protocol/composer.json19
-rw-r--r--vendor/clue/redis-protocol/example/client.php22
-rw-r--r--vendor/clue/redis-protocol/example/perf.php31
-rw-r--r--vendor/clue/redis-protocol/phpunit.xml.dist19
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php51
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php34
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php34
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php31
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php23
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php100
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php53
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php34
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php40
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php10
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php28
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php125
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php151
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php111
-rw-r--r--vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php83
-rw-r--r--vendor/clue/redis-protocol/tests/FactoryTest.php34
-rw-r--r--vendor/clue/redis-protocol/tests/Model/AbstractModelTest.php22
-rw-r--r--vendor/clue/redis-protocol/tests/Model/BulkReplyTest.php43
-rw-r--r--vendor/clue/redis-protocol/tests/Model/ErrorReplyTest.php19
-rw-r--r--vendor/clue/redis-protocol/tests/Model/IntegerReplyTest.php40
-rw-r--r--vendor/clue/redis-protocol/tests/Model/MultiBulkReplyTest.php115
-rw-r--r--vendor/clue/redis-protocol/tests/Model/RequestTest.php37
-rw-r--r--vendor/clue/redis-protocol/tests/Model/StatusReplyTest.php19
-rw-r--r--vendor/clue/redis-protocol/tests/Parser/AbstractParserTest.php67
-rw-r--r--vendor/clue/redis-protocol/tests/Parser/RequestParserTest.php132
-rw-r--r--vendor/clue/redis-protocol/tests/Parser/ResponseParserTest.php130
-rw-r--r--vendor/clue/redis-protocol/tests/Serializer/AbstractSerializerTest.php141
-rw-r--r--vendor/clue/redis-protocol/tests/Serializer/RecursiveSerializerTest.php11
-rw-r--r--vendor/clue/redis-protocol/tests/bootstrap.php7
36 files changed, 2013 insertions, 0 deletions
diff --git a/vendor/clue/redis-protocol/.travis.yml b/vendor/clue/redis-protocol/.travis.yml
new file mode 100644
index 0000000..2af5cf5
--- /dev/null
+++ b/vendor/clue/redis-protocol/.travis.yml
@@ -0,0 +1,8 @@
+language: php
+php:
+ - 5.4
+ - 5.3
+before_script:
+ - composer install --dev --prefer-source --no-interaction
+script:
+ - phpunit --coverage-text
diff --git a/vendor/clue/redis-protocol/CHANGELOG.md b/vendor/clue/redis-protocol/CHANGELOG.md
new file mode 100644
index 0000000..d037017
--- /dev/null
+++ b/vendor/clue/redis-protocol/CHANGELOG.md
@@ -0,0 +1,50 @@
+# Changelog
+
+## 0.3.1 (2017-06-06)
+
+* Fix: Fix server-side parsing of legacy inline protocol when multiple requests are processed at once
+ (#12 by @kelunik and #13 by @clue)
+
+## 0.3.0 (2014-01-27)
+
+* Feature: Add dedicated and faster `RequestParser` that also support the old
+ inline request protocol.
+* Feature: Message serialization can now be handled directly by the Serializer
+ again without having to construct the appropriate model first.
+* BC break: The `Factory` now has two distinct methods to create parsers:
+ * `createResponseParser()` for a client-side library
+ * `createRequestParser()` for a server-side library / testing framework
+* BC break: Simplified parser API, now `pushIncoming()` returns an array of all
+ parsed message models.
+* BC break: The signature for getting a serialized message from a model was
+ changed and now requires a Serializer passed:
+ ```php
+ModelInterface::getMessageSerialized($serializer)
+```
+* Many, many performance improvements
+
+## 0.2.0 (2014-01-21)
+
+* Re-organize the whole API into dedicated
+ * `Parser` (protocol reader) and
+ * `Serializer` (protocol writer) sub-namespaces. (#4)
+
+* Use of the factory has now been unified:
+
+ ```php
+ $factory = new Clue\Redis\Protocol\Factory();
+ $parser = $factory->createParser();
+ $serializer = $factory->createSerializer();
+ ```
+
+* Add a dedicated `Model` for each type of reply. Among others, this now allows
+ you to distinguish a single line `StatusReply` from a binary-safe `BulkReply`. (#2)
+
+* Fix parsing binary values and do not trip over trailing/leading whitespace. (#4)
+
+* Improve parser and serializer performance by up to 20%. (#4)
+
+## 0.1.0 (2013-09-10)
+
+* First tagged release
+
diff --git a/vendor/clue/redis-protocol/README.md b/vendor/clue/redis-protocol/README.md
new file mode 100644
index 0000000..ea36a67
--- /dev/null
+++ b/vendor/clue/redis-protocol/README.md
@@ -0,0 +1,139 @@
+# clue/redis-protocol [![Build Status](https://travis-ci.org/clue/php-redis-protocol.png?branch=master)](https://travis-ci.org/clue/php-redis-protocol)
+
+A streaming redis protocol parser and serializer written in PHP
+
+This parser and serializer implementation allows you to parse redis protocol
+messages into native PHP values and vice-versa. This is usually needed by a
+redis client implementation which also handles the connection socket.
+
+To re-iterate: This is *not* a redis client implementation. This is a protocol
+implementation that is usually used by a redis client implementation. If you're
+looking for an easy way to build your own client implementation, then this is
+for you. If you merely want to connect to a redis server and issue some
+commands, you're probably better off using one of the existing client
+implementations.
+
+**Table of contents**
+
+* [Quickstart example](#quickstart-example)
+* [Usage](#usage)
+ * [Factory](#factory)
+ * [Parser](#parser)
+ * [Model](#model)
+ * [Serializer](#serializer)
+* [Install](#install)
+* [License](#license)
+
+## Quickstart example
+
+```php
+use Clue\Redis\Protocol;
+
+$factory = new Protocol\Factory();
+$parser = $factory->createResponseParser();
+$serializer = $factory->createSerializer();
+
+$fp = fsockopen('tcp://localhost', 6379);
+fwrite($fp, $serializer->getRequestMessage('SET', array('name', 'value')));
+fwrite($fp, $serializer->getRequestMessage('GET', array('name')));
+
+// the commands are pipelined, so this may parse multiple responses
+$models = $parser->pushIncoming(fread($fp, 4096));
+
+$reply1 = array_shift($models);
+$reply2 = array_shift($models);
+
+var_dump($reply1->getValueNative()); // string(2) "OK"
+var_dump($reply2->getValueNative()); // string(5) "value"
+```
+
+## Usage
+
+### Factory
+
+The factory helps with instantiating the *right* parser and serializer.
+Eventually the *best* available implementation will be chosen depending on your
+installed extensions. You're also free to instantiate them directly, but this
+will lock you down on a given implementation (which could be okay depending on
+your use-case).
+
+### Parser
+
+The library includes a streaming redis protocol parser. As such, it can safely
+parse redis protocol messages and work with an incomplete data stream. For this,
+each included parser implements a single method
+`ParserInterface::pushIncoming($chunk)`.
+
+* The `ResponseParser` is what most redis client implementation would want to
+ use in order to parse incoming response messages from a redis server instance.
+* The `RequestParser` can be used to test messages coming from a redis client or
+ even to implement a redis server.
+* The `MessageBuffer` decorates either of the available parsers and merely
+ offers some helper methods in order to work with single messages:
+ * `hasIncomingModel()` to check if there's a complete message in the pipeline
+ * `popIncomingModel()` to extract a complete message from the incoming queue.
+
+### Model
+
+Each message (response as well as request) is represented by a model
+implementing the `ModelInterface` that has two methods:
+
+* `getValueNative()` returns the wrapped value.
+* `getMessageSerialized($serializer)` returns the serialized protocol messages
+ that will be sent over the wire.
+
+These models are very lightweight and add little overhead. They help keeping the
+code organized and also provide a means to distinguish a single line
+`StatusReply` from a binary-safe `BulkReply`.
+
+The parser always returns models. Models can also be instantiated directly:
+
+```php
+$model = new Model\IntegerReply(123);
+var_dump($model->getValueNative()); // int(123)
+var_dump($model->getMessageSerialized($serializer)); // string(6) ":123\r\n"
+```
+
+### Serializer
+
+The serializer is responsible for creating serialized messages and the
+corresponing message models to be sent across the wire.
+
+```php
+$message = $serializer->getRequestMessage('ping');
+var_dump($message); // string(14) "$1\r\n*4\r\nping\r\n"
+
+$message = $serializer->getRequestMessage('set', array('key', 'value'));
+var_dump($message); // string(33) "$3\r\n*3\r\nset\r\n*3\r\nkey\r\n*5\r\nvalue\r\n"
+
+$model = $serializer->createRequestModel('get', array('key'));
+var_dump($model->getCommand()); // string(3) "get"
+var_dump($model->getArgs()); // array(1) { string(3) "key" }
+var_dump($model->getValueNative()); // array(2) { string(3) "GET", string(3) "key" }
+
+$model = $serializer->createReplyModel(array('mixed', 12, array('value')));
+assert($model implement Model\MultiBulkReply);
+```
+
+## Install
+
+It's very unlikely you'll want to use this protocol parser standalone.
+It should be added as a dependency to your redis client implementation instead.
+The recommended way to install this library is [through Composer](https://getcomposer.org).
+[New to Composer?](https://getcomposer.org/doc/00-intro.md)
+
+This will install the latest supported version:
+
+```bash
+$ composer require clue/redis-protocol:^0.3.1
+```
+
+More details and upgrade guides can be found in the [CHANGELOG](CHANGELOG.md).
+
+## License
+
+Its parser and serializer originally used to be based on
+[jpd/redisent](https://github.com/jdp/redisent), which is released under the ISC
+license, copyright (c) 2009-2012 Justin Poliey <justin@getglue.com>.
+
+Other than that, this library is MIT licensed.
diff --git a/vendor/clue/redis-protocol/composer.json b/vendor/clue/redis-protocol/composer.json
new file mode 100644
index 0000000..d99e2ee
--- /dev/null
+++ b/vendor/clue/redis-protocol/composer.json
@@ -0,0 +1,19 @@
+{
+ "name": "clue/redis-protocol",
+ "description": "A streaming redis wire protocol parser and serializer implementation in PHP",
+ "keywords": ["streaming", "redis", "protocol", "parser", "serializer"],
+ "homepage": "https://github.com/clue/php-redis-protocol",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "require": {
+ "php": ">=5.3"
+ },
+ "autoload": {
+ "psr-0": { "Clue\\Redis\\Protocol": "src" }
+ }
+}
diff --git a/vendor/clue/redis-protocol/example/client.php b/vendor/clue/redis-protocol/example/client.php
new file mode 100644
index 0000000..d1b4428
--- /dev/null
+++ b/vendor/clue/redis-protocol/example/client.php
@@ -0,0 +1,22 @@
+<?php
+
+require __DIR__ . '/../vendor/autoload.php';
+
+use Clue\Redis\Protocol;
+
+$factory = new Protocol\Factory();
+$parser = $factory->createResponseParser();
+$serializer = $factory->createSerializer();
+
+$fp = fsockopen('tcp://localhost', 6379);
+fwrite($fp, $serializer->getRequestMessage('SET', array('name', 'value')));
+fwrite($fp, $serializer->getRequestMessage('GET', array('name')));
+
+// the commands are pipelined, so this may parse multiple responses
+$models = $parser->pushIncoming(fread($fp, 4096));
+
+$reply1 = array_shift($models);
+$reply2 = array_shift($models);
+
+var_dump($reply1->getValueNative()); // string(2) "OK"
+var_dump($reply2->getValueNative()); // string(5) "value"
diff --git a/vendor/clue/redis-protocol/example/perf.php b/vendor/clue/redis-protocol/example/perf.php
new file mode 100644
index 0000000..c5ce6a7
--- /dev/null
+++ b/vendor/clue/redis-protocol/example/perf.php
@@ -0,0 +1,31 @@
+<?php
+
+use Clue\Redis\Protocol\ProtocolBuffer;
+use Clue\Redis\Protocol\Factory;
+
+require __DIR__ . '/../vendor/autoload.php';
+
+$factory = new Factory();
+$parser = $factory->createResponseParser();
+$serializer = $factory->createSerializer();
+
+$n = isset($argv[1]) ? (int)$argv[1] : 10000; // number of dummy messages to parse
+$cs = 4096; // pretend we can only read 7 bytes at once. more like 4096/8192 usually
+
+echo 'benchmarking ' . $n . ' messages (chunksize of ' . $cs .' bytes)' . PHP_EOL;
+
+$time = microtime(true);
+
+$stream = '';
+for ($i = 0; $i < $n; ++$i) {
+ $stream .= $serializer->getRequestMessage('set', array('var' . $i, 'value' . $i));
+}
+
+echo round(microtime(true) - $time, 3) . 's for serialization' . PHP_EOL;
+$time = microtime(true);
+
+for ($i = 0, $l = strlen($stream); $i < $l; $i += $cs) {
+ $parser->pushIncoming(substr($stream, $i, $cs));
+}
+
+echo round(microtime(true) - $time, 3) . 's for parsing' . PHP_EOL;
diff --git a/vendor/clue/redis-protocol/phpunit.xml.dist b/vendor/clue/redis-protocol/phpunit.xml.dist
new file mode 100644
index 0000000..4f3de2a
--- /dev/null
+++ b/vendor/clue/redis-protocol/phpunit.xml.dist
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit bootstrap="tests/bootstrap.php"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+>
+ <testsuites>
+ <testsuite name="Redis Protocol Test Suite">
+ <directory>./tests/</directory>
+ </testsuite>
+ </testsuites>
+ <filter>
+ <whitelist>
+ <directory>./src/</directory>
+ </whitelist>
+ </filter>
+</phpunit> \ No newline at end of file
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php
new file mode 100644
index 0000000..3997f04
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Factory.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Clue\Redis\Protocol;
+
+use Clue\Redis\Protocol\Parser\ParserInterface;
+use Clue\Redis\Protocol\Parser\ResponseParser;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+use Clue\Redis\Protocol\Serializer\RecursiveSerializer;
+use Clue\Redis\Protocol\Parser\RequestParser;
+
+/**
+ * Provides factory methods used to instantiate the best available protocol implementation
+ */
+class Factory
+{
+ /**
+ * instantiate the best available protocol response parser implementation
+ *
+ * This is the parser every redis client implementation should use in order
+ * to parse incoming response messages from a redis server.
+ *
+ * @return ParserInterface
+ */
+ public function createResponseParser()
+ {
+ return new ResponseParser();
+ }
+
+ /**
+ * instantiate the best available protocol request parser implementation
+ *
+ * This is most useful for a redis server implementation which needs to
+ * process client requests.
+ *
+ * @return ParserInterface
+ */
+ public function createRequestParser()
+ {
+ return new RequestParser();
+ }
+
+ /**
+ * instantiate the best available protocol serializer implementation
+ *
+ * @return SerializerInterface
+ */
+ public function createSerializer()
+ {
+ return new RecursiveSerializer();
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php
new file mode 100644
index 0000000..e069fda
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/BulkReply.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class BulkReply implements ModelInterface
+{
+ private $value;
+
+ /**
+ * create bulk reply (string reply)
+ *
+ * @param string|null $data
+ */
+ public function __construct($value)
+ {
+ if ($value !== null) {
+ $value = (string)$value;
+ }
+ $this->value = $value;
+ }
+
+ public function getValueNative()
+ {
+ return $this->value;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getBulkMessage($this->value);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php
new file mode 100644
index 0000000..556e93b
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ErrorReply.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Exception;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+/**
+ *
+ * @link http://redis.io/topics/protocol#status-reply
+ */
+class ErrorReply extends Exception implements ModelInterface
+{
+ /**
+ * create error status reply (single line error message)
+ *
+ * @param string|ErrorReplyException $message
+ * @return string
+ */
+ public function __construct($message, $code = 0, $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ }
+
+ public function getValueNative()
+ {
+ return $this->getMessage();
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getErrorMessage($this->getMessage());
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php
new file mode 100644
index 0000000..ba1ff05
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/IntegerReply.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class IntegerReply implements ModelInterface
+{
+ private $value;
+
+ /**
+ * create integer reply
+ *
+ * @param int $data
+ */
+ public function __construct($value)
+ {
+ $this->value = (int)$value;
+ }
+
+ public function getValueNative()
+ {
+ return $this->value;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getIntegerMessage($this->value);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php
new file mode 100644
index 0000000..b97939e
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/ModelInterface.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+interface ModelInterface
+{
+ /**
+ * Returns value of this model as a native representation for PHP
+ *
+ * @return mixed
+ */
+ public function getValueNative();
+
+ /**
+ * Returns the serialized representation of this protocol message
+ *
+ * @param SerializerInterface $serializer;
+ * @return string
+ */
+ public function getMessageSerialized(SerializerInterface $serializer);
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php
new file mode 100644
index 0000000..7198dc6
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/MultiBulkReply.php
@@ -0,0 +1,100 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use InvalidArgumentException;
+use UnexpectedValueException;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class MultiBulkReply implements ModelInterface
+{
+ /**
+ * @var array|null
+ */
+ private $data;
+
+ /**
+ * create multi bulk reply (an array of other replies, usually bulk replies)
+ *
+ * @param array|null $data
+ * @throws InvalidArgumentException
+ */
+ public function __construct(array $data = null)
+ {
+ $this->data = $data;
+ }
+
+ public function getValueNative()
+ {
+ if ($this->data === null) {
+ return null;
+ }
+
+ $ret = array();
+ foreach ($this->data as $one) {
+ if ($one instanceof ModelInterface) {
+ $ret []= $one->getValueNative();
+ } else {
+ $ret []= $one;
+ }
+ }
+ return $ret;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getMultiBulkMessage($this->data);
+ }
+
+ /**
+ * Checks whether this model represents a valid unified request protocol message
+ *
+ * The new unified protocol was introduced in Redis 1.2, but it became the
+ * standard way for talking with the Redis server in Redis 2.0. The unified
+ * request protocol is what Redis already uses in replies in order to send
+ * list of items to clients, and is called a Multi Bulk Reply.
+ *
+ * @return boolean
+ * @link http://redis.io/topics/protocol
+ */
+ public function isRequest()
+ {
+ if (!$this->data) {
+ return false;
+ }
+
+ foreach ($this->data as $one) {
+ if (!($one instanceof BulkReply) && !is_string($one)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public function getRequestModel()
+ {
+ if (!$this->data) {
+ throw new UnexpectedValueException('Null-multi-bulk message can not be represented as a request, must contain string/bulk values');
+ }
+
+ $command = null;
+ $args = array();
+
+ foreach ($this->data as $one) {
+ if ($one instanceof BulkReply) {
+ $one = $one->getValueNative();
+ } elseif (!is_string($one)) {
+ throw new UnexpectedValueException('Message can not be represented as a request, must only contain string/bulk values');
+ }
+
+ if ($command === null) {
+ $command = $one;
+ } else {
+ $args []= $one;
+ }
+ }
+
+ return new Request($command, $args);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php
new file mode 100644
index 0000000..f5881e9
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/Request.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+
+class Request implements ModelInterface
+{
+ private $command;
+ private $args;
+
+ public function __construct($command, array $args = array())
+ {
+ $this->command = $command;
+ $this->args = $args;
+ }
+
+ public function getCommand()
+ {
+ return $this->command;
+ }
+
+ public function getArgs()
+ {
+ return $this->args;
+ }
+
+ public function getReplyModel()
+ {
+ $models = array(new BulkReply($this->command));
+ foreach ($this->args as $arg) {
+ $models []= new BulkReply($arg);
+ }
+
+ return new MultiBulkReply($models);
+ }
+
+ public function getValueNative()
+ {
+ $ret = $this->args;
+ array_unshift($ret, $this->command);
+
+ return $ret;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getRequestMessage($this->command, $this->args);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php
new file mode 100644
index 0000000..4ea2fcd
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Model/StatusReply.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Clue\Redis\Protocol\Model;
+
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+/**
+ *
+ * @link http://redis.io/topics/protocol#status-reply
+ */
+class StatusReply implements ModelInterface
+{
+ private $message;
+
+ /**
+ * create status reply (single line message)
+ *
+ * @param string|Status $message
+ * @return string
+ */
+ public function __construct($message)
+ {
+ $this->message = $message;
+ }
+
+ public function getValueNative()
+ {
+ return $this->message;
+ }
+
+ public function getMessageSerialized(SerializerInterface $serializer)
+ {
+ return $serializer->getStatusMessage($this->message);
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php
new file mode 100644
index 0000000..c1e3001
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/MessageBuffer.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use UnderflowException;
+
+class MessageBuffer implements ParserInterface
+{
+ private $parser;
+ private $incomingQueue = array();
+
+ public function __construct(ParserInterface $parser)
+ {
+ $this->parser = $parser;
+ }
+
+ public function popIncomingModel()
+ {
+ if (!$this->incomingQueue) {
+ throw new UnderflowException('Incoming message queue is empty');
+ }
+ return array_shift($this->incomingQueue);
+ }
+
+ public function hasIncomingModel()
+ {
+ return ($this->incomingQueue) ? true : false;
+ }
+
+ public function pushIncoming($data)
+ {
+ $ret = $this->parser->pushIncoming($data);
+
+ foreach ($ret as $one) {
+ $this->incomingQueue []= $one;
+ }
+
+ return $ret;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php
new file mode 100644
index 0000000..e57c5bc
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use UnexpectedValueException;
+
+class ParserException extends UnexpectedValueException
+{
+
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php
new file mode 100644
index 0000000..a322719
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ParserInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Parser\ParserException;
+
+interface ParserInterface
+{
+ /**
+ * push a chunk of the redis protocol message into the buffer and parse
+ *
+ * You can push any number of bytes of a redis protocol message into the
+ * parser and it will try to parse messages from its data stream. So you can
+ * pass data directly from your socket stream and the parser will return the
+ * right amount of message model objects for you.
+ *
+ * If you pass an incomplete message, expect it to return an empty array. If
+ * your incomplete message is split to across multiple chunks, the parsed
+ * message model will be returned once the parser has sufficient data.
+ *
+ * @param string $dataChunk
+ * @return ModelInterface[] 0+ message models
+ * @throws ParserException if the message can not be parsed
+ * @see self::popIncomingModel()
+ */
+ public function pushIncoming($dataChunk);
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php
new file mode 100644
index 0000000..a47d137
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/RequestParser.php
@@ -0,0 +1,125 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use Clue\Redis\Protocol\Parser\ParserException;
+use Clue\Redis\Protocol\Model\Request;
+
+class RequestParser implements ParserInterface
+{
+ const CRLF = "\r\n";
+
+ private $incomingBuffer = '';
+ private $incomingOffset = 0;
+
+ public function pushIncoming($dataChunk)
+ {
+ $this->incomingBuffer .= $dataChunk;
+
+ $parsed = array();
+
+ do {
+ $saved = $this->incomingOffset;
+ $message = $this->readRequest();
+ if ($message === null) {
+ // restore previous position for next parsing attempt
+ $this->incomingOffset = $saved;
+ break;
+ }
+
+ if ($message !== false) {
+ $parsed []= $message;
+ }
+ } while($this->incomingBuffer !== '');
+
+ if ($this->incomingOffset !== 0) {
+ $this->incomingBuffer = (string)substr($this->incomingBuffer, $this->incomingOffset);
+ $this->incomingOffset = 0;
+ }
+
+ return $parsed;
+ }
+
+ /**
+ * try to parse request from incoming buffer
+ *
+ * @throws ParserException if the incoming buffer is invalid
+ * @return Request|null
+ */
+ private function readRequest()
+ {
+ $crlf = strpos($this->incomingBuffer, "\r\n", $this->incomingOffset);
+ if ($crlf === false) {
+ return null;
+ }
+
+ // line starts with a multi-bulk header "*"
+ if (isset($this->incomingBuffer[$this->incomingOffset]) && $this->incomingBuffer[$this->incomingOffset] === '*') {
+ $line = substr($this->incomingBuffer, $this->incomingOffset + 1, $crlf - $this->incomingOffset + 1);
+ $this->incomingOffset = $crlf + 2;
+ $count = (int)$line;
+
+ if ($count <= 0) {
+ return false;
+ }
+ $command = null;
+ $args = array();
+ for ($i = 0; $i < $count; ++$i) {
+ $sub = $this->readBulk();
+ if ($sub === null) {
+ return null;
+ }
+ if ($command === null) {
+ $command = $sub;
+ } else {
+ $args []= $sub;
+ }
+ }
+ return new Request($command, $args);
+ }
+
+ // parse an old inline request instead
+ $line = substr($this->incomingBuffer, $this->incomingOffset, $crlf - $this->incomingOffset);
+ $this->incomingOffset = $crlf + 2;
+
+ $args = preg_split('/ +/', trim($line, ' '));
+ $command = array_shift($args);
+
+ if ($command === '') {
+ return false;
+ }
+
+ return new Request($command, $args);
+ }
+
+ private function readBulk()
+ {
+ $crlf = strpos($this->incomingBuffer, "\r\n", $this->incomingOffset);
+ if ($crlf === false) {
+ return null;
+ }
+
+ // line has to start with a bulk header "$"
+ if (!isset($this->incomingBuffer[$this->incomingOffset]) || $this->incomingBuffer[$this->incomingOffset] !== '$') {
+ throw new ParserException('ERR Protocol error: expected \'$\', got \'' . substr($this->incomingBuffer, $this->incomingOffset, 1) . '\'');
+ }
+
+ $line = substr($this->incomingBuffer, $this->incomingOffset + 1, $crlf - $this->incomingOffset + 1);
+ $this->incomingOffset = $crlf + 2;
+ $size = (int)$line;
+
+ if ($size < 0) {
+ throw new ParserException('ERR Protocol error: invalid bulk length');
+ }
+
+ if (!isset($this->incomingBuffer[$this->incomingOffset + $size + 1])) {
+ // check enough bytes + crlf are buffered
+ return null;
+ }
+
+ $ret = substr($this->incomingBuffer, $this->incomingOffset, $size);
+ $this->incomingOffset += $size + 2;
+
+ return $ret;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php
new file mode 100644
index 0000000..19ac90c
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Parser/ResponseParser.php
@@ -0,0 +1,151 @@
+<?php
+
+namespace Clue\Redis\Protocol\Parser;
+
+use Clue\Redis\Protocol\Parser\ParserInterface;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\ErrorReply;
+use Clue\Redis\Protocol\Model\IntegerReply;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Model\StatusReply;
+use Clue\Redis\Protocol\Parser\ParserException;
+
+/**
+ * Simple recursive redis wire protocol parser
+ *
+ * Heavily influenced by blocking parser implementation from jpd/redisent.
+ *
+ * @link https://github.com/jdp/redisent
+ * @link http://redis.io/topics/protocol
+ */
+class ResponseParser implements ParserInterface
+{
+ const CRLF = "\r\n";
+
+ private $incomingBuffer = '';
+ private $incomingOffset = 0;
+
+ public function pushIncoming($dataChunk)
+ {
+ $this->incomingBuffer .= $dataChunk;
+
+ return $this->tryParsingIncomingMessages();
+ }
+
+ private function tryParsingIncomingMessages()
+ {
+ $messages = array();
+
+ do {
+ $message = $this->readResponse();
+ if ($message === null) {
+ // restore previous position for next parsing attempt
+ $this->incomingOffset = 0;
+ break;
+ }
+
+ $messages []= $message;
+
+ $this->incomingBuffer = (string)substr($this->incomingBuffer, $this->incomingOffset);
+ $this->incomingOffset = 0;
+ } while($this->incomingBuffer !== '');
+
+ return $messages;
+ }
+
+ private function readLine()
+ {
+ $pos = strpos($this->incomingBuffer, "\r\n", $this->incomingOffset);
+
+ if ($pos === false) {
+ return null;
+ }
+
+ $ret = (string)substr($this->incomingBuffer, $this->incomingOffset, $pos - $this->incomingOffset);
+ $this->incomingOffset = $pos + 2;
+
+ return $ret;
+ }
+
+ private function readLength($len)
+ {
+ $ret = substr($this->incomingBuffer, $this->incomingOffset, $len);
+ if (strlen($ret) !== $len) {
+ return null;
+ }
+
+ $this->incomingOffset += $len;
+
+ return $ret;
+ }
+
+ /**
+ * try to parse response from incoming buffer
+ *
+ * ripped from jdp/redisent, with some minor modifications to read from
+ * the incoming buffer instead of issuing a blocking fread on a stream
+ *
+ * @throws ParserException if the incoming buffer is invalid
+ * @return ModelInterface|null
+ * @link https://github.com/jdp/redisent
+ */
+ private function readResponse()
+ {
+ /* Parse the response based on the reply identifier */
+ $reply = $this->readLine();
+ if ($reply === null) {
+ return null;
+ }
+ switch (substr($reply, 0, 1)) {
+ /* Error reply */
+ case '-':
+ $response = new ErrorReply(substr($reply, 1));
+ break;
+ /* Inline reply */
+ case '+':
+ $response = new StatusReply(substr($reply, 1));
+ break;
+ /* Bulk reply */
+ case '$':
+ $size = (int)substr($reply, 1);
+ if ($size === -1) {
+ return new BulkReply(null);
+ }
+ $data = $this->readLength($size);
+ if ($data === null) {
+ return null;
+ }
+ if ($this->readLength(2) === null) { /* discard crlf */
+ return null;
+ }
+ $response = new BulkReply($data);
+ break;
+ /* Multi-bulk reply */
+ case '*':
+ $count = (int)substr($reply, 1);
+ if ($count === -1) {
+ return new MultiBulkReply(null);
+ }
+ $response = array();
+ for ($i = 0; $i < $count; $i++) {
+ $sub = $this->readResponse();
+ if ($sub === null) {
+ return null;
+ }
+ $response []= $sub;
+ }
+ $response = new MultiBulkReply($response);
+ break;
+ /* Integer reply */
+ case ':':
+ $response = new IntegerReply(substr($reply, 1));
+ break;
+ default:
+ throw new ParserException('Invalid message can not be parsed: "' . $reply . '"');
+ break;
+ }
+ /* Party on */
+ return $response;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php
new file mode 100644
index 0000000..6e25125
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/RecursiveSerializer.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace Clue\Redis\Protocol\Serializer;
+
+use Clue\Redis\Protocol\Model\StatusReply;
+use InvalidArgumentException;
+use Exception;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\IntegerReply;
+use Clue\Redis\Protocol\Model\ErrorReply;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\Request;
+
+class RecursiveSerializer implements SerializerInterface
+{
+ const CRLF = "\r\n";
+
+ public function getRequestMessage($command, array $args = array())
+ {
+ $data = '*' . (count($args) + 1) . "\r\n$" . strlen($command) . "\r\n" . $command . "\r\n";
+ foreach ($args as $arg) {
+ $data .= '$' . strlen($arg) . "\r\n" . $arg . "\r\n";
+ }
+ return $data;
+ }
+
+ public function createRequestModel($command, array $args = array())
+ {
+ return new Request($command, $args);
+ }
+
+ public function getReplyMessage($data)
+ {
+ if (is_string($data) || $data === null) {
+ return $this->getBulkMessage($data);
+ } else if (is_int($data) || is_float($data) || is_bool($data)) {
+ return $this->getIntegerMessage($data);
+ } else if ($data instanceof Exception) {
+ return $this->getErrorMessage($data->getMessage());
+ } else if (is_array($data)) {
+ return $this->getMultiBulkMessage($data);
+ } else {
+ throw new InvalidArgumentException('Invalid data type passed for serialization');
+ }
+ }
+
+ public function createReplyModel($data)
+ {
+ if (is_string($data) || $data === null) {
+ return new BulkReply($data);
+ } else if (is_int($data) || is_float($data) || is_bool($data)) {
+ return new IntegerReply($data);
+ } else if ($data instanceof Exception) {
+ return new ErrorReply($data->getMessage());
+ } else if (is_array($data)) {
+ $models = array();
+ foreach ($data as $one) {
+ $models []= $this->createReplyModel($one);
+ }
+ return new MultiBulkReply($models);
+ } else {
+ throw new InvalidArgumentException('Invalid data type passed for serialization');
+ }
+ }
+
+ public function getBulkMessage($data)
+ {
+ if ($data === null) {
+ /* null bulk reply */
+ return '$-1' . self::CRLF;
+ }
+ /* bulk reply */
+ return '$' . strlen($data) . self::CRLF . $data . self::CRLF;
+ }
+
+ public function getErrorMessage($data)
+ {
+ /* error status reply */
+ return '-' . $data . self::CRLF;
+ }
+
+ public function getIntegerMessage($data)
+ {
+ return ':' . (int)$data . self::CRLF;
+ }
+
+ public function getMultiBulkMessage($data)
+ {
+ if ($data === null) {
+ /* null multi bulk reply */
+ return '*-1' . self::CRLF;
+ }
+ /* multi bulk reply */
+ $ret = '*' . count($data) . self::CRLF;
+ foreach ($data as $one) {
+ if ($one instanceof ModelInterface) {
+ $ret .= $one->getMessageSerialized($this);
+ } else {
+ $ret .= $this->getReplyMessage($one);
+ }
+ }
+ return $ret;
+ }
+
+ public function getStatusMessage($data)
+ {
+ /* status reply */
+ return '+' . $data . self::CRLF;
+ }
+}
diff --git a/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php
new file mode 100644
index 0000000..bb7cb3e
--- /dev/null
+++ b/vendor/clue/redis-protocol/src/Clue/Redis/Protocol/Serializer/SerializerInterface.php
@@ -0,0 +1,83 @@
+<?php
+
+namespace Clue\Redis\Protocol\Serializer;
+
+use Clue\Redis\Protocol\Model\ErrorReplyException;
+use Clue\Redis\Protocol\Model\ModelInterface;
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+
+interface SerializerInterface
+{
+ /**
+ * create a serialized unified request protocol message
+ *
+ * This is the *one* method most redis client libraries will likely want to
+ * use in order to send a serialized message (a request) over the* wire to
+ * your redis server instance.
+ *
+ * This method should be used in favor of constructing a request model and
+ * then serializing it. While its effect might be equivalent, this method
+ * is likely to (i.e. it /could/) provide a faster implementation.
+ *
+ * @param string $command
+ * @param array $args
+ * @return string
+ * @see self::createRequestMessage()
+ */
+ public function getRequestMessage($command, array $args = array());
+
+ /**
+ * create a unified request protocol message model
+ *
+ * @param string $command
+ * @param array $args
+ * @return MultiBulkReply
+ */
+ public function createRequestModel($command, array $args = array());
+
+ /**
+ * create a serialized unified protocol reply message
+ *
+ * This is most useful for a redis server implementation which needs to
+ * process client requests and send resulting reply messages.
+ *
+ * This method does its best to guess to right reply type and then returns
+ * a serialized version of the message. It follows the "redis to lua
+ * conversion table" (see link) which means most basic types can be mapped
+ * as is.
+ *
+ * This method should be used in favor of constructing a reply model and
+ * then serializing it. While its effect might be equivalent, this method
+ * is likely to (i.e. it /could/) provide a faster implementation.
+ *
+ * Note however, you may still want to explicitly create a nested reply
+ * model hierarchy if you need more control over the serialized message. For
+ * instance, a null value will always be returned as a Null-Bulk-Reply, so
+ * there's no way to express a Null-Multi-Bulk-Reply, unless you construct
+ * it explicitly.
+ *
+ * @param mixed $data
+ * @return string
+ * @see self::createReplyModel()
+ * @link http://redis.io/commands/eval
+ */
+ public function getReplyMessage($data);
+
+ /**
+ * create response message by determining datatype from given argument
+ *
+ * @param mixed $data
+ * @return ModelInterface
+ */
+ public function createReplyModel($data);
+
+ public function getBulkMessage($data);
+
+ public function getErrorMessage($data);
+
+ public function getIntegerMessage($data);
+
+ public function getMultiBulkMessage($data);
+
+ public function getStatusMessage($data);
+}
diff --git a/vendor/clue/redis-protocol/tests/FactoryTest.php b/vendor/clue/redis-protocol/tests/FactoryTest.php
new file mode 100644
index 0000000..b669223
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/FactoryTest.php
@@ -0,0 +1,34 @@
+<?php
+
+use Clue\Redis\Protocol\Factory;
+
+class FactoryTest extends TestCase
+{
+ private $factory;
+
+ public function setUp()
+ {
+ $this->factory = new Factory();
+ }
+
+ public function testCreateResponseParser()
+ {
+ $parser = $this->factory->createResponseParser();
+
+ $this->assertInstanceOf('Clue\Redis\Protocol\Parser\ParserInterface', $parser);
+ }
+
+ public function testCreateRequestParser()
+ {
+ $parser = $this->factory->createRequestParser();
+
+ $this->assertInstanceOf('Clue\Redis\Protocol\Parser\ParserInterface', $parser);
+ }
+
+ public function testCreateSerializer()
+ {
+ $serializer = $this->factory->createSerializer();
+
+ $this->assertInstanceOf('Clue\Redis\Protocol\Serializer\SerializerInterface', $serializer);
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Model/AbstractModelTest.php b/vendor/clue/redis-protocol/tests/Model/AbstractModelTest.php
new file mode 100644
index 0000000..1358533
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Model/AbstractModelTest.php
@@ -0,0 +1,22 @@
+<?php
+
+use Clue\Redis\Protocol\Serializer\RecursiveSerializer;
+
+abstract class AbstractModelTest extends TestCase
+{
+ protected $serializer;
+
+ abstract protected function createModel($value);
+
+ public function setUp()
+ {
+ $this->serializer = new RecursiveSerializer();
+ }
+
+ public function testConstructor()
+ {
+ $model = $this->createModel(null);
+
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\ModelInterface', $model);
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Model/BulkReplyTest.php b/vendor/clue/redis-protocol/tests/Model/BulkReplyTest.php
new file mode 100644
index 0000000..78ed04c
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Model/BulkReplyTest.php
@@ -0,0 +1,43 @@
+<?php
+
+use Clue\Redis\Protocol\Model\BulkReply;
+
+class BulkReplyTest extends AbstractModelTest
+{
+ protected function createModel($value)
+ {
+ return new BulkReply($value);
+ }
+
+ public function testStringReply()
+ {
+ $model = $this->createModel('test');
+
+ $this->assertEquals('test', $model->getValueNative());
+ $this->assertEquals("$4\r\ntest\r\n", $model->getMessageSerialized($this->serializer));
+ }
+
+ public function testEmptyStringReply()
+ {
+ $model = $this->createModel('');
+
+ $this->assertEquals('', $model->getValueNative());
+ $this->assertEquals("$0\r\n\r\n", $model->getMessageSerialized($this->serializer));
+ }
+
+ public function testIntegerCast()
+ {
+ $model = $this->createModel(123);
+
+ $this->assertEquals('123', $model->getValueNative());
+ $this->assertEquals("$3\r\n123\r\n", $model->getMessageSerialized($this->serializer));
+ }
+
+ public function testNullBulkReply()
+ {
+ $model = $this->createModel(null);
+
+ $this->assertEquals(null, $model->getValueNative());
+ $this->assertEquals("$-1\r\n", $model->getMessageSerialized($this->serializer));
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Model/ErrorReplyTest.php b/vendor/clue/redis-protocol/tests/Model/ErrorReplyTest.php
new file mode 100644
index 0000000..2585b08
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Model/ErrorReplyTest.php
@@ -0,0 +1,19 @@
+<?php
+
+use Clue\Redis\Protocol\Model\ErrorReply;
+
+class ErrorReplyTest extends AbstractModelTest
+{
+ protected function createModel($value)
+ {
+ return new ErrorReply($value);
+ }
+
+ public function testError()
+ {
+ $model = $this->createModel('ERR error');
+
+ $this->assertEquals('ERR error', $model->getValueNative());
+ $this->assertEquals("-ERR error\r\n", $model->getMessageSerialized($this->serializer));
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Model/IntegerReplyTest.php b/vendor/clue/redis-protocol/tests/Model/IntegerReplyTest.php
new file mode 100644
index 0000000..f6a2e10
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Model/IntegerReplyTest.php
@@ -0,0 +1,40 @@
+<?php
+
+use Clue\Redis\Protocol\Model\IntegerReply;
+
+class IntegerReplyTest extends AbstractModelTest
+{
+ protected function createModel($value)
+ {
+ return new IntegerReply($value);
+ }
+
+ public function testIntegerReply()
+ {
+ $model = $this->createModel(0);
+ $this->assertEquals(0, $model->getValueNative());
+ $this->assertEquals(":0\r\n", $model->getMessageSerialized($this->serializer));
+ }
+
+ public function testFloatCasted()
+ {
+ $model = $this->createModel(-12.99);
+ $this->assertEquals(-12, $model->getValueNative());
+ $this->assertEquals(":-12\r\n", $model->getMessageSerialized($this->serializer));
+
+ $model = $this->createModel(14.99);
+ $this->assertEquals(14, $model->getValueNative());
+ $this->assertEquals(":14\r\n", $model->getMessageSerialized($this->serializer));
+ }
+
+ public function testBooleanCasted()
+ {
+ $model = $this->createModel(true);
+ $this->assertEquals(1, $model->getValueNative());
+ $this->assertEquals(":1\r\n", $model->getMessageSerialized($this->serializer));
+
+ $model = $this->createModel(false);
+ $this->assertEquals(0, $model->getValueNative());
+ $this->assertEquals(":0\r\n", $model->getMessageSerialized($this->serializer));
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Model/MultiBulkReplyTest.php b/vendor/clue/redis-protocol/tests/Model/MultiBulkReplyTest.php
new file mode 100644
index 0000000..04dd389
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Model/MultiBulkReplyTest.php
@@ -0,0 +1,115 @@
+<?php
+
+use Clue\Redis\Protocol\Model\MultiBulkReply;
+use Clue\Redis\Protocol\Model\BulkReply;
+use Clue\Redis\Protocol\Model\IntegerReply;
+
+class MultiBulkReplyTest extends AbstractModelTest
+{
+ protected function createModel($value)
+ {
+ return new MultiBulkReply($value);
+ }
+
+ public function testEmptyArray()
+ {
+ $model = $this->createModel(array());
+
+ $this->assertEquals(array(), $model->getValueNative());
+ $this->assertEquals("*0\r\n", $model->getMessageSerialized($this->serializer));
+
+ $this->assertFalse($model->isRequest());
+ }
+
+ public function testNullMultiBulkReply()
+ {
+ $model = $this->createModel(null);
+
+ $this->assertEquals(null, $model->getValueNative());
+ $this->assertEquals("*-1\r\n", $model->getMessageSerialized($this->serializer));
+
+ $this->assertFalse($model->isRequest());
+
+ return $model;
+ }
+
+ /**
+ * @param MultiBulkReply $model
+ * @depends testNullMultiBulkReply
+ * @expectedException UnexpectedValueException
+ */
+ public function testNullMultiBulkReplyIsNotARequest(MultiBulkReply $model)
+ {
+ $model->getRequestModel();
+ }
+
+ public function testSingleBulkEnclosed()
+ {
+ $model = $this->createModel(array(new BulkReply('test')));
+
+ $this->assertEquals(array('test'), $model->getValueNative());
+ $this->assertEquals("*1\r\n$4\r\ntest\r\n", $model->getMessageSerialized($this->serializer));
+
+ $this->assertTrue($model->isRequest());
+
+ // this can be represented by a request
+ $request = $model->getRequestModel();
+ $this->assertEquals($model->getValueNative(), $request->getValueNative());
+
+ // representing the request as a reply should return our original instance
+ $reply = $request->getReplyModel();
+ $this->assertEquals($model, $reply);
+
+ return $model;
+ }
+
+ /**
+ * @depends testSingleBulkEnclosed
+ */
+ public function testStringEnclosedEqualsSingleBulk(MultiBulkReply $expected)
+ {
+ $model = $this->createModel(array('test'));
+
+ $this->assertEquals($expected->getValueNative(), $model->getValueNative());
+ $this->assertEquals($expected->getMessageSerialized($this->serializer), $model->getMessageSerialized($this->serializer));
+
+ $this->assertTrue($model->isRequest());
+ }
+
+ public function testMixedReply()
+ {
+ $model = $this->createModel(array(new BulkReply('test'), new IntegerReply(123)));
+
+ $this->assertEquals(array('test', 123), $model->getValueNative());
+ $this->assertEquals("*2\r\n$4\r\ntest\r\n:123\r\n", $model->getMessageSerialized($this->serializer));
+
+ $this->assertFalse($model->isRequest());
+
+ return $model;
+ }
+
+ /**
+ * @param MultiBulkReply $model
+ * @depends testMixedReply
+ * @expectedException UnexpectedValueException
+ */
+ public function testMixedReplyIsNotARequest(MultiBulkReply $model)
+ {
+ $model->getRequestModel();
+ }
+
+ public function testMultiStrings()
+ {
+ $model = $this->createModel(array('SET', 'a', 'b'));
+
+ $this->assertEquals(array('SET', 'a', 'b'), $model->getValueNative());
+
+ $this->assertTrue($model->isRequest());
+
+ $request = $model->getRequestModel();
+
+ // this can be represented by a request
+ $request = $model->getRequestModel();
+ $this->assertEquals($model->getValueNative(), $request->getValueNative());
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Model/RequestTest.php b/vendor/clue/redis-protocol/tests/Model/RequestTest.php
new file mode 100644
index 0000000..6719481
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Model/RequestTest.php
@@ -0,0 +1,37 @@
+<?php
+
+use Clue\Redis\Protocol\Model\Request;
+
+class RequestTest extends AbstractModelTest
+{
+ protected function createModel($value)
+ {
+ return new Request('QUIT');
+ }
+
+ public function testPing()
+ {
+ $model = new Request('PING');
+
+ $this->assertEquals('PING', $model->getCommand());
+ $this->assertEquals(array(), $model->getArgs());
+ $this->assertEquals(array('PING'), $model->getValueNative());
+ $this->assertEquals("*1\r\n$4\r\nPING\r\n", $model->getMessageSerialized($this->serializer));
+
+ $reply = $model->getReplyModel();
+ $this->assertEquals($model->getValueNative(), $reply->getValueNative());
+ }
+
+ public function testGet()
+ {
+ $model = new Request('GET', array('a'));
+
+ $this->assertEquals('GET', $model->getCommand());
+ $this->assertEquals(array('a'), $model->getArgs());
+ $this->assertEquals(array('GET', 'a'), $model->getValueNative());
+ $this->assertEquals("*2\r\n$3\r\nGET\r\n$1\r\na\r\n", $model->getMessageSerialized($this->serializer));
+
+ $reply = $model->getReplyModel();
+ $this->assertEquals($model->getValueNative(), $reply->getValueNative());
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Model/StatusReplyTest.php b/vendor/clue/redis-protocol/tests/Model/StatusReplyTest.php
new file mode 100644
index 0000000..8debd85
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Model/StatusReplyTest.php
@@ -0,0 +1,19 @@
+<?php
+
+use Clue\Redis\Protocol\Model\StatusReply;
+
+class StatusReplyTest extends AbstractModelTest
+{
+ protected function createModel($value)
+ {
+ return new StatusReply($value);
+ }
+
+ public function testStatusOk()
+ {
+ $model = $this->createModel('OK');
+
+ $this->assertEquals('OK', $model->getValueNative());
+ $this->assertEquals("+OK\r\n", $model->getMessageSerialized($this->serializer));
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Parser/AbstractParserTest.php b/vendor/clue/redis-protocol/tests/Parser/AbstractParserTest.php
new file mode 100644
index 0000000..3d45c20
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Parser/AbstractParserTest.php
@@ -0,0 +1,67 @@
+<?php
+
+use Clue\Redis\Protocol\Parser\ParserInterface;
+use Clue\Redis\Protocol\Parser\MessageBuffer;
+
+abstract class AbstractParserTest extends TestCase
+{
+ /**
+ *
+ * @var ParserInterface
+ */
+ protected $parser;
+
+ abstract protected function createParser();
+
+ public function setUp()
+ {
+ $this->parser = $this->createParser();
+ $this->assertInstanceOf('Clue\Redis\Protocol\Parser\ParserInterface', $this->parser);
+ }
+
+ public function testParsingMessageOne()
+ {
+ // getRequestMessage('test')
+ $message = $expected = "*1\r\n$4\r\ntest\r\n";
+
+ $models = $this->parser->pushIncoming($message);
+ $this->assertCount(1, $models);
+
+ $model = reset($models);
+ $this->assertEquals(array('test'), $model->getValueNative());
+ }
+
+ public function testParsingMessageTwoPartial()
+ {
+ // getRequestMessage('test', array('second'))
+ $message = "*2\r\n$4\r\ntest\r\n$6\r\nsecond\r\n";
+
+ $this->assertEquals(array(), $this->parser->pushIncoming(substr($message, 0, 1)));
+ $this->assertEquals(array(), $this->parser->pushIncoming(substr($message, 1, 1)));
+ $this->assertEquals(array(), $this->parser->pushIncoming(substr($message, 2, 1)));
+ $this->assertEquals(array(), $this->parser->pushIncoming(substr($message, 3, 10)));
+ $this->assertCount(1, $models = $this->parser->pushIncoming(substr($message, 13)));
+
+ $model = reset($models);
+
+ $this->assertEquals(array('test', 'second'), $model->getValueNative());
+ }
+
+ public function testMessageBuffer()
+ {
+ $buffer = new MessageBuffer($this->parser);
+
+ $this->assertFalse($buffer->hasIncomingModel());
+
+ $data = "*1\r\n$4\r\ntest\r\n";
+ $this->assertCount(1, $models = $buffer->pushIncoming($data));
+ $this->assertTrue($buffer->hasIncomingModel());
+
+ $expected = reset($models);
+ $this->assertSame($expected, $buffer->popIncomingModel());
+ $this->assertFalse($buffer->hasIncomingModel());
+
+ $this->setExpectedException('UnderflowException');
+ $buffer->popIncomingModel();
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Parser/RequestParserTest.php b/vendor/clue/redis-protocol/tests/Parser/RequestParserTest.php
new file mode 100644
index 0000000..645b673
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Parser/RequestParserTest.php
@@ -0,0 +1,132 @@
+<?php
+
+use Clue\Redis\Protocol\Parser\RequestParser;
+
+class RequestParserTest extends AbstractParserTest
+{
+ protected function createParser()
+ {
+ return new RequestParser();
+ }
+
+ public function testSimplePingRequest()
+ {
+ $message = "*1\r\n$4\r\nping\r\n";
+
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $request = reset($models);
+
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\Request', $request);
+ $this->assertEquals('ping', $request->getCommand());
+ $this->assertEquals(array(), $request->getArgs());
+
+ return $request;
+ }
+
+ /**
+ *
+ * @param Request $expected
+ * @depends testSimplePingRequest
+ */
+ public function testInlinePingRequest($expected)
+ {
+ $message = "ping\r\n";
+
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $request = reset($models);
+
+ $this->assertEquals($expected, $request);
+ }
+
+ public function testInlineWhitespaceIsIgnored()
+ {
+ $message = " set name value \r\n";
+
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $request = reset($models);
+
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\Request', $request);
+ $this->assertEquals('set', $request->getCommand());
+ $this->assertEquals(array('name', 'value'), $request->getArgs());
+ }
+
+ public function testIncompleteSuccessive()
+ {
+ $this->assertEquals(array(), $this->parser->pushIncoming("*1\r\n"));
+ $this->assertEquals(array(), $this->parser->pushIncoming("$4\r\n"));
+ $this->assertEquals(array(), $this->parser->pushIncoming("test"));
+ $this->assertCount(1, $models = $this->parser->pushIncoming("\r\n"));
+ }
+
+ public function testNullMultiBulkRequestIsIgnored()
+ {
+ $message = "*-1\r\n";
+
+ $this->assertEquals(array(), $this->parser->pushIncoming($message));
+ }
+
+ public function testEmptyMultiBulkRequestIsIgnored()
+ {
+ $message = "*0\r\n";
+
+ $this->assertEquals(array(), $this->parser->pushIncoming($message));
+ }
+
+ public function testEmptyInlineIsIgnored()
+ {
+ $message = "\r\n";
+
+ $this->assertEquals(array(), $this->parser->pushIncoming($message));
+ }
+
+ public function testInlineParsesMultipleRequestsAtOnce()
+ {
+ $message = "hello\r\n\world\r\ntest\r\n";
+
+ $this->assertCount(3, $models = $this->parser->pushIncoming($message));
+ }
+
+
+ public function testEmptyInlineAroundInlineIsIgnored()
+ {
+ $message = "\r\n\r\n" . "ping\r\n\r\n";
+
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $request = reset($models);
+
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\Request', $request);
+ $this->assertEquals('ping', $request->getCommand());
+ $this->assertEquals(array(), $request->getArgs());
+ }
+
+ public function testWhitespaceInlineIsIgnored()
+ {
+ $message = " \r\n";
+
+ $this->assertEquals(array(), $this->parser->pushIncoming($message));
+ }
+
+ /**
+ * @expectedException Clue\Redis\Protocol\Parser\ParserException
+ */
+ public function testInvalidMultiBulkMustContainBulk()
+ {
+ $message = "*1\r\n:123\r\n";
+
+ $this->parser->pushIncoming($message);
+ }
+
+ /**
+ * @expectedException Clue\Redis\Protocol\Parser\ParserException
+ */
+ public function testInvalidBulkLength()
+ {
+ $message = "*1\r\n$-1\r\n";
+
+ $this->parser->pushIncoming($message);
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Parser/ResponseParserTest.php b/vendor/clue/redis-protocol/tests/Parser/ResponseParserTest.php
new file mode 100644
index 0000000..762c8bd
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Parser/ResponseParserTest.php
@@ -0,0 +1,130 @@
+<?php
+
+use Clue\Redis\Protocol\Parser\ResponseParser;
+
+class RecursiveParserTest extends AbstractParserTest
+{
+ protected function createParser()
+ {
+ return new ResponseParser();
+ }
+
+ public function testPartialIncompleteBulkReply()
+ {
+ $this->assertEquals(array(), $this->parser->pushIncoming("$20\r\nincompl"));
+ }
+
+ public function testParsingStatusReplies()
+ {
+ // C: PING
+ $message = "+PONG\r\n";
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals('PONG', $data);
+
+ // C: SET key value
+ $message = "+OK\r\n";
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals('OK', $data);
+ }
+
+ public function testParsingErrorReply()
+ {
+ $message = "-WRONGTYPE Operation against a key holding the wrong kind of value\r\n";
+
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+ $exception = reset($models);
+
+ $this->assertInstanceOf('Exception', $exception);
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\ErrorReply', $exception);
+ $this->assertEquals('WRONGTYPE Operation against a key holding the wrong kind of value', $exception->getMessage());
+ }
+
+ public function testParsingIntegerReply()
+ {
+ // C: INCR mykey
+ $message = ":1\r\n";
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals(1, $data);
+ }
+
+ public function testParsingBulkReply()
+ {
+ // C: GET mykey
+ $message = "$6\r\nfoobar\r\n";
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals("foobar", $data);
+ }
+
+ public function testParsingNullBulkReply()
+ {
+ // C: GET nonexistingkey
+ $message = "$-1\r\n";
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals(null, $data);
+ }
+
+ public function testParsingEmptyMultiBulkReply()
+ {
+ // C: LRANGE nokey 0 1
+ $message = "*0\r\n";
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals(array(), $data);
+ }
+
+ public function testParsingNullMultiBulkReply()
+ {
+ // C: BLPOP key 1
+ $message = "*-1\r\n";
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals(null, $data);
+ }
+
+ public function testParsingMultiBulkReplyWithMixedElements()
+ {
+ $message = "*5\r\n:1\r\n:2\r\n:3\r\n:4\r\n$6\r\nfoobar\r\n";
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals(array(1, 2, 3, 4, 'foobar'), $data);
+ }
+
+ public function testParsingMultiBulkReplyWithIncompletePush()
+ {
+ $this->assertCount(0, $this->parser->pushIncoming("*5\r\n:1\r\n:2\r"));
+ $this->assertCount(1, $models = $this->parser->pushIncoming("\n:3\r\n:4\r\n$6\r\nfoobar\r\n"));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals(array(1, 2, 3, 4, 'foobar'), $data);
+ }
+
+ public function testParsingMultiBulkReplyWithNullElement()
+ {
+ $message = "*3\r\n$3\r\nfoo\r\n$-1\r\n$3\r\nbar\r\n";
+ $this->assertCount(1, $models = $this->parser->pushIncoming($message));
+
+ $data = reset($models)->getValueNative();
+ $this->assertEquals(array('foo', null, 'bar'), $data);
+ }
+
+ /**
+ * @expectedException Clue\Redis\Protocol\Parser\ParserException
+ */
+ public function testParseError()
+ {
+ $this->parser->pushIncoming("invalid string\r\n");
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/Serializer/AbstractSerializerTest.php b/vendor/clue/redis-protocol/tests/Serializer/AbstractSerializerTest.php
new file mode 100644
index 0000000..ba2200a
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Serializer/AbstractSerializerTest.php
@@ -0,0 +1,141 @@
+<?php
+
+use Clue\Redis\Protocol\Serializer\SerializerInterface;
+use Clue\Redis\Protocol\Model\Status;
+use Clue\Redis\Protocol\Model\ErrorReplyException;
+//use Exception;
+
+abstract class AbstractSerializerTest extends TestCase
+{
+ /**
+ * @return SerializerInterface
+ */
+ abstract protected function createSerializer();
+
+ public function setUp()
+ {
+ $this->serializer = $this->createSerializer();
+ }
+
+ public function testIntegerReply()
+ {
+ $model = $this->serializer->createReplyModel(0);
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\IntegerReply', $model);
+ $this->assertEquals(0, $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage(0));
+ }
+
+ public function testFloatCastIntegerReply()
+ {
+ $model = $this->serializer->createReplyModel(-12.99);
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\IntegerReply', $model);
+ $this->assertEquals(-12, $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage(-12.99));
+
+ $model = $this->serializer->createReplyModel(14.99);
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\IntegerReply', $model);
+ $this->assertEquals(14, $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage(14.99));
+ }
+
+ public function testBooleanCastIntegerReply()
+ {
+ $model = $this->serializer->createReplyModel(true);
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\IntegerReply', $model);
+ $this->assertEquals(1, $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage(true));
+
+ $model = $this->serializer->createReplyModel(false);
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\IntegerReply', $model);
+ $this->assertEquals(0, $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage(false));
+ }
+
+ public function testStringReply()
+ {
+ $model = $this->serializer->createReplyModel('test');
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\BulkReply', $model);
+ $this->assertEquals('test', $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage('test'));
+ }
+
+ public function testNullCastNullBulkReply()
+ {
+ $model = $this->serializer->createReplyModel(null);
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\BulkReply', $model);
+ $this->assertEquals(null, $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage(null));
+ }
+
+ public function testEmptyArrayMultiBulkReply()
+ {
+ $model = $this->serializer->createReplyModel(array());
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\MultiBulkReply', $model);
+ $this->assertEquals(array(), $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage(array()));
+ }
+
+ public function testArrayMultiBulkReply()
+ {
+ $model = $this->serializer->createReplyModel(array('test', 123));
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\MultiBulkReply', $model);
+ $this->assertEquals(array('test', 123), $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage(array('test', 123)));
+ }
+
+ public function testErrorReply()
+ {
+ $model = $this->serializer->createReplyModel(new Exception('ERR failure'));
+ $this->assertInstanceOf('Clue\Redis\Protocol\Model\ErrorReply', $model);
+ $this->assertEquals('ERR failure', $model->getValueNative());
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $this->serializer->getReplyMessage(new Exception('ERR failure')));
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testInvalidArgument()
+ {
+ $this->serializer->createReplyModel((object)array());
+ }
+
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testInvalidReplyData()
+ {
+ $this->serializer->getReplyMessage((object)array());
+ }
+
+ /**
+ *
+ * @param array $data
+ * @dataProvider provideRequestMessage
+ */
+ public function testRequestMessage($command, $args)
+ {
+ // the model is already unit-tested, so just compare against its message
+ $model = $this->serializer->createRequestModel($command, $args);
+
+ $message = $this->serializer->getRequestMessage($command, $args);
+
+ $this->assertEquals($model->getMessageSerialized($this->serializer), $message);
+ }
+
+ public function provideRequestMessage()
+ {
+ return array(
+ array('PING', array()),
+ array('GET', array('a')),
+ array('SET', array('a', 'b')),
+ array('SET', array('empty', ''))
+ );
+ }
+
+// public function testBenchCreateRequest()
+// {
+// for ($i = 0; $i < 100000; ++$i) {
+// $this->serializer->createReplyModel(array('a', 'b', 'c'));
+// }
+// }
+}
diff --git a/vendor/clue/redis-protocol/tests/Serializer/RecursiveSerializerTest.php b/vendor/clue/redis-protocol/tests/Serializer/RecursiveSerializerTest.php
new file mode 100644
index 0000000..fe62ac5
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/Serializer/RecursiveSerializerTest.php
@@ -0,0 +1,11 @@
+<?php
+
+use Clue\Redis\Protocol\Serializer\RecursiveSerializer;
+
+class RecursiveSerializerTest extends AbstractSerializerTest
+{
+ protected function createSerializer()
+ {
+ return new RecursiveSerializer();
+ }
+}
diff --git a/vendor/clue/redis-protocol/tests/bootstrap.php b/vendor/clue/redis-protocol/tests/bootstrap.php
new file mode 100644
index 0000000..0b2ea18
--- /dev/null
+++ b/vendor/clue/redis-protocol/tests/bootstrap.php
@@ -0,0 +1,7 @@
+<?php
+
+(include_once __DIR__ . '/../vendor/autoload.php') OR die(PHP_EOL . 'ERROR: composer autoloader not found, run "composer install" or see README for instructions' . PHP_EOL);
+
+class TestCase extends PHPUnit_Framework_TestCase
+{
+}