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(); } }