userRepo = new FakeUserRepository; $this->hasher = new FakePasswordHasher; $this->useCase = new AuthenticateUser( $this->userRepo, $this->hasher, ); } private function seedUser( string $email, string $displayName, string $password, bool $isAdmin, ): User { return $this->userRepo->create(new CreateUserDto( email: new EmailAddress($email), displayName: $displayName, passwordHash: $this->hasher->hash($password), isAdmin: $isAdmin, emailConfirmedAt: null, )); } public function test_null_email_throws_bad_request(): void { $this->expectException(BadRequestException::class); $this->useCase->execute(new AuthenticateUserRequest( email: null, password: 'correctpassword', )); } public function test_empty_email_throws_bad_request(): void { $this->expectException(BadRequestException::class); $this->useCase->execute(new AuthenticateUserRequest( email: '', password: 'correctpassword', )); } public function test_null_password_throws_bad_request(): void { $this->expectException(BadRequestException::class); $this->useCase->execute(new AuthenticateUserRequest( email: 'user@example.com', password: null, )); } public function test_empty_password_throws_bad_request(): void { $this->expectException(BadRequestException::class); $this->useCase->execute(new AuthenticateUserRequest( email: 'user@example.com', password: '', )); } public function test_malformed_email_throws_bad_request(): void { $this->expectException(BadRequestException::class); $this->useCase->execute(new AuthenticateUserRequest( email: 'not-an-email', password: 'correctpassword', )); } public function test_unknown_email_throws_unauthorized(): void { $this->expectException(UnauthorizedException::class); $this->useCase->execute(new AuthenticateUserRequest( email: 'nobody@example.com', password: 'correctpassword', )); } public function test_wrong_password_throws_unauthorized(): void { $this->seedUser( email: 'user@example.com', displayName: 'user', password: 'correctpassword', isAdmin: false, ); $this->expectException(UnauthorizedException::class); $this->useCase->execute(new AuthenticateUserRequest( email: 'user@example.com', password: 'wrongpassword', )); } public function test_valid_credentials_return_user(): void { $seeded = $this->seedUser( email: 'user@example.com', displayName: 'user', password: 'correctpassword', isAdmin: false, ); $authenticated = $this->useCase->execute( new AuthenticateUserRequest( email: 'user@example.com', password: 'correctpassword', ) ); $this->assertInstanceOf(User::class, $authenticated); $this->assertSame($seeded->getId(), $authenticated->getId()); $this->assertSame( 'user@example.com', $authenticated->getEmail()->value(), ); $this->assertFalse($authenticated->isAdmin()); } public function test_admin_flag_is_preserved_on_authentication(): void { $this->seedUser( email: 'admin@example.com', displayName: 'admin', password: 'adminpassword', isAdmin: true, ); $authenticated = $this->useCase->execute( new AuthenticateUserRequest( email: 'admin@example.com', password: 'adminpassword', ) ); $this->assertTrue($authenticated->isAdmin()); } }