186 lines
6.1 KiB
C#
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);
|
||
|
|
}
|
||
|
|
}
|