Completed
Pull Request — master (#1)
by Marco
06:26
created

testWillSendExpirationCookieWhenSessionContentsAreCleared()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 10
nc 1
nop 1
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license.
17
 */
18
19
declare(strict_types=1);
20
21
namespace PSR7SessionTest\Storageless\Http;
22
23
use DateTimeImmutable;
24
use Dflydev\FigCookies\FigResponseCookies;
25
use Dflydev\FigCookies\SetCookie;
26
use Lcobucci\JWT\Builder;
27
use Lcobucci\JWT\Parser;
28
use Lcobucci\JWT\Signer;
29
use Lcobucci\JWT\Signer\Hmac\Sha256;
30
use Lcobucci\JWT\Token;
31
use PHPUnit_Framework_TestCase;
32
use Psr\Http\Message\ResponseInterface;
33
use Psr\Http\Message\ServerRequestInterface;
34
use PSR7Session\Storageless\Http\SessionMiddleware;
35
use PSR7Session\Storageless\Session\DefaultSessionData;
36
use PSR7Session\Storageless\Session\SessionInterface;
37
use PSR7Session\Storageless\Time\SystemCurrentTime;
38
use PSR7SessionTest\Storageless\Time\FakeCurrentTime;
39
use Zend\Diactoros\Response;
40
use Zend\Diactoros\ServerRequest;
41
use Zend\Stratigility\MiddlewareInterface;
42
43
final class SessionMiddlewareTest extends PHPUnit_Framework_TestCase
44
{
45
    /**
46
     * @dataProvider validMiddlewaresProvider
47
     */
48
    public function testSkipsInjectingSessionCookieOnEmptyContainer(SessionMiddleware $middleware)
49
    {
50
        $response = $this->ensureSameResponse($middleware, new ServerRequest(), $this->emptyValidationMiddleware());
51
52
        self::assertNull($this->getCookie($response)->getValue());
53
    }
54
55
    /**
56
     * @dataProvider validMiddlewaresProvider
57
     */
58
    public function testExtractsSessionContainerFromEmptyRequest(SessionMiddleware $middleware)
59
    {
60
        $this->ensureSameResponse($middleware, new ServerRequest(), $this->emptyValidationMiddleware());
61
    }
62
63
    /**
64
     * @dataProvider validMiddlewaresProvider
65
     */
66
    public function testInjectsSessionInResponseCookies(SessionMiddleware $middleware)
67
    {
68
        $initialResponse = new Response();
69
        $response = $middleware(new ServerRequest(), $initialResponse, $this->writingMiddleware());
70
71
        self::assertNotSame($initialResponse, $response);
72
        self::assertEmpty($this->getCookie($response, 'non-existing')->getValue());
73
        self::assertInstanceOf(Token::class, (new Parser())->parse($this->getCookie($response)->getValue()));
74
    }
75
76
    /**
77
     * @dataProvider validMiddlewaresProvider
78
     */
79
    public function testSessionContainerCanBeReusedOverMultipleRequests(SessionMiddleware $middleware)
80
    {
81
        $sessionValue = uniqid('', true);
82
83
        $checkingMiddleware = $this->fakeMiddleware(
84
            function (ServerRequestInterface $request, ResponseInterface $response) use ($sessionValue) {
85
                /* @var $session SessionInterface */
86
                $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
87
88
                self::assertSame($sessionValue, $session->get('foo'));
89
                self::assertFalse($session->hasChanged());
90
91
                $session->set('foo', $sessionValue . 'changed');
92
93
                self::assertTrue(
94
                    $session->hasChanged(),
95
                    'ensuring that the cookie is sent again: '
96
                    . 'non-modified session containers are not to be re-serialized into a token'
97
                );
98
99
                return $response;
100
            }
101
        );
102
103
        $firstResponse = $middleware(new ServerRequest(), new Response(), $this->writingMiddleware($sessionValue));
104
105
        $initialResponse = new Response();
106
107
        $response = $middleware(
108
            $this->requestWithResponseCookies($firstResponse),
109
            $initialResponse,
110
            $checkingMiddleware
111
        );
112
113
        self::assertNotSame($initialResponse, $response);
114
    }
115
116
    /**
117
     * @dataProvider validMiddlewaresProvider
118
     */
119
    public function testWillIgnoreRequestsWithExpiredTokens(SessionMiddleware $middleware)
120
    {
121
        $expiredToken = (new ServerRequest())
122
            ->withCookieParams([
123
                SessionMiddleware::DEFAULT_COOKIE => $this->createToken(
124
                    $middleware,
125
                    new \DateTime('-1 day'),
126
                    new \DateTime('-2 day')
127
                )
128
            ]);
129
130
        $this->ensureSameResponse($middleware, $expiredToken, $this->emptyValidationMiddleware());
131
    }
132
133
    /**
134
     * @dataProvider validMiddlewaresProvider
135
     */
136
    public function testWillIgnoreRequestsWithTokensFromFuture(SessionMiddleware $middleware)
137
    {
138
        $tokenInFuture = (new ServerRequest())
139
            ->withCookieParams([
140
                SessionMiddleware::DEFAULT_COOKIE => $this->createToken(
141
                    $middleware,
142
                    new \DateTime('+1 day'),
143
                    new \DateTime('-2 day')
144
                )
145
            ]);
146
147
        $this->ensureSameResponse($middleware, $tokenInFuture, $this->emptyValidationMiddleware());
148
    }
149
150
    /**
151
     * @dataProvider validMiddlewaresProvider
152
     */
153
    public function testWillIgnoreUnSignedTokens(SessionMiddleware $middleware)
154
    {
155
        $unsignedToken = (new ServerRequest())
156
            ->withCookieParams([
157
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
158
                    ->setIssuedAt((new \DateTime('-1 day'))->getTimestamp())
159
                    ->setExpiration((new \DateTime('+1 day'))->getTimestamp())
160
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
161
                    ->getToken()
162
            ]);
163
164
        $this->ensureSameResponse($middleware, $unsignedToken, $this->emptyValidationMiddleware());
165
    }
166
167
    /**
168
     * @dataProvider validMiddlewaresProvider
169
     */
170
    public function testWillNotRefreshSignedTokensWithoutIssuedAt(SessionMiddleware $middleware)
171
    {
172
        $unsignedToken = (new ServerRequest())
173
            ->withCookieParams([
174
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
175
                    ->setExpiration((new \DateTime('+1 day'))->getTimestamp())
176
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::newEmptySession())
177
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
178
                    ->getToken()
179
            ]);
180
181
        $this->ensureSameResponse($middleware, $unsignedToken, $this->emptyValidationMiddleware());
182
    }
183
184
    /**
185
     * @dataProvider validMiddlewaresProvider
186
     */
187
    public function testWillSkipInjectingSessionCookiesWhenSessionIsNotChanged(SessionMiddleware $middleware)
188
    {
189
        $this->ensureSameResponse(
190
            $middleware,
191
            $this->requestWithResponseCookies(
192
                $middleware(new ServerRequest(), new Response(), $this->writingMiddleware())
193
            ),
194
            $this->fakeMiddleware(
195
                function (ServerRequestInterface $request, ResponseInterface $response) {
196
                    /* @var $session SessionInterface */
197
                    $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
198
199
                    // note: we set the same data just to make sure that we are indeed interacting with the session
200
                    $session->set('foo', 'bar');
201
202
                    self::assertFalse($session->hasChanged());
203
204
                    return $response;
205
                }
206
            )
207
        );
208
    }
209
210
    /**
211
     * @dataProvider validMiddlewaresProvider
212
     */
213
    public function testWillSendExpirationCookieWhenSessionContentsAreCleared(SessionMiddleware $middleware)
214
    {
215
        $this->ensureClearsSessionCookie(
216
            $middleware,
217
            $this->requestWithResponseCookies(
218
                $middleware(new ServerRequest(), new Response(), $this->writingMiddleware())
219
            ),
220
            $this->fakeMiddleware(
221
                function (ServerRequestInterface $request, ResponseInterface $response) {
222
                    /* @var $session SessionInterface */
223
                    $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
224
225
                    $session->clear();
226
227
                    return $response;
228
                }
229
            )
230
        );
231
    }
232
233
    /**
234
     * @dataProvider validMiddlewaresProvider
235
     */
236
    public function testWillIgnoreMalformedTokens(SessionMiddleware $middleware)
237
    {
238
        $this->ensureSameResponse(
239
            $middleware,
240
            (new ServerRequest())->withCookieParams([SessionMiddleware::DEFAULT_COOKIE => 'malformed content']),
241
            $this->emptyValidationMiddleware()
242
        );
243
    }
244
245
    public function testRejectsTokensWithInvalidSignature()
246
    {
247
        $middleware = new SessionMiddleware(
248
            new Sha256(),
249
            'foo',
250
            'bar', // wrong symmetric key (on purpose)
251
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
252
            new Parser(),
253
            100,
254
            new SystemCurrentTime()
255
        );
256
257
        $this->ensureSameResponse(
258
            $middleware,
259
            $this->requestWithResponseCookies(
260
                $middleware(new ServerRequest(), new Response(), $this->writingMiddleware())
261
            ),
262
            $this->emptyValidationMiddleware()
263
        );
264
    }
265
266
    public function testAllowsModifyingCookieDetails()
267
    {
268
        $defaultCookie = SetCookie::create('a-different-cookie-name')
269
            ->withDomain('foo.bar')
270
            ->withPath('/yadda')
271
            ->withHttpOnly(false)
272
            ->withMaxAge('123123')
273
            ->withValue('a-random-value');
274
275
        $dateTime   = new DateTimeImmutable();
276
        $middleware = new SessionMiddleware(
277
            new Sha256(),
278
            'foo',
279
            'foo',
280
            $defaultCookie,
281
            new Parser(),
282
            123456,
283
            new FakeCurrentTime($dateTime),
284
            123
285
        );
286
287
        $initialResponse = new Response();
288
        $response = $middleware(new ServerRequest(), $initialResponse, $this->writingMiddleware());
289
290
        self::assertNotSame($initialResponse, $response);
291
        self::assertNull($this->getCookie($response)->getValue());
292
293
        $tokenCookie = $this->getCookie($response, 'a-different-cookie-name');
294
295
        self::assertNotEmpty($tokenCookie->getValue());
296
        self::assertNotSame($defaultCookie->getValue(), $tokenCookie->getValue());
297
        self::assertSame($defaultCookie->getDomain(), $tokenCookie->getDomain());
298
        self::assertSame($defaultCookie->getPath(), $tokenCookie->getPath());
299
        self::assertSame($defaultCookie->getHttpOnly(), $tokenCookie->getHttpOnly());
300
        self::assertSame($defaultCookie->getMaxAge(), $tokenCookie->getMaxAge());
301
        self::assertEquals($dateTime->getTimestamp() + 123456, $tokenCookie->getExpires());
302
    }
303
304
    public function testSessionTokenParsingIsDelayedWhenSessionIsNotBeingUsed()
305
    {
306
        /* @var $signer Signer|\PHPUnit_Framework_MockObject_MockObject */
307
        $signer = $this->createMock(Signer::class);
308
309
        $signer->expects($this->never())->method('verify');
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in Lcobucci\JWT\Signer.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
310
311
        $currentTimeProvider = new SystemCurrentTime();
312
        $setCookie  = SetCookie::create(SessionMiddleware::DEFAULT_COOKIE);
313
        $middleware = new SessionMiddleware($signer, 'foo', 'foo', $setCookie, new Parser(), 100, $currentTimeProvider);
0 ignored issues
show
Bug introduced by
It seems like $signer defined by $this->createMock(\Lcobucci\JWT\Signer::class) on line 307 can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, PSR7Session\Storageless\...ddleware::__construct() does only seem to accept object<Lcobucci\JWT\Signer>, 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...
314
        $request    = (new ServerRequest())
315
            ->withCookieParams([
316
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
317
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
318
                    ->getToken()
319
            ]);
320
321
        $middleware(
322
            $request,
323
            new Response(),
324
            $this->fakeMiddleware(function (ServerRequestInterface $request, ResponseInterface $response) {
325
                self::assertInstanceOf(
326
                    SessionInterface::class,
327
                    $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE)
328
                );
329
330
                return $response;
331
            })
332
        );
333
    }
334
335
    public function testShouldRegenerateTokenWhenRequestHasATokenThatIsAboutToExpire()
336
    {
337
        $dateTime   = new DateTimeImmutable();
338
        $middleware = new SessionMiddleware(
339
            new Sha256(),
340
            'foo',
341
            'foo',
342
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
343
            new Parser(),
344
            1000,
345
            new FakeCurrentTime($dateTime),
346
            300
347
        );
348
349
        $expiringToken = (new ServerRequest())
350
            ->withCookieParams([
351
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
352
                    ->setIssuedAt((new \DateTime('-800 second'))->getTimestamp())
353
                    ->setExpiration((new \DateTime('+200 second'))->getTimestamp())
354
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
355
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
356
                    ->getToken()
357
            ]);
358
359
        $initialResponse = new Response();
360
        $response = $middleware($expiringToken, $initialResponse);
361
362
        self::assertNotSame($initialResponse, $response);
363
364
        $tokenCookie = $this->getCookie($response);
365
366
        self::assertNotEmpty($tokenCookie->getValue());
367
        self::assertEquals($dateTime->getTimestamp() + 1000, $tokenCookie->getExpires());
368
    }
369
370
    public function testShouldNotRegenerateTokenWhenRequestHasATokenThatIsFarFromExpiration()
371
    {
372
        $middleware = new SessionMiddleware(
373
            new Sha256(),
374
            'foo',
375
            'foo',
376
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
377
            new Parser(),
378
            1000,
379
            new SystemCurrentTime(),
380
            300
381
        );
382
383
        $validToken = (new ServerRequest())
384
            ->withCookieParams([
385
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
386
                    ->setIssuedAt((new \DateTime('-100 second'))->getTimestamp())
387
                    ->setExpiration((new \DateTime('+900 second'))->getTimestamp())
388
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
389
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
390
                    ->getToken()
391
            ]);
392
393
        $this->ensureSameResponse($middleware, $validToken);
394
    }
395
396
    /**
397
     * @return SessionMiddleware[][]
398
     */
399
    public function validMiddlewaresProvider()
400
    {
401
        return [
402
            [new SessionMiddleware(
403
                new Sha256(),
404
                'foo',
405
                'foo',
406
                SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
407
                new Parser(),
408
                100,
409
                new SystemCurrentTime()
410
            )],
411
            [SessionMiddleware::fromSymmetricKeyDefaults('not relevant', 100)],
412
            [SessionMiddleware::fromAsymmetricKeyDefaults(
413
                file_get_contents(__DIR__ . '/../../keys/private_key.pem'),
414
                file_get_contents(__DIR__ . '/../../keys/public_key.pem'),
415
                200
416
            )],
417
        ];
418
    }
419
420
    /**
421
     * @group #46
422
     */
423
    public function testFromSymmetricKeyDefaultsWillHaveADefaultSessionPath()
424
    {
425
        self::assertSame(
426
            '/',
427
            $this
428
                ->getCookie(
429
                    SessionMiddleware::fromSymmetricKeyDefaults('not relevant', 100)
0 ignored issues
show
Bug introduced by
It seems like \PSR7Session\Storageless...s->writingMiddleware()) can be null; however, getCookie() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
430
                        ->__invoke(new ServerRequest(), new Response(), $this->writingMiddleware())
431
                )
432
                ->getPath()
433
        );
434
    }
435
436
    /**
437
     * @group #46
438
     *
439
     * @throws \InvalidArgumentException
440
     * @throws \OutOfBoundsException
441
     */
442
    public function testFromAsymmetricKeyDefaultsWillHaveADefaultSessionPath()
443
    {
444
        self::assertSame(
445
            '/',
446
            $this
447
                ->getCookie(
448
                    SessionMiddleware
0 ignored issues
show
Bug introduced by
It seems like \PSR7Session\Storageless...s->writingMiddleware()) can be null; however, getCookie() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
449
                        ::fromAsymmetricKeyDefaults(
450
                            file_get_contents(__DIR__ . '/../../keys/private_key.pem'),
451
                            file_get_contents(__DIR__ . '/../../keys/public_key.pem'),
452
                            200
453
                        )
454
                        ->__invoke(new ServerRequest(), new Response(), $this->writingMiddleware())
455
                )
456
                ->getPath()
457
        );
458
    }
459
460
    /**
461
     * @param SessionMiddleware $middleware
462
     * @param ServerRequestInterface $request
463
     * @param callable $next
464
     *
465
     * @return ResponseInterface
466
     */
467
    private function ensureSameResponse(
468
        SessionMiddleware $middleware,
469
        ServerRequestInterface $request,
470
        callable $next = null
471
    ): ResponseInterface {
472
        $initialResponse = new Response();
473
        $response = $middleware($request, $initialResponse, $next);
474
475
        self::assertSame($initialResponse, $response);
476
477
        return $response;
478
    }
479
480
    /**
481
     * @param SessionMiddleware $middleware
482
     * @param ServerRequestInterface $request
483
     * @param callable $next
484
     *
485
     * @return ResponseInterface
486
     */
487
    private function ensureClearsSessionCookie(
488
        SessionMiddleware $middleware,
489
        ServerRequestInterface $request,
490
        callable $next = null
491
    ): ResponseInterface {
492
        $initialResponse = new Response();
493
        $response = $middleware($request, $initialResponse, $next);
494
495
        self::assertNotSame($initialResponse, $response);
496
497
        $cookie = $this->getCookie($response);
498
499
        self::assertLessThan((new \DateTime('-29 day'))->getTimestamp(), $cookie->getExpires());
500
        self::assertEmpty($cookie->getValue());
501
502
        return $response;
503
    }
504
505
    /**
506
     * @param SessionMiddleware $middleware
507
     * @param \DateTime $issuedAt
508
     * @param \DateTime $expiration
509
     *
510
     * @return string
511
     */
512
    private function createToken(SessionMiddleware $middleware, \DateTime $issuedAt, \DateTime $expiration): string
513
    {
514
        return (string) (new Builder())
515
            ->setIssuedAt($issuedAt->getTimestamp())
516
            ->setExpiration($expiration->getTimestamp())
517
            ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
518
            ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
519
            ->getToken();
520
    }
521
522
    /**
523
     * @return MiddlewareInterface
524
     */
525
    private function emptyValidationMiddleware(): MiddlewareInterface
526
    {
527
        return $this->fakeMiddleware(
528
            function (ServerRequestInterface $request, ResponseInterface $response) {
529
                /* @var $session SessionInterface */
530
                $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
531
532
                self::assertInstanceOf(SessionInterface::class, $session);
533
                self::assertTrue($session->isEmpty());
534
535
                return $response;
536
            }
537
        );
538
    }
539
540
    /**
541
     * @param string $value
542
     *
543
     * @return MiddlewareInterface
544
     */
545
    private function writingMiddleware($value = 'bar'): MiddlewareInterface
546
    {
547
        return $this->fakeMiddleware(
548
            function (ServerRequestInterface $request, ResponseInterface $response) use ($value) {
549
                /* @var $session SessionInterface */
550
                $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
551
                $session->set('foo', $value);
552
553
                return $response;
554
            }
555
        );
556
    }
557
558
    /**
559
     * @param callable $callback
560
     *
561
     * @return MiddlewareInterface
562
     */
563
    private function fakeMiddleware(callable $callback): MiddlewareInterface
564
    {
565
        $middleware = $this->createMock(MiddlewareInterface::class);
566
567
        $middleware->expects($this->once())
568
           ->method('__invoke')
569
           ->willReturnCallback($callback)
570
           ->with(
571
               self::isInstanceOf(ServerRequestInterface::class),
572
               self::isInstanceOf(ResponseInterface::class),
573
               self::logicalOr(self::isNull(), self::isType('callable'))
574
           );
575
576
        return $middleware;
577
    }
578
579
    /**
580
     * @param ResponseInterface $response
581
     *
582
     * @return \Zend\Diactoros\ServerRequest
583
     */
584
    private function requestWithResponseCookies(ResponseInterface $response): ServerRequestInterface
585
    {
586
        return (new ServerRequest())->withCookieParams([
587
            SessionMiddleware::DEFAULT_COOKIE => $this->getCookie($response)->getValue()
588
        ]);
589
    }
590
591
    /**
592
     * @param ResponseInterface $response
593
     *
594
     * @return SetCookie
595
     */
596
    private function getCookie(ResponseInterface $response, string $name = SessionMiddleware::DEFAULT_COOKIE): SetCookie
597
    {
598
        return FigResponseCookies::get($response, $name);
599
    }
600
601
    /**
602
     * @param SessionMiddleware $middleware
603
     *
604
     * @return Signer
605
     */
606
    private function getSigner(SessionMiddleware $middleware): Signer
607
    {
608
        return $this->getPropertyValue($middleware, 'signer');
609
    }
610
611
    /**
612
     * @param SessionMiddleware $middleware
613
     *
614
     * @return string
615
     */
616
    private function getSignatureKey(SessionMiddleware $middleware): string
617
    {
618
        return $this->getPropertyValue($middleware, 'signatureKey');
619
    }
620
621
    /**
622
     * @param object $object
623
     * @param string $name
624
     *
625
     * @return mixed
626
     */
627
    private function getPropertyValue($object, string $name)
628
    {
629
        $propertyReflection = new \ReflectionProperty($object, $name);
630
        $propertyReflection->setAccessible(true);
631
632
        return $propertyReflection->getValue($object);
633
    }
634
}
635