Completed
Push — master ( d57a51...eca990 )
by Mark
03:38
created

IntegrationTestTrait::setUnlockedFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice
9
 *
10
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11
 * @since         3.7.0
12
 * @license       https://opensource.org/licenses/mit-license.php MIT License
13
 */
14
namespace Cake\TestSuite;
15
16
use Cake\Core\Configure;
17
use Cake\Database\Exception as DatabaseException;
18
use Cake\Http\ServerRequest;
19
use Cake\Http\Session;
20
use Cake\Routing\Router;
21
use Cake\TestSuite\Constraint\Response\BodyContains;
22
use Cake\TestSuite\Constraint\Response\BodyEmpty;
23
use Cake\TestSuite\Constraint\Response\BodyEquals;
24
use Cake\TestSuite\Constraint\Response\BodyNotContains;
25
use Cake\TestSuite\Constraint\Response\BodyNotEmpty;
26
use Cake\TestSuite\Constraint\Response\BodyNotEquals;
27
use Cake\TestSuite\Constraint\Response\BodyNotRegExp;
28
use Cake\TestSuite\Constraint\Response\BodyRegExp;
29
use Cake\TestSuite\Constraint\Response\ContentType;
30
use Cake\TestSuite\Constraint\Response\CookieEncryptedEquals;
31
use Cake\TestSuite\Constraint\Response\CookieEquals;
32
use Cake\TestSuite\Constraint\Response\CookieNotSet;
33
use Cake\TestSuite\Constraint\Response\CookieSet;
34
use Cake\TestSuite\Constraint\Response\FileSent;
35
use Cake\TestSuite\Constraint\Response\FileSentAs;
36
use Cake\TestSuite\Constraint\Response\HeaderContains;
37
use Cake\TestSuite\Constraint\Response\HeaderEquals;
38
use Cake\TestSuite\Constraint\Response\HeaderNotContains;
39
use Cake\TestSuite\Constraint\Response\HeaderNotSet;
40
use Cake\TestSuite\Constraint\Response\HeaderSet;
41
use Cake\TestSuite\Constraint\Response\StatusCode;
42
use Cake\TestSuite\Constraint\Response\StatusError;
43
use Cake\TestSuite\Constraint\Response\StatusFailure;
44
use Cake\TestSuite\Constraint\Response\StatusOk;
45
use Cake\TestSuite\Constraint\Response\StatusSuccess;
46
use Cake\TestSuite\Constraint\Session\FlashParamEquals;
47
use Cake\TestSuite\Constraint\Session\SessionEquals;
48
use Cake\TestSuite\Constraint\View\LayoutFileEquals;
49
use Cake\TestSuite\Constraint\View\TemplateFileEquals;
50
use Cake\TestSuite\Stub\TestExceptionRenderer;
51
use Cake\Utility\CookieCryptTrait;
52
use Cake\Utility\Hash;
53
use Cake\Utility\Security;
54
use Cake\Utility\Text;
55
use Cake\View\Helper\SecureFieldTokenTrait;
56
use Exception;
57
use LogicException;
58
use PHPUnit\Exception as PhpunitException;
59
use Zend\Diactoros\Uri;
60
61
/**
62
 * A trait intended to make integration tests of your controllers easier.
63
 *
64
 * This test class provides a number of helper methods and features
65
 * that make dispatching requests and checking their responses simpler.
66
 * It favours full integration tests over mock objects as you can test
67
 * more of your code easily and avoid some of the maintenance pitfalls
68
 * that mock objects create.
69
 */
70
trait IntegrationTestTrait
71
{
72
    use CookieCryptTrait;
73
    use SecureFieldTokenTrait;
74
75
    /**
76
     * Track whether or not tests are run against
77
     * the PSR7 HTTP stack.
78
     *
79
     * @var bool
80
     */
81
    protected $_useHttpServer = false;
82
83
    /**
84
     * The customized application class name.
85
     *
86
     * @var string|null
87
     */
88
    protected $_appClass;
89
90
    /**
91
     * The customized application constructor arguments.
92
     *
93
     * @var array|null
94
     */
95
    protected $_appArgs;
96
97
    /**
98
     * The data used to build the next request.
99
     *
100
     * @var array
101
     */
102
    protected $_request = [];
103
104
    /**
105
     * The response for the most recent request.
106
     *
107
     * @var \Cake\Http\Response|null
108
     */
109
    protected $_response;
110
111
    /**
112
     * The exception being thrown if the case.
113
     *
114
     * @var \Exception|null
115
     */
116
    protected $_exception;
117
118
    /**
119
     * Session data to use in the next request.
120
     *
121
     * @var array
122
     */
123
    protected $_session = [];
124
125
    /**
126
     * Cookie data to use in the next request.
127
     *
128
     * @var array
129
     */
130
    protected $_cookie = [];
131
132
    /**
133
     * The controller used in the last request.
134
     *
135
     * @var \Cake\Controller\Controller|null
136
     */
137
    protected $_controller;
138
139
    /**
140
     * The last rendered view
141
     *
142
     * @var string|null
143
     */
144
    protected $_viewName;
145
146
    /**
147
     * The last rendered layout
148
     *
149
     * @var string|null
150
     */
151
    protected $_layoutName;
152
153
    /**
154
     * The session instance from the last request
155
     *
156
     * @var \Cake\Http\Session|null
157
     */
158
    protected $_requestSession;
159
160
    /**
161
     * Boolean flag for whether or not the request should have
162
     * a SecurityComponent token added.
163
     *
164
     * @var bool
165
     */
166
    protected $_securityToken = false;
167
168
    /**
169
     * Boolean flag for whether or not the request should have
170
     * a CSRF token added.
171
     *
172
     * @var bool
173
     */
174
    protected $_csrfToken = false;
175
176
    /**
177
     * Boolean flag for whether or not the request should re-store
178
     * flash messages
179
     *
180
     * @var bool
181
     */
182
    protected $_retainFlashMessages = false;
183
184
    /**
185
     * Stored flash messages before render
186
     *
187
     * @var null|array
188
     */
189
    protected $_flashMessages;
190
191
    /**
192
     *
193
     * @var null|string
194
     */
195
    protected $_cookieEncryptionKey;
196
197
    /**
198
     * List of fields that are excluded from field validation.
199
     *
200
     * @var string[]
201
     */
202
    protected $_unlockedFields = [];
203
204
    /**
205
     * Auto-detect if the HTTP middleware stack should be used.
206
     *
207
     * @before
208
     * @return void
209
     */
210
    public function setupServer()
211
    {
212
        $namespace = Configure::read('App.namespace');
213
        $this->_useHttpServer = class_exists($namespace . '\Application');
214
    }
215
216
    /**
217
     * Clears the state used for requests.
218
     *
219
     * @after
220
     * @return void
221
     */
222
    public function cleanup()
223
    {
224
        $this->_request = [];
225
        $this->_session = [];
226
        $this->_cookie = [];
227
        $this->_response = null;
228
        $this->_exception = null;
229
        $this->_controller = null;
230
        $this->_viewName = null;
231
        $this->_layoutName = null;
232
        $this->_requestSession = null;
233
        $this->_appClass = null;
234
        $this->_appArgs = null;
235
        $this->_securityToken = false;
236
        $this->_csrfToken = false;
237
        $this->_retainFlashMessages = false;
238
        $this->_useHttpServer = false;
239
    }
240
241
    /**
242
     * Toggle whether or not you want to use the HTTP Server stack.
243
     *
244
     * @param bool $enable Enable/disable the usage of the HTTP Stack.
245
     * @return void
246
     */
247
    public function useHttpServer($enable)
248
    {
249
        $this->_useHttpServer = (bool)$enable;
250
    }
251
252
    /**
253
     * Configure the application class to use in integration tests.
254
     *
255
     * Combined with `useHttpServer()` to customize the class name and constructor arguments
256
     * of your application class.
257
     *
258
     * @param string $class The application class name.
259
     * @param array|null $constructorArgs The constructor arguments for your application class.
260
     * @return void
261
     */
262
    public function configApplication($class, $constructorArgs)
263
    {
264
        $this->_appClass = $class;
265
        $this->_appArgs = $constructorArgs;
266
    }
267
268
    /**
269
     * Calling this method will enable a SecurityComponent
270
     * compatible token to be added to request data. This
271
     * lets you easily test actions protected by SecurityComponent.
272
     *
273
     * @return void
274
     */
275
    public function enableSecurityToken()
276
    {
277
        $this->_securityToken = true;
278
    }
279
280
    /**
281
     * Set list of fields that are excluded from field validation.
282
     *
283
     * @param string[] $unlockedFields List of fields that are excluded from field validation.
284
     * @return void
285
     */
286
    public function setUnlockedFields(array $unlockedFields = [])
287
    {
288
        $this->_unlockedFields = $unlockedFields;
289
    }
290
291
    /**
292
     * Calling this method will add a CSRF token to the request.
293
     *
294
     * Both the POST data and cookie will be populated when this option
295
     * is enabled. The default parameter names will be used.
296
     *
297
     * @return void
298
     */
299
    public function enableCsrfToken()
300
    {
301
        $this->_csrfToken = true;
302
    }
303
304
    /**
305
     * Calling this method will re-store flash messages into the test session
306
     * after being removed by the FlashHelper
307
     *
308
     * @return void
309
     */
310
    public function enableRetainFlashMessages()
311
    {
312
        $this->_retainFlashMessages = true;
313
    }
314
315
    /**
316
     * Configures the data for the *next* request.
317
     *
318
     * This data is cleared in the tearDown() method.
319
     *
320
     * You can call this method multiple times to append into
321
     * the current state.
322
     *
323
     * @param array $data The request data to use.
324
     * @return void
325
     */
326
    public function configRequest(array $data)
327
    {
328
        $this->_request = $data + $this->_request;
329
    }
330
331
    /**
332
     * Sets session data.
333
     *
334
     * This method lets you configure the session data
335
     * you want to be used for requests that follow. The session
336
     * state is reset in each tearDown().
337
     *
338
     * You can call this method multiple times to append into
339
     * the current state.
340
     *
341
     * @param array $data The session data to use.
342
     * @return void
343
     */
344
    public function session(array $data)
345
    {
346
        $this->_session = $data + $this->_session;
347
    }
348
349
    /**
350
     * Sets a request cookie for future requests.
351
     *
352
     * This method lets you configure the session data
353
     * you want to be used for requests that follow. The session
354
     * state is reset in each tearDown().
355
     *
356
     * You can call this method multiple times to append into
357
     * the current state.
358
     *
359
     * @param string $name The cookie name to use.
360
     * @param mixed $value The value of the cookie.
361
     * @return void
362
     */
363
    public function cookie($name, $value)
364
    {
365
        $this->_cookie[$name] = $value;
366
    }
367
368
    /**
369
     * Returns the encryption key to be used.
370
     *
371
     * @return string
372
     */
373
    protected function _getCookieEncryptionKey()
374
    {
375
        if (isset($this->_cookieEncryptionKey)) {
376
            return $this->_cookieEncryptionKey;
377
        }
378
379
        return Security::getSalt();
380
    }
381
382
    /**
383
     * Sets a encrypted request cookie for future requests.
384
     *
385
     * The difference from cookie() is this encrypts the cookie
386
     * value like the CookieComponent.
387
     *
388
     * @param string $name The cookie name to use.
389
     * @param mixed $value The value of the cookie.
390
     * @param string|bool $encrypt Encryption mode to use.
391
     * @param string|null $key Encryption key used. Defaults
392
     *   to Security.salt.
393
     * @return void
394
     * @see \Cake\Utility\CookieCryptTrait::_encrypt()
395
     */
396
    public function cookieEncrypted($name, $value, $encrypt = 'aes', $key = null)
397
    {
398
        $this->_cookieEncryptionKey = $key;
399
        $this->_cookie[$name] = $this->_encrypt($value, $encrypt);
400
    }
401
402
    /**
403
     * Performs a GET request using the current request data.
404
     *
405
     * The response of the dispatched request will be stored as
406
     * a property. You can use various assert methods to check the
407
     * response.
408
     *
409
     * @param string|array $url The URL to request.
410
     * @return void
411
     * @throws \PHPUnit\Exception
412
     */
413
    public function get($url)
414
    {
415
        $this->_sendRequest($url, 'GET');
416
    }
417
418
    /**
419
     * Performs a POST request using the current request data.
420
     *
421
     * The response of the dispatched request will be stored as
422
     * a property. You can use various assert methods to check the
423
     * response.
424
     *
425
     * @param string|array $url The URL to request.
426
     * @param string|array|null $data The data for the request.
427
     * @return void
428
     * @throws \PHPUnit\Exception
429
     */
430
    public function post($url, $data = [])
431
    {
432
        $this->_sendRequest($url, 'POST', $data);
433
    }
434
435
    /**
436
     * Performs a PATCH request using the current request data.
437
     *
438
     * The response of the dispatched request will be stored as
439
     * a property. You can use various assert methods to check the
440
     * response.
441
     *
442
     * @param string|array $url The URL to request.
443
     * @param string|array|null $data The data for the request.
444
     * @return void
445
     * @throws \PHPUnit\Exception
446
     */
447
    public function patch($url, $data = [])
448
    {
449
        $this->_sendRequest($url, 'PATCH', $data);
450
    }
451
452
    /**
453
     * Performs a PUT request using the current request data.
454
     *
455
     * The response of the dispatched request will be stored as
456
     * a property. You can use various assert methods to check the
457
     * response.
458
     *
459
     * @param string|array $url The URL to request.
460
     * @param string|array|null $data The data for the request.
461
     * @return void
462
     * @throws \PHPUnit\Exception
463
     */
464
    public function put($url, $data = [])
465
    {
466
        $this->_sendRequest($url, 'PUT', $data);
467
    }
468
469
    /**
470
     * Performs a DELETE request using the current request data.
471
     *
472
     * The response of the dispatched request will be stored as
473
     * a property. You can use various assert methods to check the
474
     * response.
475
     *
476
     * @param string|array $url The URL to request.
477
     * @return void
478
     * @throws \PHPUnit\Exception
479
     */
480
    public function delete($url)
481
    {
482
        $this->_sendRequest($url, 'DELETE');
483
    }
484
485
    /**
486
     * Performs a HEAD request using the current request data.
487
     *
488
     * The response of the dispatched request will be stored as
489
     * a property. You can use various assert methods to check the
490
     * response.
491
     *
492
     * @param string|array $url The URL to request.
493
     * @return void
494
     * @throws \PHPUnit\Exception
495
     */
496
    public function head($url)
497
    {
498
        $this->_sendRequest($url, 'HEAD');
499
    }
500
501
    /**
502
     * Performs an OPTIONS request using the current request data.
503
     *
504
     * The response of the dispatched request will be stored as
505
     * a property. You can use various assert methods to check the
506
     * response.
507
     *
508
     * @param string|array $url The URL to request.
509
     * @return void
510
     * @throws \PHPUnit\Exception
511
     */
512
    public function options($url)
513
    {
514
        $this->_sendRequest($url, 'OPTIONS');
515
    }
516
517
    /**
518
     * Creates and send the request into a Dispatcher instance.
519
     *
520
     * Receives and stores the response for future inspection.
521
     *
522
     * @param string|array $url The URL
523
     * @param string $method The HTTP method
524
     * @param string|array|null $data The request data.
525
     * @return void
526
     * @throws \PHPUnit\Exception
527
     */
528
    protected function _sendRequest($url, $method, $data = [])
529
    {
530
        $dispatcher = $this->_makeDispatcher();
531
        $url = $dispatcher->resolveUrl($url);
532
533
        try {
534
            $request = $this->_buildRequest($url, $method, $data);
535
            $response = $dispatcher->execute($request);
536
            $this->_requestSession = $request['session'];
537
            if ($this->_retainFlashMessages && $this->_flashMessages) {
538
                $this->_requestSession->write('Flash', $this->_flashMessages);
539
            }
540
            $this->_response = $response;
541
        } catch (PhpUnitException $e) {
542
            throw $e;
543
        } catch (DatabaseException $e) {
544
            throw $e;
545
        } catch (LogicException $e) {
546
            throw $e;
547
        } catch (Exception $e) {
548
            $this->_exception = $e;
549
            // Simulate the global exception handler being invoked.
550
            $this->_handleError($e);
551
        }
552
    }
553
554
    /**
555
     * Get the correct dispatcher instance.
556
     *
557
     * @return \Cake\TestSuite\MiddlewareDispatcher|\Cake\TestSuite\LegacyRequestDispatcher A dispatcher instance
558
     */
559
    protected function _makeDispatcher()
560
    {
561
        if ($this->_useHttpServer) {
562
            return new MiddlewareDispatcher($this, $this->_appClass, $this->_appArgs);
563
        }
564
565
        return new LegacyRequestDispatcher($this);
566
    }
567
568
    /**
569
     * Adds additional event spies to the controller/view event manager.
570
     *
571
     * @param \Cake\Event\Event $event A dispatcher event.
572
     * @param \Cake\Controller\Controller|null $controller Controller instance.
573
     * @return void
574
     */
575
    public function controllerSpy($event, $controller = null)
576
    {
577
        if (!$controller) {
578
            /** @var \Cake\Controller\Controller $controller */
579
            $controller = $event->getSubject();
580
        }
581
        $this->_controller = $controller;
582
        $events = $controller->getEventManager();
583
        $events->on('View.beforeRender', function ($event, $viewFile) use ($controller) {
0 ignored issues
show
Documentation introduced by
function ($event, $viewF...>read('Flash'); } } is of type object<Closure>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
584
            if (!$this->_viewName) {
585
                $this->_viewName = $viewFile;
586
            }
587
            if ($this->_retainFlashMessages) {
588
                $this->_flashMessages = $controller->getRequest()->getSession()->read('Flash');
589
            }
590
        });
591
        $events->on('View.beforeLayout', function ($event, $viewFile) {
0 ignored issues
show
Documentation introduced by
function ($event, $viewF...youtName = $viewFile; } is of type object<Closure>, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
592
            $this->_layoutName = $viewFile;
593
        });
594
    }
595
596
    /**
597
     * Attempts to render an error response for a given exception.
598
     *
599
     * This method will attempt to use the configured exception renderer.
600
     * If that class does not exist, the built-in renderer will be used.
601
     *
602
     * @param \Exception $exception Exception to handle.
603
     * @return void
604
     * @throws \Exception
605
     */
606
    protected function _handleError($exception)
607
    {
608
        $class = Configure::read('Error.exceptionRenderer');
609
        if (empty($class) || !class_exists($class)) {
610
            $class = 'Cake\Error\ExceptionRenderer';
611
        }
612
        /** @var \Cake\Error\ExceptionRenderer $instance */
613
        $instance = new $class($exception);
614
        $this->_response = $instance->render();
615
    }
616
617
    /**
618
     * Creates a request object with the configured options and parameters.
619
     *
620
     * @param string|array $url The URL
621
     * @param string $method The HTTP method
622
     * @param string|array|null $data The request data.
623
     * @return array The request context
624
     */
625
    protected function _buildRequest($url, $method, $data)
626
    {
627
        $sessionConfig = (array)Configure::read('Session') + [
628
            'defaults' => 'php',
629
        ];
630
        $session = Session::create($sessionConfig);
631
        $session->write($this->_session);
632
        list($url, $query, $hostInfo) = $this->_url($url);
633
        $tokenUrl = $url;
634
635
        if ($query) {
636
            $tokenUrl .= '?' . $query;
637
        }
638
639
        parse_str($query, $queryData);
640
        $props = [
641
            'url' => $url,
642
            'session' => $session,
643
            'query' => $queryData,
644
            'files' => [],
645
        ];
646
        if (is_string($data)) {
647
            $props['input'] = $data;
648
        }
649
        if (!isset($props['input'])) {
650
            $data = $this->_addTokens($tokenUrl, $data);
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type null or string; however, Cake\TestSuite\IntegrationTestTrait::_addTokens() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
651
            $props['post'] = $this->_castToString($data);
652
        }
653
        $props['cookies'] = $this->_cookie;
654
655
        $env = [
656
            'REQUEST_METHOD' => $method,
657
            'QUERY_STRING' => $query,
658
            'REQUEST_URI' => $url,
659
        ];
660
        if (!empty($hostInfo['ssl'])) {
661
            $env['HTTPS'] = 'on';
662
        }
663
        if (isset($hostInfo['host'])) {
664
            $env['HTTP_HOST'] = $hostInfo['host'];
665
        }
666
        if (isset($this->_request['headers'])) {
667
            foreach ($this->_request['headers'] as $k => $v) {
668
                $name = strtoupper(str_replace('-', '_', $k));
669
                if (!in_array($name, ['CONTENT_LENGTH', 'CONTENT_TYPE'])) {
670
                    $name = 'HTTP_' . $name;
671
                }
672
                $env[$name] = $v;
673
            }
674
            unset($this->_request['headers']);
675
        }
676
        $props['environment'] = $env;
677
        $props = Hash::merge($props, $this->_request);
678
679
        return $props;
680
    }
681
682
    /**
683
     * Add the CSRF and Security Component tokens if necessary.
684
     *
685
     * @param string $url The URL the form is being submitted on.
686
     * @param array $data The request body data.
687
     * @return array The request body with tokens added.
688
     */
689
    protected function _addTokens($url, $data)
690
    {
691
        if ($this->_securityToken === true) {
692
            $fields = array_diff_key($data, array_flip($this->_unlockedFields));
693
694
            $keys = array_map(function ($field) {
695
                return preg_replace('/(\.\d+)+$/', '', $field);
696
            }, array_keys(Hash::flatten($fields)));
697
698
            $tokenData = $this->_buildFieldToken($url, array_unique($keys), $this->_unlockedFields);
699
700
            $data['_Token'] = $tokenData;
701
            $data['_Token']['debug'] = 'SecurityComponent debug data would be added here';
702
        }
703
704
        if ($this->_csrfToken === true) {
705
            if (!isset($this->_cookie['csrfToken'])) {
706
                $this->_cookie['csrfToken'] = Text::uuid();
707
            }
708
            if (!isset($data['_csrfToken'])) {
709
                $data['_csrfToken'] = $this->_cookie['csrfToken'];
710
            }
711
        }
712
713
        return $data;
714
    }
715
716
    /**
717
     * Recursively casts all data to string as that is how data would be POSTed in
718
     * the real world
719
     *
720
     * @param array $data POST data
721
     * @return array
722
     */
723
    protected function _castToString($data)
724
    {
725
        foreach ($data as $key => $value) {
726
            if (is_scalar($value)) {
727
                $data[$key] = $value === false ? '0' : (string)$value;
728
729
                continue;
730
            }
731
732
            if (is_array($value)) {
733
                $looksLikeFile = isset($value['error'], $value['tmp_name'], $value['size']);
734
                if ($looksLikeFile) {
735
                    continue;
736
                }
737
738
                $data[$key] = $this->_castToString($value);
739
            }
740
        }
741
742
        return $data;
743
    }
744
745
    /**
746
     * Creates a valid request url and parameter array more like Request::_url()
747
     *
748
     * @param string|array $url The URL
749
     * @return array Qualified URL, the query parameters, and host data
750
     */
751
    protected function _url($url)
752
    {
753
        $uri = new Uri($url);
0 ignored issues
show
Bug introduced by
It seems like $url defined by parameter $url on line 751 can also be of type array; however, Zend\Diactoros\Uri::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
754
        $path = $uri->getPath();
755
        $query = $uri->getQuery();
756
757
        $hostData = [];
758
        if ($uri->getHost()) {
759
            $hostData['host'] = $uri->getHost();
760
        }
761
        if ($uri->getScheme()) {
762
            $hostData['ssl'] = $uri->getScheme() === 'https';
763
        }
764
765
        return [$path, $query, $hostData];
766
    }
767
768
    /**
769
     * Get the response body as string
770
     *
771
     * @return string The response body.
772
     */
773
    protected function _getBodyAsString()
774
    {
775
        if (!$this->_response) {
776
            $this->fail('No response set, cannot assert content.');
0 ignored issues
show
Bug introduced by
It seems like fail() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
777
        }
778
779
        return (string)$this->_response->getBody();
780
    }
781
782
    /**
783
     * Fetches a view variable by name.
784
     *
785
     * If the view variable does not exist, null will be returned.
786
     *
787
     * @param string $name The view variable to get.
788
     * @return mixed The view variable if set.
789
     */
790
    public function viewVariable($name)
791
    {
792
        if (empty($this->_controller->viewVars)) {
793
            $this->fail('There are no view variables, perhaps you need to run a request?');
0 ignored issues
show
Bug introduced by
It seems like fail() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
794
        }
795
        if (isset($this->_controller->viewVars[$name])) {
796
            return $this->_controller->viewVars[$name];
797
        }
798
799
        return null;
800
    }
801
802
    /**
803
     * Asserts that the response status code is in the 2xx range.
804
     *
805
     * @param string $message Custom message for failure.
806
     * @return void
807
     */
808
    public function assertResponseOk($message = null)
809
    {
810
        $verboseMessage = $this->extractVerboseMessage($message);
811
        $this->assertThat(null, new StatusOk($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
812
    }
813
814
    /**
815
     * Asserts that the response status code is in the 2xx/3xx range.
816
     *
817
     * @param string $message Custom message for failure.
818
     * @return void
819
     */
820
    public function assertResponseSuccess($message = null)
821
    {
822
        $verboseMessage = $this->extractVerboseMessage($message);
823
        $this->assertThat(null, new StatusSuccess($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
824
    }
825
826
    /**
827
     * Asserts that the response status code is in the 4xx range.
828
     *
829
     * @param string $message Custom message for failure.
830
     * @return void
831
     */
832
    public function assertResponseError($message = null)
833
    {
834
        $this->assertThat(null, new StatusError($this->_response), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
835
    }
836
837
    /**
838
     * Asserts that the response status code is in the 5xx range.
839
     *
840
     * @param string $message Custom message for failure.
841
     * @return void
842
     */
843
    public function assertResponseFailure($message = null)
844
    {
845
        $this->assertThat(null, new StatusFailure($this->_response), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
846
    }
847
848
    /**
849
     * Asserts a specific response status code.
850
     *
851
     * @param int $code Status code to assert.
852
     * @param string $message Custom message for failure.
853
     * @return void
854
     */
855
    public function assertResponseCode($code, $message = null)
856
    {
857
        $this->assertThat($code, new StatusCode($this->_response), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
858
    }
859
860
    /**
861
     * Asserts that the Location header is correct.
862
     *
863
     * @param string|array|null $url The URL you expected the client to go to. This
864
     *   can either be a string URL or an array compatible with Router::url(). Use null to
865
     *   simply check for the existence of this header.
866
     * @param string $message The failure message that will be appended to the generated message.
867
     * @return void
868
     */
869
    public function assertRedirect($url = null, $message = '')
870
    {
871
        $verboseMessage = $this->extractVerboseMessage($message);
872
        $this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
873
874
        if ($url) {
875
            $this->assertThat(Router::url($url, ['_full' => true]), new HeaderEquals($this->_response, 'Location'), $verboseMessage);
0 ignored issues
show
Documentation introduced by
array('_full' => true) is of type array<string,boolean,{"_full":"boolean"}>, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
876
        }
877
    }
878
879
    /**
880
     * Asserts that the Location header contains a substring
881
     *
882
     * @param string $url The URL you expected the client to go to.
883
     * @param string $message The failure message that will be appended to the generated message.
884
     * @return void
885
     */
886
    public function assertRedirectContains($url, $message = '')
887
    {
888
        $verboseMessage = $this->extractVerboseMessage($message);
889
        $this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
890
        $this->assertThat($url, new HeaderContains($this->_response, 'Location'), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
891
    }
892
893
    /**
894
     * Asserts that the Location header does not contain a substring
895
     *
896
     * @param string $url The URL you expected the client to go to.
897
     * @param string $message The failure message that will be appended to the generated message.
898
     * @return void
899
     */
900
    public function assertRedirectNotContains($url, $message = '')
901
    {
902
        $verboseMessage = $this->extractVerboseMessage($message);
903
        $this->assertThat(null, new HeaderSet($this->_response, 'Location'), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
904
        $this->assertThat($url, new HeaderNotContains($this->_response, 'Location'), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
905
    }
906
907
    /**
908
     * Asserts that the Location header is not set.
909
     *
910
     * @param string $message The failure message that will be appended to the generated message.
911
     * @return void
912
     */
913
    public function assertNoRedirect($message = '')
914
    {
915
        $verboseMessage = $this->extractVerboseMessage($message);
916
        $this->assertThat(null, new HeaderNotSet($this->_response, 'Location'), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
917
    }
918
919
    /**
920
     * Asserts response headers
921
     *
922
     * @param string $header The header to check
923
     * @param string $content The content to check for.
924
     * @param string $message The failure message that will be appended to the generated message.
925
     * @return void
926
     */
927
    public function assertHeader($header, $content, $message = '')
928
    {
929
        $verboseMessage = $this->extractVerboseMessage($message);
930
        $this->assertThat(null, new HeaderSet($this->_response, $header), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
931
        $this->assertThat($content, new HeaderEquals($this->_response, $header), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
932
    }
933
934
    /**
935
     * Asserts response header contains a string
936
     *
937
     * @param string $header The header to check
938
     * @param string $content The content to check for.
939
     * @param string $message The failure message that will be appended to the generated message.
940
     * @return void
941
     */
942
    public function assertHeaderContains($header, $content, $message = '')
943
    {
944
        $verboseMessage = $this->extractVerboseMessage($message);
945
        $this->assertThat(null, new HeaderSet($this->_response, $header), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
946
        $this->assertThat($content, new HeaderContains($this->_response, $header), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
947
    }
948
949
    /**
950
     * Asserts response header does not contain a string
951
     *
952
     * @param string $header The header to check
953
     * @param string $content The content to check for.
954
     * @param string $message The failure message that will be appended to the generated message.
955
     * @return void
956
     */
957
    public function assertHeaderNotContains($header, $content, $message = '')
958
    {
959
        $verboseMessage = $this->extractVerboseMessage($message);
960
        $this->assertThat(null, new HeaderSet($this->_response, $header), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
961
        $this->assertThat($content, new HeaderNotContains($this->_response, $header), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
962
    }
963
964
    /**
965
     * Asserts content type
966
     *
967
     * @param string $type The content-type to check for.
968
     * @param string $message The failure message that will be appended to the generated message.
969
     * @return void
970
     */
971
    public function assertContentType($type, $message = '')
972
    {
973
        $verboseMessage = $this->extractVerboseMessage($message);
974
        $this->assertThat($type, new ContentType($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
975
    }
976
977
    /**
978
     * Asserts content in the response body equals.
979
     *
980
     * @param mixed $content The content to check for.
981
     * @param string $message The failure message that will be appended to the generated message.
982
     * @return void
983
     */
984
    public function assertResponseEquals($content, $message = '')
985
    {
986
        $verboseMessage = $this->extractVerboseMessage($message);
987
        $this->assertThat($content, new BodyEquals($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
988
    }
989
990
    /**
991
     * Asserts content in the response body not equals.
992
     *
993
     * @param mixed $content The content to check for.
994
     * @param string $message The failure message that will be appended to the generated message.
995
     * @return void
996
     */
997
    public function assertResponseNotEquals($content, $message = '')
998
    {
999
        $verboseMessage = $this->extractVerboseMessage($message);
1000
        $this->assertThat($content, new BodyNotEquals($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1001
    }
1002
1003
    /**
1004
     * Asserts content exists in the response body.
1005
     *
1006
     * @param string $content The content to check for.
1007
     * @param string $message The failure message that will be appended to the generated message.
1008
     * @param bool $ignoreCase A flag to check whether we should ignore case or not.
1009
     * @return void
1010
     */
1011
    public function assertResponseContains($content, $message = '', $ignoreCase = false)
1012
    {
1013
        $verboseMessage = $this->extractVerboseMessage($message);
1014
        $this->assertThat($content, new BodyContains($this->_response, $ignoreCase), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1015
    }
1016
1017
    /**
1018
     * Asserts content does not exist in the response body.
1019
     *
1020
     * @param string $content The content to check for.
1021
     * @param string $message The failure message that will be appended to the generated message.
1022
     * @param bool $ignoreCase A flag to check whether we should ignore case or not.
1023
     * @return void
1024
     */
1025
    public function assertResponseNotContains($content, $message = '', $ignoreCase = false)
1026
    {
1027
        $verboseMessage = $this->extractVerboseMessage($message);
1028
        $this->assertThat($content, new BodyNotContains($this->_response, $ignoreCase), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1029
    }
1030
1031
    /**
1032
     * Asserts that the response body matches a given regular expression.
1033
     *
1034
     * @param string $pattern The pattern to compare against.
1035
     * @param string $message The failure message that will be appended to the generated message.
1036
     * @return void
1037
     */
1038
    public function assertResponseRegExp($pattern, $message = '')
1039
    {
1040
        $verboseMessage = $this->extractVerboseMessage($message);
1041
        $this->assertThat($pattern, new BodyRegExp($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1042
    }
1043
1044
    /**
1045
     * Asserts that the response body does not match a given regular expression.
1046
     *
1047
     * @param string $pattern The pattern to compare against.
1048
     * @param string $message The failure message that will be appended to the generated message.
1049
     * @return void
1050
     */
1051
    public function assertResponseNotRegExp($pattern, $message = '')
1052
    {
1053
        $verboseMessage = $this->extractVerboseMessage($message);
1054
        $this->assertThat($pattern, new BodyNotRegExp($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1055
    }
1056
1057
    /**
1058
     * Assert response content is not empty.
1059
     *
1060
     * @param string $message The failure message that will be appended to the generated message.
1061
     * @return void
1062
     */
1063
    public function assertResponseNotEmpty($message = '')
1064
    {
1065
        $this->assertThat(null, new BodyNotEmpty($this->_response), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1066
    }
1067
1068
    /**
1069
     * Assert response content is empty.
1070
     *
1071
     * @param string $message The failure message that will be appended to the generated message.
1072
     * @return void
1073
     */
1074
    public function assertResponseEmpty($message = '')
1075
    {
1076
        $this->assertThat(null, new BodyEmpty($this->_response), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1077
    }
1078
1079
    /**
1080
     * Asserts that the search string was in the template name.
1081
     *
1082
     * @param string $content The content to check for.
1083
     * @param string $message The failure message that will be appended to the generated message.
1084
     * @return void
1085
     */
1086
    public function assertTemplate($content, $message = '')
1087
    {
1088
        $verboseMessage = $this->extractVerboseMessage($message);
1089
        $this->assertThat($content, new TemplateFileEquals($this->_viewName), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1090
    }
1091
1092
    /**
1093
     * Asserts that the search string was in the layout name.
1094
     *
1095
     * @param string $content The content to check for.
1096
     * @param string $message The failure message that will be appended to the generated message.
1097
     * @return void
1098
     */
1099
    public function assertLayout($content, $message = '')
1100
    {
1101
        $verboseMessage = $this->extractVerboseMessage($message);
1102
        $this->assertThat($content, new LayoutFileEquals($this->_layoutName), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1103
    }
1104
1105
    /**
1106
     * Asserts session contents
1107
     *
1108
     * @param string $expected The expected contents.
1109
     * @param string $path The session data path. Uses Hash::get() compatible notation
1110
     * @param string $message The failure message that will be appended to the generated message.
1111
     * @return void
1112
     */
1113
    public function assertSession($expected, $path, $message = '')
1114
    {
1115
        $verboseMessage = $this->extractVerboseMessage($message);
1116
        $this->assertThat($expected, new SessionEquals($this->_requestSession, $path), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1117
    }
1118
1119
    /**
1120
     * Asserts a flash message was set
1121
     *
1122
     * @param string $expected Expected message
1123
     * @param string $key Flash key
1124
     * @param string $message Assertion failure message
1125
     * @return void
1126
     */
1127
    public function assertFlashMessage($expected, $key = 'flash', $message = '')
1128
    {
1129
        $verboseMessage = $this->extractVerboseMessage($message);
1130
        $this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'message'), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1131
    }
1132
1133
    /**
1134
     * Asserts a flash message was set at a certain index
1135
     *
1136
     * @param int $at Flash index
1137
     * @param string $expected Expected message
1138
     * @param string $key Flash key
1139
     * @param string $message Assertion failure message
1140
     * @return void
1141
     */
1142
    public function assertFlashMessageAt($at, $expected, $key = 'flash', $message = '')
1143
    {
1144
        $verboseMessage = $this->extractVerboseMessage($message);
1145
        $this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'message', $at), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1146
    }
1147
1148
    /**
1149
     * Asserts a flash element was set
1150
     *
1151
     * @param string $expected Expected element name
1152
     * @param string $key Flash key
1153
     * @param string $message Assertion failure message
1154
     * @return void
1155
     */
1156
    public function assertFlashElement($expected, $key = 'flash', $message = '')
1157
    {
1158
        $verboseMessage = $this->extractVerboseMessage($message);
1159
        $this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'element'), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1160
    }
1161
1162
    /**
1163
     * Asserts a flash element was set at a certain index
1164
     *
1165
     * @param int $at Flash index
1166
     * @param string $expected Expected element name
1167
     * @param string $key Flash key
1168
     * @param string $message Assertion failure message
1169
     * @return void
1170
     */
1171
    public function assertFlashElementAt($at, $expected, $key = 'flash', $message = '')
1172
    {
1173
        $verboseMessage = $this->extractVerboseMessage($message);
1174
        $this->assertThat($expected, new FlashParamEquals($this->_requestSession, $key, 'element', $at), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1175
    }
1176
1177
    /**
1178
     * Asserts cookie values
1179
     *
1180
     * @param string $expected The expected contents.
1181
     * @param string $name The cookie name.
1182
     * @param string $message The failure message that will be appended to the generated message.
1183
     * @return void
1184
     */
1185
    public function assertCookie($expected, $name, $message = '')
1186
    {
1187
        $verboseMessage = $this->extractVerboseMessage($message);
1188
        $this->assertThat($name, new CookieSet($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1189
        $this->assertThat($expected, new CookieEquals($this->_response, $name), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1190
    }
1191
1192
    /**
1193
     * Asserts a cookie has not been set in the response
1194
     *
1195
     * @param string $cookie The cookie name to check
1196
     * @param string $message The failure message that will be appended to the generated message.
1197
     * @return void
1198
     */
1199
    public function assertCookieNotSet($cookie, $message = '')
1200
    {
1201
        $verboseMessage = $this->extractVerboseMessage($message);
1202
        $this->assertThat($cookie, new CookieNotSet($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1203
    }
1204
1205
    /**
1206
     * Disable the error handler middleware.
1207
     *
1208
     * By using this function, exceptions are no longer caught by the ErrorHandlerMiddleware
1209
     * and are instead re-thrown by the TestExceptionRenderer. This can be helpful
1210
     * when trying to diagnose/debug unexpected failures in test cases.
1211
     *
1212
     * @return void
1213
     */
1214
    public function disableErrorHandlerMiddleware()
1215
    {
1216
        Configure::write('Error.exceptionRenderer', TestExceptionRenderer::class);
1217
    }
1218
1219
    /**
1220
     * Asserts cookie values which are encrypted by the
1221
     * CookieComponent.
1222
     *
1223
     * The difference from assertCookie() is this decrypts the cookie
1224
     * value like the CookieComponent for this assertion.
1225
     *
1226
     * @param string $expected The expected contents.
1227
     * @param string $name The cookie name.
1228
     * @param string|bool $encrypt Encryption mode to use.
1229
     * @param string|null $key Encryption key used. Defaults
1230
     *   to Security.salt.
1231
     * @param string $message The failure message that will be appended to the generated message.
1232
     * @return void
1233
     * @see \Cake\Utility\CookieCryptTrait::_encrypt()
1234
     */
1235
    public function assertCookieEncrypted($expected, $name, $encrypt = 'aes', $key = null, $message = '')
1236
    {
1237
        $verboseMessage = $this->extractVerboseMessage($message);
1238
        $this->assertThat($name, new CookieSet($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1239
1240
        $this->_cookieEncryptionKey = $key;
1241
        $this->assertThat($expected, new CookieEncryptedEquals($this->_response, $name, $encrypt, $this->_getCookieEncryptionKey()));
0 ignored issues
show
Bug introduced by
It seems like $encrypt defined by parameter $encrypt on line 1235 can also be of type boolean; however, Cake\TestSuite\Constrain...edEquals::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1242
    }
1243
1244
    /**
1245
     * Asserts that a file with the given name was sent in the response
1246
     *
1247
     * @param string $expected The absolute file path that should be sent in the response.
1248
     * @param string $message The failure message that will be appended to the generated message.
1249
     * @return void
1250
     */
1251
    public function assertFileResponse($expected, $message = '')
1252
    {
1253
        $verboseMessage = $this->extractVerboseMessage($message);
1254
        $this->assertThat(null, new FileSent($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1255
        $this->assertThat($expected, new FileSentAs($this->_response), $verboseMessage);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
1256
    }
1257
1258
    /**
1259
     * Inspect controller to extract possible causes of the failed assertion
1260
     *
1261
     * @param string $message Original message to use as a base
1262
     * @return null|string
1263
     */
1264
    protected function extractVerboseMessage($message = null)
1265
    {
1266
        if ($this->_exception instanceof \Exception) {
1267
            $message .= $this->extractExceptionMessage($this->_exception);
1268
        }
1269
        if ($this->_controller === null) {
1270
            return $message;
1271
        }
1272
        $error = Hash::get($this->_controller->viewVars, 'error');
1273
        if ($error instanceof \Exception) {
1274
            $message .= $this->extractExceptionMessage($this->viewVariable('error'));
1275
        }
1276
1277
        return $message;
1278
    }
1279
1280
    /**
1281
     * Extract verbose message for existing exception
1282
     *
1283
     * @param \Exception $exception Exception to extract
1284
     * @return string
1285
     */
1286
    protected function extractExceptionMessage(\Exception $exception)
1287
    {
1288
        return PHP_EOL .
1289
            sprintf('Possibly related to %s: "%s" ', get_class($exception), $exception->getMessage()) .
1290
            PHP_EOL .
1291
            $exception->getTraceAsString();
1292
    }
1293
}
1294