academia/tests/Application.Tests/Auth/ResetPasswordCommandTests.cs

186 lines
6.1 KiB
C#

namespace Application.Tests.Auth;
using Application.Auth;
using Application.Auth.Commands;
using Domain.Entities;
using Domain.Ports.Repositories;
using FluentAssertions;
using NSubstitute;
using Xunit;
public class ResetPasswordCommandTests
{
private readonly IUserRepository _userRepository;
private readonly IPasswordService _passwordService;
private readonly IUnitOfWork _unitOfWork;
private readonly ResetPasswordCommandHandler _handler;
public ResetPasswordCommandTests()
{
_userRepository = Substitute.For<IUserRepository>();
_passwordService = Substitute.For<IPasswordService>();
_unitOfWork = Substitute.For<IUnitOfWork>();
_passwordService.HashPassword(Arg.Any<string>()).Returns("new_hashed_password");
_handler = new ResetPasswordCommandHandler(
_userRepository,
_passwordService,
_unitOfWork
);
}
[Fact]
public async Task Handle_WithValidRecoveryCode_ShouldResetPassword()
{
// Arrange
var user = CreateUser("testuser", "old_password_hash", "recovery_code_hash");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("VALIDCODE123", "recovery_code_hash")
.Returns(true);
var command = new ResetPasswordCommand("testuser", "VALIDCODE123", "newpassword123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeTrue();
result.Error.Should().BeNull();
}
[Fact]
public async Task Handle_WithInvalidRecoveryCode_ShouldReturnError()
{
// Arrange
var user = CreateUser("testuser", "old_password_hash", "recovery_code_hash");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("INVALIDCODE", "recovery_code_hash")
.Returns(false);
var command = new ResetPasswordCommand("testuser", "INVALIDCODE", "newpassword123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Error.Should().Contain("invalido");
}
[Fact]
public async Task Handle_WithNonExistentUser_ShouldReturnError()
{
// Arrange
_userRepository.GetByUsernameAsync("nonexistent", Arg.Any<CancellationToken>())
.Returns((User?)null);
var command = new ResetPasswordCommand("nonexistent", "ANYCODE123", "newpassword123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Error.Should().Contain("no encontrado");
}
[Fact]
public async Task Handle_WithShortNewPassword_ShouldReturnError()
{
// Arrange
var user = CreateUser("testuser", "old_password_hash", "recovery_code_hash");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
var command = new ResetPasswordCommand("testuser", "VALIDCODE123", "12345"); // 5 chars
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Error.Should().Contain("al menos 6 caracteres");
}
[Fact]
public async Task Handle_ShouldHashNewPassword()
{
// Arrange
var user = CreateUser("testuser", "old_password_hash", "recovery_code_hash");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("VALIDCODE123", "recovery_code_hash")
.Returns(true);
var command = new ResetPasswordCommand("testuser", "VALIDCODE123", "newpassword123");
// Act
await _handler.Handle(command, CancellationToken.None);
// Assert
_passwordService.Received(1).HashPassword("newpassword123");
}
[Fact]
public async Task Handle_ShouldSaveChangesOnSuccess()
{
// Arrange
var user = CreateUser("testuser", "old_password_hash", "recovery_code_hash");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("VALIDCODE123", "recovery_code_hash")
.Returns(true);
var command = new ResetPasswordCommand("testuser", "VALIDCODE123", "newpassword123");
// Act
await _handler.Handle(command, CancellationToken.None);
// Assert
await _unitOfWork.Received(1).SaveChangesAsync(Arg.Any<CancellationToken>());
}
[Fact]
public async Task Handle_ShouldNotSaveChangesOnError()
{
// Arrange
_userRepository.GetByUsernameAsync("nonexistent", Arg.Any<CancellationToken>())
.Returns((User?)null);
var command = new ResetPasswordCommand("nonexistent", "ANYCODE123", "newpassword123");
// Act
await _handler.Handle(command, CancellationToken.None);
// Assert
await _unitOfWork.DidNotReceive().SaveChangesAsync(Arg.Any<CancellationToken>());
}
[Fact]
public async Task Handle_ShouldUpdateUserPasswordHash()
{
// Arrange
var user = CreateUser("testuser", "old_password_hash", "recovery_code_hash");
_userRepository.GetByUsernameAsync("testuser", Arg.Any<CancellationToken>())
.Returns(user);
_passwordService.VerifyPassword("VALIDCODE123", "recovery_code_hash")
.Returns(true);
var command = new ResetPasswordCommand("testuser", "VALIDCODE123", "newpassword123");
// Act
await _handler.Handle(command, CancellationToken.None);
// Assert
user.PasswordHash.Should().Be("new_hashed_password");
}
private static User CreateUser(string username, string passwordHash, string recoveryCodeHash)
{
return User.Create(username, passwordHash, recoveryCodeHash, UserRoles.Student);
}
}