Completed
Branch feature/phpstanLevel3 (de378e)
by Schlaefer
02:30
created

IntegrationTestCase::_unsetUserAgent()   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 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types = 1);
4
5
/**
6
 * Saito - The Threaded Web Forum
7
 *
8
 * @copyright Copyright (c) the Saito Project Developers 2012-2018
9
 * @link https://github.com/Schlaefer/Saito
10
 * @license http://opensource.org/licenses/MIT
11
 */
12
13
namespace Saito\Test;
14
15
use App\Test\Fixture\UserFixture;
16
17
use Cake\Core\Configure;
18
use Cake\Event\Event;
19
use Cake\Event\EventManager;
20
use Cake\ORM\TableRegistry;
21
use Cake\Routing\Router;
22
use Cake\TestSuite\IntegrationTestTrait;
23
use Cake\TestSuite\TestCase;
24
25
/**
26
 * Setup/teardown, helper and assumptions for Saito integration tests
27
 */
28
abstract class IntegrationTestCase extends TestCase
29
{
30
    use AssertTrait;
31
    use IntegrationTestTrait {
32
        _sendRequest as _sendRequestParent;
33
    }
34
    use SecurityMockTrait;
35
    use TestCaseTrait {
36
        getMockForTable as getMockForTableParent;
37
    }
38
39
    /**
40
     * @var array cache environment variables
41
     */
42
    protected $_env = [];
43
44
    /**
45
     * {@inheritDoc}
46
     */
47
    public function setUp()
48
    {
49
        parent::setUp();
50
        $this->disableErrorHandlerMiddleware();
51
        $this->setUpSaito();
52
        $this->_clearCaches();
53
        $this->markUpdated();
54
    }
55
56
    /**
57
     * {@inheritDoc}
58
     */
59
    public function tearDown()
60
    {
61
        $this->tearDownSaito();
62
        $this->_unsetAjax();
63
        $this->_unsetJson();
64
        $this->_unsetUserAgent();
65
        parent::tearDown();
66
        $this->_clearCaches();
67
    }
68
69
    /**
70
     * set request ajax
71
     *
72
     * @return void
73
     */
74
    protected function _setAjax()
75
    {
76
        $this->disableCsrf();
77
        $_ENV['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
78
    }
79
80
    /**
81
     * unset request ajax
82
     *
83
     * @return void
84
     */
85
    protected function _unsetAjax()
86
    {
87
        unset($_ENV['HTTP_X_REQUESTED_WITH']);
88
    }
89
90
    /**
91
     * set request json
92
     *
93
     * @return void
94
     */
95
    protected function _setJson()
96
    {
97
        $this->configRequest([
98
            'headers' => ['Accept' => 'application/json']
99
        ]);
100
    }
101
102
    /**
103
     * unset request json
104
     *
105
     * @return void
106
     */
107
    protected function _unsetJson()
108
    {
109
        $this->configRequest([
110
            'headers' => ['Accept' => 'text/html,application/xhtml+xml,application/xml']
111
        ]);
112
    }
113
114
    /**
115
     * Set user agent
116
     *
117
     * @param string $agent agent
118
     * @return void
119
     */
120
    protected function _setUserAgent($agent)
121
    {
122
        if (isset($this->_env['HTTP_USER_AGENT'])) {
123
            $this->_env['HTTP_USER_AGENT'] = $_ENV['HTTP_USER_AGENT'];
124
        }
125
        $_ENV['HTTP_USER_AGENT'] = $agent;
126
    }
127
128
    /**
129
     * Resets user agent
130
     *
131
     * @return void
132
     */
133
    protected function _unsetUserAgent()
134
    {
135
        unset($_ENV['HTTP_USER_AGENT']);
136
    }
137
138
    /**
139
     * Mocks a table with methods
140
     *
141
     * @param string $table table-name
142
     * @param array $methods methods to mock
143
     * @return mixed
144
     */
145
    public function getMockForTable($table, array $methods = [])
146
    {
147
        $Mock = $this->getMockForTableParent($table, $methods);
148
        EventManager::instance()->on(
149
            'Controller.initialize',
150
            function (Event $event) use ($table, $Mock) {
0 ignored issues
show
Documentation introduced by
function (\Cake\Event\Ev...er->{$table} = $Mock; } 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...
151
                $Controller = $event->getSubject();
152
                $Controller->{$table} = $Mock;
153
            }
154
        );
155
156
        return $Mock;
157
    }
158
159
    /**
160
     * Configure next request as user authenticated with JWT-Token
161
     *
162
     * @param int $userId user
163
     * @return void
164
     */
165
    protected function loginJwt(int $userId)
166
    {
167
        $jwtKey = Configure::read('Security.cookieSalt');
168
        $jwtPayload = ['sub' => $userId];
169
        $jwtToken = \Firebase\JWT\JWT::encode($jwtPayload, $jwtKey);
170
171
        $this->configRequest([
172
            'headers' => [
173
                'Accept' => 'application/json',
174
                'Authorization' => 'bearer ' . $jwtToken,
175
            ]
176
        ]);
177
    }
178
179
    /**
180
     * Login user
181
     *
182
     * @param int $id user-ID
183
     * @return mixed
184
     */
185
    protected function _loginUser($id)
186
    {
187
        // see: http://stackoverflow.com/a/10411128/1372085
188
        $this->_logoutUser();
189
        $userFixture = new UserFixture();
190
        $users = $userFixture->records;
191
        $user = $users[$id - 1];
192
        $this->session(['Auth.User' => $user]);
193
194
        return $user;
195
    }
196
197
    /**
198
     * Logout user
199
     *
200
     * @return void
201
     */
202
    protected function _logoutUser()
203
    {
204
        // if user is logged-in it should interfere with test runs
205
        if (isset($_COOKIE['Saito-AU'])) :
206
            unset($_COOKIE['Saito-AU']);
207
        endif;
208
        if (isset($_COOKIE['Saito'])) :
209
            unset($_COOKIE['Saito']);
210
        endif;
211
        unset($this->_session['Auth.User']);
212
    }
213
214
    /**
215
     * {@inheritdoc}
216
     */
217
    protected function _sendRequest($url, $method, $data = [])
218
    {
219
        // Workaround for Cake 3.6 Router on test bug with named routes in plugins
220
        // "A route named "<foo>" has already been connected to "<bar>".
221
        Router::reload();
222
        $this->_sendRequestParent($url, $method, $data);
223
    }
224
225
    /**
226
     * Skip test on particular datasource
227
     *
228
     * @param string $datasource MySQL|Postgres
229
     * @return void
230
     */
231
    protected function skipOnDataSource(string $datasource): void
232
    {
233
        $datasource = strtolower($datasource);
234
235
        $driver = TableRegistry::get('Entries')->getConnection()->getDriver();
0 ignored issues
show
Deprecated Code introduced by
The method Cake\ORM\TableRegistry::get() has been deprecated with message: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
236
        $class = strtolower(get_class($driver));
237
238
        if (strpos($class, $datasource)) {
239
            $this->markTestSkipped("Skipped on datasource '$datasource'");
240
        }
241
    }
242
243
    /**
244
     * Marks the Saito installation installed and updated (don't run installer or updater)
245
     *
246
     * @return void
247
     */
248
    private function markUpdated()
249
    {
250
        Configure::write('Saito.installed', true);
251
        Configure::write('Saito.updated', true);
252
    }
253
254
    /**
255
     * Check if only specific roles is allowed on action
256
     *
257
     * @param string $route URL
258
     * @param string $role role
259
     * @param true|string|null $referer true: same as $url, null: none, string: URL
260
     * @param string $method HTTP-method
261
     * @return void
262
     */
263
    public function assertRouteForRole($route, $role, $referer = true, $method = 'GET')
264
    {
265
        if ($referer === true) {
266
            $referer = $route;
267
        }
268
        $method = strtolower($method);
269
        $types = ['admin' => 3, 'mod' => 2, 'user' => 1, 'anon' => 0];
270
271
        foreach ($types as $title => $type) {
272
            switch ($title) {
273
                case 'anon':
274
                    break;
275
                case 'user':
276
                    $this->_loginUser(3);
277
                    break;
278
                case 'mod':
279
                    $this->_loginUser(2);
280
                    break;
281
                case 'admin':
282
                    $this->_loginUser(1);
283
                    break;
284
            }
285
286
            if ($type < $types[$role]) {
287
                $this->{$method}($route);
288
                $method = strtoupper($method);
289
                $this->assertRedirectLogin($referer, "No login redirect for $role on $method $route");
290
            } else {
291
                $this->{$method}($route);
292
                $method = strtoupper($method);
293
                $this->assertNoRedirect("Redirect wasn't expected for user-role '$role' on $method $route");
294
            }
295
        }
296
    }
297
298
    /**
299
     * Check that an redirect to the login is performed
300
     *
301
     * @param string $redirectUrl redirect URL '/where/I/come/from'
302
     * @param string $msg Message
303
     * @return void
304
     */
305
    public function assertRedirectLogin($redirectUrl = null, string $msg = '')
306
    {
307
        /** @var Response $response */
308
        $response = $this->_controller->response;
309
        $expected = Router::url([
310
            '_name' => 'login',
311
            'plugin' => false,
312
            '?' => ['redirect' => $redirectUrl]
313
        ], true);
314
        $redirectHeader = $response->getHeader('Location')[0];
315
        $this->assertEquals($expected, $redirectHeader, $msg);
316
    }
317
318
    /**
319
     * assert contains tags
320
     *
321
     * @param array $expected expected
322
     * @return void
323
     */
324
    public function assertResponseContainsTags($expected)
325
    {
326
        $this->assertContainsTag(
327
            $expected,
328
            (string)$this->_controller->response->getBody()
329
        );
330
    }
331
}
332