now = new DateTimeImmutable( '2026-04-29T12:00:00', new DateTimeZone('UTC') ); $this->sessionRepo = new FakeSessionRepository(); $this->clock = new FakeClock($this->now); $this->middleware = new AuthMiddleware( $this->sessionRepo, $this->clock, ); } private function makeRequest(?string $token): Request { $request = Request::create('/api/anything', 'POST'); if ($token !== null) { $request->cookies->set('auth_token', $token); } return $request; } private function nextThatRecords(?Request &$captured): Closure { return function (Request $request) use (&$captured) { $captured = $request; return new JsonResponse(['ok' => true], 200); }; } public function testMissingCookieReturnsUnauthorizedJson(): void { $captured = null; $response = $this->middleware->handle( $this->makeRequest(null), $this->nextThatRecords($captured), ); $this->assertSame(401, $response->getStatusCode()); $this->assertSame( ['error' => 'unauthenticated'], json_decode($response->getContent(), true), ); $this->assertNull($captured); } public function testUnknownTokenReturnsUnauthorized(): void { $captured = null; $response = $this->middleware->handle( $this->makeRequest('does-not-exist'), $this->nextThatRecords($captured), ); $this->assertSame(401, $response->getStatusCode()); $this->assertNull($captured); } public function testExpiredSessionReturnsUnauthorizedAndIsDeleted(): void { $user = new User( id: 7, email: new EmailAddress('user@example.com'), passwordHash: 'password', ); $this->sessionRepo->create(new CreateSessionDto( token: 'expired-token', user: $user, createdAt: $this->now->modify('-8 days'), expiresAt: $this->now->modify('-1 day'), )); $captured = null; $response = $this->middleware->handle( $this->makeRequest('expired-token'), $this->nextThatRecords($captured), ); $this->assertSame(401, $response->getStatusCode()); $this->assertNull($captured); $this->assertNull( $this->sessionRepo->findByToken('expired-token') ); } public function testValidSessionAttachesUserAndCallsNext(): void { $user = new User( id: 7, email: new EmailAddress('user@example.com'), passwordHash: 'password', ); $this->sessionRepo->create(new CreateSessionDto( token: 'valid-token', user: $user, createdAt: $this->now, expiresAt: $this->now->modify('+7 days'), )); $captured = null; $response = $this->middleware->handle( $this->makeRequest('valid-token'), $this->nextThatRecords($captured), ); $this->assertSame(200, $response->getStatusCode()); $this->assertNotNull($captured); $attachedUser = $captured->attributes->get('user'); $this->assertInstanceOf(User::class, $attachedUser); $this->assertSame(7, $attachedUser->getId()); } }