test(core/slice-1): full portal+logout event-sequence ordering + no-duplicate-fire coverage
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f1b59f3a64
commit
c3d6eccf51
1 changed files with 111 additions and 0 deletions
|
|
@ -341,4 +341,115 @@ public sealed class TeleportAnimSequencerTests
|
||||||
Assert.Equal(TeleportAnimState.TunnelContinue, seq.State);
|
Assert.Equal(TeleportAnimState.TunnelContinue, seq.State);
|
||||||
Assert.True(snap2.ShowPleaseWait);
|
Assert.True(snap2.ShowPleaseWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Task 1.5: Full portal event sequence and logout event sequence ---
|
||||||
|
|
||||||
|
// Helper: run the sequencer to completion collecting ordered events.
|
||||||
|
private static List<TeleportAnimEvent> RunToOff(
|
||||||
|
TeleportEntryKind kind, bool worldReadyAfterFirstTunnel = true, float step = 0.05f)
|
||||||
|
{
|
||||||
|
var seq = new TeleportAnimSequencer();
|
||||||
|
var allEvts = new List<TeleportAnimEvent>();
|
||||||
|
seq.Begin(kind);
|
||||||
|
|
||||||
|
int safetyNet = 5000;
|
||||||
|
while (seq.IsActive && --safetyNet > 0)
|
||||||
|
{
|
||||||
|
// Simulate world becoming ready on first Tick inside Tunnel
|
||||||
|
bool ready = worldReadyAfterFirstTunnel && seq.State == TeleportAnimState.Tunnel;
|
||||||
|
var (_, evts) = seq.Tick(step, worldReady: ready);
|
||||||
|
allEvts.AddRange(evts);
|
||||||
|
}
|
||||||
|
return allEvts;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Portal_FullSequence_EventsInOrder()
|
||||||
|
{
|
||||||
|
var evts = RunToOff(TeleportEntryKind.Portal);
|
||||||
|
|
||||||
|
// Required events in order: PlayEnterSound, Place, PlayExitSound, FireLoginComplete.
|
||||||
|
// EnterTunnel is optional but must come before Place if present.
|
||||||
|
int enterIdx = evts.IndexOf(TeleportAnimEvent.PlayEnterSound);
|
||||||
|
int placeIdx = evts.IndexOf(TeleportAnimEvent.Place);
|
||||||
|
int exitIdx = evts.IndexOf(TeleportAnimEvent.PlayExitSound);
|
||||||
|
int loginIdx = evts.IndexOf(TeleportAnimEvent.FireLoginComplete);
|
||||||
|
|
||||||
|
Assert.True(enterIdx >= 0, "PlayEnterSound must fire");
|
||||||
|
Assert.True(placeIdx >= 0, "Place must fire");
|
||||||
|
Assert.True(exitIdx >= 0, "PlayExitSound must fire");
|
||||||
|
Assert.True(loginIdx >= 0, "FireLoginComplete must fire");
|
||||||
|
|
||||||
|
Assert.True(enterIdx < placeIdx, "PlayEnterSound must precede Place");
|
||||||
|
Assert.True(placeIdx < exitIdx, "Place must precede PlayExitSound");
|
||||||
|
Assert.True(exitIdx < loginIdx, "PlayExitSound must precede FireLoginComplete");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Logout_FullSequence_EventsInOrder_WithEnterTunnelAfterFades()
|
||||||
|
{
|
||||||
|
var evts = RunToOff(TeleportEntryKind.Logout);
|
||||||
|
|
||||||
|
int enterIdx = evts.IndexOf(TeleportAnimEvent.PlayEnterSound);
|
||||||
|
int tunnelIdx = evts.IndexOf(TeleportAnimEvent.EnterTunnel);
|
||||||
|
int placeIdx = evts.IndexOf(TeleportAnimEvent.Place);
|
||||||
|
int exitIdx = evts.IndexOf(TeleportAnimEvent.PlayExitSound);
|
||||||
|
int loginIdx = evts.IndexOf(TeleportAnimEvent.FireLoginComplete);
|
||||||
|
|
||||||
|
Assert.True(enterIdx >= 0, "PlayEnterSound must fire");
|
||||||
|
Assert.True(tunnelIdx >= 0, "EnterTunnel must fire (Logout path goes through WorldFadeOut->TunnelFadeIn->Tunnel)");
|
||||||
|
Assert.True(placeIdx >= 0, "Place must fire");
|
||||||
|
Assert.True(exitIdx >= 0, "PlayExitSound must fire");
|
||||||
|
Assert.True(loginIdx >= 0, "FireLoginComplete must fire");
|
||||||
|
|
||||||
|
Assert.True(enterIdx < tunnelIdx, "PlayEnterSound must precede EnterTunnel");
|
||||||
|
Assert.True(tunnelIdx < placeIdx, "EnterTunnel must precede Place");
|
||||||
|
Assert.True(placeIdx < exitIdx, "Place must precede PlayExitSound");
|
||||||
|
Assert.True(exitIdx < loginIdx, "PlayExitSound must precede FireLoginComplete");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Portal_NoEventsFiredTwice()
|
||||||
|
{
|
||||||
|
var evts = RunToOff(TeleportEntryKind.Portal);
|
||||||
|
Assert.Equal(1, evts.Count(e => e == TeleportAnimEvent.PlayEnterSound));
|
||||||
|
Assert.Equal(1, evts.Count(e => e == TeleportAnimEvent.Place));
|
||||||
|
Assert.Equal(1, evts.Count(e => e == TeleportAnimEvent.PlayExitSound));
|
||||||
|
Assert.Equal(1, evts.Count(e => e == TeleportAnimEvent.FireLoginComplete));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Death_BehavesIdenticallyToPortal_FullSequence()
|
||||||
|
{
|
||||||
|
var portalEvts = RunToOff(TeleportEntryKind.Portal);
|
||||||
|
var deathEvts = RunToOff(TeleportEntryKind.Death);
|
||||||
|
// Same event sequence (both enter at Tunnel)
|
||||||
|
Assert.Equal(portalEvts, deathEvts);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Login_BehavesIdenticallyToPortal_FullSequence()
|
||||||
|
{
|
||||||
|
var portalEvts = RunToOff(TeleportEntryKind.Portal);
|
||||||
|
var loginEvts = RunToOff(TeleportEntryKind.Login);
|
||||||
|
Assert.Equal(portalEvts, loginEvts);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AfterOff_IsActiveIsFalse_AndStateIsOff()
|
||||||
|
{
|
||||||
|
RunToOff(TeleportEntryKind.Portal);
|
||||||
|
var seq = new TeleportAnimSequencer();
|
||||||
|
seq.Begin(TeleportEntryKind.Portal);
|
||||||
|
|
||||||
|
// Drain to Off
|
||||||
|
for (int i = 0; i < 5000 && seq.IsActive; i++)
|
||||||
|
{
|
||||||
|
bool ready = seq.State == TeleportAnimState.Tunnel;
|
||||||
|
seq.Tick(0.05f, worldReady: ready);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.False(seq.IsActive);
|
||||||
|
Assert.Equal(TeleportAnimState.Off, seq.State);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue