141 lines
5.3 KiB
C#
141 lines
5.3 KiB
C#
using FluentAssertions;
|
|
using SpaceGame.Api.Shared.Runtime;
|
|
using SpaceGame.Api.Ships.Runtime;
|
|
using Xunit;
|
|
|
|
namespace SpaceGame.Api.Tests;
|
|
|
|
public sealed class ShipOrderQueueTests
|
|
{
|
|
[Fact]
|
|
public void Enqueue_Throws_WhenQueueIsFull()
|
|
{
|
|
var queue = new ShipOrderQueue();
|
|
foreach (var index in Enumerable.Range(0, ShipOrderQueue.MaxOrders))
|
|
{
|
|
queue.Enqueue(CreateOrder($"order-{index}", ShipOrderSourceKind.Player, priority: index));
|
|
}
|
|
|
|
var act = () => queue.Enqueue(CreateOrder("overflow", ShipOrderSourceKind.Player));
|
|
|
|
act.Should().Throw<InvalidOperationException>()
|
|
.WithMessage("Order queue is full.");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetCurrentOrder_UsesQueueOrder()
|
|
{
|
|
var queue = new ShipOrderQueue();
|
|
queue.EnqueuePlayerOrder(CreateOrder("player-first", ShipOrderSourceKind.Player));
|
|
queue.EnqueueManagedOrder(CreateOrder("commander-second", ShipOrderSourceKind.Commander, priority: 100));
|
|
queue.EnqueueManagedOrder(CreateOrder("behavior-third", ShipOrderSourceKind.Behavior, priority: 999));
|
|
|
|
var currentOrder = queue.GetCurrentOrder();
|
|
|
|
currentOrder.Should().NotBeNull();
|
|
currentOrder!.Id.Should().Be("player-first");
|
|
}
|
|
|
|
[Fact]
|
|
public void GetCurrentOrder_IgnoresTerminalStatuses()
|
|
{
|
|
var queue = new ShipOrderQueue();
|
|
queue.EnqueuePlayerOrder(CreateOrder("completed-player", ShipOrderSourceKind.Player, priority: 100, status: OrderStatus.Completed));
|
|
queue.EnqueueManagedOrder(CreateOrder("active-commander", ShipOrderSourceKind.Commander, priority: 1, status: OrderStatus.Active));
|
|
|
|
var currentOrder = queue.GetCurrentOrder();
|
|
|
|
currentOrder.Should().NotBeNull();
|
|
currentOrder!.Id.Should().Be("active-commander");
|
|
}
|
|
|
|
[Fact]
|
|
public void EnqueuePlayerOrder_InsertsBeforeManagedOrders()
|
|
{
|
|
var queue = new ShipOrderQueue();
|
|
queue.EnqueueManagedOrder(CreateOrder("behavior-1", ShipOrderSourceKind.Behavior));
|
|
queue.EnqueuePlayerOrder(CreateOrder("player-1", ShipOrderSourceKind.Player));
|
|
queue.EnqueueManagedOrder(CreateOrder("behavior-2", ShipOrderSourceKind.Commander));
|
|
queue.EnqueuePlayerOrder(CreateOrder("player-2", ShipOrderSourceKind.Player));
|
|
|
|
queue.Select(order => order.Id).Should().Equal("player-1", "player-2", "behavior-1", "behavior-2");
|
|
queue.FindLeadingOrderForSource(ShipOrderSourceKind.Player)!.Id.Should().Be("player-1");
|
|
}
|
|
|
|
[Fact]
|
|
public void AddOrReplaceManagedOrder_ReplacesMatchingOrderWithoutGrowingQueue()
|
|
{
|
|
var queue = new ShipOrderQueue();
|
|
queue.EnqueueManagedOrder(CreateOrder("order-1", ShipOrderSourceKind.Behavior, label: "Initial label"));
|
|
|
|
queue.AddOrReplaceManagedOrder(CreateOrder("order-1", ShipOrderSourceKind.Behavior, label: "Updated label", priority: 7));
|
|
|
|
queue.Count.Should().Be(1);
|
|
queue.FindById("order-1").Should().NotBeNull();
|
|
queue.FindById("order-1")!.Label.Should().Be("Updated label");
|
|
queue.FindById("order-1")!.Priority.Should().Be(7);
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveById_RemovesMatchingOrder()
|
|
{
|
|
var queue = new ShipOrderQueue();
|
|
queue.EnqueuePlayerOrder(CreateOrder("remove-me", ShipOrderSourceKind.Player));
|
|
queue.EnqueuePlayerOrder(CreateOrder("keep-me", ShipOrderSourceKind.Player));
|
|
|
|
var removed = queue.RemoveById("remove-me");
|
|
|
|
removed.Should().BeTrue();
|
|
queue.Select(order => order.Id).Should().ContainSingle().Which.Should().Be("keep-me");
|
|
}
|
|
|
|
[Fact]
|
|
public void TryMovePlayerOrder_ReordersWithinPlayerSegment()
|
|
{
|
|
var queue = new ShipOrderQueue();
|
|
queue.EnqueuePlayerOrder(CreateOrder("player-1", ShipOrderSourceKind.Player));
|
|
queue.EnqueuePlayerOrder(CreateOrder("player-2", ShipOrderSourceKind.Player));
|
|
queue.EnqueueManagedOrder(CreateOrder("behavior-1", ShipOrderSourceKind.Behavior));
|
|
|
|
var moved = queue.TryMovePlayerOrder("player-2", 0);
|
|
|
|
moved.Should().BeTrue();
|
|
queue.Select(order => order.Id).Should().Equal("player-2", "player-1", "behavior-1");
|
|
}
|
|
|
|
[Fact]
|
|
public void TryCompleteOrder_RemovesCompletedDirectOrderFromQueue()
|
|
{
|
|
var queue = new ShipOrderQueue();
|
|
queue.EnqueuePlayerOrder(CreateOrder("direct-order", ShipOrderSourceKind.Player, status: OrderStatus.Active));
|
|
queue.EnqueueManagedOrder(CreateOrder("behavior-order", ShipOrderSourceKind.Behavior));
|
|
|
|
var completed = queue.TryCompleteOrder("direct-order");
|
|
|
|
completed.Should().BeTrue();
|
|
queue.FindById("direct-order").Should().BeNull();
|
|
queue.GetCurrentOrder()!.Id.Should().Be("behavior-order");
|
|
}
|
|
|
|
private static ShipOrderRuntime CreateOrder(
|
|
string id,
|
|
ShipOrderSourceKind sourceKind,
|
|
int priority = 0,
|
|
OrderStatus status = OrderStatus.Queued,
|
|
string? label = null,
|
|
DateTimeOffset? createdAtUtc = null)
|
|
{
|
|
return new ShipOrderRuntime
|
|
{
|
|
Id = id,
|
|
Kind = "test-order",
|
|
SourceKind = sourceKind,
|
|
SourceId = $"{sourceKind}-source",
|
|
Priority = priority,
|
|
Status = status,
|
|
Label = label,
|
|
CreatedAtUtc = createdAtUtc ?? new DateTimeOffset(2026, 4, 8, 12, 0, 0, TimeSpan.Zero),
|
|
};
|
|
}
|
|
}
|