/ GUNRPG.Tests / AwarenessModelTests.cs
AwarenessModelTests.cs
  1  using GUNRPG.Core.Combat;
  2  using GUNRPG.Core.Operators;
  3  using Xunit;
  4  
  5  namespace GUNRPG.Tests;
  6  
  7  /// <summary>
  8  /// Unit tests for the AwarenessModel - visibility and recognition mechanics.
  9  /// </summary>
 10  public class AwarenessModelTests
 11  {
 12      #region CanSeeTarget Tests
 13  
 14      [Fact]
 15      public void CanSeeTarget_NoCover_ReturnsTrue()
 16      {
 17          Assert.True(AwarenessModel.CanSeeTarget(CoverState.None));
 18      }
 19  
 20      [Fact]
 21      public void CanSeeTarget_PartialCover_ReturnsTrue()
 22      {
 23          Assert.True(AwarenessModel.CanSeeTarget(CoverState.Partial));
 24      }
 25  
 26      [Fact]
 27      public void CanSeeTarget_FullCover_ReturnsFalse()
 28      {
 29          Assert.False(AwarenessModel.CanSeeTarget(CoverState.Full));
 30      }
 31  
 32      #endregion
 33  
 34      #region GetVisibilityLevel Tests
 35  
 36      [Fact]
 37      public void GetVisibilityLevel_NoCover_ReturnsOne()
 38      {
 39          Assert.Equal(1.0f, AwarenessModel.GetVisibilityLevel(CoverState.None));
 40      }
 41  
 42      [Fact]
 43      public void GetVisibilityLevel_PartialCover_ReturnsHalf()
 44      {
 45          Assert.Equal(0.5f, AwarenessModel.GetVisibilityLevel(CoverState.Partial));
 46      }
 47  
 48      [Fact]
 49      public void GetVisibilityLevel_FullCover_ReturnsZero()
 50      {
 51          Assert.Equal(0.0f, AwarenessModel.GetVisibilityLevel(CoverState.Full));
 52      }
 53  
 54      #endregion
 55  
 56      #region Recognition Delay Tests
 57  
 58      [Fact]
 59      public void CalculateRecognitionDelayMs_HighProficiency_ReturnsLowDelay()
 60      {
 61          float delay = AwarenessModel.CalculateRecognitionDelayMs(
 62              observerAccuracyProficiency: 1.0f,
 63              observerSuppressionLevel: 0f);
 64  
 65          // High proficiency should approach minimum delay
 66          Assert.True(delay <= AwarenessModel.MinRecognitionDelayMs + 10f,
 67              $"High proficiency should result in low delay. Got: {delay}ms");
 68      }
 69  
 70      [Fact]
 71      public void CalculateRecognitionDelayMs_LowProficiency_ReturnsHighDelay()
 72      {
 73          float delay = AwarenessModel.CalculateRecognitionDelayMs(
 74              observerAccuracyProficiency: 0.0f,
 75              observerSuppressionLevel: 0f);
 76  
 77          // Low proficiency should result in base delay
 78          Assert.True(delay >= AwarenessModel.BaseRecognitionDelayMs * 0.9f,
 79              $"Low proficiency should result in high delay. Got: {delay}ms");
 80      }
 81  
 82      [Fact]
 83      public void CalculateRecognitionDelayMs_SuppressionIncreasesDelay()
 84      {
 85          float noSuppressionDelay = AwarenessModel.CalculateRecognitionDelayMs(
 86              observerAccuracyProficiency: 0.5f,
 87              observerSuppressionLevel: 0f);
 88  
 89          float fullSuppressionDelay = AwarenessModel.CalculateRecognitionDelayMs(
 90              observerAccuracyProficiency: 0.5f,
 91              observerSuppressionLevel: 1.0f);
 92  
 93          Assert.True(fullSuppressionDelay > noSuppressionDelay,
 94              $"Suppression should increase delay. No suppression: {noSuppressionDelay}ms, Full suppression: {fullSuppressionDelay}ms");
 95      }
 96  
 97      [Fact]
 98      public void CalculateRecognitionDelayMs_ClampsToMinimum()
 99      {
100          float delay = AwarenessModel.CalculateRecognitionDelayMs(
101              observerAccuracyProficiency: 1.0f,
102              observerSuppressionLevel: 0f);
103  
104          Assert.True(delay >= AwarenessModel.MinRecognitionDelayMs,
105              $"Delay should be at least {AwarenessModel.MinRecognitionDelayMs}ms. Got: {delay}ms");
106      }
107  
108      [Fact]
109      public void CalculateRecognitionDelayMs_ClampsToMaximum()
110      {
111          float delay = AwarenessModel.CalculateRecognitionDelayMs(
112              observerAccuracyProficiency: 0.0f,
113              observerSuppressionLevel: 1.0f);
114  
115          Assert.True(delay <= AwarenessModel.MaxRecognitionDelayMs,
116              $"Delay should be at most {AwarenessModel.MaxRecognitionDelayMs}ms. Got: {delay}ms");
117      }
118  
119      #endregion
120  
121      #region Recognition Accuracy Multiplier Tests
122  
123      [Fact]
124      public void GetRecognitionAccuracyMultiplier_ZeroProgress_ReturnsLowMultiplier()
125      {
126          float multiplier = AwarenessModel.GetRecognitionAccuracyMultiplier(0f);
127  
128          Assert.Equal(AwarenessModel.RecognitionPenaltyAccuracyMultiplier, multiplier);
129      }
130  
131      [Fact]
132      public void GetRecognitionAccuracyMultiplier_FullProgress_ReturnsOne()
133      {
134          float multiplier = AwarenessModel.GetRecognitionAccuracyMultiplier(1.0f);
135  
136          Assert.Equal(1.0f, multiplier);
137      }
138  
139      [Fact]
140      public void GetRecognitionAccuracyMultiplier_HalfProgress_ReturnsMidValue()
141      {
142          float multiplier = AwarenessModel.GetRecognitionAccuracyMultiplier(0.5f);
143  
144          float expected = AwarenessModel.RecognitionPenaltyAccuracyMultiplier +
145                          (1.0f - AwarenessModel.RecognitionPenaltyAccuracyMultiplier) * 0.5f;
146  
147          Assert.Equal(expected, multiplier, precision: 3);
148      }
149  
150      #endregion
151  }