Seditio Source
Root |
./othercms/croogo-4.0.7/vendor/cakephp/cakephp/src/TestSuite/IntegrationTestTrait.php
<?php
/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @since         3.7.0
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 */
namespace Cake\TestSuite;

use
Cake\Core\Configure;
use
Cake\Database\Exception as DatabaseException;
use
Cake\Http\ServerRequest;
use
Cake\Http\Session;
use
Cake\Routing\Router;
use
Cake\TestSuite\Constraint\Response\BodyContains;
use
Cake\TestSuite\Constraint\Response\BodyEmpty;
use
Cake\TestSuite\Constraint\Response\BodyEquals;
use
Cake\TestSuite\Constraint\Response\BodyNotContains;
use
Cake\TestSuite\Constraint\Response\BodyNotEmpty;
use
Cake\TestSuite\Constraint\Response\BodyNotEquals;
use
Cake\TestSuite\Constraint\Response\BodyNotRegExp;
use
Cake\TestSuite\Constraint\Response\BodyRegExp;
use
Cake\TestSuite\Constraint\Response\ContentType;
use
Cake\TestSuite\Constraint\Response\CookieEncryptedEquals;
use
Cake\TestSuite\Constraint\Response\CookieEquals;
use
Cake\TestSuite\Constraint\Response\CookieNotSet;
use
Cake\TestSuite\Constraint\Response\CookieSet;
use
Cake\TestSuite\Constraint\Response\FileSent;
use
Cake\TestSuite\Constraint\Response\FileSentAs;
use
Cake\TestSuite\Constraint\Response\HeaderContains;
use
Cake\TestSuite\Constraint\Response\HeaderEquals;
use
Cake\TestSuite\Constraint\Response\HeaderNotContains;
use
Cake\TestSuite\Constraint\Response\HeaderNotSet;
use
Cake\TestSuite\Constraint\Response\HeaderSet;
use
Cake\TestSuite\Constraint\Response\StatusCode;
use
Cake\TestSuite\Constraint\Response\StatusError;
use
Cake\TestSuite\Constraint\Response\StatusFailure;
use
Cake\TestSuite\Constraint\Response\StatusOk;
use
Cake\TestSuite\Constraint\Response\StatusSuccess;
use
Cake\TestSuite\Constraint\Session\FlashParamEquals;
use
Cake\TestSuite\Constraint\Session\SessionEquals;
use
Cake\TestSuite\Constraint\View\LayoutFileEquals;
use
Cake\TestSuite\Constraint\View\TemplateFileEquals;
use
Cake\TestSuite\Stub\TestExceptionRenderer;
use
Cake\Utility\CookieCryptTrait;
use
Cake\Utility\Hash;
use
Cake\Utility\Security;
use
Cake\Utility\Text;
use
Cake\View\Helper\SecureFieldTokenTrait;
use
Exception;
use
LogicException;
use
PHPUnit\Exception as PhpunitException;
use
Zend\Diactoros\Uri;

/**
 * A trait intended to make integration tests of your controllers easier.
 *
 * This test class provides a number of helper methods and features
 * that make dispatching requests and checking their responses simpler.
 * It favours full integration tests over mock objects as you can test
 * more of your code easily and avoid some of the maintenance pitfalls
 * that mock objects create.
 */
trait IntegrationTestTrait
{
    use
CookieCryptTrait;
    use
SecureFieldTokenTrait;

   
/**
     * Track whether or not tests are run against
     * the PSR7 HTTP stack.
     *
     * @var bool
     */
   
protected $_useHttpServer = false;

   
/**
     * The customized application class name.
     *
     * @var string|null
     */
   
protected $_appClass;

   
/**
     * The customized application constructor arguments.
     *
     * @var array|null
     */
   
protected $_appArgs;

   
/**
     * The data used to build the next request.
     *
     * @var array
     */
   
protected $_request = [];

   
/**
     * The response for the most recent request.
     *
     * @var \Cake\Http\Response|null
     */
   
protected $_response;

   
/**
     * The exception being thrown if the case.
     *
     * @var \Exception|null
     */
   
protected $_exception;

   
/**
     * Session data to use in the next request.
     *
     * @var array
     */
   
protected $_session = [];

   
/**
     * Cookie data to use in the next request.
     *
     * @var array
     */
   
protected $_cookie = [];

   
/**
     * The controller used in the last request.
     *
     * @var \Cake\Controller\Controller|null
     */
   
protected $_controller;

   
/**
     * The last rendered view
     *
     * @var string|null
     */
   
protected $_viewName;

   
/**
     * The last rendered layout
     *
     * @var string|null
     */
   
protected $_layoutName;

   
/**
     * The session instance from the last request
     *
     * @var \Cake\Http\Session|null
     */
   
protected $_requestSession;

   
/**
     * Boolean flag for whether or not the request should have
     * a SecurityComponent token added.
     *
     * @var bool
     */
   
protected $_securityToken = false;

   
/**
     * Boolean flag for whether or not the request should have
     * a CSRF token added.
     *
     * @var bool
     */
   
protected $_csrfToken = false;

   
/**
     * Boolean flag for whether or not the request should re-store
     * flash messages
     *
     * @var bool
     */
   
protected $_retainFlashMessages = false;

   
/**
     * Stored flash messages before render
     *
     * @var array|null
     */
   
protected $_flashMessages;

   
/**
     *
     * @var string|null
     */
   
protected $_cookieEncryptionKey;

   
/**
     * List of fields that are excluded from field validation.
     *
     * @var string[]
     */
   
protected $_unlockedFields = [];

   
/**
     * Auto-detect if the HTTP middleware stack should be used.
     *
     * @before
     * @return void
     */
   
public function setupServer()
    {
       
$namespace = Configure::read('App.namespace');
       
$this->_useHttpServer = class_exists($namespace . '\Application');
    }

   
/**
     * Clears the state used for requests.
     *
     * @after
     * @return void
     */
   
public function cleanup()
    {
       
$this->_request = [];
       
$this->_session = [];
       
$this->_cookie = [];
       
$this->_response = null;
       
$this->_exception = null;
       
$this->_controller = null;
       
$this->_viewName = null;
       
$this->_layoutName = null;
       
$this->_requestSession = null;
       
$this->_appClass = null;
       
$this->_appArgs = null;
       
$this->_securityToken = false;
       
$this->_csrfToken = false;
       
$this->_retainFlashMessages = false;
       
$this->_useHttpServer = false;
    }

   
/**
     * Toggle whether or not you want to use the HTTP Server stack.
     *
     * @param bool $enable Enable/disable the usage of the HTTP Stack.
     * @return void
     */
   
public function useHttpServer($enable)
    {
       
$this->_useHttpServer = (bool)$enable;
    }

   
/**
     * Configure the application class to use in integration tests.
     *
     * Combined with `useHttpServer()` to customize the class name and constructor arguments
     * of your application class.
     *
     * @param string $class The application class name.
     * @param array|null $constructorArgs The constructor arguments for your application class.
     * @return void
     */
   
public function configApplication($class, $constructorArgs)
    {
       
$this->_appClass = $class;
       
$this->_appArgs = $constructorArgs;
    }

   
/**
     * Calling this method will enable a SecurityComponent
     * compatible token to be added to request data. This
     * lets you easily test actions protected by SecurityComponent.
     *
     * @return void
     */
   
public function enableSecurityToken()
    {
       
$this->_securityToken = true;
    }

   
/**
     * Set list of fields that are excluded from field validation.
     *
     * @param string[] $unlockedFields List of fields that are excluded from field validation.
     * @return void
     */
   
public function setUnlockedFields(array $unlockedFields = [])
    {
       
$this->_unlockedFields = $unlockedFields;
    }

   
/**
     * Calling this method will add a CSRF token to the request.
     *
     * Both the POST data and cookie will be populated when this option
     * is enabled. The default parameter names will be used.
     *
     * @return void
     */
   
public function enableCsrfToken()
    {
       
$this->_csrfToken = true;
    }

   
/**
     * Calling this method will re-store flash messages into the test session
     * after being removed by the FlashHelper
     *
     * @return void
     */
   
public function enableRetainFlashMessages()
    {
       
$this->_retainFlashMessages = true;
    }

   
/**
     * Configures the data for the *next* request.
     *
     * This data is cleared in the tearDown() method.
     *
     * You can call this method multiple times to append into
     * the current state.
     *
     * @param array $data The request data to use.
     * @return void
     */
   
public function configRequest(array $data)
    {
       
$this->_request = $data + $this->_request;
    }

   
/**
     * Sets session data.
     *
     * This method lets you configure the session data
     * you want to be used for requests that follow. The session
     * state is reset in each tearDown().
     *
     * You can call this method multiple times to append into
     * the current state.
     *
     * @param array $data The session data to use.
     * @return void
     */
   
public function session(array $data)
    {
       
$this->_session = $data + $this->_session;
    }

   
/**
     * Sets a request cookie for future requests.
     *
     * This method lets you configure the session data
     * you want to be used for requests that follow. The session
     * state is reset in each tearDown().
     *
     * You can call this method multiple times to append into
     * the current state.
     *
     * @param string $name The cookie name to use.
     * @param mixed $value The value of the cookie.
     * @return void
     */
   
public function cookie($name, $value)
    {
       
$this->_cookie[$name] = $value;
    }

   
/**
     * Returns the encryption key to be used.
     *
     * @return string
     */
   
protected function _getCookieEncryptionKey()
    {
        if (isset(
$this->_cookieEncryptionKey)) {
            return
$this->_cookieEncryptionKey;
        }

        return
Security::getSalt();
    }

   
/**
     * Sets a encrypted request cookie for future requests.
     *
     * The difference from cookie() is this encrypts the cookie
     * value like the CookieComponent.
     *
     * @param string $name The cookie name to use.
     * @param mixed $value The value of the cookie.
     * @param string|bool $encrypt Encryption mode to use.
     * @param string|null $key Encryption key used. Defaults
     *   to Security.salt.
     * @return void
     * @see \Cake\Utility\CookieCryptTrait::_encrypt()
     */
   
public function cookieEncrypted($name, $value, $encrypt = 'aes', $key = null)
    {
       
$this->_cookieEncryptionKey = $key;
       
$this->_cookie[$name] = $this->_encrypt($value, $encrypt);
    }

   
/**
     * Performs a GET request using the current request data.
     *
     * The response of the dispatched request will be stored as
     * a property. You can use various assert methods to check the
     * response.
     *
     * @param string|array $url The URL to request.
     * @return void
     * @throws \PHPUnit\Exception
     */
   
public function get($url)
    {
       
$this->_sendRequest($url, 'GET');
    }

   
/**
     * Performs a POST request using the current request data.
     *
     * The response of the dispatched request will be stored as
     * a property. You can use various assert methods to check the
     * response.
     *
     * @param string|array $url The URL to request.
     * @param string|array|null $data The data for the request.
     * @return void
     * @throws \PHPUnit\Exception
     */
   
public function post($url, $data = [])
    {
       
$this->_sendRequest($url, 'POST', $data);
    }

   
/**
     * Performs a PATCH request using the current request data.
     *
     * The response of the dispatched request will be stored as
     * a property. You can use various assert methods to check the
     * response.
     *
     * @param string|array $url The URL to request.
     * @param string|array|null $data The data for the request.
     * @return void
     * @throws \PHPUnit\Exception
     */
   
public function patch($url, $data = [])
    {
       
$this->_sendRequest($url, 'PATCH', $data);
    }

   
/**
     * Performs a PUT request using the current request data.
     *
     * The response of the dispatched request will be stored as
     * a property. You can use various assert methods to check the
     * response.
     *
     * @param string|array $url The URL to request.
     * @param string|array|null $data The data for the request.
     * @return void
     * @throws \PHPUnit\Exception
     */
   
public function put($url, $data = [])
    {
       
$this->_sendRequest($url, 'PUT', $data);
    }

   
/**
     * Performs a DELETE request using the current request data.
     *
     * The response of the dispatched request will be stored as
     * a property. You can use various assert methods to check the
     * response.
     *
     * @param string|array $url The URL to request.
     * @return void
     * @throws \PHPUnit\Exception
     */
   
public function delete($url)
    {
       
$this->_sendRequest($url, 'DELETE');
    }

   
/**
     * Performs a HEAD request using the current request data.
     *
     * The response of the dispatched request will be stored as
     * a property. You can use various assert methods to check the
     * response.
     *
     * @param string|array $url The URL to request.
     * @return void
     * @throws \PHPUnit\Exception
     */
   
public function head($url)
    {
       
$this->_sendRequest($url, 'HEAD');
    }

   
/**
     * Performs an OPTIONS request using the current request data.
     *
     * The response of the dispatched request will be stored as
     * a property. You can use various assert methods to check the
     * response.
     *
     * @param string|array $url The URL to request.
     * @return void
     * @throws \PHPUnit\Exception
     */
   
public function options($url)
    {
       
$this->_sendRequest($url, 'OPTIONS');
    }

   
/**
     * Creates and send the request into a Dispatcher instance.
     *
     * Receives and stores the response for future inspection.
     *
     * @param string|array $url The URL
     * @param string $method The HTTP method
     * @param string|array|null $data The request data.
     * @return void
     * @throws \PHPUnit\Exception
     */
   
protected function _sendRequest($url, $method, $data = [])
    {
       
$dispatcher = $this->_makeDispatcher();
       
$url = $dispatcher->resolveUrl($url);

        try {
           
$request = $this->_buildRequest($url, $method, $data);
           
$response = $dispatcher->execute($request);
           
$this->_requestSession = $request['session'];
            if (
$this->_retainFlashMessages && $this->_flashMessages) {
               
$this->_requestSession->write('Flash', $this->_flashMessages);
            }
           
$this->_response = $response;
        } catch (
PhpUnitException $e) {
            throw
$e;
        } catch (
DatabaseException $e) {
            throw
$e;
        } catch (
LogicException $e) {
            throw
$e;
        } catch (
Exception $e) {
           
$this->_exception = $e;
           
// Simulate the global exception handler being invoked.
           
$this->_handleError($e);
        }
    }

   
/**
     * Get the correct dispatcher instance.
     *
     * @return \Cake\TestSuite\MiddlewareDispatcher|\Cake\TestSuite\LegacyRequestDispatcher A dispatcher instance
     */
   
protected function _makeDispatcher()
    {
        if (
$this->_useHttpServer) {
            return new
MiddlewareDispatcher($this, $this->_appClass, $this->_appArgs);
        }

        return new
LegacyRequestDispatcher($this);
    }

   
/**
     * Adds additional event spies to the controller/view event manager.
     *
     * @param \Cake\Event\Event $event A dispatcher event.
     * @param \Cake\Controller\Controller|null $controller Controller instance.
     * @return void
     */
   
public function controllerSpy($event, $controller = null)
    {
        if (!
$controller) {
           
/** @var \Cake\Controller\Controller $controller */
           
$controller = $event->getSubject();
        }
       
$this->_controller = $controller;
       
$events = $controller->getEventManager();
       
$events->on('View.beforeRender', function ($event, $viewFile) use ($controller) {
            if (!
$this->_viewName) {
               
$this->_viewName = $viewFile;
            }
            if (
$this->_retainFlashMessages) {
               
$this->_flashMessages = $controller->getRequest()->getSession()->read('Flash');
            }
        });
       
$events->on('View.beforeLayout', function ($event, $viewFile) {
           
$this->_layoutName = $viewFile;
        });
    }

   
/**
     * Attempts to render an error response for a given exception.
     *
     * This method will attempt to use the configured exception renderer.
     * If that class does not exist, the built-in renderer will be used.
     *
     * @param \Exception $exception Exception to handle.
     * @return void
     * @throws \Exception
     */
   
protected function _handleError($exception)
    {
       
$class = Configure::read('Error.exceptionRenderer');
        if (empty(
$class) || !class_exists($class)) {
           
$class = 'Cake\Error\ExceptionRenderer';
        }
       
/** @var \Cake\Error\ExceptionRenderer $instance */
       
$instance = new $class($exception);
       
$this->_response = $instance->render();
    }

   
/**
     * Creates a request object with the configured options and parameters.
     *
     * @param string|array $url The URL
     * @param string $method The HTTP method
     * @param string|array|null $data The request data.
     * @return array The request context
     */
   
protected function _buildRequest($url, $method, $data)
    {
       
$sessionConfig = (array)Configure::read('Session') + [
           
'defaults' => 'php',
        ];
       
$session = Session::create($sessionConfig);
       
$session->write($this->_session);
        list(
$url, $query, $hostInfo) = $this->_url($url);
       
$tokenUrl = $url;

        if (
$query) {
           
$tokenUrl .= '?' . $query;
        }

       
parse_str($query, $queryData);
       
$props = [
           
'url' => $url,
           
'session' => $session,
           
'query' => $queryData,
           
'files' => [],
        ];
        if (
is_string($data)) {
           
$props['input'] = $data;
        }
        if (!isset(
$props['input'])) {
           
$data = $this->_addTokens($tokenUrl, $data);
           
$props['post'] = $this->_castToString($data);
        }
       
$props['cookies'] = $this->_cookie;

       
$env = [
           
'REQUEST_METHOD' => $method,
           
'QUERY_STRING' => $query,
           
'REQUEST_URI' => $url,
        ];
        if (!empty(
$hostInfo['ssl'])) {
           
$env['HTTPS'] = 'on';
        }
        if (isset(
$hostInfo['host'])) {
           
$env['HTTP_HOST'] = $hostInfo['host'];
        }
        if (isset(
$this->_request['headers'])) {
            foreach (
$this->_request['headers'] as $k => $v) {
               
$name = strtoupper(str_replace('-', '_', $k));
                if (!
in_array($name, ['CONTENT_LENGTH', 'CONTENT_TYPE'])) {
                   
$name = 'HTTP_' . $name;
                }
               
$env[$name] = $v;
            }
            unset(
$this->_request['headers']);
        }
       
$props['environment'] = $env;
       
$props = Hash::merge($props, $this->_request);

        return
$props;
    }

   
/**
     * Add the CSRF and Security Component tokens if necessary.
     *
     * @param string $url The URL the form is being submitted on.
     * @param array $data The request body data.
     * @return array The request body with tokens added.
     */
   
protected function _addTokens($url, $data)
    {
        if (
$this->_securityToken === true) {
           
$fields = array_diff_key($data, array_flip($this->_unlockedFields));

           
$keys = array_map(function ($field) {
                return
preg_replace('/(\.\d+)+$/', '', $field);
            },
array_keys(Hash::flatten($fields)));

           
$tokenData = $this->_buildFieldToken($url, array_unique($keys), $this->_unlockedFields);

           
$data['_Token'] = $tokenData;
           
$data['_Token']['debug'] = 'SecurityComponent debug data would be added here';
        }

        if (
$this->_csrfToken === true) {
            if (!isset(
$this->_cookie['csrfToken'])) {
               
$this->_cookie['csrfToken'] = Text::uuid();
            }
            if (!isset(
$data['_csrfToken'])) {
               
$data['_csrfToken'] = $this->_cookie['csrfToken'];
            }
        }

        return
$data;
    }

   
/**
     * Recursively casts all data to string as that is how data would be POSTed in
     * the real world
     *
     * @param array $data POST data
     * @return array
     */
   
protected function _castToString($data)
    {
        foreach (
$data as $key => $value) {
            if (
is_scalar($value)) {
               
$data[$key] = $value === false ? '0' : (string)$value;

                continue;
            }

            if (
is_array($value)) {
               
$looksLikeFile = isset($value['error'], $value['tmp_name'], $value['size']);
                if (
$looksLikeFile) {
                    continue;
                }

               
$data[$key] = $this->_castToString($value);
            }
        }

        return
$data;
    }

   
/**
     * Creates a valid request url and parameter array more like Request::_url()
     *
     * @param string|array $url The URL
     * @return array Qualified URL, the query parameters, and host data
     */
   
protected function _url($url)
    {
       
$uri = new Uri($url);
       
$path = $uri->getPath();
       
$query = $uri->getQuery();

       
$hostData = [];
        if (
$uri->getHost()) {
           
$hostData['host'] = $uri->getHost();
        }
        if (
$uri->getScheme()) {
           
$hostData['ssl'] = $uri->getScheme() === 'https';
        }

        return [
$path, $query, $hostData];
    }

   
/**
     * Get the response body as string
     *
     * @return string The response body.
     */
   
protected function _getBodyAsString()
    {
        if (!
$this->_response) {
           
$this->fail('No response set, cannot assert content.');
        }

        return (string)
$this->_response->getBody();
    }

   
/**
     * Fetches a view variable by name.
     *
     * If the view variable does not exist, null will be returned.
     *
     * @param string $name The view variable to get.
     * @return mixed The view variable if set.
     */
   
public function viewVariable($name)
    {
        if (empty(
$this->_controller->viewVars)) {
           
$this->fail('There are no view variables, perhaps you need to run a request?');
        }
        if (isset(
$this->_controller->viewVars[$name])) {
            return
$this->_controller->viewVars[$name];
        }

        return
null;
    }

   
/**
     * Asserts that the response status code is in the 2xx range.
     *
     * @param string $message Custom message for failure.
     * @return void
     */
   
public function assertResponseOk($message = null)
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new StatusOk($this->_response), $verboseMessage);
    }

   
/**
     * Asserts that the response status code is in the 2xx/3xx range.
     *
     * @param string $message Custom message for failure.
     * @return void
     */
   
public function assertResponseSuccess($message = null)
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new StatusSuccess($this->_response), $verboseMessage);
    }

   
/**
     * Asserts that the response status code is in the 4xx range.
     *
     * @param string $message Custom message for failure.
     * @return void
     */
   
public function assertResponseError($message = null)
    {
       
$this->assertThat(null, new StatusError($this->_response), $message);
    }

   
/**
     * Asserts that the response status code is in the 5xx range.
     *
     * @param string $message Custom message for failure.
     * @return void
     */
   
public function assertResponseFailure($message = null)
    {
       
$this->assertThat(null, new StatusFailure($this->_response), $message);
    }

   
/**
     * Asserts a specific response status code.
     *
     * @param int $code Status code to assert.
     * @param string $message Custom message for failure.
     * @return void
     */
   
public function assertResponseCode($code, $message = null)
    {
       
$this->assertThat($code, new StatusCode($this->_response), $message);
    }

   
/**
     * Asserts that the Location header is correct. Comparison is made against a full URL.
     *
     * @param string|array|null $url The URL you expected the client to go to. This
     *   can either be a string URL or an array compatible with Router::url(). Use null to
     *   simply check for the existence of this header.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertRedirect($url = null, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);

        if (
$url) {
           
$this->assertThat(Router::url($url, ['_full' => true]), new HeaderEquals($this->_response, 'Location'), $verboseMessage);
        }
    }

   
/**
     * Asserts that the Location header is correct. Comparison is made against exactly the URL provided.
     *
     * @param string|array|null $url The URL you expected the client to go to. This
     *   can either be a string URL or an array compatible with Router::url(). Use null to
     *   simply check for the existence of this header.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertRedirectEquals($url = null, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);

        if (
$url) {
           
$this->assertThat(Router::url($url), new HeaderEquals($this->_response, 'Location'), $verboseMessage);
        }
    }

   
/**
     * Asserts that the Location header contains a substring
     *
     * @param string $url The URL you expected the client to go to.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertRedirectContains($url, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);
       
$this->assertThat($url, new HeaderContains($this->_response, 'Location'), $verboseMessage);
    }

   
/**
     * Asserts that the Location header does not contain a substring
     *
     * @param string $url The URL you expected the client to go to.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertRedirectNotContains($url, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);
       
$this->assertThat($url, new HeaderNotContains($this->_response, 'Location'), $verboseMessage);
    }

   
/**
     * Asserts that the Location header is not set.
     *
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertNoRedirect($message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new HeaderNotSet($this->_response, 'Location'), $verboseMessage);
    }

   
/**
     * Asserts response headers
     *
     * @param string $header The header to check
     * @param string $content The content to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertHeader($header, $content, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new HeaderSet($this->_response, $header), $verboseMessage);
       
$this->assertThat($content, new HeaderEquals($this->_response, $header), $verboseMessage);
    }

   
/**
     * Asserts response header contains a string
     *
     * @param string $header The header to check
     * @param string $content The content to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertHeaderContains($header, $content, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new HeaderSet($this->_response, $header), $verboseMessage);
       
$this->assertThat($content, new HeaderContains($this->_response, $header), $verboseMessage);
    }

   
/**
     * Asserts response header does not contain a string
     *
     * @param string $header The header to check
     * @param string $content The content to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertHeaderNotContains($header, $content, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new HeaderSet($this->_response, $header), $verboseMessage);
       
$this->assertThat($content, new HeaderNotContains($this->_response, $header), $verboseMessage);
    }

   
/**
     * Asserts content type
     *
     * @param string $type The content-type to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertContentType($type, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($type, new ContentType($this->_response), $verboseMessage);
    }

   
/**
     * Asserts content in the response body equals.
     *
     * @param mixed $content The content to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertResponseEquals($content, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($content, new BodyEquals($this->_response), $verboseMessage);
    }

   
/**
     * Asserts content in the response body not equals.
     *
     * @param mixed $content The content to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertResponseNotEquals($content, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($content, new BodyNotEquals($this->_response), $verboseMessage);
    }

   
/**
     * Asserts content exists in the response body.
     *
     * @param string $content The content to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @param bool $ignoreCase A flag to check whether we should ignore case or not.
     * @return void
     */
   
public function assertResponseContains($content, $message = '', $ignoreCase = false)
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($content, new BodyContains($this->_response, $ignoreCase), $verboseMessage);
    }

   
/**
     * Asserts content does not exist in the response body.
     *
     * @param string $content The content to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @param bool $ignoreCase A flag to check whether we should ignore case or not.
     * @return void
     */
   
public function assertResponseNotContains($content, $message = '', $ignoreCase = false)
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($content, new BodyNotContains($this->_response, $ignoreCase), $verboseMessage);
    }

   
/**
     * Asserts that the response body matches a given regular expression.
     *
     * @param string $pattern The pattern to compare against.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertResponseRegExp($pattern, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($pattern, new BodyRegExp($this->_response), $verboseMessage);
    }

   
/**
     * Asserts that the response body does not match a given regular expression.
     *
     * @param string $pattern The pattern to compare against.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertResponseNotRegExp($pattern, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($pattern, new BodyNotRegExp($this->_response), $verboseMessage);
    }

   
/**
     * Assert response content is not empty.
     *
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertResponseNotEmpty($message = '')
    {
       
$this->assertThat(null, new BodyNotEmpty($this->_response), $message);
    }

   
/**
     * Assert response content is empty.
     *
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertResponseEmpty($message = '')
    {
       
$this->assertThat(null, new BodyEmpty($this->_response), $message);
    }

   
/**
     * Asserts that the search string was in the template name.
     *
     * @param string $content The content to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertTemplate($content, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($content, new TemplateFileEquals($this->_viewName), $verboseMessage);
    }

   
/**
     * Asserts that the search string was in the layout name.
     *
     * @param string $content The content to check for.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertLayout($content, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($content, new LayoutFileEquals($this->_layoutName), $verboseMessage);
    }

   
/**
     * Asserts session contents
     *
     * @param string $expected The expected contents.
     * @param string $path The session data path. Uses Hash::get() compatible notation
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertSession($expected, $path, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($expected, new SessionEquals($this->_requestSession, $path), $verboseMessage);
    }

   
/**
     * Asserts a flash message was set
     *
     * @param string $expected Expected message
     * @param string $key Flash key
     * @param string $message Assertion failure message
     * @return void
     */
   
public function assertFlashMessage($expected, $key = 'flash', $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'message'), $verboseMessage);
    }

   
/**
     * Asserts a flash message was set at a certain index
     *
     * @param int $at Flash index
     * @param string $expected Expected message
     * @param string $key Flash key
     * @param string $message Assertion failure message
     * @return void
     */
   
public function assertFlashMessageAt($at, $expected, $key = 'flash', $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'message', $at), $verboseMessage);
    }

   
/**
     * Asserts a flash element was set
     *
     * @param string $expected Expected element name
     * @param string $key Flash key
     * @param string $message Assertion failure message
     * @return void
     */
   
public function assertFlashElement($expected, $key = 'flash', $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'element'), $verboseMessage);
    }

   
/**
     * Asserts a flash element was set at a certain index
     *
     * @param int $at Flash index
     * @param string $expected Expected element name
     * @param string $key Flash key
     * @param string $message Assertion failure message
     * @return void
     */
   
public function assertFlashElementAt($at, $expected, $key = 'flash', $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'element', $at), $verboseMessage);
    }

   
/**
     * Asserts cookie values
     *
     * @param string $expected The expected contents.
     * @param string $name The cookie name.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertCookie($expected, $name, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($name, new CookieSet($this->_response), $verboseMessage);
       
$this->assertThat($expected, new CookieEquals($this->_response, $name), $verboseMessage);
    }

   
/**
     * Asserts a cookie has not been set in the response
     *
     * @param string $cookie The cookie name to check
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertCookieNotSet($cookie, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($cookie, new CookieNotSet($this->_response), $verboseMessage);
    }

   
/**
     * Disable the error handler middleware.
     *
     * By using this function, exceptions are no longer caught by the ErrorHandlerMiddleware
     * and are instead re-thrown by the TestExceptionRenderer. This can be helpful
     * when trying to diagnose/debug unexpected failures in test cases.
     *
     * @return void
     */
   
public function disableErrorHandlerMiddleware()
    {
       
Configure::write('Error.exceptionRenderer', TestExceptionRenderer::class);
    }

   
/**
     * Asserts cookie values which are encrypted by the
     * CookieComponent.
     *
     * The difference from assertCookie() is this decrypts the cookie
     * value like the CookieComponent for this assertion.
     *
     * @param string $expected The expected contents.
     * @param string $name The cookie name.
     * @param string|bool $encrypt Encryption mode to use.
     * @param string|null $key Encryption key used. Defaults
     *   to Security.salt.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     * @see \Cake\Utility\CookieCryptTrait::_encrypt()
     */
   
public function assertCookieEncrypted($expected, $name, $encrypt = 'aes', $key = null, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat($name, new CookieSet($this->_response), $verboseMessage);

       
$this->_cookieEncryptionKey = $key;
       
$this->assertThat($expected, new CookieEncryptedEquals($this->_response, $name, $encrypt, $this->_getCookieEncryptionKey()));
    }

   
/**
     * Asserts that a file with the given name was sent in the response
     *
     * @param string $expected The absolute file path that should be sent in the response.
     * @param string $message The failure message that will be appended to the generated message.
     * @return void
     */
   
public function assertFileResponse($expected, $message = '')
    {
       
$verboseMessage = $this->extractVerboseMessage($message);
       
$this->assertThat(null, new FileSent($this->_response), $verboseMessage);
       
$this->assertThat($expected, new FileSentAs($this->_response), $verboseMessage);
    }

   
/**
     * Inspect controller to extract possible causes of the failed assertion
     *
     * @param string $message Original message to use as a base
     * @return string|null
     */
   
protected function extractVerboseMessage($message = null)
    {
        if (
$this->_exception instanceof \Exception) {
           
$message .= $this->extractExceptionMessage($this->_exception);
        }
        if (
$this->_controller === null) {
            return
$message;
        }
       
$error = Hash::get($this->_controller->viewVars, 'error');
        if (
$error instanceof \Exception) {
           
$message .= $this->extractExceptionMessage($this->viewVariable('error'));
        }

        return
$message;
    }

   
/**
     * Extract verbose message for existing exception
     *
     * @param \Exception $exception Exception to extract
     * @return string
     */
   
protected function extractExceptionMessage(\Exception $exception)
    {
        return
PHP_EOL .
           
sprintf('Possibly related to %s: "%s" ', get_class($exception), $exception->getMessage()) .
           
PHP_EOL .
           
$exception->getTraceAsString();
    }
}