diff --git a/backend/tests/Unit/Auth/UseCases/AuthenticateUserTest.php b/backend/tests/Unit/Auth/UseCases/AuthenticateUserTest.php new file mode 100644 index 0000000..6d00862 --- /dev/null +++ b/backend/tests/Unit/Auth/UseCases/AuthenticateUserTest.php @@ -0,0 +1,156 @@ +userRepo = new FakeUserRepository; + $this->hasher = new FakePasswordHasher; + $this->useCase = new AuthenticateUser( + $this->userRepo, + $this->hasher, + ); + } + + private function seedUser( + string $email, + string $password, + bool $isAdmin, + ): User { + return $this->userRepo->create(new CreateUserDto( + email: new EmailAddress($email), + passwordHash: $this->hasher->hash($password), + isAdmin: $isAdmin, + )); + } + + 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', + 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', + 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', + password: 'adminpassword', + isAdmin: true, + ); + + $authenticated = $this->useCase->execute( + new AuthenticateUserRequest( + email: 'admin@example.com', + password: 'adminpassword', + ) + ); + + $this->assertTrue($authenticated->isAdmin()); + } +}