/ GUNRPG.Tests / Core / IntentValidationTests.cs
IntentValidationTests.cs
  1  using GUNRPG.Core;
  2  using GUNRPG.Core.Intents;
  3  using GUNRPG.Core.Operators;
  4  
  5  namespace GUNRPG.Tests.Core;
  6  
  7  /// <summary>
  8  /// Domain-level tests for intent validation logic.
  9  /// These tests focus on the core domain rules without application or API concerns.
 10  /// </summary>
 11  public class IntentValidationTests
 12  {
 13      [Fact]
 14      public void FireWeaponIntent_RequiresAmmo()
 15      {
 16          var op = CreateOperator();
 17          op.CurrentAmmo = 0;
 18  
 19          var intent = new FireWeaponIntent(op.Id);
 20          var (isValid, errorMessage) = intent.Validate(op);
 21  
 22          Assert.False(isValid);
 23          Assert.Contains("no ammo", errorMessage, StringComparison.OrdinalIgnoreCase);
 24      }
 25  
 26      [Fact]
 27      public void FireWeaponIntent_ValidWithAmmo()
 28      {
 29          var op = CreateOperator();
 30          op.CurrentAmmo = 10;
 31  
 32          var intent = new FireWeaponIntent(op.Id);
 33          var (isValid, errorMessage) = intent.Validate(op);
 34  
 35          Assert.True(isValid);
 36          Assert.Null(errorMessage);
 37      }
 38  
 39      [Fact]
 40      public void ReloadIntent_FailsWhenMagazineFull()
 41      {
 42          var op = CreateOperator();
 43          op.CurrentAmmo = op.EquippedWeapon!.MagazineSize;
 44  
 45          var intent = new ReloadIntent(op.Id);
 46          var (isValid, errorMessage) = intent.Validate(op);
 47  
 48          Assert.False(isValid);
 49          Assert.Contains("full", errorMessage, StringComparison.OrdinalIgnoreCase);
 50      }
 51  
 52      [Fact]
 53      public void ReloadIntent_ValidWhenNotFull()
 54      {
 55          var op = CreateOperator();
 56          op.CurrentAmmo = 5;
 57  
 58          var intent = new ReloadIntent(op.Id);
 59          var (isValid, errorMessage) = intent.Validate(op);
 60  
 61          Assert.True(isValid);
 62          Assert.Null(errorMessage);
 63      }
 64  
 65      [Fact]
 66      public void SprintIntent_RequiresStamina()
 67      {
 68          var op = CreateOperator();
 69          op.Stamina = 0;
 70  
 71          var intent = new SprintIntent(op.Id, towardOpponent: true);
 72          var (isValid, errorMessage) = intent.Validate(op);
 73  
 74          Assert.False(isValid);
 75          Assert.Contains("stamina", errorMessage, StringComparison.OrdinalIgnoreCase);
 76      }
 77  
 78      [Fact]
 79      public void SprintIntent_ValidWithStamina()
 80      {
 81          var op = CreateOperator();
 82          op.Stamina = 50;
 83  
 84          var intent = new SprintIntent(op.Id, towardOpponent: true);
 85          var (isValid, errorMessage) = intent.Validate(op);
 86  
 87          Assert.True(isValid);
 88          Assert.Null(errorMessage);
 89      }
 90  
 91      [Fact]
 92      public void EnterADSIntent_FailsWhenAlreadyInADS()
 93      {
 94          var op = CreateOperator();
 95          op.AimState = AimState.ADS;
 96  
 97          var intent = new EnterADSIntent(op.Id);
 98          var (isValid, errorMessage) = intent.Validate(op);
 99  
100          Assert.False(isValid);
101          Assert.Contains("already", errorMessage, StringComparison.OrdinalIgnoreCase);
102      }
103  
104      [Fact]
105      public void EnterADSIntent_ValidWhenInHipFire()
106      {
107          var op = CreateOperator();
108          op.AimState = AimState.Hip;
109  
110          var intent = new EnterADSIntent(op.Id);
111          var (isValid, errorMessage) = intent.Validate(op);
112  
113          Assert.True(isValid);
114          Assert.Null(errorMessage);
115      }
116  
117      private static Operator CreateOperator()
118      {
119          return new Operator("TestOperator")
120          {
121              EquippedWeapon = WeaponFactory.CreateSokol545(),
122              CurrentAmmo = 30,
123              Stamina = 100
124          };
125      }
126  }