147 lines
4.4 KiB
C#
147 lines
4.4 KiB
C#
using System.Collections.Generic;
|
|
using System.Numerics;
|
|
using AcDream.App.World;
|
|
using Xunit;
|
|
|
|
namespace AcDream.App.Tests.World;
|
|
|
|
public class TeleportArrivalControllerTests
|
|
{
|
|
// Records each Place(destPos, destCell, forced) call.
|
|
private sealed record PlaceCall(Vector3 Pos, uint Cell, bool Forced);
|
|
|
|
private static TeleportArrivalController Make(
|
|
ArrivalReadiness verdict,
|
|
List<PlaceCall> placed,
|
|
int maxHoldFrames = TeleportArrivalController.DefaultMaxHoldFrames)
|
|
=> new(
|
|
readiness: (_, _) => verdict,
|
|
place: (pos, cell, forced) => placed.Add(new PlaceCall(pos, cell, forced)),
|
|
maxHoldFrames: maxHoldFrames);
|
|
|
|
[Fact]
|
|
public void BeginArrival_EntersHolding()
|
|
{
|
|
var placed = new List<PlaceCall>();
|
|
var c = Make(ArrivalReadiness.NotReady, placed);
|
|
|
|
c.BeginArrival(new Vector3(1, 2, 3), 0x01250126u);
|
|
|
|
Assert.Equal(TeleportArrivalPhase.Holding, c.Phase);
|
|
Assert.Empty(placed);
|
|
}
|
|
|
|
[Fact]
|
|
public void Tick_WhenIdle_IsNoOp()
|
|
{
|
|
var placed = new List<PlaceCall>();
|
|
var c = Make(ArrivalReadiness.Ready, placed);
|
|
|
|
c.Tick(); // never began
|
|
|
|
Assert.Equal(TeleportArrivalPhase.Idle, c.Phase);
|
|
Assert.Empty(placed);
|
|
}
|
|
|
|
[Fact]
|
|
public void Tick_NotReady_KeepsHolding_DoesNotPlace()
|
|
{
|
|
var placed = new List<PlaceCall>();
|
|
var c = Make(ArrivalReadiness.NotReady, placed);
|
|
c.BeginArrival(new Vector3(1, 2, 3), 0x01250126u);
|
|
|
|
c.Tick();
|
|
c.Tick();
|
|
|
|
Assert.Equal(TeleportArrivalPhase.Holding, c.Phase);
|
|
Assert.Empty(placed);
|
|
}
|
|
|
|
[Fact]
|
|
public void Tick_Ready_PlacesUnforced_AndIdles()
|
|
{
|
|
var placed = new List<PlaceCall>();
|
|
var c = Make(ArrivalReadiness.Ready, placed);
|
|
c.BeginArrival(new Vector3(30, -60, 6.005f), 0x01250126u);
|
|
|
|
c.Tick();
|
|
|
|
Assert.Equal(TeleportArrivalPhase.Idle, c.Phase);
|
|
var call = Assert.Single(placed);
|
|
Assert.False(call.Forced);
|
|
Assert.Equal(0x01250126u, call.Cell);
|
|
Assert.Equal(new Vector3(30, -60, 6.005f), call.Pos);
|
|
}
|
|
|
|
[Fact]
|
|
public void Tick_Impossible_PlacesForced_AndIdles()
|
|
{
|
|
var placed = new List<PlaceCall>();
|
|
var c = Make(ArrivalReadiness.Impossible, placed);
|
|
c.BeginArrival(new Vector3(1, 2, 3), 0x0125FF00u);
|
|
|
|
c.Tick();
|
|
|
|
Assert.Equal(TeleportArrivalPhase.Idle, c.Phase);
|
|
var call = Assert.Single(placed);
|
|
Assert.True(call.Forced);
|
|
}
|
|
|
|
[Fact]
|
|
public void Tick_Timeout_PlacesForced_AfterMaxHoldFrames()
|
|
{
|
|
var placed = new List<PlaceCall>();
|
|
var c = Make(ArrivalReadiness.NotReady, placed, maxHoldFrames: 3);
|
|
c.BeginArrival(new Vector3(1, 2, 3), 0x01250126u);
|
|
|
|
c.Tick(); // 1
|
|
c.Tick(); // 2
|
|
Assert.Empty(placed);
|
|
Assert.Equal(TeleportArrivalPhase.Holding, c.Phase);
|
|
|
|
c.Tick(); // 3 -> timeout
|
|
|
|
var call = Assert.Single(placed);
|
|
Assert.True(call.Forced);
|
|
Assert.Equal(TeleportArrivalPhase.Idle, c.Phase);
|
|
}
|
|
|
|
[Fact]
|
|
public void BeginArrival_AfterPlace_ReArms()
|
|
{
|
|
var placed = new List<PlaceCall>();
|
|
var c = Make(ArrivalReadiness.Ready, placed);
|
|
|
|
c.BeginArrival(new Vector3(1, 0, 0), 0x01250126u);
|
|
c.Tick(); // places #1, idle
|
|
c.BeginArrival(new Vector3(2, 0, 0), 0x01250127u);
|
|
c.Tick(); // places #2, idle
|
|
|
|
Assert.Equal(2, placed.Count);
|
|
Assert.Equal(0x01250127u, placed[1].Cell);
|
|
}
|
|
|
|
[Fact]
|
|
public void BeginArrival_DuringHold_ResetsTimeoutCounter()
|
|
{
|
|
var placed = new List<PlaceCall>();
|
|
var c = Make(ArrivalReadiness.NotReady, placed, maxHoldFrames: 3);
|
|
|
|
c.BeginArrival(new Vector3(1, 0, 0), 0x01250126u);
|
|
c.Tick(); // held=1
|
|
c.Tick(); // held=2 (one short of the timeout)
|
|
|
|
// Re-arm mid-hold with a fresh destination: the counter must restart.
|
|
c.BeginArrival(new Vector3(2, 0, 0), 0x01250199u);
|
|
c.Tick(); // held=1 again (NOT 3 -> no placement yet)
|
|
c.Tick(); // held=2
|
|
Assert.Empty(placed);
|
|
Assert.Equal(TeleportArrivalPhase.Holding, c.Phase);
|
|
|
|
c.Tick(); // held=3 -> timeout, forced place of the SECOND destination
|
|
var call = Assert.Single(placed);
|
|
Assert.True(call.Forced);
|
|
Assert.Equal(0x01250199u, call.Cell);
|
|
Assert.Equal(new Vector3(2, 0, 0), call.Pos);
|
|
}
|
|
}
|