240 lines
5.9 KiB
C#
240 lines
5.9 KiB
C#
using FluentAssertions;
|
|
using FnbEngine.Domain.AggregatesModel.TableAggregate;
|
|
using FnbEngine.Domain.Exceptions;
|
|
using Xunit;
|
|
|
|
namespace FnbEngine.UnitTests.Domain;
|
|
|
|
/// <summary>
|
|
/// EN: Unit tests for Table aggregate behavior.
|
|
/// VI: Unit tests cho hanh vi aggregate Table.
|
|
/// </summary>
|
|
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<DomainException>()
|
|
.WithMessage("*Shop ID*");
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_WithEmptyTableNumber_ShouldThrowDomainException()
|
|
{
|
|
// Act
|
|
var action = () => new Table(ValidShopId, "", 4);
|
|
|
|
// Assert
|
|
action.Should().Throw<DomainException>()
|
|
.WithMessage("*Table number*");
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_WithWhitespaceTableNumber_ShouldThrowDomainException()
|
|
{
|
|
// Act
|
|
var action = () => new Table(ValidShopId, " ", 4);
|
|
|
|
// Assert
|
|
action.Should().Throw<DomainException>();
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_WithZeroCapacity_ShouldThrowDomainException()
|
|
{
|
|
// Act
|
|
var action = () => new Table(ValidShopId, "A-01", 0);
|
|
|
|
// Assert
|
|
action.Should().Throw<DomainException>()
|
|
.WithMessage("*Capacity*");
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_WithNegativeCapacity_ShouldThrowDomainException()
|
|
{
|
|
// Act
|
|
var action = () => new Table(ValidShopId, "A-01", -1);
|
|
|
|
// Assert
|
|
action.Should().Throw<DomainException>();
|
|
}
|
|
|
|
[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<DomainException>();
|
|
}
|
|
|
|
[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<DomainException>();
|
|
}
|
|
|
|
[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();
|
|
}
|
|
}
|