using FluentAssertions; using FnbEngine.Domain.AggregatesModel.ReservationAggregate; using FnbEngine.Domain.Exceptions; using Xunit; namespace FnbEngine.UnitTests.Domain; /// /// EN: Unit tests for Reservation aggregate behavior. /// VI: Unit tests cho hanh vi aggregate Reservation. /// public class ReservationTests { private static readonly Guid ValidShopId = Guid.NewGuid(); private static readonly DateTime FutureTime = DateTime.UtcNow.AddHours(2); [Fact] public void Constructor_WithValidData_ShouldCreatePendingReservation() { // Act var reservation = new Reservation(ValidShopId, "Nguyen Van A", 4, FutureTime, "0901234567"); // Assert reservation.Id.Should().NotBeEmpty(); reservation.ShopId.Should().Be(ValidShopId); reservation.GuestName.Should().Be("Nguyen Van A"); reservation.PartySize.Should().Be(4); reservation.ReservationTime.Should().Be(FutureTime); reservation.Phone.Should().Be("0901234567"); reservation.Status.Should().Be("pending"); reservation.TableId.Should().BeNull(); reservation.Note.Should().BeNull(); reservation.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5)); } [Fact] public void Constructor_WithAllOptionalParams_ShouldSetAllFields() { // Arrange var tableId = Guid.NewGuid(); // Act var reservation = new Reservation(ValidShopId, "Tran Thi B", 6, FutureTime, "0909876543", tableId, "Window seat preferred"); // Assert reservation.TableId.Should().Be(tableId); reservation.Note.Should().Be("Window seat preferred"); reservation.Phone.Should().Be("0909876543"); } [Fact] public void Constructor_WithEmptyShopId_ShouldThrowDomainException() { var action = () => new Reservation(Guid.Empty, "Guest", 2, FutureTime); action.Should().Throw().WithMessage("*Shop ID*"); } [Fact] public void Constructor_WithEmptyGuestName_ShouldThrowDomainException() { var action = () => new Reservation(ValidShopId, "", 2, FutureTime); action.Should().Throw().WithMessage("*Guest name*"); } [Fact] public void Constructor_WithWhitespaceGuestName_ShouldThrowDomainException() { var action = () => new Reservation(ValidShopId, " ", 2, FutureTime); action.Should().Throw(); } [Fact] public void Constructor_WithZeroPartySize_ShouldThrowDomainException() { var action = () => new Reservation(ValidShopId, "Guest", 0, FutureTime); action.Should().Throw().WithMessage("*Party size*"); } [Fact] public void Constructor_ShouldTrimGuestNameAndPhone() { var reservation = new Reservation(ValidShopId, " Nguyen Van A ", 2, FutureTime, " 0901234567 "); reservation.GuestName.Should().Be("Nguyen Van A"); reservation.Phone.Should().Be("0901234567"); } [Fact] public void Confirm_ShouldSetStatusToConfirmed() { var reservation = new Reservation(ValidShopId, "Guest", 2, FutureTime); reservation.Confirm(); reservation.Status.Should().Be("confirmed"); } [Fact] public void Seat_ShouldSetStatusToSeated() { var reservation = new Reservation(ValidShopId, "Guest", 2, FutureTime); reservation.Seat(); reservation.Status.Should().Be("seated"); } [Fact] public void Cancel_ShouldSetStatusToCancelled() { var reservation = new Reservation(ValidShopId, "Guest", 2, FutureTime); reservation.Cancel(); reservation.Status.Should().Be("cancelled"); } [Fact] public void NoShow_ShouldSetStatusToNoShow() { var reservation = new Reservation(ValidShopId, "Guest", 2, FutureTime); reservation.NoShow(); reservation.Status.Should().Be("no_show"); } [Fact] public void AssignTable_ShouldSetTableId() { var reservation = new Reservation(ValidShopId, "Guest", 2, FutureTime); var tableId = Guid.NewGuid(); reservation.AssignTable(tableId); reservation.TableId.Should().Be(tableId); } [Fact] public void UpdateStatus_WithValidStatus_ShouldSucceed() { var reservation = new Reservation(ValidShopId, "Guest", 2, FutureTime); reservation.UpdateStatus("confirmed"); reservation.Status.Should().Be("confirmed"); reservation.UpdateStatus("seated"); reservation.Status.Should().Be("seated"); } [Fact] public void UpdateStatus_WithInvalidStatus_ShouldThrowDomainException() { var reservation = new Reservation(ValidShopId, "Guest", 2, FutureTime); var action = () => reservation.UpdateStatus("invalid_status"); action.Should().Throw() .WithMessage("*Invalid reservation status*"); } }