using FluentAssertions;
using MiningService.API.Application.Commands;
using MiningService.Domain.AggregatesModel.MinerAggregate;
using MiningService.Domain.Exceptions;
using MiningService.Domain.SeedWork;
using NSubstitute;
using Xunit;
namespace MiningService.UnitTests.Application.Commands;
///
/// EN: Unit tests for StartMiningCommandHandler.
/// VI: Unit tests cho StartMiningCommandHandler.
///
public class StartMiningCommandHandlerTests
{
private readonly IMinerRepository _minerRepository;
private readonly IUnitOfWork _unitOfWork;
private readonly StartMiningCommandHandler _handler;
public StartMiningCommandHandlerTests()
{
_unitOfWork = Substitute.For();
_unitOfWork.SaveEntitiesAsync(Arg.Any()).Returns(true);
_minerRepository = Substitute.For();
_minerRepository.UnitOfWork.Returns(_unitOfWork);
_handler = new StartMiningCommandHandler(_minerRepository);
}
[Fact]
public async Task Handle_ExistingMiner_StartsSession()
{
// Arrange
var userId = Guid.NewGuid();
var miner = Miner.Create(userId);
var command = new StartMiningCommand(userId);
_minerRepository.GetByUserIdAsync(userId, Arg.Any())
.Returns(miner);
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Should().NotBeNull();
result.SessionId.Should().NotBeEmpty();
result.HourlyRate.Should().BeGreaterThan(0);
await _unitOfWork.Received(1).SaveEntitiesAsync(Arg.Any());
}
[Fact]
public async Task Handle_NewUser_CreatesMinerAndStartsSession()
{
// Arrange
var userId = Guid.NewGuid();
var command = new StartMiningCommand(userId);
_minerRepository.GetByUserIdAsync(userId, Arg.Any())
.Returns((Miner?)null);
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Should().NotBeNull();
result.SessionId.Should().NotBeEmpty();
_minerRepository.Received(1).Add(Arg.Is(m => m.UserId == userId));
}
[Fact]
public async Task Handle_SuspendedMiner_ThrowsException()
{
// Arrange
var userId = Guid.NewGuid();
var miner = Miner.Create(userId);
miner.Suspend();
var command = new StartMiningCommand(userId);
_minerRepository.GetByUserIdAsync(userId, Arg.Any())
.Returns(miner);
// Act & Assert
await Assert.ThrowsAsync(() =>
_handler.Handle(command, CancellationToken.None));
}
[Fact]
public async Task Handle_AlreadyMining_ThrowsException()
{
// Arrange
var userId = Guid.NewGuid();
var miner = Miner.Create(userId);
miner.StartMiningSession();
var command = new StartMiningCommand(userId);
_minerRepository.GetByUserIdAsync(userId, Arg.Any())
.Returns(miner);
// Act & Assert
await Assert.ThrowsAsync(() =>
_handler.Handle(command, CancellationToken.None));
}
}