now = new DateTimeImmutable( '2026-07-31T12:00:00', new DateTimeZone('UTC'), ); $this->sessionRepository = new FakeSessionRepository; $this->middleware = new AuthMiddleware( sessionRepository: $this->sessionRepository, clock: new FakeClock($this->now), ); } public function test_missing_cookie_returns_unauthenticated(): void { $capturedRequest = null; $response = $this->middleware->handle( $this->requestWithToken(null), $this->captureNextRequest($capturedRequest), ); $this->assertSame(401, $response->getStatusCode()); $this->assertSame( ['error' => 'unauthenticated'], json_decode($response->getContent(), true), ); $this->assertNull($capturedRequest); } public function test_empty_cookie_returns_unauthenticated(): void { $capturedRequest = null; $response = $this->middleware->handle( $this->requestWithToken(''), $this->captureNextRequest($capturedRequest), ); $this->assertSame(401, $response->getStatusCode()); $this->assertNull($capturedRequest); } public function test_unknown_token_returns_unauthenticated(): void { $capturedRequest = null; $response = $this->middleware->handle( $this->requestWithToken('unknown-token'), $this->captureNextRequest($capturedRequest), ); $this->assertSame(401, $response->getStatusCode()); $this->assertNull($capturedRequest); } public function test_expired_session_is_deleted(): void { $this->sessionRepository->create(new CreateSessionDto( token: 'expired-token', user: $this->user(), createdAt: $this->now->modify('-8 days'), expiresAt: $this->now->modify('-1 day'), )); $capturedRequest = null; $response = $this->middleware->handle( $this->requestWithToken('expired-token'), $this->captureNextRequest($capturedRequest), ); $this->assertSame(401, $response->getStatusCode()); $this->assertNull($capturedRequest); $this->assertNull( $this->sessionRepository->findByToken('expired-token'), ); } public function test_valid_session_attaches_user_and_calls_next(): void { $user = $this->user(); $this->sessionRepository->create(new CreateSessionDto( token: 'valid-token', user: $user, createdAt: $this->now, expiresAt: $this->now->modify('+7 days'), )); $capturedRequest = null; $response = $this->middleware->handle( $this->requestWithToken('valid-token'), $this->captureNextRequest($capturedRequest), ); $this->assertSame(200, $response->getStatusCode()); $this->assertNotNull($capturedRequest); $this->assertSame( $user, $capturedRequest->attributes->get('user'), ); } private function requestWithToken(?string $token): Request { $request = Request::create('/anything', 'GET'); if ($token !== null) { $request->cookies->set(AuthMiddleware::COOKIE_NAME, $token); } return $request; } /** * @param Request|null $capturedRequest * @return Closure(Request): JsonResponse */ private function captureNextRequest( ?Request &$capturedRequest, ): Closure { return function (Request $request) use (&$capturedRequest) { $capturedRequest = $request; return new JsonResponse(['ok' => true]); }; } private function user(): User { return new User( id: 7, email: new EmailAddress('user@example.com'), passwordHash: 'hashed-password', ); } }