Просмотр исходного кода

Adding Esprima syntax validation, removing the need for phantomloader.

Jonny Wenmoth 11 лет назад
Родитель
Сommit
2950edfa3b
48 измененных файлов с 2117 добавлено и 1262 удалено
  1. 1 1
      composer.json
  2. 46 101
      src/JonnyW/PhantomJs/Client.php
  3. 13 35
      src/JonnyW/PhantomJs/ClientInterface.php
  4. 19 0
      src/JonnyW/PhantomJs/Exception/RequirementException.php
  5. 51 0
      src/JonnyW/PhantomJs/Exception/SyntaxException.php
  6. 20 18
      src/JonnyW/PhantomJs/Http/AbstractRequest.php
  7. 13 13
      src/JonnyW/PhantomJs/Http/CaptureRequest.php
  8. 1 1
      src/JonnyW/PhantomJs/Http/CaptureRequestInterface.php
  9. 12 12
      src/JonnyW/PhantomJs/Http/MessageFactory.php
  10. 11 11
      src/JonnyW/PhantomJs/Http/MessageFactoryInterface.php
  11. 3 3
      src/JonnyW/PhantomJs/Http/Request.php
  12. 3 3
      src/JonnyW/PhantomJs/Http/RequestInterface.php
  13. 9 6
      src/JonnyW/PhantomJs/Http/Response.php
  14. 1 1
      src/JonnyW/PhantomJs/Http/ResponseInterface.php
  15. 68 0
      src/JonnyW/PhantomJs/Procedure/Input.php
  16. 20 0
      src/JonnyW/PhantomJs/Procedure/InputInterface.php
  17. 110 0
      src/JonnyW/PhantomJs/Procedure/Output.php
  18. 26 0
      src/JonnyW/PhantomJs/Procedure/OutputInterface.php
  19. 37 31
      src/JonnyW/PhantomJs/Procedure/Procedure.php
  20. 16 9
      src/JonnyW/PhantomJs/Procedure/ProcedureInterface.php
  21. 4 4
      src/JonnyW/PhantomJs/Procedure/ProcedureLoader.php
  22. 116 0
      src/JonnyW/PhantomJs/Procedure/ProcedureValidator.php
  23. 30 0
      src/JonnyW/PhantomJs/Procedure/ProcedureValidatorInterface.php
  24. 13 4
      src/JonnyW/PhantomJs/Resources/config/config.yml
  25. 56 14
      src/JonnyW/PhantomJs/Resources/config/services.yml
  26. 18 18
      src/JonnyW/PhantomJs/Resources/procedures/http_capture.proc
  27. 13 13
      src/JonnyW/PhantomJs/Resources/procedures/http_default.proc
  28. 29 0
      src/JonnyW/PhantomJs/Resources/procedures/validator.proc
  29. 59 0
      src/JonnyW/PhantomJs/Resources/validators/esprima-2.0.0.js
  30. 8 41
      src/JonnyW/PhantomJs/Tests/Integration/ClientTest.php
  31. 294 0
      src/JonnyW/PhantomJs/Tests/Integration/Procedure/ProcedureValidatorTest.php
  32. 27 69
      src/JonnyW/PhantomJs/Tests/Unit/Cache/FileCacheTest.php
  33. 116 391
      src/JonnyW/PhantomJs/Tests/Unit/ClientTest.php
  34. 64 90
      src/JonnyW/PhantomJs/Tests/Unit/Http/CaptureRequestTest.php
  35. 28 35
      src/JonnyW/PhantomJs/Tests/Unit/Http/MessageFactoryTest.php
  36. 63 84
      src/JonnyW/PhantomJs/Tests/Unit/Http/RequestTest.php
  37. 48 50
      src/JonnyW/PhantomJs/Tests/Unit/Http/ResponseTest.php
  38. 15 37
      src/JonnyW/PhantomJs/Tests/Unit/Procedure/ChainProcedureLoaderTest.php
  39. 55 0
      src/JonnyW/PhantomJs/Tests/Unit/Procedure/InputTest.php
  40. 88 0
      src/JonnyW/PhantomJs/Tests/Unit/Procedure/OutputTest.php
  41. 27 20
      src/JonnyW/PhantomJs/Tests/Unit/Procedure/ProcedureFactoryTest.php
  42. 8 9
      src/JonnyW/PhantomJs/Tests/Unit/Procedure/ProcedureLoaderFactoryTest.php
  43. 79 42
      src/JonnyW/PhantomJs/Tests/Unit/Procedure/ProcedureLoaderTest.php
  44. 94 63
      src/JonnyW/PhantomJs/Tests/Unit/Procedure/ProcedureTest.php
  45. 30 33
      src/JonnyW/PhantomJs/Tests/Unit/Template/TemplateRendererTest.php
  46. 119 0
      src/JonnyW/PhantomJs/Tests/Unit/Validator/EsprimaTest.php
  47. 25 0
      src/JonnyW/PhantomJs/Validator/EngineInterface.php
  48. 111 0
      src/JonnyW/PhantomJs/Validator/Esprima.php

+ 1 - 1
composer.json

@@ -19,7 +19,7 @@
         "symfony/filesystem": "~2.3",
         "symfony/yaml": "~2.3",
         "twig/twig": "~1.16",
-        "jakoch/phantomjs-installer": "1.9.7"
+        "jakoch/phantomjs-installer": "2.0.0"
     },
     "require-dev": {
         "phpunit/phpunit": "~4.0"

+ 46 - 101
src/JonnyW/PhantomJs/Client.php

@@ -10,9 +10,10 @@ namespace JonnyW\PhantomJs;
 
 use JonnyW\PhantomJs\Exception\InvalidExecutableException;
 use JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface;
-use JonnyW\PhantomJs\Message\MessageFactoryInterface;
-use JonnyW\PhantomJs\Message\RequestInterface;
-use JonnyW\PhantomJs\Message\ResponseInterface;
+use JonnyW\PhantomJs\Procedure\ProcedureValidatorInterface;
+use JonnyW\PhantomJs\Http\MessageFactoryInterface;
+use JonnyW\PhantomJs\Http\RequestInterface;
+use JonnyW\PhantomJs\Http\ResponseInterface;
 use JonnyW\PhantomJs\DependencyInjection\ServiceContainer;
 
 /**
@@ -23,7 +24,7 @@ use JonnyW\PhantomJs\DependencyInjection\ServiceContainer;
 class Client implements ClientInterface
 {
     /**
-     * Client instance
+     * Client.
      *
      * @var \JonnyW\PhantomJs\ClientInterface
      * @access private
@@ -31,7 +32,7 @@ class Client implements ClientInterface
     private static $instance;
 
     /**
-     * Procedure loader instance
+     * Procedure loader.
      *
      * @var \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface
      * @access protected
@@ -39,20 +40,20 @@ class Client implements ClientInterface
     protected $procedureLoader;
 
     /**
-     * Message factory instance
+     * Procedure validator.
      *
-     * @var \JonnyW\PhantomJs\Message\MessageFactoryInterface
+     * @var \JonnyW\PhantomJs\Procedure\ProcedureValidatorInterface
      * @access protected
      */
-    protected $messageFactory;
+    protected $procedureValidator;
 
     /**
-     * Bin directory path.
+     * Message factory.
      *
-     * @var string
+     * @var \JonnyW\PhantomJs\Http\MessageFactoryInterface
      * @access protected
      */
-    protected $binDir;
+    protected $messageFactory;
 
     /**
      * Path to PhantomJs executable
@@ -63,15 +64,7 @@ class Client implements ClientInterface
     protected $phantomJs;
 
     /**
-     * Path to PhantomJs loader executable
-     *
-     * @var string
-     * @access protected
-     */
-    protected $phantomLoader;
-
-    /**
-     * Debug.
+     * Debug flag.
      *
      * @var boolean
      * @access protected
@@ -79,36 +72,37 @@ class Client implements ClientInterface
     protected $debug;
 
     /**
-     * Log info
+     * PhantomJs run options.
      *
      * @var array
      * @access protected
      */
-    protected $log;
+    protected $options;
 
     /**
-     * PhantomJs run options
+     * Log info
      *
-     * @var mixed
+     * @var string
      * @access protected
      */
-    protected $options;
+    protected $log;
 
     /**
      * Internal constructor
      *
      * @access public
-     * @param \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface $procedureLoader
-     * @param \JonnyW\PhantomJs\Message\MessageFactoryInterface    $messageFactory
+     * @param  \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface    $procedureLoader
+     * @param  \JonnyW\PhantomJs\Procedure\ProcedureValidatorInterface $procedureValidator
+     * @param  \JonnyW\PhantomJs\Http\MessageFactoryInterface          $messageFactory
+     * @return void
      */
-    public function __construct(ProcedureLoaderInterface $procedureLoader, MessageFactoryInterface $messageFactory)
+    public function __construct(ProcedureLoaderInterface $procedureLoader, ProcedureValidatorInterface $procedureValidator, MessageFactoryInterface $messageFactory)
     {
-        $this->procedureLoader = $procedureLoader;
-        $this->messageFactory  = $messageFactory;
-        $this->binDir          = 'bin';
-        $this->phantomJs       = '%s/phantomjs';
-        $this->phantomLoader   = '%s/phantomloader';
-        $this->options         = array();
+        $this->procedureLoader    = $procedureLoader;
+        $this->procedureValidator = $procedureValidator;
+        $this->messageFactory     = $messageFactory;
+        $this->phantomJs          = 'bin/phantomjs';
+        $this->options            = array();
     }
 
     /**
@@ -125,6 +119,7 @@ class Client implements ClientInterface
 
             self::$instance = new Client(
                 $serviceContainer->get('procedure_loader'),
+                $serviceContainer->get('procedure_validator'),
                 $serviceContainer->get('message_factory')
             );
         }
@@ -136,7 +131,7 @@ class Client implements ClientInterface
      * Get message factory instance
      *
      * @access public
-     * @return \JonnyW\PhantomJs\Message\MessageFactoryInterface
+     * @return \JonnyW\PhantomJs\Http\MessageFactoryInterface
      */
     public function getMessageFactory()
     {
@@ -158,15 +153,20 @@ class Client implements ClientInterface
      * Send request
      *
      * @access public
-     * @param  \JonnyW\PhantomJs\Message\RequestInterface  $request
-     * @param  \JonnyW\PhantomJs\Message\ResponseInterface $response
-     * @return \JonnyW\PhantomJs\Message\ResponseInterface
+     * @param  \JonnyW\PhantomJs\Http\RequestInterface  $request
+     * @param  \JonnyW\PhantomJs\Http\ResponseInterface $response
+     * @return \JonnyW\PhantomJs\Http\ResponseInterface
      */
     public function send(RequestInterface $request, ResponseInterface $response)
     {
-        $this->clearLog();
-
         $procedure = $this->procedureLoader->load($request->getType());
+
+        $this->procedureValidator->validate(
+            $this,
+            $procedure,
+            $request
+        );
+
         $procedure->run($this, $request, $response);
 
         return $response;
@@ -181,44 +181,16 @@ class Client implements ClientInterface
      */
     public function getCommand()
     {
-        $phantomJs     = $this->getPhantomJs();
-        $phantomLoader = $this->getPhantomLoader();
+        $phantomJs = $this->getPhantomJs();
+        $options   = $this->getOptions();
 
         $this->validateExecutable($phantomJs);
-        $this->validateExecutable($phantomLoader);
-
-        $options = $this->getOptions();
 
         if ($this->debug) {
             array_push($options, '--debug=true');
         }
 
-        return sprintf('%s %s %s', $phantomJs, implode(' ', $options), $phantomLoader);
-    }
-
-    /**
-     * Set bin directory.
-     *
-     * @access public
-     * @param  string                   $path
-     * @return \JonnyW\PhantomJs\Client
-     */
-    public function setBinDir($path)
-    {
-        $this->binDir = rtrim($path, '/\\');
-
-        return $this;
-    }
-
-    /**
-     * Get bin directory.
-     *
-     * @access public
-     * @return string
-     */
-    public function getBinDir()
-    {
-        return $this->binDir;
+        return sprintf('%s %s', $phantomJs, implode(' ', $options));
     }
 
     /**
@@ -245,34 +217,7 @@ class Client implements ClientInterface
      */
     public function getPhantomJs()
     {
-        return sprintf($this->phantomJs, $this->getBinDir());
-    }
-
-    /**
-     * Set PhantomJs loader executable path.
-     *
-     * @access public
-     * @param  string                   $path
-     * @return \JonnyW\PhantomJs\Client
-     */
-    public function setPhantomLoader($path)
-    {
-        $this->validateExecutable($path);
-
-        $this->phantomLoader = $path;
-
-        return $this;
-    }
-
-    /**
-     * Get PhantomJs loader executable path.
-     *
-     * @access public
-     * @return string
-     */
-    public function getPhantomLoader()
-    {
-        return sprintf($this->phantomLoader, $this->getBinDir());
+        return $this->phantomJs;
     }
 
     /**
@@ -331,13 +276,13 @@ class Client implements ClientInterface
     }
 
     /**
-     * Set log info.
+     * Log info.
      *
      * @access public
      * @param  string                   $info
      * @return \JonnyW\PhantomJs\Client
      */
-    public function setLog($info)
+    public function log($info)
     {
         $this->log = $info;
 

+ 13 - 35
src/JonnyW/PhantomJs/ClientInterface.php

@@ -8,8 +8,8 @@
  */
 namespace JonnyW\PhantomJs;
 
-use JonnyW\PhantomJs\Message\RequestInterface;
-use JonnyW\PhantomJs\Message\ResponseInterface;
+use JonnyW\PhantomJs\Http\RequestInterface;
+use JonnyW\PhantomJs\Http\ResponseInterface;
 
 /**
  * PHP PhantomJs
@@ -30,7 +30,7 @@ interface ClientInterface
      * Get message factory instance
      *
      * @access public
-     * @return \JonnyW\PhantomJs\Message\MessageFactoryInterface
+     * @return \JonnyW\PhantomJs\Http\MessageFactoryInterface
      */
     public function getMessageFactory();
 
@@ -38,27 +38,19 @@ interface ClientInterface
      * Send request
      *
      * @access public
-     * @param \JonnyW\PhantomJs\Message\RequestInterface  $request
-     * @param \JonnyW\PhantomJs\Message\ResponseInterface $response
+     * @param \JonnyW\PhantomJs\Http\RequestInterface  $request
+     * @param \JonnyW\PhantomJs\Http\ResponseInterface $response
      */
     public function send(RequestInterface $request, ResponseInterface $response);
 
     /**
-     * Set bin directory.
-     *
-     * @access public
-     * @param  string                   $path
-     * @return \JonnyW\PhantomJs\Client
-     */
-    public function setBinDir($path);
-
-    /**
-     * Get bin directory.
+     * Get PhantomJs run command with
+     * loader and run options.
      *
      * @access public
      * @return string
      */
-    public function getBinDir();
+    public function getCommand();
 
     /**
      * Set new PhantomJs executable path.
@@ -76,22 +68,6 @@ interface ClientInterface
      */
     public function getPhantomJs();
 
-        /**
-     * Set PhantomJs loader executable path.
-     *
-     * @access public
-     * @param string $path
-     */
-    public function setPhantomLoader($path);
-
-    /**
-     * Get PhantomJs loader executable path.
-     *
-     * @access public
-     * @return string
-     */
-    public function getPhantomLoader();
-
     /**
      * Set PhantomJs run options.
      *
@@ -125,12 +101,13 @@ interface ClientInterface
     public function debug($doDebug);
 
     /**
-     * Set log info.
+     * Log info.
      *
      * @access public
-     * @param string $info
+     * @param  string                   $info
+     * @return \JonnyW\PhantomJs\Client
      */
-    public function setLog($info);
+    public function log($info);
 
     /**
      * Get log info.
@@ -144,6 +121,7 @@ interface ClientInterface
      * Clear log info.
      *
      * @access public
+     * @return \JonnyW\PhantomJs\Client
      */
     public function clearLog();
 }

+ 19 - 0
src/JonnyW/PhantomJs/Exception/RequirementException.php

@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Exception;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class RequirementException extends PhantomJsException
+{
+
+}

+ 51 - 0
src/JonnyW/PhantomJs/Exception/SyntaxException.php

@@ -0,0 +1,51 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Exception;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class SyntaxException extends PhantomJsException
+{
+    /**
+     * Error storage.
+     *
+     * @var array
+     * @access protected
+     */
+    protected $errors;
+
+    /**
+     * Internal constructor.
+     *
+     * @access public
+     * @param  string $exception
+     * @param  array  $errors    (default: array())
+     * @return void
+     */
+    public function __construct($exception, array $errors = array())
+    {
+        parent::__construct($exception);
+
+        $this->errors = $errors;
+    }
+
+    /**
+     * Get errors.
+     *
+     * @access public
+     * @return array
+     */
+    public function getErrors()
+    {
+        return $this->errors;
+    }
+}

+ 20 - 18
src/JonnyW/PhantomJs/Message/AbstractRequest.php → src/JonnyW/PhantomJs/Http/AbstractRequest.php

@@ -7,17 +7,19 @@
  * file that was distributed with this source code.
  */
 
-namespace JonnyW\PhantomJs\Message;
+namespace JonnyW\PhantomJs\Http;
 
 use JonnyW\PhantomJs\Exception\InvalidUrlException;
 use JonnyW\PhantomJs\Exception\InvalidMethodException;
+use JonnyW\PhantomJs\Procedure\InputInterface;
 
 /**
  * PHP PhantomJs
  *
  * @author Jon Wenmoth <contact@jonnyw.me>
  */
-abstract class AbstractRequest implements RequestInterface
+abstract class AbstractRequest
+    implements RequestInterface, InputInterface
 {
     /**
      * Headers
@@ -112,13 +114,13 @@ abstract class AbstractRequest implements RequestInterface
      *
      * @access public
      * @param  string                                             $method
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      * @throws \JonnyW\PhantomJs\Exception\InvalidMethodException
      */
     public function setMethod($method)
     {
         $method     = strtoupper($method);
-        $reflection = new \ReflectionClass('\JonnyW\PhantomJs\Message\RequestInterface');
+        $reflection = new \ReflectionClass('\JonnyW\PhantomJs\Http\RequestInterface');
 
         if (!$reflection->hasConstant('METHOD_' . $method)) {
             throw new InvalidMethodException(sprintf('Invalid method provided: %s', $method));
@@ -144,8 +146,8 @@ abstract class AbstractRequest implements RequestInterface
      * Set timeout period
      *
      * @access public
-     * @param  int                                       $timeout
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @param  int                                    $timeout
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      */
     public function setTimeout($timeout)
     {
@@ -169,8 +171,8 @@ abstract class AbstractRequest implements RequestInterface
      * Set page load delay time (seconds).
      *
      * @access public
-     * @param  int                                       $delay
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @param  int                                    $delay
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      */
     public function setDelay($delay)
     {
@@ -231,7 +233,7 @@ abstract class AbstractRequest implements RequestInterface
      *
      * @access public
      * @param  string                                          $url
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      * @throws \JonnyW\PhantomJs\Exception\InvalidUrlException
      */
     public function setUrl($url)
@@ -290,8 +292,8 @@ abstract class AbstractRequest implements RequestInterface
      * Set request data
      *
      * @access public
-     * @param  array                                     $data
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @param  array                                  $data
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      */
     public function setRequestData(array $data)
     {
@@ -320,8 +322,8 @@ abstract class AbstractRequest implements RequestInterface
      * Set headers
      *
      * @access public
-     * @param  array                                     $headers
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @param  array                                  $headers
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      */
     public function setHeaders(array $headers)
     {
@@ -332,9 +334,9 @@ abstract class AbstractRequest implements RequestInterface
      * Add single header
      *
      * @access public
-     * @param  string                                    $header
-     * @param  string                                    $value
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @param  string                                 $header
+     * @param  string                                 $value
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      */
     public function addHeader($header, $value)
     {
@@ -347,8 +349,8 @@ abstract class AbstractRequest implements RequestInterface
      * Merge headers with existing
      *
      * @access public
-     * @param  array                                     $headers
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @param  array                                  $headers
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      */
     public function addHeaders(array $headers)
     {

+ 13 - 13
src/JonnyW/PhantomJs/Message/CaptureRequest.php → src/JonnyW/PhantomJs/Http/CaptureRequest.php

@@ -7,7 +7,7 @@
  * file that was distributed with this source code.
  */
 
-namespace JonnyW\PhantomJs\Message;
+namespace JonnyW\PhantomJs\Http;
 
 use JonnyW\PhantomJs\Exception\NotWritableException;
 
@@ -71,10 +71,10 @@ class CaptureRequest extends AbstractRequest
      * Internal constructor
      *
      * @access public
-     * @param  string                                   $url     (default: null)
-     * @param  string                                   $method  (default: RequestInterface::METHOD_GET)
-     * @param  int                                      $timeout (default: 5000)
-     * @return \JonnyW\PhantomJs\Message\CaptureRequest
+     * @param  string                                $url     (default: null)
+     * @param  string                                $method  (default: RequestInterface::METHOD_GET)
+     * @param  int                                   $timeout (default: 5000)
+     * @return \JonnyW\PhantomJs\Http\CaptureRequest
      */
     public function __construct($url = null, $method = RequestInterface::METHOD_GET, $timeout = 5000)
     {
@@ -105,8 +105,8 @@ class CaptureRequest extends AbstractRequest
      * Set request type
      *
      * @access public
-     * @param  string                                    $type
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @param  string                                 $type
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      */
     public function setType($type)
     {
@@ -119,11 +119,11 @@ class CaptureRequest extends AbstractRequest
      * Set viewport size.
      *
      * @access public
-     * @param  int                                       $width
-     * @param  int                                       $height
-     * @param  int                                       $top    (default: 0)
-     * @param  int                                       $left   (default: 0)
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @param  int                                    $width
+     * @param  int                                    $height
+     * @param  int                                    $top    (default: 0)
+     * @param  int                                    $left   (default: 0)
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      */
     public function setCaptureDimensions($width, $height, $top = 0, $left = 0)
     {
@@ -185,7 +185,7 @@ class CaptureRequest extends AbstractRequest
      * @access public
      * @param  string                                           $file
      * @throws \JonnyW\PhantomJs\Exception\NotWritableException
-     * @return \JonnyW\PhantomJs\Message\CaptureRequest
+     * @return \JonnyW\PhantomJs\Http\CaptureRequest
      */
     public function setCaptureFile($file)
     {

+ 1 - 1
src/JonnyW/PhantomJs/Message/CaptureRequestInterface.php → src/JonnyW/PhantomJs/Http/CaptureRequestInterface.php

@@ -7,7 +7,7 @@
  * file that was distributed with this source code.
  */
 
-namespace JonnyW\PhantomJs\Message;
+namespace JonnyW\PhantomJs\Http;
 
 /**
  * PHP PhantomJs

+ 12 - 12
src/JonnyW/PhantomJs/Message/MessageFactory.php → src/JonnyW/PhantomJs/Http/MessageFactory.php

@@ -6,7 +6,7 @@
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
-namespace JonnyW\PhantomJs\Message;
+namespace JonnyW\PhantomJs\Http;
 
 /**
  * PHP PhantomJs
@@ -18,7 +18,7 @@ class MessageFactory implements MessageFactoryInterface
     /**
      * Client instance
      *
-     * @var \JonnyW\PhantomJs\Message\MessageFactory
+     * @var \JonnyW\PhantomJs\Http\MessageFactory
      * @access private
      */
     private static $instance;
@@ -27,7 +27,7 @@ class MessageFactory implements MessageFactoryInterface
      * Get singleton instance.
      *
      * @access public
-     * @return \JonnyW\PhantomJs\Message\MessageFactory
+     * @return \JonnyW\PhantomJs\Http\MessageFactory
      */
     public static function getInstance()
     {
@@ -42,10 +42,10 @@ class MessageFactory implements MessageFactoryInterface
      * Create request instance.
      *
      * @access public
-     * @param  string                            $url
-     * @param  string                            $method
-     * @param  int                               $timeout
-     * @return \JonnyW\PhantomJs\Message\Request
+     * @param  string                         $url
+     * @param  string                         $method
+     * @param  int                            $timeout
+     * @return \JonnyW\PhantomJs\Http\Request
      */
     public function createRequest($url = null, $method = RequestInterface::METHOD_GET, $timeout = 5000)
     {
@@ -56,10 +56,10 @@ class MessageFactory implements MessageFactoryInterface
      * Create capture request instance.
      *
      * @access public
-     * @param  string                            $url
-     * @param  string                            $method
-     * @param  int                               $timeout
-     * @return \JonnyW\PhantomJs\Message\Request
+     * @param  string                         $url
+     * @param  string                         $method
+     * @param  int                            $timeout
+     * @return \JonnyW\PhantomJs\Http\Request
      */
     public function createCaptureRequest($url = null, $method = RequestInterface::METHOD_GET, $timeout = 5000)
     {
@@ -70,7 +70,7 @@ class MessageFactory implements MessageFactoryInterface
      * Create response instance.
      *
      * @access public
-     * @return \JonnyW\PhantomJs\Message\Response
+     * @return \JonnyW\PhantomJs\Http\Response
      */
     public function createResponse()
     {

+ 11 - 11
src/JonnyW/PhantomJs/Message/MessageFactoryInterface.php → src/JonnyW/PhantomJs/Http/MessageFactoryInterface.php

@@ -6,7 +6,7 @@
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
-namespace JonnyW\PhantomJs\Message;
+namespace JonnyW\PhantomJs\Http;
 
 /**
  * PHP PhantomJs
@@ -19,7 +19,7 @@ interface MessageFactoryInterface
      * Get singleton instance.
      *
      * @access public
-     * @return \JonnyW\PhantomJs\Message\MessageFactoryInterface
+     * @return \JonnyW\PhantomJs\Http\MessageFactoryInterface
      */
     public static function getInstance();
 
@@ -27,10 +27,10 @@ interface MessageFactoryInterface
      * Create request instance.
      *
      * @access public
-     * @param  string                                     $url     (default: null)
-     * @param  string                                     $method  (default: RequestInterface::METHOD_GET)
-     * @param  int                                        $timeout (default: 5000)
-     * @return \JonnyW\PhantomJs\Message\RequestInterface
+     * @param  string                                  $url     (default: null)
+     * @param  string                                  $method  (default: RequestInterface::METHOD_GET)
+     * @param  int                                     $timeout (default: 5000)
+     * @return \JonnyW\PhantomJs\Http\RequestInterface
      */
     public function createRequest($url = null, $method = RequestInterface::METHOD_GET, $timeout = 5000);
 
@@ -38,10 +38,10 @@ interface MessageFactoryInterface
      * Create capture request instance.
      *
      * @access public
-     * @param  string                                     $url     (default: null)
-     * @param  string                                     $method  (default: RequestInterface::METHOD_GET)
-     * @param  int                                        $timeout (default: 5000)
-     * @return \JonnyW\PhantomJs\Message\RequestInterface
+     * @param  string                                  $url     (default: null)
+     * @param  string                                  $method  (default: RequestInterface::METHOD_GET)
+     * @param  int                                     $timeout (default: 5000)
+     * @return \JonnyW\PhantomJs\Http\RequestInterface
      */
     public function createCaptureRequest($url = null, $method = RequestInterface::METHOD_GET, $timeout = 5000);
 
@@ -49,7 +49,7 @@ interface MessageFactoryInterface
      * Create response instance.
      *
      * @access public
-     * @return \JonnyW\PhantomJs\Message\ResponseInterface
+     * @return \JonnyW\PhantomJs\Http\ResponseInterface
      */
     public function createResponse();
 }

+ 3 - 3
src/JonnyW/PhantomJs/Message/Request.php → src/JonnyW/PhantomJs/Http/Request.php

@@ -7,7 +7,7 @@
  * file that was distributed with this source code.
  */
 
-namespace JonnyW\PhantomJs\Message;
+namespace JonnyW\PhantomJs\Http;
 
 /**
  * PHP PhantomJs
@@ -43,8 +43,8 @@ class Request extends AbstractRequest
      * Set request type
      *
      * @access public
-     * @param  string                                    $type
-     * @return \JonnyW\PhantomJs\Message\AbstractRequest
+     * @param  string                                 $type
+     * @return \JonnyW\PhantomJs\Http\AbstractRequest
      */
     public function setType($type)
     {

+ 3 - 3
src/JonnyW/PhantomJs/Message/RequestInterface.php → src/JonnyW/PhantomJs/Http/RequestInterface.php

@@ -7,7 +7,7 @@
  * file that was distributed with this source code.
  */
 
-namespace JonnyW\PhantomJs\Message;
+namespace JonnyW\PhantomJs\Http;
 
 /**
  * PHP PhantomJs
@@ -24,8 +24,8 @@ interface RequestInterface
     const METHOD_DELETE  = 'DELETE';
     const METHOD_PATCH   = 'PATCH';
 
-    const REQUEST_TYPE_DEFAULT = 'default';
-    const REQUEST_TYPE_CAPTURE = 'capture';
+    const REQUEST_TYPE_DEFAULT = 'http_default';
+    const REQUEST_TYPE_CAPTURE = 'http_capture';
 
     /**
      * Get request type

+ 9 - 6
src/JonnyW/PhantomJs/Message/Response.php → src/JonnyW/PhantomJs/Http/Response.php

@@ -6,14 +6,17 @@
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
-namespace JonnyW\PhantomJs\Message;
+namespace JonnyW\PhantomJs\Http;
+
+use JonnyW\PhantomJs\Procedure\OutputInterface;
 
 /**
  * PHP PhantomJs
  *
  * @author Jon Wenmoth <contact@jonnyw.me>
  */
-class Response implements ResponseInterface
+class Response
+    implements ResponseInterface, OutputInterface
 {
     /**
      * Http headers array
@@ -83,8 +86,8 @@ class Response implements ResponseInterface
      * Import response data
      *
      * @access public
-     * @param  array                              $data
-     * @return \JonnyW\PhantomJs\Message\Response
+     * @param  array                           $data
+     * @return \JonnyW\PhantomJs\Http\Response
      */
     public function import(array $data)
     {
@@ -112,8 +115,8 @@ class Response implements ResponseInterface
      * Set headers array
      *
      * @access protected
-     * @param  array                              $headers
-     * @return \JonnyW\PhantomJs\Message\Response
+     * @param  array                           $headers
+     * @return \JonnyW\PhantomJs\Http\Response
      */
     protected function setHeaders(array $headers)
     {

+ 1 - 1
src/JonnyW/PhantomJs/Message/ResponseInterface.php → src/JonnyW/PhantomJs/Http/ResponseInterface.php

@@ -7,7 +7,7 @@
  * file that was distributed with this source code.
  */
 
-namespace JonnyW\PhantomJs\Message;
+namespace JonnyW\PhantomJs\Http;
 
 /**
  * PHP PhantomJs

+ 68 - 0
src/JonnyW/PhantomJs/Procedure/Input.php

@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace JonnyW\PhantomJs\Procedure;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class Input implements InputInterface
+{
+    /**
+     * Data storage.
+     *
+     * @var array
+     * @access protected
+     */
+    protected $data;
+
+    /**
+     * Internal constructor.
+     *
+     * @access public
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->data = array();
+    }
+
+    /**
+     * Set data value.
+     *
+     * @access public
+     * @param  string                            $name
+     * @param  mixed                             $value
+     * @return \JonnyW\PhantomJs\Procedure\Input
+     */
+    public function set($name, $value)
+    {
+        $this->data[$name] = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get data value.
+     *
+     * @access public
+     * @param  string $name
+     * @return mixed
+     */
+    public function get($name)
+    {
+        if (isset($this->data[$name])) {
+            return $this->data[$name];
+        }
+
+        return '';
+    }
+}

+ 20 - 0
src/JonnyW/PhantomJs/Procedure/InputInterface.php

@@ -0,0 +1,20 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace JonnyW\PhantomJs\Procedure;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+interface InputInterface
+{
+
+}

+ 110 - 0
src/JonnyW/PhantomJs/Procedure/Output.php

@@ -0,0 +1,110 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace JonnyW\PhantomJs\Procedure;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class Output implements OutputInterface
+{
+    /**
+     * Output data.
+     *
+     * @var array
+     * @access protected
+     */
+    protected $data;
+
+    /**
+     * Output logs.
+     *
+     * @var array
+     * @access protected
+     */
+    protected $logs;
+
+    /**
+     * Internal constructor.
+     *
+     * @access public
+     * @return void
+     */
+    public function __construct()
+    {
+        $this->data = array();
+        $this->logs = array();
+    }
+
+    /**
+     * Import data.
+     *
+     * @param array $data
+     * @access public
+     */
+    public function import(array $data)
+    {
+        $this->data = $data;
+    }
+
+    /**
+     * Set data value.
+     *
+     * @access public
+     * @param  string                             $name
+     * @param  mixed                              $value
+     * @return \JonnyW\PhantomJs\Procedure\Output
+     */
+    public function set($name, $value)
+    {
+        $this->data[$name] = $value;
+
+        return $this;
+    }
+
+    /**
+     * Get data value.
+     *
+     * @access public
+     * @param  string $name
+     * @return mixed
+     */
+    public function get($name)
+    {
+        if (isset($this->data[$name])) {
+            return $this->data[$name];
+        }
+
+        return '';
+    }
+
+    /**
+     * Log data.
+     *
+     * @access public
+     * @param string $data
+     */
+    public function log($data)
+    {
+        $this->logs[] = $data;
+    }
+
+    /**
+     * Get log data.
+     *
+     * @access public
+     * @return array
+     */
+    public function getLogs()
+    {
+        return $this->logs;
+    }
+}

+ 26 - 0
src/JonnyW/PhantomJs/Procedure/OutputInterface.php

@@ -0,0 +1,26 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace JonnyW\PhantomJs\Procedure;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+interface OutputInterface
+{
+    /**
+     * Import data.
+     *
+     * @param array $data
+     * @access public
+     */
+    public function import(array $data);
+}

+ 37 - 31
src/JonnyW/PhantomJs/Procedure/Procedure.php

@@ -11,8 +11,6 @@ namespace JonnyW\PhantomJs\Procedure;
 use JonnyW\PhantomJs\ClientInterface;
 use JonnyW\PhantomJs\Cache\CacheInterface;
 use JonnyW\PhantomJs\Parser\ParserInterface;
-use JonnyW\PhantomJs\Message\RequestInterface;
-use JonnyW\PhantomJs\Message\ResponseInterface;
 use JonnyW\PhantomJs\Template\TemplateRendererInterface;
 use JonnyW\PhantomJs\Exception\NotWritableException;
 use JonnyW\PhantomJs\Exception\ProcedureFailedException;
@@ -41,20 +39,20 @@ class Procedure implements ProcedureInterface
     protected $cacheHandler;
 
     /**
-     * Procedure template.
+     * Template renderer.
      *
-     * @var string
+     * @var \JonnyW\PhantomJs\Template\TemplateRendererInterface
      * @access protected
      */
-    protected $procedure;
+    protected $renderer;
 
     /**
-     * Template renderer.
+     * Procedure template.
      *
-     * @var \JonnyW\PhantomJs\Template\TemplateRendererInterface
+     * @var string
      * @access protected
      */
-    protected $renderer;
+    protected $template;
 
     /**
      * Internal constructor.
@@ -76,21 +74,19 @@ class Procedure implements ProcedureInterface
      *
      * @access public
      * @param  \JonnyW\PhantomJs\ClientInterface                    $client
-     * @param  \JonnyW\PhantomJs\Message\RequestInterface           $request
-     * @param  \JonnyW\PhantomJs\Message\ResponseInterface          $response
+     * @param  \JonnyW\PhantomJs\Procedure\InputInterface           $input
+     * @param  \JonnyW\PhantomJs\Procedure\OutputInterface          $output
      * @throws \JonnyW\PhantomJs\Exception\ProcedureFailedException
-     * @throws \Exception
      * @throws \JonnyW\PhantomJs\Exception\NotWritableException
      * @return void
      */
-    public function run(ClientInterface $client, RequestInterface $request, ResponseInterface $response)
+    public function run(ClientInterface $client, InputInterface $input, OutputInterface $output)
     {
         try {
 
-            $template  = $this->getProcedure();
-            $procedure = $this->renderer->render($template, array('request' => $request));
-
-            $executable = $this->write($procedure);
+            $executable = $this->write(
+                $this->compile($input)
+            );
 
             $descriptorspec = array(
                 array('pipe', 'r'),
@@ -113,11 +109,11 @@ class Procedure implements ProcedureInterface
 
             proc_close($process);
 
-            $response->import(
+            $output->import(
                 $this->parser->parse($result)
             );
 
-            $client->setLog($log);
+            $client->log($log);
 
             $this->remove($executable);
 
@@ -129,20 +125,20 @@ class Procedure implements ProcedureInterface
                 $this->remove($executable);
             }
 
-            throw new ProcedureFailedException(sprintf('Error when executing PhantomJs procedure "%s" - %s', $request->getType(), $e->getMessage()));
+            throw new ProcedureFailedException(sprintf('Error when executing PhantomJs procedure - %s', $e->getMessage()));
         }
     }
 
     /**
-     * Load procedure.
+     * Set procedure template.
      *
      * @access public
-     * @param  string                                $procedure
+     * @param  string                                $template
      * @return \JonnyW\PhantomJs\Procedure\Procedure
      */
-    public function load($procedure)
+    public function setTemplate($template)
     {
-        $this->procedure = $procedure;
+        $this->template = $template;
 
         return $this;
     }
@@ -153,23 +149,33 @@ class Procedure implements ProcedureInterface
      * @access public
      * @return string
      */
-    public function getProcedure()
+    public function getTemplate()
+    {
+        return $this->template;
+    }
+
+    /**
+     * Compile procedure.
+     *
+     * @access public
+     * @param  \JonnyW\PhantomJs\Procedure\InputInterface $input
+     * @return void
+     */
+    public function compile(InputInterface $input)
     {
-        return $this->procedure;
+       return $this->renderer->render($this->getTemplate(), array('input' => $input));
     }
 
     /**
-     * Write procedure script cache.
+     * Write compiled procedure to cache.
      *
      * @access protected
-     * @param  string $procedure
+     * @param  string $compiled
      * @return string
      */
-    protected function write($procedure)
+    protected function write($compiled)
     {
-        $executable = $this->cacheHandler->save(uniqid(), $procedure);
-
-        return $executable;
+        return $this->cacheHandler->save(uniqid(), $compiled);
     }
 
     /**

+ 16 - 9
src/JonnyW/PhantomJs/Procedure/ProcedureInterface.php

@@ -9,8 +9,6 @@
 namespace JonnyW\PhantomJs\Procedure;
 
 use JonnyW\PhantomJs\ClientInterface;
-use JonnyW\PhantomJs\Message\RequestInterface;
-use JonnyW\PhantomJs\Message\ResponseInterface;
 
 /**
  * PHP PhantomJs
@@ -24,18 +22,18 @@ interface ProcedureInterface
      *
      * @access public
      * @param \JonnyW\PhantomJs\ClientInterface           $client
-     * @param \JonnyW\PhantomJs\Message\RequestInterface  $request
-     * @param \JonnyW\PhantomJs\Message\ResponseInterface $response
+     * @param \JonnyW\PhantomJs\Procedure\InputInterface  $input
+     * @param \JonnyW\PhantomJs\Procedure\OutputInterface $output
      */
-    public function run(ClientInterface $client, RequestInterface $request, ResponseInterface $response);
+    public function run(ClientInterface $client, InputInterface $input, OutputInterface $output);
 
     /**
-     * Load procedure.
+     * Set procedure template.
      *
      * @access public
-     * @param string $procedure
+     * @param string $template
      */
-    public function load($procedure);
+    public function setTemplate($template);
 
     /**
      * Get procedure template.
@@ -43,5 +41,14 @@ interface ProcedureInterface
      * @access public
      * @return string
      */
-    public function getProcedure();
+    public function getTemplate();
+
+    /**
+     * Compile procedure.
+     *
+     * @access public
+     * @param  \JonnyW\PhantomJs\Procedure\InputInterface $input
+     * @return string
+     */
+    public function compile(InputInterface $input);
 }

+ 4 - 4
src/JonnyW/PhantomJs/Procedure/ProcedureLoader.php

@@ -21,7 +21,7 @@ class ProcedureLoader implements ProcedureLoaderInterface
     /**
      * Procedure factory.
      *
-     * @var mixed
+     * @var \JonnyW\PhantomJs\Procedure\ProcedureFactoryInterface
      * @access protected
      */
     protected $procedureFactory;
@@ -56,11 +56,11 @@ class ProcedureLoader implements ProcedureLoaderInterface
      */
     public function load($id)
     {
-        $path    = $this->locator->locate(sprintf('%s.proc', $id));
-        $content = $this->loadFile($path);
+        $path     = $this->locator->locate(sprintf('%s.proc', $id));
+        $template = $this->loadFile($path);
 
         $procedure = $this->procedureFactory->createProcedure();
-        $procedure->load($content);
+        $procedure->setTemplate($template);
 
         return $procedure;
     }

+ 116 - 0
src/JonnyW/PhantomJs/Procedure/ProcedureValidator.php

@@ -0,0 +1,116 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Procedure;
+
+use JonnyW\PhantomJs\ClientInterface;
+use JonnyW\PhantomJs\Validator\EngineInterface;
+use JonnyW\PhantomJs\Exception\SyntaxException;
+use JonnyW\PhantomJs\Exception\RequirementException;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class ProcedureValidator implements ProcedureValidatorInterface
+{
+    /**
+     * Procedure loader.
+     *
+     * @var \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface
+     * @access protected
+     */
+    protected $procedureLoader;
+
+    /**
+     * Validator engine
+     *
+     * @var \JonnyW\PhantomJs\Validator\EngineInterface
+     * @access protected
+     */
+    protected $engine;
+
+    /**
+     * Internal constructor.
+     *
+     * @access public
+     * @param \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface $procedureLoader
+     * @param \JonnyW\PhantomJs\Validator\EngineInterface          $engine
+     */
+    public function __construct(ProcedureLoaderInterface $procedureLoader, EngineInterface $engine)
+    {
+        $this->procedureLoader = $procedureLoader;
+        $this->engine          = $engine;
+    }
+
+    /**
+     * Validate procedure.
+     *
+     * @access public
+     * @param  \JonnyW\PhantomJs\ClientInterface                        $client
+     * @param  \JonnyW\PhantomJs\Procedure\ProcedureInterface           $procedure
+     * @param  \JonnyW\PhantomJs\Procedure\InputInterface               $message
+     * @return boolean
+     * @throws \JonnyW\PhantomJs\Exception\ProcedureValidationException
+     */
+    public function validate(ClientInterface $client, ProcedureInterface $procedure, InputInterface $message)
+    {
+        $compiled = $procedure->compile(
+            $message
+        );
+
+        $this->validateSyntax($client, $compiled);
+        $this->validateRequirements($client, $compiled);
+
+        return true;
+    }
+
+    /**
+     * Validate syntax.
+     *
+     * @access protected
+     * @param  \JonnyW\PhantomJs\ClientInterface           $client
+     * @param  stromg                                      $compiled
+     * @return void
+     * @throws \JonnyW\PhantomJs\Exception\SyntaxException
+     */
+    protected function validateSyntax(ClientInterface $client, $compiled)
+    {
+        $input  = new Input();
+        $output = new Output();
+
+        $input->set('procedure', $compiled);
+        $input->set('engine', $this->engine->toString());
+
+        $validator = $this->procedureLoader->load('validator');
+        $validator->run($client, $input, $output);
+
+        $errors = $output->get('errors');
+
+        if (!empty($errors)) {
+            throw new SyntaxException('Your procedure failed to compile due to a javascript syntax error', (array) $errors);
+        }
+    }
+
+    /**
+     * validateRequirements function.
+     *
+     * @access protected
+     * @param  \JonnyW\PhantomJs\ClientInterface                $client
+     * @param  stromg                                           $compiled
+     * @return void
+     * @throws \JonnyW\PhantomJs\Exception\RequirementException
+     */
+    protected function validateRequirements(ClientInterface $client, $compiled)
+    {
+        if (preg_match('/phantom\.exit\(/', $compiled, $matches) !== 1) {
+            throw new RequirementException('Your procedure must contain a \'phantom.exit(1);\' command to avoid the PhantomJS process hanging');
+        }
+    }
+}

+ 30 - 0
src/JonnyW/PhantomJs/Procedure/ProcedureValidatorInterface.php

@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Procedure;
+
+use JonnyW\PhantomJs\ClientInterface;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+interface ProcedureValidatorInterface
+{
+    /**
+     * Validate procedure.
+     *
+     * @access public
+     * @param  \JonnyW\PhantomJs\ClientInterface              $client
+     * @param  \JonnyW\PhantomJs\Procedure\ProcedureInterface $procedure
+     * @param  \JonnyW\PhantomJs\Procedure\InputInterface     $message
+     * @return boolean
+     */
+    public function validate(ClientInterface $client, ProcedureInterface $procedure, InputInterface $message);
+}

+ 13 - 4
src/JonnyW/PhantomJs/Resources/config/config.yml

@@ -7,6 +7,8 @@ parameters:
     phantomjs.cache_dir: /tmp
     phantomjs.procedure_dir: "%phantomjs.resource_dir%/procedures"
     phantomjs.procedure_extension: proc
+    phantomjs.validator_dir: "%phantomjs.resource_dir%/validators"
+    phantomjs.validator_engine: "esprima-2.0.0.js"
 
 ##################
 ### PROCEDURES ###
@@ -16,12 +18,13 @@ parameters:
     phantomjs.procedure.chain_loader.class: JonnyW\PhantomJs\Procedure\ChainProcedureLoader
     phantomjs.procedure.procedure_factory.class: JonnyW\PhantomJs\Procedure\ProcedureFactory
     phantomjs.procedure.procedure_loader_factory.class: JonnyW\PhantomJs\Procedure\ProcedureLoaderFactory
+    phantomjs.procedure.procedure_validator.class: JonnyW\PhantomJs\Procedure\ProcedureValidator
 
-################
-### MESSAGES ###
-################
+############
+### HTTP ###
+############
 
-    phantomjs.message.message_factory.class: JonnyW\PhantomJs\Message\MessageFactory
+    phantomjs.http.message_factory.class: JonnyW\PhantomJs\Http\MessageFactory
 
 ################
 ### PARSING ####
@@ -29,6 +32,12 @@ parameters:
 
     phantomjs.parser.json_parser.class: JonnyW\PhantomJs\Parser\JsonParser
 
+###################
+### VALIDATION ####
+###################
+
+    phantomjs.validator.esprima.class: JonnyW\PhantomJs\Validator\Esprima
+
 ##################
 ### TEMPLATES ####
 ##################

+ 56 - 14
src/JonnyW/PhantomJs/Resources/config/services.yml

@@ -7,43 +7,61 @@ services:
     procedure_loader:
         alias: phantomjs.procedure.chain_loader
 
+    procedure_validator:
+        alias: phantomjs.procedure.procedure_validator
+
     procedure_loader_factory:
         alias: phantomjs.procedure.procedure_loader_factory
 
     phantomjs.procedure.file_locator:
         class: %phantomjs.loader.file_locator.class%
-        arguments: [ %phantomjs.procedure_dir% ]
+        arguments:
+            - %phantomjs.procedure_dir%
         public: false
 
     phantomjs.procedure.procedure_loader:
         class: %phantomjs.procedure.procedure_loader.class%
-        arguments: [ @phantomjs.procedure.procedure_factory, @phantomjs.procedure.file_locator ]
+        arguments:
+            - @phantomjs.procedure.procedure_factory
+            - @phantomjs.procedure.file_locator
         public: false
 
     phantomjs.procedure.chain_loader:
         class: %phantomjs.procedure.chain_loader.class%
-        arguments: [ [ @phantomjs.procedure.procedure_loader ] ]
+        arguments:
+            - [ @phantomjs.procedure.procedure_loader ]
         public: false
 
     phantomjs.procedure.procedure_factory:
         class: %phantomjs.procedure.procedure_factory.class%
-        arguments: [ @phantomjs.parser.json_parser, @phantomjs.cache.file_cache, @phantomjs.template.template_renderer ]
+        arguments:
+            - @phantomjs.parser.json_parser
+            - @phantomjs.cache.file_cache
+            - @phantomjs.template.template_renderer
         public: false
 
     phantomjs.procedure.procedure_loader_factory:
         class: %phantomjs.procedure.procedure_loader_factory.class%
-        arguments: [ @phantomjs.procedure.procedure_factory ]
+        arguments:
+            - @phantomjs.procedure.procedure_factory
         public: false
 
-################
-### MESSAGES ###
-################
+    phantomjs.procedure.procedure_validator:
+        class: %phantomjs.procedure.procedure_validator.class%
+        arguments:
+            - @procedure_loader
+            - @validator
+        public: false
+
+############
+### HTTP ###
+############
 
     message_factory:
-        alias: phantomjs.message.message_factory
+        alias: phantomjs.http.message_factory
 
-    phantomjs.message.message_factory:
-        class: %phantomjs.message.message_factory.class%
+    phantomjs.http.message_factory:
+        class: %phantomjs.http.message_factory.class%
         public: false
 
 ################
@@ -54,18 +72,40 @@ services:
         class: %phantomjs.parser.json_parser.class%
         public: false
 
+###################
+### VALIDATION ####
+###################
+
+    validator:
+        alias: phantomjs.validator.esprima
+
+    phantomjs.validator.file_locator:
+        class: %phantomjs.loader.file_locator.class%
+        arguments:
+            - %phantomjs.validator_dir%
+        public: false
+
+    phantomjs.validator.esprima:
+        class: %phantomjs.validator.esprima.class%
+        arguments:
+            - @phantomjs.validator.file_locator
+            - %phantomjs.validator_engine%
+        public: false
+
 ##################
 ### TEMPLATES ####
 ##################
 
     phantomjs.template.template_renderer:
         class: %phantomjs.template.template_renderer.class%
-        arguments: [ @phantomjs.twig.environment ]
+        arguments:
+            - @phantomjs.twig.environment
         public: false
 
     phantomjs.twig.environment:
         class: %phantomjs.twig.environment.class%
-        arguments: [ @phantomjs.twig.string_loader ]
+        arguments:
+            - @phantomjs.twig.string_loader
         public: false
 
     phantomjs.twig.string_loader:
@@ -78,5 +118,7 @@ services:
 
     phantomjs.cache.file_cache:
         class: %phantomjs.cache.file_cache.class%
-        arguments: [ %phantomjs.cache_dir%, %phantomjs.procedure_extension% ]
+        arguments:
+            - %phantomjs.cache_dir%
+            - %phantomjs.procedure_extension%
         public: false

+ 18 - 18
src/JonnyW/PhantomJs/Resources/procedures/capture.proc → src/JonnyW/PhantomJs/Resources/procedures/http_capture.proc

@@ -6,14 +6,14 @@
 var page       = require('webpage').create(),
     system     = require('system'),
     response   = {},
-    headers    = {{ request.getHeaders('json') }},
-    delay      = {{ request.getDelay() }},
-    top        = {{ request.getRectTop() }},
-    left       = {{ request.getRectLeft() }},
-    width      = {{ request.getRectWidth() }},
-    height     = {{ request.getRectHeight() }},
-    vpWidth    = {{ request.getViewportWidth() }},
-    vpHeight   = {{ request.getViewportHeight() }},
+    headers    = {{ input.getHeaders('json') }},
+    delay      = {{ input.getDelay() }},
+    top        = {{ input.getRectTop() }},
+    left       = {{ input.getRectLeft() }},
+    width      = {{ input.getRectWidth() }},
+    height     = {{ input.getRectHeight() }},
+    vpWidth    = {{ input.getViewportWidth() }},
+    vpHeight   = {{ input.getViewportHeight() }},
     debug      = [],
     logs       = [],
     procedure  = {};
@@ -55,7 +55,7 @@ page.customHeaders = headers ? headers : {};
 /**
  * Set timeout.
  */
-page.settings.resourceTimeout = {{ request.getTimeout() }};
+page.settings.resourceTimeout = {{ input.getTimeout() }};
 
 /**
  * Set error in response on timeout.
@@ -104,19 +104,19 @@ phantom.onError = function(msg, trace) {
     response.content = msg;
     response.console = stack;
 
-    console.log(JSON.stringify(response, undefined, 4));
+    system.stdout.write(JSON.stringify(response, undefined, 4));
     phantom.exit(1);
 };
 
 /**
  * Open page.
  *
- * @param string $url
- * @param string $method
- * @param string $parameters
- * @param callable $callback
+ * @param string url
+ * @param string method
+ * @param string parameters
+ * @param callable callback
  */
-page.open ('{{ request.getUrl() }}', '{{ request.getMethod() }}', '{{ request.getBody() }}', function (status) {
+page.open ('{{ input.getUrl() }}', '{{ input.getMethod() }}', '{{ input.getBody() }}', function (status) {
 
     if(!delay) {
         return procedure.execute(status);
@@ -141,7 +141,7 @@ procedure.execute = function (status) {
         
         try {
         
-            page.render('{{ request.getCaptureFile() }}');
+            page.render('{{ input.getCaptureFile() }}');
             
             response.content = page.evaluate(function () {
                 return document.getElementsByTagName('html')[0].innerHTML
@@ -156,8 +156,8 @@ procedure.execute = function (status) {
     
     response.console = logs;
     
-    system.stderr.write(debug.join('\n') + '\n');
-    console.log(JSON.stringify(response, undefined, 4));
+    system.stderr.write(debug.join('\\n') + '\\n');
+    system.stdout.write(JSON.stringify(response, undefined, 4));
     
     phantom.exit();
 };

+ 13 - 13
src/JonnyW/PhantomJs/Resources/procedures/default.proc → src/JonnyW/PhantomJs/Resources/procedures/http_default.proc

@@ -5,10 +5,10 @@
  */
 var page       = require('webpage').create(),
     system     = require('system'),
-    headers    = {{ request.getHeaders('json') }},
-    delay      = {{ request.getDelay() }},
-    vpWidth    = {{ request.getViewportWidth() }},
-    vpHeight   = {{ request.getViewportHeight() }},
+    headers    = {{ input.getHeaders('json') }},
+    delay      = {{ input.getDelay() }},
+    vpWidth    = {{ input.getViewportWidth() }},
+    vpHeight   = {{ input.getViewportHeight() }},
     response   = {},
     debug      = [],
     logs       = [],
@@ -35,7 +35,7 @@ page.customHeaders = headers ? headers : {};
 /**
  * Set timeout.
  */
-page.settings.resourceTimeout = {{ request.getTimeout() }};
+page.settings.resourceTimeout = {{ input.getTimeout() }};
 
 /**
  * Set error in response on timeout.
@@ -84,19 +84,19 @@ phantom.onError = function(msg, trace) {
     response.content = msg;
     response.console = stack;
 
-    console.log(JSON.stringify(response, undefined, 4));
+    system.stdout.write(JSON.stringify(response, undefined, 4));
     phantom.exit(1);
 };
 
 /**
  * Open page.
  *
- * @param string $url
- * @param string $method
- * @param string $parameters
- * @param callable $callback
+ * @param string url
+ * @param string method
+ * @param string parameters
+ * @param callable callback
  */
-page.open ('{{ request.getUrl() }}', '{{ request.getMethod() }}', '{{ request.getBody() }}', function (status) {
+page.open ('{{ input.getUrl() }}', '{{ input.getMethod() }}', '{{ input.getBody() }}', function (status) {
     
     if(!delay) {
         return procedure.execute(status);
@@ -134,8 +134,8 @@ procedure.execute = function (status) {
     
     response.console = logs;
     
-    system.stderr.write(debug.join('\n') + '\n');
-    console.log(JSON.stringify(response, undefined, 4));
+    system.stderr.write(debug.join('\\n') + '\\n');
+    system.stdout.write(JSON.stringify(response, undefined, 4));
     
     phantom.exit();
 };

+ 29 - 0
src/JonnyW/PhantomJs/Resources/procedures/validator.proc

@@ -0,0 +1,29 @@
+{% autoescape false %}
+
+{{ input.get('engine') }}
+
+var system  = require('system'),
+  syntax = {};
+
+try {
+    
+  syntax = esprima.parse("{{ input.get('procedure')|replace({'"': '\'', '\n': ' ', '\r': ' '}) }}");
+      
+} catch(e) {
+    
+  syntax.errors = [{
+    column:      e.column,
+    description: e.description,
+    index:       e.index,
+    lineNumber:  e.lineNumber,
+    message:     e.message   
+  }];
+}
+
+system.stdout.write(
+  JSON.stringify(syntax, undefined, 4)
+);
+
+phantom.exit(1);
+
+{% endautoescape %}

Разница между файлами не показана из-за своего большого размера
+ 59 - 0
src/JonnyW/PhantomJs/Resources/validators/esprima-2.0.0.js


+ 8 - 41
src/JonnyW/PhantomJs/Tests/Integration/ClientTest.php

@@ -73,47 +73,16 @@ EOF;
     }
 
     /**
-     * Test request returns a status code of zero
-     * if a procedure parse exception is encountered.
+     * Test syntax exception is thrown if request
+     * procedure contains syntax error.
      *
      * @access public
      * @return void
      */
-    public function testRequestReturnsAStatusCodeOfZeroIfAProcedureParseExceptionIsEncountered()
+    public function testSyntaxExceptionIsThrownIfRequestProcedureContainsSyntaxError()
     {
-        $content = 'TEST_PROCEDURE';
-
-        $procedure = <<<EOF
-    console.log(;
-EOF;
+        $this->setExpectedException('\JonnyW\PhantomJs\Exception\SyntaxException');
 
-        $this->writeProcedure($procedure);
-
-        $procedureLoaderFactory = $this->getContainer()->get('procedure_loader_factory');
-        $procedureLoader        = $procedureLoaderFactory->createProcedureLoader($this->directory);
-
-        $client = $this->getClient();
-        $client->getProcedureLoader()->addLoader($procedureLoader);
-
-        $request  = $client->getMessageFactory()->createRequest();
-        $response = $client->getMessageFactory()->createResponse();
-
-        $request->setType('test');
-
-        $client->send($request, $response);
-
-        $this->assertEquals(0, $response->getStatus());
-    }
-
-    /**
-     * Test client contains parse error in log if
-     * a parse exception is encountered.
-     *
-     * @access public
-     * @return void
-     */
-    public function testClientContainsParseErrorInLogIfAParseExceptionIsEncountered()
-    {
         $content = 'TEST_PROCEDURE';
 
         $procedure = <<<EOF
@@ -134,8 +103,6 @@ EOF;
         $request->setType('test');
 
         $client->send($request, $response);
-
-        $this->assertContains('SyntaxError: Parse error', $client->getLog());
     }
 
     /**
@@ -505,7 +472,7 @@ EOF;
 
         $client->send($request, $response);
 
-        $logs = explode("\n", $client->getLog());
+        $logs = explode("\\n", $client->getLog());
 
         $startIndex = $this->getLogEntryIndex($logs, 'Delaying page render for');
         $endIndex   = $this->getLogEntryIndex($logs, 'Rendering page after');
@@ -538,7 +505,7 @@ EOF;
 
         $client->send($request, $response);
 
-        $logs = explode("\n", $client->getLog());
+        $logs = explode("\\n", $client->getLog());
 
         $startIndex = $this->getLogEntryIndex($logs, 'Delaying page render for');
 
@@ -567,7 +534,7 @@ EOF;
 
         $client->send($request, $response);
 
-        $logs = explode("\n", $client->getLog());
+        $logs = explode("\\n", $client->getLog());
 
         $endIndex = $this->getLogEntryIndex($logs, 'Rendering page after');
 
@@ -596,7 +563,7 @@ EOF;
 
         $client->send($request, $response);
 
-        $logs = explode("\n", $client->getLog());
+        $logs = explode("\\n", $client->getLog());
 
         $startIndex = $this->getLogEntryIndex($logs, 'Delaying page render for');
         $endIndex   = $this->getLogEntryIndex($logs, 'Rendering page after');

+ 294 - 0
src/JonnyW/PhantomJs/Tests/Integration/Procedure/ProcedureValidatorTest.php

@@ -0,0 +1,294 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Tests\Integration\Procedure;
+
+use Twig_Environment;
+use Twig_Loader_String;
+use Symfony\Component\Config\FileLocator;
+use JonnyW\PhantomJs\Client;
+use JonnyW\PhantomJs\Cache\FileCache;
+use JonnyW\PhantomJs\Parser\JsonParser;
+use JonnyW\PhantomJs\Template\TemplateRenderer;
+use JonnyW\PhantomJs\Procedure\Input;
+use JonnyW\PhantomJs\Procedure\Procedure;
+use JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface;
+use JonnyW\PhantomJs\Procedure\ProcedureValidator;
+use JonnyW\PhantomJs\Validator\Esprima;
+use JonnyW\PhantomJs\Validator\EngineInterface;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class ProcedureValidatorTest extends \PHPUnit_Framework_TestCase
+{
+
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++++++ TESTS ++++++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
+    /**
+     * Test syntax exception is
+     * thrown if procedure contains
+     * syntax error.
+     *
+     * @access public
+     * @return void
+     */
+    public function testProcedureSyntaxExceptionIsThrownIfProcedureContainsSyntaxError()
+    {
+        $this->setExpectedException('\JonnyW\PhantomJs\Exception\SyntaxException');
+
+        $procedureLoader = $this->getProcedureLoader();
+        $esprima         = $this->getEsprima();
+
+        $client    = $this->getClient();
+        $procedure = $this->getProcedure();
+        $message   = $this->getInput();
+
+        $procedure->setTemplate('return false; var');
+
+        $validator = $this->getValidator($procedureLoader, $esprima);
+        $validator->validate($client, $procedure, $message);
+    }
+
+    /**
+     * Test syntax exception contains errors.
+     *
+     * @access public
+     * @return void
+     */
+    public function testSyntaxExceptionContainsErrors()
+    {
+        $procedureLoader = $this->getProcedureLoader();
+        $esprima         = $this->getEsprima();
+
+        $client    = $this->getClient();
+        $procedure = $this->getProcedure();
+        $message   = $this->getInput();
+
+        $procedure->setTemplate('return false; var');
+
+        try {
+
+            $validator = $this->getValidator($procedureLoader, $esprima);
+            $validator->validate($client, $procedure, $message);
+
+        } catch (\JonnyW\PhantomJs\Exception\SyntaxException $e) {
+            $this->assertNotEmpty($e->getErrors());
+        }
+    }
+
+    /**
+     * Test requirement exception is thrown
+     * if procedure does not contain phantom
+     * exit statement.
+     *
+     * @access public
+     * @return void
+     */
+    public function testRequirementExceptionIsThrownIfProcedureDoesNotContainPhanomtExitStatement()
+    {
+        $this->setExpectedException('\JonnyW\PhantomJs\Exception\RequirementException');
+
+        $procedureLoader = $this->getProcedureLoader();
+        $esprima         = $this->getEsprima();
+
+        $client    = $this->getClient();
+        $procedure = $this->getProcedure();
+        $message   = $this->getInput();
+
+        $procedure->setTemplate('var test = function () { console.log("ok"); }');
+
+        $validator = $this->getValidator($procedureLoader, $esprima);
+        $validator->validate($client, $procedure, $message);
+    }
+
+    /**
+     * Test true is returned if procedure is valid
+     *
+     * @access public
+     * @return void
+     */
+    public function testTrueIsReturnedIfProcedureIsValid()
+    {
+        $procedureLoader = $this->getProcedureLoader();
+        $esprima         = $this->getEsprima();
+
+        $client    = $this->getClient();
+        $procedure = $this->getProcedure();
+        $message   = $this->getInput();
+
+        $procedure->setTemplate('var test = function () { console.log("ok"); }; phantom.exit(1);');
+
+        $validator = $this->getValidator($procedureLoader, $esprima);
+
+        $this->assertTrue($validator->validate($client, $procedure, $message));
+    }
+
+    /**
+     * Test procedure is valid if procedure
+     * has comments.
+     *
+     * @access public
+     * @return void
+     */
+    public function testProcedureIsValidIfProcedureHasComments()
+    {
+        $procedureLoader = $this->getProcedureLoader();
+        $esprima         = $this->getEsprima();
+
+        $client    = $this->getClient();
+        $procedure = $this->getProcedure();
+        $message   = $this->getInput();
+
+        $procedure->setTemplate('/** * Test comment **/ var test = function () { console.log("ok"); }; phantom.exit(1);');
+
+        $validator = $this->getValidator($procedureLoader, $esprima);
+
+        $this->assertTrue($validator->validate($client, $procedure, $message));
+    }
+
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++ TEST ENTITIES ++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
+    /**
+     * Get procedure validator.
+     *
+     * @access protected
+     * @param  \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface $procedureLoader
+     * @param  \JonnyW\PhantomJs\Validator\EngineInterface          $engine
+     * @return \JonnyW\PhantomJs\Procedure\ProcedureValidator
+     */
+    protected function getValidator(ProcedureLoaderInterface $procedureLoader, EngineInterface $engine)
+    {
+        $validator = new ProcedureValidator($procedureLoader, $engine);
+
+        return $validator;
+    }
+
+    /**
+     * Get client.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Client
+     */
+    protected function getClient()
+    {
+        $client = Client::getInstance();
+        $client->setPhantomJs(sprintf('%s/../../../../../../bin/phantomjs', __DIR__));
+
+        return $client;
+    }
+
+    /**
+     * Get procedure loader.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Procedure\ProcedureLoader
+     */
+    protected function getProcedureLoader()
+    {
+        return  Client::getInstance()->getProcedureLoader();
+    }
+
+    /**
+     * Get procedure instance.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Procedure\Procedure
+     */
+    protected function getProcedure()
+    {
+        $procedure = new Procedure(
+            $this->getParser(),
+            $this->getCache(),
+            $this->getRenderer()
+        );
+
+        return $procedure;
+    }
+
+    /**
+     * Get parser.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Parser\JsonParser
+     */
+    protected function getParser()
+    {
+        $parser = new JsonParser();
+
+        return $parser;
+    }
+
+    /**
+     * Get cache.
+     *
+     * @access protected
+     * @param  string                            $cacheDir  (default: '')
+     * @param  string                            $extension (default: 'proc')
+     * @return \JonnyW\PhantomJs\Cache\FileCache
+     */
+    protected function getCache($cacheDir = '', $extension = 'proc')
+    {
+        $cache = new FileCache(($cacheDir ? $cacheDir : sys_get_temp_dir()), 'proc');
+
+        return $cache;
+    }
+
+    /**
+     * Get template renderer.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Template\TemplateRenderer
+     */
+    protected function getRenderer()
+    {
+        $twig = new Twig_Environment(
+            new Twig_Loader_String()
+        );
+
+        $renderer = new TemplateRenderer($twig);
+
+        return $renderer;
+    }
+
+    /**
+     * Get input
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Procedure\Input
+     */
+    protected function getInput()
+    {
+        $input = new Input();
+
+        return $input;
+    }
+
+    /**
+     * Get esprima.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Validator\Esprima
+     */
+    protected function getEsprima()
+    {
+        $fileLocator = new FileLocator(
+            sprintf('%s/../../../Resources/validators/', __DIR__)
+        );
+
+        $esprima = new Esprima($fileLocator, 'esprima-2.0.0.js');
+
+        return $esprima;
+    }
+}

+ 27 - 69
src/JonnyW/PhantomJs/Tests/Unit/Cache/FileCacheTest.php

@@ -38,13 +38,13 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test exists returns false if
-     * file does not exist.
+     * Test false is returned if file
+     * does not exist.
      *
      * @access public
      * @return void
      */
-    public function testExistsReturnsFalesIfFileDoesNotExist()
+    public function testFalseIsReturnedIfFileDoesNotExist()
     {
         $fileCache = $this->getFileCache($this->directory, 'txt');
 
@@ -52,13 +52,12 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test exists returns true if
-     * file does exist.
+     * Test true is returned if file does exist.
      *
      * @access public
      * @return void
      */
-    public function testExistsReturnsTrueIfFileDoesExist()
+    public function testTrueIsReturnedIfFileDoesExist()
     {
         touch($this->getFilename());
 
@@ -68,12 +67,12 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test save throws not writable
-     * exception if file is not writable
+     * Test not writable exception is thrown if file
+     * cannot be saved due to write permissions.
      *
      * @return void
      */
-    public function testSaveThrowsNotWritableExceptionIfFileIsNotWritable()
+    public function testNotWritableExceptionIsThrownIfFileCannotBeSavedDueToWritePermissions()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\NotWritableException');
 
@@ -82,32 +81,13 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test save throws not writable
-     * exception if write data returns
-     * false
+     * Test test file location is returned
+     * if file is successfully saved.
      *
      * @access public
      * @return void
      */
-    public function testSaveThrowsNotWritableExceptionIfWriteFileReturnsFalse()
-    {
-        $this->setExpectedException('\JonnyW\PhantomJs\Exception\NotWritableException');
-
-        $fileCache = $this->getMockFileCache(array('writeData'), $this->directory, 'txt');
-        $fileCache->method('writeData')
-            ->will($this->returnValue(false));
-
-        $fileCache->save($this->filename, 'Test');
-    }
-
-    /**
-     * Test save returns file location if
-     * file is successfully saved.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSaveReturnsFileLocationIfFileIsSuccessfullySaved()
+    public function testFileLocationIsReturnedIfFileIsSuccessfullySaved()
     {
         $fileCache  = $this->getFileCache($this->directory, 'txt');
         $file       = $fileCache->save($this->filename, 'Test');
@@ -117,13 +97,13 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test save with directory path
-     * saves file to directory
+     * Test file can be saved
+     * with directory path
      *
      * @access public
      * @return void
      */
-    public function testSaveWithDirectoryPathSavesFileToDirectory()
+    public function testFileCanBeSavedWithDirectoryPath()
     {
         $fileCache  = $this->getFileCache('', 'txt');
         $file       = $fileCache->save($this->directory, 'Test');
@@ -134,14 +114,13 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test save with directory path
-     * throws not writable exception
-     * if path is not writable
+     * Test not writable exception is thrown
+     * if directory path is not writable.
      *
      * @access public
      * @return void
      */
-    public function testSaveWithDirectoryPathThrowsNotWritableExceptionIfPathIsNotWritable()
+    public function testNotWritableExceptionIsThrownIfDirectoryPathIsNotWritable()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\NotWritableException');
 
@@ -150,13 +129,13 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test save with absolute filename
-     * saves file.
+     * Test file can be saved with absolute
+     * path.
      *
      * @access public
      * @return void
      */
-    public function testSaveWithAbsoluteFilenameSavesFile()
+    public function testFileCanBeSavedWithAbsolutePath()
     {
         $test = sprintf('%1$s/%2$s', $this->directory, 'new-file.txt');
 
@@ -169,13 +148,13 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test fetch data returns not exists
-     * exception if file does not exist.
+     * Test not exists exception is thrown when
+     * fetching data that doesn't exsit
      *
      * @access public
      * @return void
      */
-    public function testFetchDataThrowsNotExistsExceptionIfFileDoesNotExist()
+    public function testNotExistsExceptionIsThrownIfWhenFetchingDataThatDoesntExist()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\NotExistsException');
 
@@ -185,13 +164,12 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test fetch data returns data if
-     * file exists..
+     * Test data can be fetched from cache.
      *
      * @access public
      * @return void
      */
-    public function testFetchDataReturnsDataIfFileExists()
+    public function testDataCanBeFetchedFromCache()
     {
         $test = 'Test';
 
@@ -204,12 +182,12 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test delete removes file.
+     * Test data can be deleted from cache.
      *
      * @access public
      * @return void
      */
-    public function testDeleteRemovesFile()
+    public function testDataCanBeDeletedFromCache()
     {
         $fileCache = $this->getFileCache($this->directory, 'txt');
 
@@ -238,26 +216,6 @@ class FileCacheTest extends \PHPUnit_Framework_TestCase
         return $fileCache;
     }
 
-/** +++++++++++++++++++++++++++++++++++ **/
-/** ++++++++++ MOCKS / STUBS ++++++++++ **/
-/** +++++++++++++++++++++++++++++++++++ **/
-
-    /**
-     * Get mock file cache.
-     *
-     * @access protected
-     * @param  array                             $methods
-     * @param  string                            $directory
-     * @param  string                            $extension
-     * @return \JonnyW\PhantomJs\Cache\FileCache
-     */
-    protected function getMockFileCache(array $methods, $directory, $extension)
-    {
-        $mockFileCache = $this->getMock('\JonnyW\PhantomJs\Cache\FileCache', $methods, array($directory, $extension));
-
-        return $mockFileCache;
-    }
-
 /** +++++++++++++++++++++++++++++++++++ **/
 /** ++++++++++++ UTILITIES ++++++++++++ **/
 /** +++++++++++++++++++++++++++++++++++ **/

+ 116 - 391
src/JonnyW/PhantomJs/Tests/Unit/ClientTest.php

@@ -9,8 +9,9 @@
 namespace JonnyW\PhantomJs\Tests\Unit;
 
 use JonnyW\PhantomJs\Client;
-use JonnyW\PhantomJs\Message\MessageFactoryInterface;
+use JonnyW\PhantomJs\Http\MessageFactoryInterface;
 use JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface;
+use JonnyW\PhantomJs\Procedure\ProcedureValidatorInterface;
 
 /**
  * PHP PhantomJs
@@ -25,181 +26,145 @@ class ClientTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test get instance returns instance
-     * of client.
+     * Test can get client through
+     * factory method.
      *
      * @access public
      * @return void
      */
-    public function testGetInstanceReturnsInstanceOfClient()
+    public function testCanGetClientThroughFactoryMethod()
     {
         $this->assertInstanceOf('\JonnyW\PhantomJs\Client', Client::getInstance());
     }
 
     /**
-     * Test get message factory returns instance
-     * of message factory.
+     * Test can get message factory
      *
      * @return void
      */
-    public function testGetMessageFactoryReturnsInstanceOfMessageFactory()
+    public function testCanGetMessageFactory()
     {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
 
-        $this->assertInstanceOf('\JonnyW\PhantomJs\Message\MessageFactoryInterface', $client->getMessageFactory());
+        $this->assertInstanceOf('\JonnyW\PhantomJs\Http\MessageFactoryInterface', $client->getMessageFactory());
     }
 
     /**
-     * Test get procedure loader returns
-     * instance of proecure loader.
+     * Test can get procedure loader.
      *
      * @return void
      */
-    public function testGetProcedureLoaderReturnsInstanceOfProcedureLoader()
+    public function testCanGetProcedureLoader()
     {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
 
         $this->assertInstanceOf('\JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface', $client->getProcedureLoader());
     }
 
     /**
-     * Test set phantom JS throws invalid
-     * executable exception if phantom
-     * JS path is invalid.
+     * Test invalid executable exception is thrown
+     * if phantom JS path is invalid.
      *
      * @access public
      * @return void
      */
-    public function testSetPhantomJsThrowsInvalidExecutableExceptionIfPhantomJsPathIsInvalid()
+    public function testInvalidExecutableExceptionIsThrownIfPhantomJSPathIsInvalid()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidExecutableException');
 
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
         $client->setPhantomJs('/invalid/phantomjs/path');
     }
 
     /**
-     * Test set phantom loader throws invalid
-     * executable exception if phantom
-     * loader path is invalid.
+     * Test default phantom JS path is returned
+     * if no custom path is set.
      *
      * @access public
      * @return void
      */
-    public function testSetPhantomLoaderThrowsInvalidExecutableExceptionIfPhantomLoaderPathIsInvalid()
+    public function testDefaultPhantomJSPathIsReturnedIfNoCustomPathIsSet()
     {
-        $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidExecutableException');
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setPhantomLoader('/invalid/phantomloader/path');
-    }
-
-    /**
-     * Test get phantom JS returns default path
-     * to phantom JS executable.
-     *
-     * @access public
-     * @return void
-     */
-    public function testGetPhantomJsReturnsDefaultPathToPhantomJsExecutable()
-    {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
 
         $this->assertSame('bin/phantomjs', $client->getPhantomJs());
     }
 
     /**
-     * Test get phantom loader returns default path
-     * to phantom loader executable.
+     * Test can log data.
      *
      * @access public
      * @return void
      */
-    public function testGetPhantomLoaderReturnsDefaultPathToPhantomLoaderExecutable()
+    public function testCanLogData()
     {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-
-        $this->assertSame('bin/phantomloader', $client->getPhantomLoader());
-    }
-
-    /**
-     * Test set log sets log info in
-     * client.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetLogSetsLogInfoInClient()
-    {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
         $log = 'Test log info';
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setLog($log);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
+        $client->log($log);
 
         $this->assertSame($log, $client->getLog());
     }
 
     /**
-     * Test clear log clears log
-     * info in client.
+     * Test can clear log.
      *
      * @access public
      * @return void
      */
-    public function testClearLogsClearsLogInfoInClient()
+    public function testCanClearLog()
     {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
         $log = 'Test log info';
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setLog($log);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
+        $client->log($log);
         $client->clearLog();
 
         $this->assertEmpty($client->getLog());
     }
 
     /**
-     * Test add option adds option to
-     * Phantom Js run options if option
-     * is not set.
+     * Test can add run option.
      *
      * @access public
      * @return void
      */
-    public function testAddOptionAddsOptionToPhantomJsRunOptionsIfOptionIsNotSet()
+    public function testCanAddRunOption()
     {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
         $options = array(
             'option1',
             'option2'
         );
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
         $client->setOptions($options);
         $client->addOption('option3');
 
@@ -209,45 +174,21 @@ class ClientTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test add option does not add option
-     * to Phantom Js run options if option
-     * is set.
+     * Test invalid executable exception is thrown when
+     * building command if path to phantom JS is valid.
      *
      * @access public
      * @return void
      */
-    public function testAddOptionDoesNotAddOptionToPhantomJsRunOptionsIfOptionIsSet()
-    {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $options = array(
-            'option1',
-            'option2'
-        );
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setOptions($options);
-        $client->addOption('option2');
-
-        $this->assertSame($options, $client->getOptions());
-    }
-
-    /**
-     * Test get command throws invalid executable
-     * exception if PhantomJs is invalid.
-     *
-     * @access public
-     * @return void
-     */
-    public function testGetCommandThrowsInvalidExecutableExceptionIfPhantomJsIsInvalid()
+    public function testInvalidExecutableExceptionIsThrownWhenBuildingCommandIfPathToPhantomJSIsInvalid()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidExecutableException');
 
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
 
         $phantomJs = new \ReflectionProperty(get_class($client), 'phantomJs');
         $phantomJs->setAccessible(true);
@@ -257,131 +198,76 @@ class ClientTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get command throws invalid executable
-     * exception if PhantomLoader is invalid..
+     * Test command contains phantom JS executable
      *
      * @access public
      * @return void
      */
-    public function testGetCommandThrowsInvalidExecutableExceptionIfPhantomLoaderIsInvalid()
+    public function testCommandContainsPhantomJSExecutable()
     {
-        $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidExecutableException');
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
-
-        $phantomLoader = new \ReflectionProperty(get_class($client), 'phantomLoader');
-        $phantomLoader->setAccessible(true);
-        $phantomLoader->setValue($client, 'invalid/path');
-
-        $client->getCommand();
-    }
-
-    /**
-     * Test get command contains PhantomKs executable.
-     *
-     * @access public
-     * @return void
-     */
-    public function testGetCommandContainsPhantomJsExecutable()
-    {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
 
         $this->assertContains($client->getPhantomJs(), $client->getCommand());
     }
 
     /**
-     * Test get command contains PhantomLoader executable.
-     *
-     * @access public
-     * @return void
-     */
-    public function testGetCommandContainsPhantomLoaderExecutable()
-    {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-
-        $this->assertContains($client->getPhantomLoader(), $client->getCommand());
-    }
-
-    /**
-     * Test get command sets debug flag if debug is
-     * set to true.
+     * Test debug flag can be set.
      *
      * @access public
      * @return void
      */
-    public function testGetCommandSetsDebugFlagIfDebugIsSetToTrue()
+    public function testDebugFlagCanBeSet()
     {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
         $client->debug(true);
 
         $this->assertContains('--debug=true', $client->getCommand());
     }
 
     /**
-     * Test get command does not set debug flag if
-     * debug is set to false.
+     * Test debug flag is not set if
+     * debugging is not enabled.
      *
      * @access public
      * @return void
      */
-    public function testGetCommandDoesNotSetDebugFlagIfDebugIsSetToFalse()
+    public function testDebugFlagIsNotSetIfDebuggingIsNotEnabled()
     {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
         $client->debug(false);
 
         $this->assertNotContains('--debug=true', $client->getCommand());
     }
 
     /**
-     * Test get command sets 1 option.
-     *
-     * @access public
-     * @return void
-     */
-    public function testGetCommandSets1Option()
-    {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $option = '--local-storage-path=/some/path';
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->addOption($option);
-
-        $this->assertContains($option, $client->getCommand());
-    }
-
-    /**
-     * Test get command sets multiple options.
+     * Test command contains run options.
      *
      * @access public
      * @return void
      */
-    public function testGetCommandSetsMultipleOptions()
+    public function testCommandContainsRunOptions()
     {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
         $option1 = '--local-storage-path=/some/path';
         $option2 = '--local-storage-quota=5';
         $option3 = '--local-to-remote-url-access=true';
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
         $client->addOption($option1);
         $client->addOption($option2);
         $client->addOption($option3);
@@ -394,20 +280,21 @@ class ClientTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get command sets debug option if
-     * additional options are set.
+     * Test debug flag is set if runs options
+     * are also set.
      *
      * @access public
      * @return void
      */
-    public function testGetCommandSetsDebugOptionIfAdditionalOptionsAreSet()
+    public function testDebugFlagIsSetIfRunOptionsAreAlsoSet()
     {
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
+        $procedureLoader    = $this->getProcedureLoader();
+        $procedureValidator = $this->getProcedureValidator();
+        $messageFactory     = $this->getMessageFactory();
 
         $option = '--local-storage-path=/some/path';
 
-        $client = $this->getClient($procedureLoader, $messageFactory);
+        $client = $this->getClient($procedureLoader, $procedureValidator, $messageFactory);
         $client->addOption($option);
         $client->debug(true);
 
@@ -417,182 +304,6 @@ class ClientTest extends \PHPUnit_Framework_TestCase
         $this->assertContains('--debug=true', $command);
     }
 
-    /**
-     * Test set bin dir strips forward
-     * slash from end.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetBinDirStripsForwardSlashFromEnd()
-    {
-        $binDir = '/path/to/bin/dir/';
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setBinDir($binDir);
-
-        $this->assertSame('/path/to/bin/dir', $client->getBinDir());
-    }
-
-    /**
-     * Test set bin dir strips multiple forward
-     * slashes from end.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetBinDirStripsMultipleForwardSlashesFromEnd()
-    {
-        $binDir = '/path/to/bin/dir//';
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setBinDir($binDir);
-
-        $this->assertSame('/path/to/bin/dir', $client->getBinDir());
-    }
-
-    /**
-     * Test set bin dir strips backslash
-     * from end.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetBinDirStripsBackslashFromEnd()
-    {
-        $binDir = '\path\to\bin\dir\\';
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setBinDir($binDir);
-
-        $this->assertSame('\path\to\bin\dir', $client->getBinDir());
-    }
-
-    /**
-     * Test set bin dir strips multiple
-     * backslashes from end.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetBinDirStripsMultipleBackslashesFromEnd()
-    {
-        $binDir = '\path\to\bin\dir\\\\';
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setBinDir($binDir);
-
-        $this->assertSame('\path\to\bin\dir', $client->getBinDir());
-    }
-
-    /**
-     * Test set bin dir sets path of
-     * PhantomJs executable.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetBinDirSetsPathOfPhantomJsExecutable()
-    {
-        $binDir = '/path/to/bin/dir';
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setBinDir($binDir);
-
-        $this->assertSame('/path/to/bin/dir/phantomjs', $client->getPhantomJs());
-    }
-
-    /**
-     * Test set bin dir sets path of
-     * Phantom loader executable.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetBinDirSetsPathOfPhantomLoaderExecutable()
-    {
-        $binDir = '/path/to/bin/dir';
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-        $client->setBinDir($binDir);
-
-        $this->assertSame('/path/to/bin/dir/phantomloader', $client->getPhantomLoader());
-    }
-
-    /**
-     * Test set bin dir does not set
-     * path of PhantomJs executable if
-     * custom PhantomJs executable path
-     * is set.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetBinDirDoesNotSetPathToPhantomJsExecutableIfCustomPhantomJsPathIsSet()
-    {
-        $binDir  = '/path/to/bin/dir';
-        $path    = '/path/to/phantomjs';
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-
-        $phantomJs = new \ReflectionProperty(get_class($client), 'phantomJs');
-        $phantomJs->setAccessible(true);
-        $phantomJs->setValue($client, $path);
-
-        $client->setBinDir($binDir);
-
-        $this->assertSame($path, $client->getPhantomJs());
-    }
-
-    /**
-     * Test set bin dir does not set
-     * path of Phantom loader executable if
-     * custom Phantom loader executable path
-     * is set.
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetBinDirDoesNotSetPathToPhantomLoaderExecutableIfCustomPhantomLoaderPathIsSet()
-    {
-        $binDir  = '/path/to/bin/dir';
-        $path    = '/path/to/phantomloader';
-
-        $procedureLoader = $this->getProcedureLoader();
-        $messageFactory  = $this->getMessageFactory();
-
-        $client = $this->getClient($procedureLoader, $messageFactory);
-
-        $phantomLoader = new \ReflectionProperty(get_class($client), 'phantomLoader');
-        $phantomLoader->setAccessible(true);
-        $phantomLoader->setValue($client, $path);
-
-        $client->setBinDir($binDir);
-
-        $this->assertSame($path, $client->getPhantomLoader());
-    }
-
 /** +++++++++++++++++++++++++++++++++++ **/
 /** ++++++++++ TEST ENTITIES ++++++++++ **/
 /** +++++++++++++++++++++++++++++++++++ **/
@@ -600,13 +311,14 @@ class ClientTest extends \PHPUnit_Framework_TestCase
     /**
      * Get client instance
      *
-     * @param  \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface $procedureLoader
-     * @param  \JonnyW\PhantomJs\Message\MessageFactoryInterface    $messageFactory
+     * @param  \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface    $procedureLoader
+     * @param  \JonnyW\PhantomJs\Procedure\ProcedureValidatorInterface $procedureValidator
+     * @param  \JonnyW\PhantomJs\Http\MessageFactoryInterface          $messageFactory
      * @return \JonnyW\PhantomJs\Client
      */
-    protected function getClient(ProcedureLoaderInterface $procedureLoader, MessageFactoryInterface $messageFactory)
+    protected function getClient(ProcedureLoaderInterface $procedureLoader, ProcedureValidatorInterface $procedureValidator, MessageFactoryInterface $messageFactory)
     {
-        $client = new Client($procedureLoader, $messageFactory);
+        $client = new Client($procedureLoader, $procedureValidator, $messageFactory);
 
         return $client;
     }
@@ -616,28 +328,41 @@ class ClientTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Get mock message factory instance.
+     * Get message factory
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Message\MessageFactoryInterface
+     * @return \JonnyW\PhantomJs\Http\MessageFactoryInterface
      */
     protected function getMessageFactory()
     {
-        $mockMessageFactory = $this->getMock('\JonnyW\PhantomJs\Message\MessageFactoryInterface');
+        $messageFactory = $this->getMock('\JonnyW\PhantomJs\Http\MessageFactoryInterface');
 
-        return $mockMessageFactory;
+        return $messageFactory;
     }
 
     /**
-     * Get mock procedure loader instance.
+     * Get procedure loader.
      *
      * @access protected
      * @return \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface
      */
     protected function getProcedureLoader()
     {
-        $mockProcedureLoader = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface');
+        $procedureLoader = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface');
+
+        return $procedureLoader;
+    }
+
+    /**
+     * Get procedure validator.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface
+     */
+    protected function getProcedureValidator()
+    {
+        $procedureValidator = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureValidatorInterface');
 
-        return $mockProcedureLoader;
+        return $procedureValidator;
     }
 }

+ 64 - 90
src/JonnyW/PhantomJs/Tests/Unit/Message/CaptureRequestTest.php → src/JonnyW/PhantomJs/Tests/Unit/Http/CaptureRequestTest.php

@@ -6,10 +6,10 @@
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
-namespace JonnyW\PhantomJs\Tests\Unit\Message;
+namespace JonnyW\PhantomJs\Tests\Unit\Http;
 
-use JonnyW\PhantomJs\Message\CaptureRequest;
-use JonnyW\PhantomJs\Message\RequestInterface;
+use JonnyW\PhantomJs\Http\CaptureRequest;
+use JonnyW\PhantomJs\Http\RequestInterface;
 
 /**
  * PHP PhantomJs
@@ -38,12 +38,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test custom type is returned if type is set.
+     * Test custom type can be set.
      *
      * @access public
      * @return void
      */
-    public function testCustomTypeIsReturnedIfTypeIsSet()
+    public function testCustomTypeCanBeSet()
     {
         $requestType = 'testType';
 
@@ -96,13 +96,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test set method throws invalid method
-     * exception if an invalid method is set
+     * Test invalid method is thrown if method
+     * is invalid.
      *
      * @access public
      * @return void
      */
-    public function testSetMethodThrowsInvalidMethodExceptionIfAnInvalidMethodIsSet()
+    public function testInvalidMethodIsThrownIfMethodIsInvalid()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidMethodException');
 
@@ -110,29 +110,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
         $captureRequest->setMethod('INVALID_METHOD');
     }
 
-  /**
-     * Test set method throws invalid method
-     * exception if an invalid method is set
-     * via constructor
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetMethodThrowsInvalidMethodExceptionIfAnInvalidMethodIsSetViaConstructor()
-    {
-        $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidMethodException');
-
-        $this->getCaptureRequest('http://test.com', 'INVALID_METHOD');
-    }
-
     /**
-     * Test set capture dimensions sets
-     * rect width.
+     * Test rect width can be set.
      *
      * @access public
      * @return void
      */
-    public function testSetCaptureDimensionsSetsRectWidth()
+    public function testRectWidthCanBeSet()
     {
         $width  = 100;
         $height = 200;
@@ -144,13 +128,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test set capture dimensions sets
-     * rect height.
+     * Test rect height can be set.
      *
      * @access public
      * @return void
      */
-    public function testSetCaptureDimensionsSetsRectHeight()
+    public function testRectHeightCanBeSet()
     {
         $width  = 100;
         $height = 200;
@@ -162,13 +145,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test set capture dimensions sets
-     * rect top.
+     * Test rect top can be set.
      *
      * @access public
      * @return void
      */
-    public function testSetCaptureDimensionsSetsRectTop()
+    public function testRectTopCanBeSet()
     {
         $width  = 100;
         $height = 200;
@@ -181,13 +163,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test set capture dimensions sets
-     * rect left.
+     * Test rect left can be set.
      *
      * @access public
      * @return void
      */
-    public function testSetCaptureDimensionsSetsRectLeft()
+    public function testRectLeftCanBeSet()
     {
         $width  = 100;
         $height = 200;
@@ -200,14 +181,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test set URL throws invalid
-     * URL exception if an invalid
-     * URL is set.
+     * Test invalid URL exception is thrown
+     * if URL is invalid format.
      *
      * @access public
      * @return void
      */
-    public function testSetUrlThrowsInvalidUrlExceptionIfAnInvalidUrlIsSet()
+    public function testInvalidUrlExceptionIsThrownIfUrlIsInvalidFormat()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidUrlException');
 
@@ -216,13 +196,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get URL returns URL without query
-     * paramters if method is not HEAD or GET.
+     * Test URL does not contain query params if
+     * mehtod is not HEAD or GET.
      *
      * @access public
      * @return void
      */
-    public function testGetUrlReturnsUrlWithoutQueryParametersIfMethodIsNotHeadOrGet()
+    public function testUrlDoesNotContainQueryParamsIfMethodIsNotHeadOrGet()
     {
         $url = 'http://test.com';
 
@@ -240,13 +220,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get URL returns URL with query
-     * parameters if method is GET.
+     * Test URL does contain query params if mehthod
+     * is GET.
      *
      * @access public
      * @return void
      */
-    public function testGetUrlReturnsUrlWithQueryParametersIfMethodIsGet()
+    public function testUrlDoesContainQueryParamsIfMethodIsGet()
     {
         $url = 'http://test.com';
 
@@ -266,13 +246,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get URL returns URL with query
-     * parameters if method is HEAD.
+     * Test URL does contain query params if method
+     * is HEAD.
      *
      * @access public
      * @return void
      */
-    public function testGetUrlReturnsUrlWithQueryParametersIfMethodIsHead()
+    public function testUrlDoesContainQueryParamsIfMethodIsHead()
     {
         $url = 'http://test.com';
 
@@ -292,13 +272,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get URL returns URL with query
-     * parameters if method is HEAD.
+     * Test query params are appended to URL if
+     * URL contains existng query params.
      *
      * @access public
      * @return void
      */
-    public function testGetUrlAppendsQueryParametersIfUrlHasExistingQueryParameters()
+    public function testQueryParamsAreAppendedToUrlIfUrlContainsExistingQueryParams()
     {
         $url = 'http://test.com?existing_param=Existing';
 
@@ -318,13 +298,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get body returns an empty
-     * string if method is GET.
+     * Test request contains no body if method
+     * is GET.
      *
      * @access public
      * @return void
      */
-    public function testGetBodyReturnsAnEmptyStringIfMethodIsGet()
+    public function testRequestContainsNoBodyIfMethodIsGet()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -339,13 +319,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get body returns and empty
-     * string if method is HEAD.
+     * Test request contains no body if method
+     * is HEAD.
      *
      * @access public
      * @return void
      */
-    public function testGetBodyReturnsAnEmptyStringIfMethodIsHead()
+    public function testRequestContainsNoBodyIfMethodIsHead()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -360,13 +340,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get body returns query string if
-     * method is not HEAD or GET.
+     * Test request contains a body if method is
+     * not HEAD or GET.
      *
      * @access public
      * @return void
      */
-    public function testGetBodyReturnsQueryStringIfMethodIsNotHeadOrGet()
+    public function testRequestContainsABodyIfMethodIsNotHeadOrGet()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -383,13 +363,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get request data returns flattened
-     * request data if flatten is set to true.
+     * Test request data can be flattened.
      *
      * @access public
      * @return void
      */
-    public function testGetRequestDataReturnsFlattenedRequestDataIfFlattenIsSetToTrue()
+    public function testRequestDataCanBeFalttened()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -412,13 +391,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get request data returns unflattened
-     * request data if flatten is set to false
+     * Test raw request data can be accessed.
      *
      * @access public
      * @return void
      */
-    public function testGetRequestDataReturnsUnflattenedRequestDataIfFlattenIsSetToFalse()
+    public function testRawRequestDataCanBeAccessed()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -435,13 +413,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test add headers merge headers with
-     * existing headers.
+     * Test headers can be added.
      *
      * @access public
      * @return void
      */
-    public function testAddHeadersMergesHeadersWithExistingHeaders()
+    public function testHeadersCanBeAdded()
     {
         $existingHeaders = array(
             'Header1' => 'Header 1'
@@ -462,13 +439,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get headers returns JSON encoded
-     * headers if format is set to JSON.
+     * Test headers can be accessed in
+     * JSON format
      *
      * @access public
      * @return void
      */
-    public function testGetHeadersReturnsJsonEncodedHeadersIfFormatIsSetToJson()
+    public function testHeadersCanBeAccessedInJsonFormat()
     {
         $headers = array(
             'Header1' => 'Header 1',
@@ -484,13 +461,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get headers returns headers as
-     * array if format is not set to json
+     * Test raw headers can be accessed.
      *
      * @access public
      * @return void
      */
-    public function testGetHeadersReturnsHeadersAsArrayIfFormatIsNotSetToJson()
+    public function testRawHeadersCanBeAccessed()
     {
         $headers = array(
             'Header1' => 'Header 1',
@@ -504,14 +480,13 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test set capture file throws not
-     * writable exception if file path
-     * is not writable.
+     * Test not writable exception is thrown if
+     * capture path is not writable.
      *
      * @access public
      * @return void
      */
-    public function testSetCaptureFileThrowsNotWriteableExceptionIfFilePathIsNotWriteable()
+    public function tesNotWritableExceptonIsThrownIfCapturePathIsNotWritable()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\NotWritableException');
 
@@ -522,13 +497,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get capture file returns capture
-     * file if capture file is set.
+     * Test can set capture file.
      *
      * @access public
      * @return void
      */
-    public function testGetCaptureFileReturnsCaptureFileIfCaptureFileIsSet()
+    public function testCanSetCaptureFile()
     {
         $captureFile = sprintf('%s/test.jpg', sys_get_temp_dir());
 
@@ -539,12 +513,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test set viewport size sets viewport width.
+     * Test can set viewport width.
      *
      * @access public
      * @return void
      */
-    public function testSetViewportSizeSetsViewportWidth()
+    public function testCanSetViewportWidth()
     {
         $width  = 100;
         $height = 200;
@@ -556,12 +530,12 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test set viewport size sets viewport height.
+     * Test can set viewport height.
      *
      * @access public
      * @return void
      */
-    public function testSetViewportSizeSetsViewportHeight()
+    public function testCanSetViewportHeight()
     {
         $width  = 100;
         $height = 200;
@@ -580,10 +554,10 @@ class CaptureRequestTest extends \PHPUnit_Framework_TestCase
      * Get capture request instance.
      *
      * @access protected
-     * @param  string                                   $url     (default: null)
-     * @param  string                                   $method  (default: RequestInterface::METHOD_GET)
-     * @param  int                                      $timeout (default: 5000)
-     * @return \JonnyW\PhantomJs\Message\CaptureRequest
+     * @param  string                                $url     (default: null)
+     * @param  string                                $method  (default: RequestInterface::METHOD_GET)
+     * @param  int                                   $timeout (default: 5000)
+     * @return \JonnyW\PhantomJs\Http\CaptureRequest
      */
     protected function getCaptureRequest($url = null, $method = RequestInterface::METHOD_GET, $timeout = 5000)
     {

+ 28 - 35
src/JonnyW/PhantomJs/Tests/Unit/Message/MessageFactoryTest.php → src/JonnyW/PhantomJs/Tests/Unit/Http/MessageFactoryTest.php

@@ -6,9 +6,9 @@
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
-namespace JonnyW\PhantomJs\Tests\Unit\Message;
+namespace JonnyW\PhantomJs\Tests\Unit\Http;
 
-use JonnyW\PhantomJs\Message\MessageFactory;
+use JonnyW\PhantomJs\Http\MessageFactory;
 
 /**
  * PHP PhantomJs
@@ -23,38 +23,36 @@ class MessageFactoryTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test get instance returns instance of
-     * message factory.
+     * Test factory method creates message factory.
      *
      * @access public
      * @return void
      */
-    public function testGetInstanceReturnsInstanceOfMessageFactory()
+    public function testFactoryMethodCreatesMessageFactory()
     {
-        $this->assertInstanceOf('\JonnyW\PhantomJs\Message\MessageFactory', MessageFactory::getInstance());
+        $this->assertInstanceOf('\JonnyW\PhantomJs\Http\MessageFactory', MessageFactory::getInstance());
     }
 
     /**
-     * Test create request returns instance of request.
+     * Test can create request.
      *
      * @access public
      * @return void
      */
-    public function testCreateRequestReturnsInstanceOfRequest()
+    public function testCanCreateRequest()
     {
         $messageFactory = $this->getMessageFactory();
 
-        $this->assertInstanceOf('\JonnyW\PhantomJs\Message\Request', $messageFactory->createRequest());
+        $this->assertInstanceOf('\JonnyW\PhantomJs\Http\Request', $messageFactory->createRequest());
     }
 
     /**
-     * Test create request with URL sets
-     * URL in request.
+     * Test can create request with URL.
      *
      * @access public
      * @return void
      */
-    public function testCreateRequestWithUrlSetsUrlInRequest()
+    public function testCanCreateRequestWithUrl()
     {
         $url = 'http://test.com';
 
@@ -65,13 +63,12 @@ class MessageFactoryTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test create request with method sets
-     * method in request.
+     * Test can create request with method.
      *
      * @access public
      * @return void
      */
-    public function testCreateRequestWithMethodSetsMethodInRequest()
+    public function testCanCreateRequestWithMethod()
     {
         $method = 'POST';
 
@@ -82,13 +79,12 @@ class MessageFactoryTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test create request with timeout sets
-     * timeout in request.
+     * Test can create request with timeout.
      *
      * @access public
      * @return void
      */
-    public function testCreateRequestWithTimeoutSetsTimeoutInRequest()
+    public function testCanCreateRequestWithTimeout()
     {
         $timeout = 123456789;
 
@@ -99,27 +95,25 @@ class MessageFactoryTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test create capture request returns
-     * instance of capture request.
+     * Test can create capture request.
      *
      * @access public
      * @return void
      */
-    public function testCreateCaptureRequestReturnsInstanceOfCaptureRequest()
+    public function testCanCreateCaptureRequest()
     {
         $messageFactory = $this->getMessageFactory();
 
-        $this->assertInstanceOf('\JonnyW\PhantomJs\Message\CaptureRequest', $messageFactory->createCaptureRequest());
+        $this->assertInstanceOf('\JonnyW\PhantomJs\Http\CaptureRequest', $messageFactory->createCaptureRequest());
     }
 
     /**
-     * Test create capture request with URL sets
-     * URL in capture request.
+     * Test can create capture request with URL.
      *
      * @access public
      * @return void
      */
-    public function testCreateCaptureRequestWithUrlSetsUrlInCaptureRequest()
+    public function testCanCreateCaptureRequestWithUrl()
     {
         $url = 'http://test.com';
 
@@ -130,13 +124,13 @@ class MessageFactoryTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test create capture request with method sets
-     * method in capture request.
+     * Test can create capture request
+     * with method.
      *
      * @access public
      * @return void
      */
-    public function testCreateCaptureRequestWithMethodSetsMethodInCaptureRequest()
+    public function testCanCreateCaptureRequestWithMethod()
     {
         $method = 'POST';
 
@@ -147,13 +141,12 @@ class MessageFactoryTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test create capture request with timeout sets
-     * timeout in capture request.
+     * Test can create capture request with timeout.
      *
      * @access public
      * @return void
      */
-    public function testCreateCaptureRequestWithTimeoutSetsTimeoutInCaptureRequest()
+    public function testCanCreateCaptureRequestWithTimeout()
     {
         $timeout = 123456789;
 
@@ -164,16 +157,16 @@ class MessageFactoryTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test create response returns instance of response.
+     * Test can create response.
      *
      * @access public
      * @return void
      */
-    public function testCreateResponseReturnsInstanceOfResponse()
+    public function testCanCreateResponse()
     {
         $messageFactory = $this->getMessageFactory();
 
-        $this->assertInstanceOf('\JonnyW\PhantomJs\Message\Response', $messageFactory->createResponse());
+        $this->assertInstanceOf('\JonnyW\PhantomJs\Http\Response', $messageFactory->createResponse());
     }
 
 /** +++++++++++++++++++++++++++++++++++ **/
@@ -184,7 +177,7 @@ class MessageFactoryTest extends \PHPUnit_Framework_TestCase
      * Get message factory instance.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Message\MessageFactory
+     * @return \JonnyW\PhantomJs\Http\MessageFactory
      */
     protected function getMessageFactory()
     {

+ 63 - 84
src/JonnyW/PhantomJs/Tests/Unit/Message/RequestTest.php → src/JonnyW/PhantomJs/Tests/Unit/Http/RequestTest.php

@@ -6,10 +6,10 @@
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
-namespace JonnyW\PhantomJs\Tests\Unit\Message;
+namespace JonnyW\PhantomJs\Tests\Unit\Http;
 
-use JonnyW\PhantomJs\Message\Request;
-use JonnyW\PhantomJs\Message\RequestInterface;
+use JonnyW\PhantomJs\Http\Request;
+use JonnyW\PhantomJs\Http\RequestInterface;
 
 /**
  * PHP PhantomJs
@@ -24,13 +24,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test get type returns default request
-     * type if not type is set.
+     * Test default type is returned by default
+     * if no type is set.
      *
      * @access public
      * @return void
      */
-    public function testGetTypeReturnsDefaultRequestTypeIfNoTypeIsSet()
+    public function testDefaultTypeIsReturnedByDefaultIfNotTypeIsSet()
     {
         $request = $this->getRequest();
 
@@ -38,13 +38,12 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get type returns set request
-     * type.
+     * Test custom type can be set.
      *
      * @access public
      * @return void
      */
-    public function testGetTypeReturnsSetRequestType()
+    public function testCustomTypeCanBeSet()
     {
         $requestType = 'testType';
 
@@ -62,7 +61,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
      */
     public function testUrlCanBeSetViaConstructor()
     {
-        $url     = 'http://test.com';
+        $url            = 'http://test.com';
         $request = $this->getRequest($url);
 
         $this->assertSame($url, $request->getUrl());
@@ -76,7 +75,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
      */
     public function testMethodCanBeSetViaConstructor()
     {
-        $method  = 'GET';
+        $method         = 'GET';
         $request = $this->getRequest(null, $method);
 
         $this->assertSame($method, $request->getMethod());
@@ -90,20 +89,20 @@ class RequestTest extends \PHPUnit_Framework_TestCase
      */
     public function testTimeoutCanBeSetViaConstructor()
     {
-        $timeout = 100000;
+        $timeout        = 100000;
         $request = $this->getRequest('http://test.com', 'GET', $timeout);
 
         $this->assertSame($timeout, $request->getTimeout());
     }
 
     /**
-     * Test set method throws invalid method
-     * exception if an invalid method is set
+     * Test invalid method is thrown if method
+     * is invalid.
      *
      * @access public
      * @return void
      */
-    public function testSetMethodThrowsInvalidMethodExceptionIfAnInvalidMethodIsSet()
+    public function testInvalidMethodIsThrownIfMethodIsInvalid()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidMethodException');
 
@@ -111,30 +110,14 @@ class RequestTest extends \PHPUnit_Framework_TestCase
         $request->setMethod('INVALID_METHOD');
     }
 
-  /**
-     * Test set method throws invalid method
-     * exception if an invalid method is set
-     * via constructor
-     *
-     * @access public
-     * @return void
-     */
-    public function testSetMethodThrowsInvalidMethodExceptionIfAnInvalidMethodIsSetViaConstructor()
-    {
-        $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidMethodException');
-
-        $this->getRequest('http://test.com', 'INVALID_METHOD');
-    }
-
     /**
-     * Test set URL throws invalid
-     * URL exception if an invalid
-     * URL is set.
+     * Test invalid URL exception is thrown
+     * if URL is invalid format.
      *
      * @access public
      * @return void
      */
-    public function testSetUrlThrowsInvalidUrlExceptionIfAnInvalidUrlIsSet()
+    public function testInvalidUrlExceptionIsThrownIfUrlIsInvalidFormat()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\InvalidUrlException');
 
@@ -143,13 +126,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get URL returns URL without query
-     * paramters if method is not HEAD or GET.
+     * Test URL does not contain query params if
+     * mehtod is not HEAD or GET.
      *
      * @access public
      * @return void
      */
-    public function testGetUrlReturnsUrlWithoutQueryParametersIfMethodIsNotHeadOrGet()
+    public function testUrlDoesNotContainQueryParamsIfMethodIsNotHeadOrGet()
     {
         $url = 'http://test.com';
 
@@ -167,13 +150,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get URL returns URL with query
-     * parameters if method is GET.
+     * Test URL does contain query params if mehthod
+     * is GET.
      *
      * @access public
      * @return void
      */
-    public function testGetUrlReturnsUrlWithQueryParametersIfMethodIsGet()
+    public function testUrlDoesContainQueryParamsIfMethodIsGet()
     {
         $url = 'http://test.com';
 
@@ -193,13 +176,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get URL returns URL with query
-     * parameters if method is HEAD.
+     * Test URL does contain query params if method
+     * is HEAD.
      *
      * @access public
      * @return void
      */
-    public function testGetUrlReturnsUrlWithQueryParametersIfMethodIsHead()
+    public function testUrlDoesContainQueryParamsIfMethodIsHead()
     {
         $url = 'http://test.com';
 
@@ -219,13 +202,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get URL returns URL with query
-     * parameters if method is HEAD.
+     * Test query params are appended to URL if
+     * URL contains existng query params.
      *
      * @access public
      * @return void
      */
-    public function testGetUrlAppendsQueryParametersIfUrlHasExistingQueryParameters()
+    public function testQueryParamsAreAppendedToUrlIfUrlContainsExistingQueryParams()
     {
         $url = 'http://test.com?existing_param=Existing';
 
@@ -245,13 +228,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get body returns an empty
-     * string if method is GET.
+     * Test request contains no body if method
+     * is GET.
      *
      * @access public
      * @return void
      */
-    public function testGetBodyReturnsAnEmptyStringIfMethodIsGet()
+    public function testRequestContainsNoBodyIfMethodIsGet()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -266,13 +249,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get body returns and empty
-     * string if method is HEAD.
+     * Test request contains no body if method
+     * is HEAD.
      *
      * @access public
      * @return void
      */
-    public function testGetBodyReturnsAnEmptyStringIfMethodIsHead()
+    public function testRequestContainsNoBodyIfMethodIsHead()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -287,13 +270,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get body returns query string if
-     * method is not HEAD or GET.
+     * Test request contains a body if method is
+     * not HEAD or GET.
      *
      * @access public
      * @return void
      */
-    public function testGetBodyReturnsQueryStringIfMethodIsNotHeadOrGet()
+    public function testRequestContainsABodyIfMethodIsNotHeadOrGet()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -310,13 +293,12 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get request data returns flattened
-     * request data if flatten is set to true.
+     * Test request data can be flattened.
      *
      * @access public
      * @return void
      */
-    public function testGetRequestDataReturnsFlattenedRequestDataIfFlattenIsSetToTrue()
+    public function testRequestDataCanBeFalttened()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -339,13 +321,12 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get request data returns unflattened
-     * request data if flatten is set to false
+     * Test raw request data can be accessed.
      *
      * @access public
      * @return void
      */
-    public function testGetRequestDataReturnsUnflattenedRequestDataIfFlattenIsSetToFalse()
+    public function testRawRequestDataCanBeAccessed()
     {
         $data = array(
             'test_param1' => 'Testing1',
@@ -362,13 +343,12 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test add headers merge headers with
-     * existing headers.
+     * Test headers can be added.
      *
      * @access public
      * @return void
      */
-    public function testAddHeadersMergesHeadersWithExistingHeaders()
+    public function testHeadersCanBeAdded()
     {
         $existingHeaders = array(
             'Header1' => 'Header 1'
@@ -389,13 +369,13 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get headers returns JSON encoded
-     * headers if format is set to JSON.
+     * Test headers can be accessed in
+     * JSON format
      *
      * @access public
      * @return void
      */
-    public function testGetHeadersReturnsJsonEncodedHeadersIfFormatIsSetToJson()
+    public function testHeadersCanBeAccessedInJsonFormat()
     {
         $headers = array(
             'Header1' => 'Header 1',
@@ -411,13 +391,12 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get headers returns headers as
-     * array if format is not set to json
+     * Test raw headers can be accessed.
      *
      * @access public
      * @return void
      */
-    public function testGetHeadersReturnsHeadersAsArrayIfFormatIsNotSetToJson()
+    public function testRawHeadersCanBeAccessed()
     {
         $headers = array(
             'Header1' => 'Header 1',
@@ -431,37 +410,37 @@ class RequestTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test set viewport size sets viewport width.
+     * Test can set viewport width.
      *
      * @access public
      * @return void
      */
-    public function testSetViewportSizeSetsViewportWidth()
+    public function testCanSetViewportWidth()
     {
         $width  = 100;
         $height = 200;
 
-        $request = $this->getRequest();
-        $request->setViewportSize($width, $height);
+        $caputreRequest = $this->getRequest();
+        $caputreRequest->setViewportSize($width, $height);
 
-        $this->assertSame($width, $request->getViewportWidth());
+        $this->assertSame($width, $caputreRequest->getViewportWidth());
     }
 
     /**
-     * Test set viewport size sets viewport height.
+     * Test can set viewport height.
      *
      * @access public
      * @return void
      */
-    public function testSetViewportSizeSetsViewportHeight()
+    public function testCanSetViewportHeight()
     {
         $width  = 100;
         $height = 200;
 
-        $request = $this->getRequest();
-        $request->setViewportSize($width, $height);
+        $caputreRequest = $this->getRequest();
+        $caputreRequest->setViewportSize($width, $height);
 
-        $this->assertSame($height, $request->getViewportHeight());
+        $this->assertSame($height, $caputreRequest->getViewportHeight());
     }
 
 /** +++++++++++++++++++++++++++++++++++ **/
@@ -472,10 +451,10 @@ class RequestTest extends \PHPUnit_Framework_TestCase
      * Get request instance.
      *
      * @access protected
-     * @param  string                            $url     (default: null)
-     * @param  string                            $method  (default: RequestInterface::METHOD_GET)
-     * @param  int                               $timeout (default: 5000)
-     * @return \JonnyW\PhantomJs\Message\Request
+     * @param  string                         $url     (default: null)
+     * @param  string                         $method  (default: RequestInterface::METHOD_GET)
+     * @param  int                            $timeout (default: 5000)
+     * @return \JonnyW\PhantomJs\Http\Request
      */
     protected function getRequest($url = null, $method = RequestInterface::METHOD_GET, $timeout = 5000)
     {

+ 48 - 50
src/JonnyW/PhantomJs/Tests/Unit/Message/ResponseTest.php → src/JonnyW/PhantomJs/Tests/Unit/Http/ResponseTest.php

@@ -6,9 +6,9 @@
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
-namespace JonnyW\PhantomJs\Tests\Unit\Message;
+namespace JonnyW\PhantomJs\Tests\Unit\Http;
 
-use JonnyW\PhantomJs\Message\Response;
+use JonnyW\PhantomJs\Http\Response;
 
 /**
  * PHP PhantomJs
@@ -23,12 +23,12 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test import sets status in response.
+     * Test status can be imported.
      *
      * @access public
      * @return void
      */
-    public function testImportSetsStatusInResponse()
+    public function testStatusCanBeImported()
     {
         $data = array(
             'status' => 200
@@ -41,12 +41,12 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test import sets content in response.
+     * Test content can be imported
      *
      * @access public
      * @return void
      */
-    public function testImportSetsContentInResponse()
+    public function testContentCanBeImported()
     {
         $data = array(
             'content' => 'Test content'
@@ -59,12 +59,12 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test import sets content in response.
+     * Test content type can be imported.
      *
      * @access public
      * @return void
      */
-    public function testImportSetsContentTypeInResponse()
+    public function testContentTypeCanBeImported()
     {
         $data = array(
             'contentType' => 'text/html'
@@ -77,12 +77,12 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test import sets URL in response.
+     * Test URL can be imported.
      *
      * @access public
      * @return void
      */
-    public function testImportSetsUrlInResponse()
+    public function testUrlCanBeImported()
     {
         $data = array(
             'url' => 'http://test.com'
@@ -95,12 +95,12 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test import sets redirect URL in response.
+     * Test redirect URL can be imported.
      *
      * @access public
      * @return void
      */
-    public function testImportSetsRedirectUrlInResponse()
+    public function testRedirectUrlCanBeImported()
     {
         $data = array(
             'redirectUrl' => 'http://test.com'
@@ -113,12 +113,12 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test import sets time in response.
+     * Test time can be imported.
      *
      * @access public
      * @return void
      */
-    public function testImportSetsTimeInResponse()
+    public function testTimeCanBeImported()
     {
         $data = array(
             'time' => 123456789
@@ -131,12 +131,12 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test import sets headers in response.
+     * Test headers can be imported.
      *
      * @access public
      * @return void
      */
-    public function testImportSetsHeadersInResponse()
+    public function testHeadersCanBeImported()
     {
         $headers = array(
             array(
@@ -160,13 +160,12 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get header returns null if header
-     * is not set.
+     * Test null is returned if header is not set.
      *
      * @access public
      * @return void
      */
-    public function testGetHeadersReturnsNullIfHeaderIsNotSet()
+    public function testNullIsReturnedIfHeaderIsNotSet()
     {
         $response = $this->getResponse();
 
@@ -174,13 +173,12 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test get header returns header if
-     * header is set.
+     * Test can get header.
      *
      * @access public
      * @return void
      */
-    public function testGetHeaderReturnsHeaderIfHeaderIsSet()
+    public function testCanGetHeader()
     {
         $headers = array(
             array(
@@ -200,13 +198,13 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test is redirect returns true if
-     * status equals 300.
+     * Test is redirect if status code
+     * is 300.
      *
      * @access public
      * @return void
      */
-    public function testIsRedirectReturnsTrueIfStatusEquals300()
+    public function testIsRedirectIfStatusCodeIs300()
     {
         $data = array(
             'status' => 300
@@ -219,13 +217,13 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test is redirect returns true if
-     * status equals 301.
+     * Test is redirect if status code
+     * is 301.
      *
      * @access public
      * @return void
      */
-    public function testIsRedirectReturnsTrueIfStatusEquals301()
+    public function testIsRedirectIfStatusCodeIs301()
     {
         $data = array(
             'status' => 301
@@ -238,13 +236,13 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test is redirect returns true if
-     * status equals 302.
+     * Test is redirect if status code
+     * is 302.
      *
      * @access public
      * @return void
      */
-    public function testIsRedirectReturnsTrueIfStatusEquals302()
+    public function testIsRedirectIfStatusCodeIs302()
     {
         $data = array(
             'status' => 302
@@ -257,13 +255,13 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test is redirect returns true if
-     * status equals 303.
+     * Test is redirect if status code
+     * is 303.
      *
      * @access public
      * @return void
      */
-    public function testIsRedirectReturnsTrueIfStatusEquals303()
+    public function testIsRedirectIfStatusCodeIs303()
     {
         $data = array(
             'status' => 303
@@ -276,13 +274,13 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test is redirect returns true if
-     * status equals 304.
+     * Test is redirect if status code
+     * is 304.
      *
      * @access public
      * @return void
      */
-    public function testIsRedirectReturnsTrueIfStatusEquals304()
+    public function testIsRedirectIfStatusCodeIs304()
     {
         $data = array(
             'status' => 304
@@ -295,13 +293,13 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test is redirect returns true if
-     * status equals 305.
+     * Test is redirect if status code
+     * is 305.
      *
      * @access public
      * @return void
      */
-    public function testIsRedirectReturnsTrueIfStatusEquals305()
+    public function testIsRedirectIfStatusCodeIs305()
     {
         $data = array(
             'status' => 305
@@ -314,13 +312,13 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test is redirect returns true if
-     * status equals 306.
+     * Test is redirect if status code
+     * is 306.
      *
      * @access public
      * @return void
      */
-    public function testIsRedirectReturnsTrueIfStatusEquals306()
+    public function testIsRedirectIfStatusCodeIs306()
     {
         $data = array(
             'status' => 306
@@ -333,13 +331,13 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test is redirect returns true if
-     * status equals 307.
+     * Test is redirect if status code
+     * is 307.
      *
      * @access public
      * @return void
      */
-    public function testIsRedirectReturnsTrueIfStatusEquals307()
+    public function testIsRedirectIfStatusCodeIs307()
     {
         $data = array(
             'status' => 307
@@ -352,13 +350,13 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test is redirect returns false if status
-     * code is not a valid redirect code.
+     * Test is not redirect if status code is
+     * not redirect.
      *
      * @access public
      * @return void
      */
-    public function testIsRedirectReturnsFalseIfStatusCodeIsNotAValidRedirectCode()
+    public function testIsNotRedirectIfStatusCodeIsNotRedirect()
     {
         $data = array(
             'status' => 401
@@ -378,7 +376,7 @@ class ResponseTest extends \PHPUnit_Framework_TestCase
      * Get response instance.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Message\Response
+     * @return \JonnyW\PhantomJs\Http\Response
      */
     protected function getResponse()
     {

+ 15 - 37
src/JonnyW/PhantomJs/Tests/Unit/Procedure/ChainProcedureLoaderTest.php

@@ -23,13 +23,13 @@ class ChainProcedureLoaderTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test load throws invalid argument exception
-     * if no valid procedure loader could be found.
+     * Test invalid argument exception is thrown if
+     * not valid loader can be found.
      *
      * @access public
      * @return void
      */
-    public function testLoadThrowsInvalidArgumentExceptionIfNoValidProcedureLoaderCouldBeFound()
+    public function testInvalidArgumentExceptionIsThrownIfNoValidLoaderCanBeFound()
     {
         $this->setExpectedException('\InvalidArgumentException');
 
@@ -40,35 +40,13 @@ class ChainProcedureLoaderTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test load throws invalid argument exception if
-     * procedure loader throws exception.
+     * Test instance of procedure is returned
+     * if procedure is loaded
      *
      * @access public
      * @return void
      */
-    public function testLoadThrowsInvalidArgumentExceptionIfProcedureLoaderThrowsException()
-    {
-        $this->setExpectedException('\InvalidArgumentException');
-
-        $procedureLoader = $this->getProcedureLoader();
-        $procedureLoader->method('load')
-            ->will($this->throwException(new \Exception()));
-
-        $procedureLoaders = array(
-            $procedureLoader
-        );
-
-        $chainProcedureLoader = $this->getChainProcedureLoader($procedureLoaders);
-        $chainProcedureLoader->load('test');
-    }
-
-    /**
-     * Test load returns instance of procedure.
-     *
-     * @access public
-     * @return void
-     */
-    public function testLoadReturnsInstanceOfProcedure()
+    public function testInstanceOfProcedureIsReturnedIfProcedureIsLoaded()
     {
         $procedure = $this->getProcedure();
 
@@ -86,13 +64,13 @@ class ChainProcedureLoaderTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test add loader adds procedure loader
-     * to chain loader.
+     * Test loader can be added to chain
+     * loader.
      *
      * @access public
      * @return void
      */
-    public function testAddLoaderAddsProcedureLoaderToChainLoader()
+    public function testLoaderCanBeAddedToChainLoader()
     {
         $chainProcedureLoader = $this->getChainProcedureLoader(array());
 
@@ -127,28 +105,28 @@ class ChainProcedureLoaderTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Get mock procedure loader instance.
+     * Get procedure loader.
      *
      * @access protected
      * @return \JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface
      */
     protected function getProcedureLoader()
     {
-        $mockProcedureLoader = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface');
+        $procedureLoader = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureLoaderInterface');
 
-        return $mockProcedureLoader;
+        return $procedureLoader;
     }
 
     /**
-     * Get mock procedure instance.
+     * Get procedure.
      *
      * @access protected
      * @return \JonnyW\PhantomJs\Procedure\ProcedureInterface
      */
     protected function getProcedure()
     {
-        $mockProcedure = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureInterface');
+        $procedure = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureInterface');
 
-        return $mockProcedure;
+        return $procedure;
     }
 }

+ 55 - 0
src/JonnyW/PhantomJs/Tests/Unit/Procedure/InputTest.php

@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Tests\Unit\Procedure;
+
+use JonnyW\PhantomJs\Procedure\Input;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class InputTest extends \PHPUnit_Framework_TestCase
+{
+
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++++++ TESTS ++++++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
+    /**
+     * Test data storage.
+     *
+     * @access public
+     * @return void
+     */
+    public function testDataStorage()
+    {
+        $input = $this->getInput();
+        $input->set('test', 'Test value');
+
+        $this->assertSame('Test value', $input->get('test'));
+    }
+
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++ TEST ENTITIES ++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
+    /**
+     * Get input.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Procedure\Input
+     */
+    protected function getInput()
+    {
+        $input = new Input();
+
+        return $input;
+    }
+}

+ 88 - 0
src/JonnyW/PhantomJs/Tests/Unit/Procedure/OutputTest.php

@@ -0,0 +1,88 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Tests\Unit\Procedure;
+
+use JonnyW\PhantomJs\Procedure\Output;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class OutputTest extends \PHPUnit_Framework_TestCase
+{
+
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++++++ TESTS ++++++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
+    /**
+     * Test data storage.
+     *
+     * @access public
+     * @return void
+     */
+    public function testDataStorage()
+    {
+        $output = $this->getOutput();
+        $output->set('test', 'Test value');
+
+        $this->assertSame('Test value', $output->get('test'));
+    }
+
+    /**
+     * Test can import data.
+     *
+     * @access public
+     * @return void
+     */
+    public function testCanImportData()
+    {
+        $data = array(
+          'test'  => 'Test value',
+          'test2' => 'Test value 2'
+        );
+
+        $output = $this->getOutput();
+        $output->import($data);
+
+        $this->assertSame('Test value', $output->get('test'));
+    }
+
+    /**
+     * Test can log data.
+     *
+     * @access public
+     * @return void
+     */
+    public function testCanLogData()
+    {
+        $output = $this->getOutput();
+        $output->log('Test log');
+
+        $this->assertContains('Test log', $output->getLogs());
+    }
+
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++ TEST ENTITIES ++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
+    /**
+     * Get output.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Procedure\Output
+     */
+    protected function getOutput()
+    {
+        $output = new Output();
+
+        return $output;
+    }
+}

+ 27 - 20
src/JonnyW/PhantomJs/Tests/Unit/Procedure/ProcedureFactoryTest.php

@@ -8,8 +8,13 @@
  */
 namespace JonnyW\PhantomJs\Tests\Unit\Procedure;
 
+use Twig_Environment;
+use Twig_Loader_String;
+use JonnyW\PhantomJs\Cache\FileCache;
 use JonnyW\PhantomJs\Cache\CacheInterface;
+use JonnyW\PhantomJs\Parser\JsonParser;
 use JonnyW\PhantomJs\Parser\ParserInterface;
+use JonnyW\PhantomJs\Template\TemplateRenderer;
 use JonnyW\PhantomJs\Template\TemplateRendererInterface;
 use JonnyW\PhantomJs\Procedure\ProcedureFactory;
 
@@ -26,13 +31,13 @@ class ProcedureFactoryTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test create procedure returns instance
-     * of procedure.
+     * Test factory can create instance of
+     * procedure.
      *
      * @access public
      * @return void
      */
-    public function testCreateProcedureReturnsInstanceOfProcedure()
+    public function testFactoryCanCreateInstanceOfProcedure()
     {
         $parser    = $this->getParser();
         $cache     = $this->getCache();
@@ -63,46 +68,48 @@ class ProcedureFactoryTest extends \PHPUnit_Framework_TestCase
         return $procedureFactory;
     }
 
-/** +++++++++++++++++++++++++++++++++++ **/
-/** ++++++++++ MOCKS / STUBS ++++++++++ **/
-/** +++++++++++++++++++++++++++++++++++ **/
-
     /**
-     * Get mock parser instance.
+     * Get parser.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Parser\ParserInterface
+     * @return \JonnyW\PhantomJs\Parser\JsonParser
      */
     protected function getParser()
     {
-        $mockParser = $this->getMock('\JonnyW\PhantomJs\Parser\ParserInterface');
+        $parser = new JsonParser();
 
-        return $mockParser;
+        return $parser;
     }
 
     /**
-     * Get mock cache instance.
+     * Get cache.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Cache\CacheInterface
+     * @param  string                            $cacheDir  (default: '')
+     * @param  string                            $extension (default: 'proc')
+     * @return \JonnyW\PhantomJs\Cache\FileCache
      */
-    protected function getCache()
+    protected function getCache($cacheDir = '', $extension = 'proc')
     {
-        $mockCache = $this->getMock('\JonnyW\PhantomJs\Cache\CacheInterface');
+        $cache = new FileCache(($cacheDir ? $cacheDir : sys_get_temp_dir()), 'proc');
 
-        return $mockCache;
+        return $cache;
     }
 
     /**
-     * Get mock template renderer instance.
+     * Get template renderer.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Template\TemplateRendererInterface
+     * @return \JonnyW\PhantomJs\Template\TemplateRenderer
      */
     protected function getRenderer()
     {
-        $mockTemplateRenderer = $this->getMock('\JonnyW\PhantomJs\Template\TemplateRendererInterface');
+        $twig = new Twig_Environment(
+            new Twig_Loader_String()
+        );
+
+        $renderer = new TemplateRenderer($twig);
 
-        return $mockTemplateRenderer;
+        return $renderer;
     }
 }

+ 8 - 9
src/JonnyW/PhantomJs/Tests/Unit/Procedure/ProcedureLoaderFactoryTest.php

@@ -31,13 +31,13 @@ class ProcedureLoaderFactoryTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test create procedure loader throws invalid
-     * argument exception if directory is not readable.
+     * Test invalid argument exceptions is thrown if directory
+     * is not readable when creating procedure loader.
      *
      * @access public
      * @return void
      */
-    public function testCreateProcedureLoaderThrowsInvalidArgumentExceptionIfDirectoryIsNotReadable()
+    public function testInvalidArgumentExceptionIsThrownIfDirectoryIsNotReadableWhenCreatingProcedureLoader()
     {
         $this->setExpectedException('\InvalidArgumentException');
 
@@ -48,13 +48,12 @@ class ProcedureLoaderFactoryTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test create procedure loader returns instance of
-     * procedure loader.
+     * Test procedure loader can be created.
      *
      * @access public
      * @return void
      */
-    public function testCreateProcedureLoaderReturnsInstanceOfProcedureLoader()
+    public function testProcedureLoaderCanBeCreated()
     {
         $procedureFactory = $this->getProcedureFactory();
 
@@ -87,16 +86,16 @@ class ProcedureLoaderFactoryTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Get mock procedure factory instance.
+     * Get procedure factory.
      *
      * @access protected
      * @return \JonnyW\PhantomJs\Procedure\ProcedureFactoryInterface
      */
     protected function getProcedureFactory()
     {
-        $mockProcedureFactory = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureFactoryInterface');
+        $procedureFactory = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureFactoryInterface');
 
-        return $mockProcedureFactory;
+        return $procedureFactory;
     }
 
 /** +++++++++++++++++++++++++++++++++++ **/

+ 79 - 42
src/JonnyW/PhantomJs/Tests/Unit/Procedure/ProcedureLoaderTest.php

@@ -8,7 +8,16 @@
  */
 namespace JonnyW\PhantomJs\Tests\Unit\Procedure;
 
+use Twig_Environment;
+use Twig_Loader_String;
 use Symfony\Component\Config\FileLocatorInterface;
+use JonnyW\PhantomJs\Cache\FileCache;
+use JonnyW\PhantomJs\Cache\CacheInterface;
+use JonnyW\PhantomJs\Parser\JsonParser;
+use JonnyW\PhantomJs\Parser\ParserInterface;
+use JonnyW\PhantomJs\Template\TemplateRenderer;
+use JonnyW\PhantomJs\Template\TemplateRendererInterface;
+use JonnyW\PhantomJs\Procedure\ProcedureFactory;
 use JonnyW\PhantomJs\Procedure\ProcedureFactoryInterface;
 use JonnyW\PhantomJs\Procedure\ProcedureLoader;
 
@@ -40,13 +49,13 @@ class ProcedureLoaderTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test load throws invalid argument exception
-     * if file is not a local stream.
+     * Test invalid argument exception is thrown if procedure
+     * file is not local.
      *
      * @access public
      * @return void
      */
-    public function testLoadThrowsInvalidArgumentExceptionIfFileIsNotALocalStream()
+    public function testInvalidArgumentExceptionIsThrownIfProcedureFileIsNotLocal()
     {
         $this->setExpectedException('\InvalidArgumentException');
 
@@ -62,12 +71,12 @@ class ProcedureLoaderTest extends \PHPUnit_Framework_TestCase
 
     /**
      * Test load throws not exists exception if
-     * file does not exist.
+     * if procedure file does not exist.
      *
      * @access public
      * @return void
      */
-    public function testLoadThrowsNotExistsExceptionIfFileDoesNotExist()
+    public function testNotExistsExceptionIsThrownIfProcedureFileDoesNotExist()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\NotExistsException');
 
@@ -82,56 +91,48 @@ class ProcedureLoaderTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * Test load returns procedure instance.
+     * Test procedure can be laoded.
      *
      * @access public
      * @return void
      */
-    public function testLoadReturnsProcedureInstance()
+    public function testProcedureCanBeLoaded()
     {
-        $body = 'PROCEDURE BODY';
+        $body = 'TEST_PROCEDURE';
         $file = $this->writeProcedure($body);
 
         $procedureFactory = $this->getProcedureFactory();
         $fileLocator      = $this->getFileLocator();
-        $procedure        = $this->getProcedure();
 
         $fileLocator->method('locate')
             ->will($this->returnValue($file));
 
-        $procedureFactory->method('createProcedure')
-            ->will($this->returnValue($procedure));
-
         $procedureLoader = $this->getProcedureLoader($procedureFactory, $fileLocator);
 
         $this->assertInstanceOf('\JonnyW\PhantomJs\Procedure\ProcedureInterface', $procedureLoader->load('test'));
     }
 
     /**
-     * Test load sets procedure body in
-     * procedure instance.
+     * Test procedure template is set in procedure
+     * instance.
      *
      * @access public
      * @return void
      */
-    public function testLoadSetsProcedureBodyInProcedureInstance()
+    public function testProcedureTemplateIsSetInProcedureInstance()
     {
-        $body = 'PROCEDURE BODY';
+        $body = 'TEST_PROCEDURE';
         $file = $this->writeProcedure($body);
 
         $procedureFactory = $this->getProcedureFactory();
         $fileLocator      = $this->getFileLocator();
-        $procedure        = $this->getProcedure();
 
         $fileLocator->method('locate')
             ->will($this->returnValue($file));
 
-        $procedureFactory->method('createProcedure')
-            ->will($this->returnValue($procedure));
-
         $procedureLoader = $this->getProcedureLoader($procedureFactory, $fileLocator);
 
-        $this->assertSame($body, $procedureLoader->load('test')->getProcedure());
+        $this->assertSame($body, $procedureLoader->load('test')->getTemplate());
     }
 
 /** +++++++++++++++++++++++++++++++++++ **/
@@ -153,50 +154,86 @@ class ProcedureLoaderTest extends \PHPUnit_Framework_TestCase
         return $procedureLoader;
     }
 
-/** +++++++++++++++++++++++++++++++++++ **/
-/** ++++++++++ MOCKS / STUBS ++++++++++ **/
-/** +++++++++++++++++++++++++++++++++++ **/
-
     /**
-     * Get mock procedure factory instance.
+     * Get procedure factory instance.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Procedure\ProcedureFactoryInterface
+     * @param  \JonnyW\PhantomJs\Parser\ParserInterface             $parser
+     * @param  \JonnyW\PhantomJs\Cache\CacheInterface               $cacheHandler
+     * @param  \JonnyW\PhantomJs\Template\TemplateRendererInterface $renderer
+     * @return \JonnyW\PhantomJs\Procedure\ProcedureFactory
      */
     protected function getProcedureFactory()
     {
-        $mockProcedureFactory = $this->getMock('\JonnyW\PhantomJs\Procedure\ProcedureFactoryInterface');
+        $parser   = $this->getParser();
+        $cache    = $this->getCache();
+        $renderer = $this->getRenderer();
 
-        return $mockProcedureFactory;
+        $procedureFactory = new ProcedureFactory($parser, $cache, $renderer);
+
+        return $procedureFactory;
     }
 
     /**
-     * Get mock file locator instance.
+     * Get parser.
      *
      * @access protected
-     * @return \Symfony\Component\Config\FileLocatorInterface
+     * @return \JonnyW\PhantomJs\Parser\JsonParser
      */
-    protected function getFileLocator()
+    protected function getParser()
+    {
+        $parser = new JsonParser();
+
+        return $parser;
+    }
+
+    /**
+     * Get cache.
+     *
+     * @access protected
+     * @param  string                            $cacheDir  (default: '')
+     * @param  string                            $extension (default: 'proc')
+     * @return \JonnyW\PhantomJs\Cache\FileCache
+     */
+    protected function getCache($cacheDir = '', $extension = 'proc')
+    {
+        $cache = new FileCache(($cacheDir ? $cacheDir : sys_get_temp_dir()), 'proc');
+
+        return $cache;
+    }
+
+    /**
+     * Get template renderer.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Template\TemplateRenderer
+     */
+    protected function getRenderer()
     {
-        $mockFileLocator = $this->getMock('\Symfony\Component\Config\FileLocatorInterface');
+        $twig = new Twig_Environment(
+            new Twig_Loader_String()
+        );
+
+        $renderer = new TemplateRenderer($twig);
 
-        return $mockFileLocator;
+        return $renderer;
     }
 
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++ MOCKS / STUBS ++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
     /**
-     * Get mock procedure instance.
+     * Get file locator.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Procedure\Procedure
+     * @return \Symfony\Component\Config\FileLocatorInterface
      */
-    protected function getProcedure()
+    protected function getFileLocator()
     {
-        $mockProcedure = $this->getMockBuilder('\JonnyW\PhantomJs\Procedure\Procedure')
-            ->setMethods(null)
-            ->disableOriginalConstructor()
-            ->getMock();
+        $fileLocator = $this->getMock('\Symfony\Component\Config\FileLocatorInterface');
 
-        return $mockProcedure;
+        return $fileLocator;
     }
 
 /** +++++++++++++++++++++++++++++++++++ **/

+ 94 - 63
src/JonnyW/PhantomJs/Tests/Unit/Procedure/ProcedureTest.php

@@ -8,9 +8,16 @@
  */
 namespace JonnyW\PhantomJs\Tests\Unit\Procedure;
 
+use Twig_Environment;
+use Twig_Loader_String;
+use JonnyW\PhantomJs\Cache\FileCache;
 use JonnyW\PhantomJs\Cache\CacheInterface;
+use JonnyW\PhantomJs\Parser\JsonParser;
 use JonnyW\PhantomJs\Parser\ParserInterface;
+use JonnyW\PhantomJs\Template\TemplateRenderer;
 use JonnyW\PhantomJs\Template\TemplateRendererInterface;
+use JonnyW\PhantomJs\Procedure\Input;
+use JonnyW\PhantomJs\Procedure\Output;
 use JonnyW\PhantomJs\Procedure\Procedure;
 
 /**
@@ -26,79 +33,96 @@ class ProcedureTest extends \PHPUnit_Framework_TestCase
 /** +++++++++++++++++++++++++++++++++++ **/
 
     /**
-     * Test load procedure sets procedure
-     * body in procedure instance.
+     * Test procedure template can be
+     * set in procedure
      *
      * @access public
      * @return void
      */
-    public function testLoadProcedureSetsProcedureBodyInProcedureInstance()
+    public function testProcedureTemplateCanBeSetInProcedure()
     {
-        $template = 'TEST PRODCEDURE';
+        $template = 'PROCEDURE_TEMPLATE';
 
         $parser    = $this->getParser();
         $cache     = $this->getCache();
         $renderer  = $this->getRenderer();
 
         $procedure = $this->getProcedure($parser, $cache, $renderer);
-        $procedure->load($template);
+        $procedure->setTemplate($template);
 
-        $this->assertSame($procedure->getProcedure(), $template);
+        $this->assertSame($procedure->getTemplate(), $template);
     }
 
     /**
-     * Test run throws note writeable exception
-     * if procedure executable file cannot
-     * be written.
+     * Test procedure can be compiled.
      *
      * @access public
      * @return void
      */
-    public function testRunThrowsNotWriteableExceptionIfProcedureExecutableFileCannotBeWritten()
+    public function testProcedureCanBeCompiled()
+    {
+        $template = 'TEST_{{ input.get("uncompiled") }}_PROCEDURE';
+
+        $parser    = $this->getParser();
+        $cache     = $this->getCache();
+        $renderer  = $this->getRenderer();
+
+        $input  = $this->getInput();
+        $input->set('uncompiled', 'COMPILED');
+
+        $procedure = $this->getProcedure($parser, $cache, $renderer);
+        $procedure->setTemplate($template);
+
+        $this->assertSame('TEST_COMPILED_PROCEDURE', $procedure->compile($input));
+    }
+
+    /**
+     * Test not writable exception is thrown if procedure
+     * script cannot be written to file
+     *
+     * @access public
+     * @return void
+     */
+    public function testNotWritableExceptionIsThrownIfProcedureScriptCannotBeWrittenToFile()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\NotWritableException');
 
         $parser   = $this->getParser();
         $renderer = $this->getRenderer();
 
-        $cache = $this->getCache();
-        $cache->expects($this->once())
-            ->method('save')
-            ->will($this->throwException(new \JonnyW\PhantomJs\Exception\NotWritableException()));
+        $cache = $this->getCache('/an/invalid/dir');
 
-        $client   = $this->getClient();
-        $request  = $this->getRequest();
-        $response = $this->getResponse();
+        $client = $this->getClient();
+        $input  = $this->getInput();
+        $output = $this->getOutput();
 
         $procedure = $this->getProcedure($parser, $cache, $renderer);
-        $procedure->run($client, $request, $response);
+        $procedure->run($client, $input, $output);
     }
 
     /**
-     * Test run throws procedure failed exception
-     * if an exception is encountered.
+     * Test procedure failed exception is thrown if procedure
+     * cannot be run.
      *
      * @access public
      * @return void
      */
-    public function testRunThrowsProcedureFailedExceptionIfAnExceptionIsEncountered()
+    public function testProcedureFailedExceptionIsThrownIfProcedureCannotBeRun()
     {
         $this->setExpectedException('\JonnyW\PhantomJs\Exception\ProcedureFailedException');
 
-        $parser = $this->getParser();
-        $cache  = $this->getCache();
-
+        $parser   = $this->getParser();
+        $cache    = $this->getCache();
         $renderer = $this->getRenderer();
-        $renderer->expects($this->once())
-            ->method('render')
-            ->will($this->throwException(new \Exception()));
+        $input    = $this->getInput();
+        $output   = $this->getOutput();
 
-        $client   = $this->getClient();
-        $request  = $this->getRequest();
-        $response = $this->getResponse();
+        $client = $this->getClient();
+        $client->method('getCommand')
+            ->will($this->throwException(new \Exception()));
 
         $procedure = $this->getProcedure($parser, $cache, $renderer);
-        $procedure->run($client, $request, $response);
+        $procedure->run($client, $input, $output);
     }
 
 /** +++++++++++++++++++++++++++++++++++ **/
@@ -121,85 +145,92 @@ class ProcedureTest extends \PHPUnit_Framework_TestCase
         return $procedure;
     }
 
-/** +++++++++++++++++++++++++++++++++++ **/
-/** ++++++++++ MOCKS / STUBS ++++++++++ **/
-/** +++++++++++++++++++++++++++++++++++ **/
-
     /**
-     * Get mock parser instance.
+     * Get parser.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Parser\ParserInterface
+     * @return \JonnyW\PhantomJs\Parser\JsonParser
      */
     protected function getParser()
     {
-        $mockParser = $this->getMock('\JonnyW\PhantomJs\Parser\ParserInterface');
+        $parser = new JsonParser();
 
-        return $mockParser;
+        return $parser;
     }
 
     /**
-     * Get mock cache instance.
+     * Get cache.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Cache\CacheInterface
+     * @param  string                            $cacheDir  (default: '')
+     * @param  string                            $extension (default: 'proc')
+     * @return \JonnyW\PhantomJs\Cache\FileCache
      */
-    protected function getCache()
+    protected function getCache($cacheDir = '', $extension = 'proc')
     {
-        $mockCache = $this->getMock('\JonnyW\PhantomJs\Cache\CacheInterface');
+        $cache = new FileCache(($cacheDir ? $cacheDir : sys_get_temp_dir()), 'proc');
 
-        return $mockCache;
+        return $cache;
     }
 
     /**
-     * Get mock template renderer instance.
+     * Get template renderer.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Template\TemplateRendererInterface
+     * @return \JonnyW\PhantomJs\Template\TemplateRenderer
      */
     protected function getRenderer()
     {
-        $mockTemplateRenderer = $this->getMock('\JonnyW\PhantomJs\Template\TemplateRendererInterface');
+        $twig = new Twig_Environment(
+            new Twig_Loader_String()
+        );
 
-        return $mockTemplateRenderer;
+        $renderer = new TemplateRenderer($twig);
+
+        return $renderer;
     }
 
     /**
-     * Get mock client instance.
+     * Get input
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\ClientInterface
+     * @return \JonnyW\PhantomJs\Procedure\Input
      */
-    protected function getClient()
+    protected function getInput()
     {
-        $mockClient = $this->getMock('\JonnyW\PhantomJs\ClientInterface');
+        $input = new Input();
 
-        return $mockClient;
+        return $input;
     }
 
     /**
-     * Get mock request instance.
+     * Get output.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Message\RequestInterface
+     * @return \JonnyW\PhantomJs\Procedure\Output
      */
-    protected function getRequest()
+    protected function getOutput()
     {
-        $mockRequest = $this->getMock('\JonnyW\PhantomJs\Message\RequestInterface');
+        $output = new Output();
 
-        return $mockRequest;
+        return $output;
     }
 
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++ MOCKS / STUBS ++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
     /**
-     * Get mock response instance.
+     * Get client.
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Message\ResponseInterface
+     * @return \JonnyW\PhantomJs\ClientInterface
      */
-    protected function getResponse()
+    protected function getClient()
     {
-        $mockResponse = $this->getMock('\JonnyW\PhantomJs\Message\ResponseInterface');
+        $client = $this->getMock('\JonnyW\PhantomJs\ClientInterface');
 
-        return $mockResponse;
+        return $client;
     }
+
 }

+ 30 - 33
src/JonnyW/PhantomJs/Tests/Integration/Template/TemplateRendererTest.php → src/JonnyW/PhantomJs/Tests/Unit/Template/TemplateRendererTest.php

@@ -6,9 +6,11 @@
  * For the full copyright and license information, please view the LICENSE
  * file that was distributed with this source code.
  */
-namespace JonnyW\PhantomJs\Tests\Integration\Template;
+namespace JonnyW\PhantomJs\Tests\Unit\Template;
 
-use JonnyW\PhantomJs\Test\TestCase;
+use Twig_Environment;
+use Twig_Loader_String;
+use JonnyW\PhantomJs\Http\Request;
 use JonnyW\PhantomJs\Template\TemplateRenderer;
 
 /**
@@ -16,7 +18,7 @@ use JonnyW\PhantomJs\Template\TemplateRenderer;
  *
  * @author Jon Wenmoth <contact@jonnyw.me>
  */
-class TemplateRendererTest extends TestCase
+class TemplateRendererTest extends \PHPUnit_Framework_TestCase
 {
 
 /** +++++++++++++++++++++++++++++++++++ **/
@@ -34,7 +36,7 @@ class TemplateRendererTest extends TestCase
     {
         $template = 'var param = "{{ test }}"';
 
-        $renderer = $this->getInjectedTemplateRenderer();
+        $renderer = $this->getTemplateRenderer();
         $result   = $renderer->render($template, array('test' => 'data'));
 
         $this->assertSame('var param = "data"', $result);
@@ -51,7 +53,7 @@ class TemplateRendererTest extends TestCase
     {
         $template = 'var param = "{{ test }}", var param2 = "{{ test2 }}"';
 
-        $renderer = $this->getInjectedTemplateRenderer();
+        $renderer = $this->getTemplateRenderer();
         $result   = $renderer->render($template, array('test' => 'data', 'test2' => 'more data'));
 
         $this->assertSame('var param = "data", var param2 = "more data"', $result);
@@ -69,10 +71,9 @@ class TemplateRendererTest extends TestCase
         $template = 'var param = {{ request.getTimeout() }}';
 
         $request = $this->getRequest();
-        $request->method('getTimeout')
-            ->will($this->returnValue(5000));
+        $request->setTimeout(5000);
 
-        $renderer = $this->getInjectedTemplateRenderer();
+        $renderer = $this->getTemplateRenderer();
         $result   = $renderer->render($template, array('request' => $request));
 
         $this->assertSame('var param = 5000', $result);
@@ -91,12 +92,12 @@ class TemplateRendererTest extends TestCase
         $template = 'var param = {{ request.getHeaders("json") }}';
 
         $request = $this->getRequest();
-        $request->expects($this->once())
-            ->method('getHeaders')
-            ->with($this->identicalTo('json'));
+        $request->addHeader('json', 'test');
 
-        $renderer = $this->getInjectedTemplateRenderer();
-        $renderer->render($template, array('request' => $request));
+        $renderer = $this->getTemplateRenderer();
+        $result = $renderer->render($template, array('request' => $request));
+
+        $this->assertSame(htmlspecialchars('var param = {"json":"test"}'), $result);
     }
 
 /** +++++++++++++++++++++++++++++++++++ **/
@@ -106,46 +107,42 @@ class TemplateRendererTest extends TestCase
     /**
      * Get template renderer instance.
      *
-     * @param  \Twig_Environment                          $twig
      * @return \JonnyW\PhantomJs\Message\TemplateRenderer
      */
-    protected function getTemplateRenderer(\Twig_Environment $twig)
+    protected function getTemplateRenderer()
     {
-        $templateRenderer = new TemplateRenderer($twig);
+        $templateRenderer = new TemplateRenderer(
+            $this->getTwig()
+        );
 
         return $templateRenderer;
     }
 
     /**
-     * Get template renderer instance
-     * injected with dependencies.
+     * Get request
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Message\TemplateRenderer
+     * @return \JonnyW\PhantomJs\Http\Request
      */
-    protected function getInjectedTemplateRenderer()
+    protected function getRequest()
     {
-        $twig = $this->getContainer()->get('phantomjs.twig.environment');
+        $request = new Request();
 
-        $templateRenderer = $this->getTemplateRenderer($twig);
-
-        return $templateRenderer;
+        return $request;
     }
 
-/** +++++++++++++++++++++++++++++++++++ **/
-/** ++++++++++ MOCKS / STUBS ++++++++++ **/
-/** +++++++++++++++++++++++++++++++++++ **/
-
     /**
-     * Get mock request instance.
+     * Get twig
      *
      * @access protected
-     * @return \JonnyW\PhantomJs\Message\RequestInterface
+     * @return \Twig_Environment
      */
-    protected function getRequest()
+    protected function getTwig()
     {
-        $mockRequest = $this->getMock('\JonnyW\PhantomJs\Message\RequestInterface');
+        $twig = new Twig_Environment(
+            new Twig_Loader_String()
+        );
 
-        return $mockRequest;
+        return $twig;
     }
 }

+ 119 - 0
src/JonnyW/PhantomJs/Tests/Unit/Validator/EsprimaTest.php

@@ -0,0 +1,119 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Tests\Unit\Validator;
+
+use Symfony\Component\Config\FileLocator;
+use JonnyW\PhantomJs\Validator\Esprima;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class EsprimaTest extends \PHPUnit_Framework_TestCase
+{
+
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++++++ TESTS ++++++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
+    /**
+     * Test invalid argument exception is thrown
+     * if file path is not local file.
+     *
+     * @access public
+     * @return void
+     */
+    public function testInvalidArgumentExceptionIsThrownIfFilePathIsNotLocalFile()
+    {
+        $this->setExpectedException('\InvalidArgumentException');
+
+        $fileLocator = $this->getFileLocator();
+        $esprima     = $this->getEsprima($fileLocator, 'http://example.com');
+
+        $esprima->load();
+    }
+
+    /**
+     * Test invalid argument exception is thrown if
+     * file does not exist.
+     *
+     * @access public
+     * @return void
+     */
+    public function testInvalidArgumentIsThrownIfFileDoesNotExist()
+    {
+        $this->setExpectedException('\InvalidArgumentException');
+
+        $fileLocator = $this->getFileLocator();
+        $esprima     = $this->getEsprima($fileLocator, 'invalidFile.js');
+
+        $esprima->load();
+    }
+
+    /**
+     * Test engine can be loaded.
+     *
+     * @access public
+     * @return void
+     */
+    public function testEngineCanBeLoaded()
+    {
+        $fileLocator = $this->getFileLocator();
+        $esprima     = $this->getEsprima($fileLocator, 'esprima-2.0.0.js');
+
+        $this->assertContains('esprima', $esprima->load());
+    }
+
+    /**
+     * Test engine can be converted to string.
+     *
+     * @access public
+     * @return void
+     */
+    public function testEngineCanBeCovertedToString()
+    {
+       $fileLocator = $this->getFileLocator();
+        $esprima     = $this->getEsprima($fileLocator, 'esprima-2.0.0.js');
+
+        $this->assertContains('esprima', (string) $esprima);
+    }
+
+/** +++++++++++++++++++++++++++++++++++ **/
+/** ++++++++++ TEST ENTITIES ++++++++++ **/
+/** +++++++++++++++++++++++++++++++++++ **/
+
+    /**
+     * Get esprima.
+     *
+     * @access protected
+     * @return \JonnyW\PhantomJs\Validator\Esprima
+     */
+    protected function getEsprima(FileLocator $fileLocator, $file)
+    {
+        $esprima = new Esprima($fileLocator, $file);
+
+        return $esprima;
+    }
+
+    /**
+     * Get file locator.
+     *
+     * @access protected
+     * @return \Symfony\Component\Config\FileLocator
+     */
+    protected function getFileLocator()
+    {
+        $fileLocator = new FileLocator(
+            sprintf('%s/../../../Resources/validators/', __DIR__)
+        );
+
+        return $fileLocator;
+    }
+}

+ 25 - 0
src/JonnyW/PhantomJs/Validator/EngineInterface.php

@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Validator;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+interface EngineInterface
+{
+    /**
+     * Returns engine as string.
+     *
+     * @access public
+     * @return string
+     */
+    public function toString();
+}

+ 111 - 0
src/JonnyW/PhantomJs/Validator/Esprima.php

@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * This file is part of the php-phantomjs.
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+namespace JonnyW\PhantomJs\Validator;
+
+use Symfony\Component\Config\FileLocatorInterface;
+
+/**
+ * PHP PhantomJs
+ *
+ * @author Jon Wenmoth <contact@jonnyw.me>
+ */
+class Esprima implements EngineInterface
+{
+    /**
+     * File locator
+     *
+     * @var \Symfony\Component\Config\FileLocatorInterface
+     * @access protected
+     */
+    protected $locator;
+
+    /**
+     * Esprima file.
+     *
+     * @var string
+     * @access protected
+     */
+    protected $file;
+
+    /**
+     * Esprima script.
+     *
+     * @var string
+     * @access protected
+     */
+    protected $esprima;
+
+    /**
+     * Internal constructor.
+     *
+     * @access public
+     * @param  \Symfony\Component\Config\FileLocatorInterface $locator
+     * @param  string                                         $file
+     * @return void
+     */
+    public function __construct($locator, $file)
+    {
+        $this->locator = $locator;
+        $this->file    = $file;
+    }
+
+    /**
+     * Returns engine as string.
+     *
+     * @access public
+     * @return string
+     */
+    public function toString()
+    {
+        $this->load();
+
+        return $this->esprima;
+    }
+
+    /**
+     * To string magic method.
+     *
+     * @access public
+     * @return string
+     */
+    public function __toString()
+    {
+        return $this->toString();
+    }
+
+    /**
+     * Load esprima script.
+     *
+     * @access public
+     * @return string
+     */
+    public function load()
+    {
+        if (!$this->esprima) {
+
+            $this->esprima = $this->loadFile(
+                $this->locator->locate($this->file)
+            );
+        }
+
+        return $this->esprima;
+    }
+
+    /**
+     * Load procedure file content.
+     *
+     * @access protected
+     * @param  string $file
+     * @return string
+     */
+    protected function loadFile($file)
+    {
+        return file_get_contents($file);
+    }
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов