using FluentAssertions;
using FnbEngine.Domain.AggregatesModel.TableAggregate;
using FnbEngine.Domain.Exceptions;
using Xunit;
namespace FnbEngine.UnitTests.Domain;
///
/// EN: Unit tests for Table aggregate behavior.
/// VI: Unit tests cho hanh vi aggregate Table.
///
public class TableAggregateTests
{
private static readonly Guid ValidShopId = Guid.NewGuid();
[Fact]
public void Constructor_WithValidData_ShouldCreateAvailableTable()
{
// Act
var table = new Table(ValidShopId, "A-01", 4, "Main Hall");
// Assert
table.Id.Should().NotBeEmpty();
table.ShopId.Should().Be(ValidShopId);
table.TableNumber.Should().Be("A-01");
table.Capacity.Should().Be(4);
table.Zone.Should().Be("Main Hall");
table.Status.Should().Be(TableStatus.Available);
table.StatusId.Should().Be(TableStatus.Available.Id);
table.HourlyRate.Should().Be(0);
table.QrToken.Should().BeNull();
table.PositionX.Should().BeNull();
table.PositionY.Should().BeNull();
table.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
}
[Fact]
public void Constructor_WithEmptyShopId_ShouldThrowDomainException()
{
// Act
var action = () => new Table(Guid.Empty, "A-01", 4);
// Assert
action.Should().Throw()
.WithMessage("*Shop ID*");
}
[Fact]
public void Constructor_WithEmptyTableNumber_ShouldThrowDomainException()
{
// Act
var action = () => new Table(ValidShopId, "", 4);
// Assert
action.Should().Throw()
.WithMessage("*Table number*");
}
[Fact]
public void Constructor_WithWhitespaceTableNumber_ShouldThrowDomainException()
{
// Act
var action = () => new Table(ValidShopId, " ", 4);
// Assert
action.Should().Throw();
}
[Fact]
public void Constructor_WithZeroCapacity_ShouldThrowDomainException()
{
// Act
var action = () => new Table(ValidShopId, "A-01", 0);
// Assert
action.Should().Throw()
.WithMessage("*Capacity*");
}
[Fact]
public void Constructor_WithNegativeCapacity_ShouldThrowDomainException()
{
// Act
var action = () => new Table(ValidShopId, "A-01", -1);
// Assert
action.Should().Throw();
}
[Fact]
public void Constructor_ShouldTrimTableNumber()
{
// Act
var table = new Table(ValidShopId, " A-01 ", 4);
// Assert
table.TableNumber.Should().Be("A-01");
}
[Fact]
public void Constructor_ShouldTrimZone()
{
// Act
var table = new Table(ValidShopId, "A-01", 4, " VIP ");
// Assert
table.Zone.Should().Be("VIP");
}
[Fact]
public void MarkAsOccupied_WhenAvailable_ShouldSucceed()
{
// Arrange
var table = new Table(ValidShopId, "B-02", 6);
// Act
table.MarkAsOccupied();
// Assert
table.Status.Should().Be(TableStatus.Occupied);
table.StatusId.Should().Be(TableStatus.Occupied.Id);
table.UpdatedAt.Should().NotBeNull();
}
[Fact]
public void MarkAsOccupied_WhenCleaning_ShouldThrowDomainException()
{
// Arrange
var table = new Table(ValidShopId, "C-03", 2);
table.MarkAsCleaning();
// Act
var action = () => table.MarkAsOccupied();
// Assert
action.Should().Throw();
}
[Fact]
public void MarkAsOccupied_WhenAlreadyOccupied_ShouldThrowDomainException()
{
// Arrange
var table = new Table(ValidShopId, "D-04", 2);
table.MarkAsOccupied();
// Act
var action = () => table.MarkAsOccupied();
// Assert
action.Should().Throw();
}
[Fact]
public void MarkAsAvailable_FromAnyStatus_ShouldSucceed()
{
// Arrange
var table = new Table(ValidShopId, "E-05", 4);
table.MarkAsOccupied();
// Act
table.MarkAsAvailable();
// Assert
table.Status.Should().Be(TableStatus.Available);
}
[Fact]
public void MarkAsCleaning_ShouldSetCleaningStatus()
{
// Arrange
var table = new Table(ValidShopId, "F-06", 4);
// Act
table.MarkAsCleaning();
// Assert
table.Status.Should().Be(TableStatus.Cleaning);
table.StatusId.Should().Be(TableStatus.Cleaning.Id);
}
[Fact]
public void SetHourlyRate_ShouldUpdateRate()
{
// Arrange
var table = new Table(ValidShopId, "G-07", 4);
// Act
table.SetHourlyRate(50_000m);
// Assert
table.HourlyRate.Should().Be(50_000m);
table.UpdatedAt.Should().NotBeNull();
}
[Fact]
public void SetPosition_ShouldUpdateCoordinates()
{
// Arrange
var table = new Table(ValidShopId, "H-08", 4);
// Act
table.SetPosition(100, 200);
// Assert
table.PositionX.Should().Be(100);
table.PositionY.Should().Be(200);
table.UpdatedAt.Should().NotBeNull();
}
[Fact]
public void GenerateQrToken_ShouldReturnNonEmptyToken()
{
// Arrange
var table = new Table(ValidShopId, "I-09", 4);
// Act
var token = table.GenerateQrToken();
// Assert
token.Should().NotBeNullOrEmpty();
token.Should().HaveLength(16);
table.QrToken.Should().Be(token);
table.UpdatedAt.Should().NotBeNull();
}
[Fact]
public void ClearQrToken_ShouldSetTokenToNull()
{
// Arrange
var table = new Table(ValidShopId, "J-10", 4);
table.GenerateQrToken();
// Act
table.ClearQrToken();
// Assert
table.QrToken.Should().BeNull();
}
}