using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Targeting; using Xunit; namespace NeonSprawl.Server.Tests.Game.Targeting; public class PlayerTargetStateReaderTests { [Fact] public void ComputeValidity_ShouldReturnInvalidTarget_WhenLockIdNotInRegistry() { // Act // Arrange var snap = new PositionSnapshot(0, 0, 0, 0); // Assert Assert.Equal(TargetValidity.InvalidTarget, PlayerTargetStateReader.ComputeValidity("not_in_registry", in snap)); } [Fact] public void ComputeValidity_ShouldReturnNone_WhenLockNull() { // Act // Arrange var snap = new PositionSnapshot(0, 0, 0, 0); // Assert Assert.Equal(TargetValidity.None, PlayerTargetStateReader.ComputeValidity(null, in snap)); } [Fact] public void ComputeValidity_AtExactLockRadius_ReturnsOk() { // Alpha anchor XZ (-3, -3), lockRadius 6 → horizontal distance 6 from (3, -3) is on boundary (inclusive). // Act // Arrange var snap = new PositionSnapshot(3, 0, -3, 0); // Assert Assert.Equal( TargetValidity.Ok, PlayerTargetStateReader.ComputeValidity(PrototypeTargetRegistry.PrototypeTargetAlphaId, in snap)); } [Fact] public void ComputeValidity_JustOutsideLockRadius_ReturnsOutOfRange() { // Act // Arrange const double eps = 1e-6; var snap = new PositionSnapshot(3 + eps, 0, -3, 0); // Assert Assert.Equal( TargetValidity.OutOfRange, PlayerTargetStateReader.ComputeValidity(PrototypeTargetRegistry.PrototypeTargetAlphaId, in snap)); } [Fact] public void ComputeValidity_AtOrigin_ShouldReturnOk_ForBothPrototypeTargets() { // NEO-24 post-merge: alpha (-3,-3) r=6 and beta (3,3) r=6 overlap at origin so Tab can // flip without locomotion. Origin is ~4.24 m from each anchor (< 6 m). // Act // Arrange var snap = new PositionSnapshot(0, 0, 0, 0); // Assert Assert.Equal( TargetValidity.Ok, PlayerTargetStateReader.ComputeValidity(PrototypeTargetRegistry.PrototypeTargetAlphaId, in snap)); Assert.Equal( TargetValidity.Ok, PlayerTargetStateReader.ComputeValidity(PrototypeTargetRegistry.PrototypeTargetBetaId, in snap)); } }