< Summary

Class:ThreatTests
Assembly:bamlab.test.editmode
File(s):/github/workspace/Assets/Tests/EditMode/ThreatTests.cs
Covered lines:109
Uncovered lines:1
Coverable lines:110
Total lines:250
Line coverage:99% (109 of 110)
Covered branches:0
Total branches:0
Covered methods:9
Total methods:9
Method coverage:100% (9 of 9)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Setup()0%110100%
Teardown()0%440100%
Threat_IsNotAssignable()0%110100%
FixedWingThreat_CalculateAccelerationInput_RespectsMaxForwardAcceleration()0%110100%
FixedWingThreat_CalculateAccelerationInput_RespectsMaxNormalAcceleration()0%110100%
RotaryWingThreat_CalculateAccelerationToWaypoint_RespectsMaxForwardAcceleration()0%110100%
RotaryWingThreat_CalculateAccelerationToWaypoint_RespectsMaxNormalAcceleration()0%110100%
RotaryWingThreat_CalculateAccelerationToWaypoint_ComputesCorrectly()0%110100%
AttackBehavior_LoadedCorrectly()0%11088%

File(s)

/github/workspace/Assets/Tests/EditMode/ThreatTests.cs

#LineLine coverage
 1using System;
 2using NUnit.Framework;
 3using UnityEngine;
 4using System.Collections.Generic;
 5using System.Linq;
 6using System.IO;
 7
 8public class ThreatTests : AgentTestBase {
 9  private FixedWingThreat _fixedWingThreat;
 10  private RotaryWingThreat _rotaryWingThreat;
 11
 12  private const string TestDirectAttackPbtxt =
 13      @"
 14      name: ""Test Direct Attack""
 15      type: DIRECT_ATTACK
 16      flight_plan {
 17        type: DISTANCE_TO_TARGET
 18        waypoints {
 19          distance: 10000
 20          altitude: 500
 21          power: MIL
 22        }
 23        waypoints {
 24          distance: 5000
 25          altitude: 100
 26          power: MAX
 27        }
 28      }
 29    ";
 30
 731  public override void Setup() {
 732    base.Setup();
 33    // Write the hard-coded attack behavior to a file.
 734    string attackConfigPath =
 35        ConfigLoader.GetStreamingAssetsFilePath("Configs/Attacks/test_direct_attack.pbtxt");
 736    Directory.CreateDirectory(Path.GetDirectoryName(attackConfigPath));
 737    File.WriteAllText(attackConfigPath, TestDirectAttackPbtxt);
 38
 739    var ucavConfig = new Configs.AgentConfig() {
 40      ConfigFile = "ucav.pbtxt", AttackBehaviorConfigFile = "test_direct_attack.pbtxt",
 41      InitialState =
 42          new Simulation.State() {
 43            Position = new Simulation.CartesianCoordinates() { X = 2000, Y = 100, Z = 4000 },
 44            Velocity = new Simulation.CartesianCoordinates() { X = -50, Y = 0, Z = -100 },
 45          },
 46      StandardDeviation =
 47          new Simulation.State() {
 48            Position = new Simulation.CartesianCoordinates() { X = 400, Y = 300, Z = 400 },
 49            Velocity = new Simulation.CartesianCoordinates() { X = 0, Y = 0, Z = 15 },
 50          },
 51      DynamicConfig =
 52          new Configs.DynamicConfig() {
 53            SensorConfig =
 54                new Simulation.SensorConfig {
 55                  Type = Simulation.SensorType.Ideal,
 56                  Frequency = 100,
 57                },
 58          }
 59    };
 60
 761    var quadcopterConfig = new Configs.AgentConfig() {
 62      ConfigFile = "quadcopter.pbtxt", AttackBehaviorConfigFile = "test_direct_attack.pbtxt",
 63      InitialState =
 64          new Simulation.State() {
 65            Position = new Simulation.CartesianCoordinates() { X = 0, Y = 600, Z = 6000 },
 66            Velocity = new Simulation.CartesianCoordinates() { X = 0, Y = 0, Z = -50 },
 67          },
 68      StandardDeviation =
 69          new Simulation.State() {
 70            Position = new Simulation.CartesianCoordinates() { X = 100, Y = 200, Z = 100 },
 71            Velocity = new Simulation.CartesianCoordinates() { X = 0, Y = 0, Z = 25 },
 72          },
 73      DynamicConfig =
 74          new Configs.DynamicConfig() {
 75            SensorConfig =
 76                new Simulation.SensorConfig {
 77                  Type = Simulation.SensorType.Ideal,
 78                  Frequency = 100,
 79                },
 80          }
 81    };
 82
 783    Agent threatAgent = CreateTestThreat(ucavConfig);
 784    Assert.IsNotNull(threatAgent);
 785    Assert.IsTrue(threatAgent is FixedWingThreat);
 786    _fixedWingThreat = (FixedWingThreat)threatAgent;
 787    Assert.IsNotNull(_fixedWingThreat);
 88
 789    threatAgent = CreateTestThreat(quadcopterConfig);
 790    Assert.IsNotNull(threatAgent);
 791    Assert.IsTrue(threatAgent is RotaryWingThreat);
 792    _rotaryWingThreat = (RotaryWingThreat)threatAgent;
 793    Assert.IsNotNull(_rotaryWingThreat);
 794  }
 95
 796  public override void Teardown() {
 797    base.Teardown();
 98    // Delete the attack configuration file.
 799    string attackConfigPath =
 100        ConfigLoader.GetStreamingAssetsFilePath("Configs/Attacks/test_direct_attack.pbtxt");
 14101    if (File.Exists(attackConfigPath)) {
 7102      File.Delete(attackConfigPath);
 7103    }
 104
 14105    if (_fixedWingThreat != null) {
 7106      GameObject.DestroyImmediate(_fixedWingThreat.gameObject);
 7107    }
 108
 14109    if (_rotaryWingThreat != null) {
 7110      GameObject.DestroyImmediate(_rotaryWingThreat.gameObject);
 7111    }
 7112  }
 113
 114  [Test]
 1115  public void Threat_IsNotAssignable() {
 1116    Assert.IsFalse(_fixedWingThreat.IsAssignable());
 1117    Assert.IsFalse(_rotaryWingThreat.IsAssignable());
 1118  }
 119
 120  [Test]
 1121  public void FixedWingThreat_CalculateAccelerationInput_RespectsMaxForwardAcceleration() {
 1122    SetPrivateField(_fixedWingThreat, "_currentWaypoint", Vector3.one * 1000f);
 1123    Vector3 acceleration =
 124        InvokePrivateMethod<Vector3>(_fixedWingThreat, "CalculateAccelerationInput");
 1125    float maxForwardAcceleration = _fixedWingThreat.CalculateMaxForwardAcceleration();
 126    const float epsilon = 1e-5f;
 1127    Assert.LessOrEqual(Vector3.Project(acceleration, _fixedWingThreat.transform.forward).magnitude,
 128                       maxForwardAcceleration + epsilon);
 1129  }
 130
 131  [Test]
 1132  public void FixedWingThreat_CalculateAccelerationInput_RespectsMaxNormalAcceleration() {
 1133    SetPrivateField(_fixedWingThreat, "_currentWaypoint", Vector3.one * 1000f);
 1134    Vector3 acceleration =
 135        InvokePrivateMethod<Vector3>(_fixedWingThreat, "CalculateAccelerationInput");
 1136    float maxNormalAcceleration = _fixedWingThreat.CalculateMaxNormalAcceleration();
 137    const float epsilon = 1e-5f;
 1138    Assert.LessOrEqual(
 139        acceleration.magnitude, maxNormalAcceleration + epsilon,
 140        $"Acceleration magnitude {acceleration.magnitude} should be less than or equal to the maximum normal acceleratio
 1141  }
 142
 143  [Test]
 1144  public void RotaryWingThreat_CalculateAccelerationToWaypoint_RespectsMaxForwardAcceleration() {
 1145    SetPrivateField(_rotaryWingThreat, "_currentWaypoint", Vector3.one * 1000f);
 1146    Vector3 acceleration =
 147        InvokePrivateMethod<Vector3>(_rotaryWingThreat, "CalculateAccelerationToWaypoint");
 1148    float maxForwardAcceleration = _rotaryWingThreat.CalculateMaxForwardAcceleration();
 149    const float epsilon = 1e-5f;
 1150    Assert.LessOrEqual(Vector3.Project(acceleration, _fixedWingThreat.transform.forward).magnitude,
 151                       maxForwardAcceleration + epsilon);
 1152  }
 153
 154  [Test]
 1155  public void RotaryWingThreat_CalculateAccelerationToWaypoint_RespectsMaxNormalAcceleration() {
 1156    SetPrivateField(_rotaryWingThreat, "_currentWaypoint", Vector3.one * 1000f);
 1157    Vector3 acceleration =
 158        InvokePrivateMethod<Vector3>(_rotaryWingThreat, "CalculateAccelerationToWaypoint");
 1159    float maxNormalAcceleration = _rotaryWingThreat.CalculateMaxNormalAcceleration();
 160    const float epsilon = 1e-5f;
 161    // Calculate the normal acceleration.
 1162    Vector3 forwardComponent = Vector3.Project(acceleration, _rotaryWingThreat.transform.forward);
 1163    Vector3 normalComponent = acceleration - forwardComponent;
 164
 1165    Assert.LessOrEqual(
 166        normalComponent.magnitude, maxNormalAcceleration + epsilon,
 167        $"Normal acceleration magnitude {normalComponent.magnitude} should be less than or equal to the maximum normal a
 1168  }
 169
 170  [Test]
 1171  public void RotaryWingThreat_CalculateAccelerationToWaypoint_ComputesCorrectly() {
 1172    Vector3 initialPosition = new Vector3(0, 0, 0);
 1173    Vector3 waypoint = new Vector3(1000, 0, 0);
 1174    Vector3 initialVelocity = new Vector3(0, 0, 0);
 1175    float desiredSpeed = 50f;
 176
 1177    _rotaryWingThreat.SetPosition(initialPosition);
 1178    SetPrivateField(_rotaryWingThreat, "_currentWaypoint", waypoint);
 1179    _rotaryWingThreat.SetVelocity(initialVelocity);
 1180    SetPrivateField(_rotaryWingThreat, "_currentPower", Configs.Power.Mil);
 181
 182    // Assume that the lookup power table returns 50 for MIL.
 1183    float power =
 184        InvokePrivateMethod<float>(_rotaryWingThreat, "LookupPowerTable", Configs.Power.Mil);
 1185    Assert.AreEqual(desiredSpeed, power);
 186
 1187    Vector3 accelerationInput =
 188        InvokePrivateMethod<Vector3>(_rotaryWingThreat, "CalculateAccelerationToWaypoint");
 189
 1190    Vector3 toWaypoint = waypoint - initialPosition;
 1191    Vector3 expectedAccelerationDir = toWaypoint.normalized;
 1192    float expectedAccelerationMag = desiredSpeed / (float)Time.fixedDeltaTime;
 1193    Vector3 expectedAcceleration = expectedAccelerationDir * expectedAccelerationMag;
 194
 195    // Decompose acceleration into forward and normal components.
 1196    Vector3 forwardAcceleration =
 197        Vector3.Project(expectedAcceleration, _rotaryWingThreat.transform.forward);
 1198    Vector3 normalAcceleration = expectedAcceleration - forwardAcceleration;
 199
 200    // Limit the acceleration magnitude.
 1201    float maxForwardAcceleration = _rotaryWingThreat.CalculateMaxNormalAcceleration();
 1202    forwardAcceleration = Vector3.ClampMagnitude(forwardAcceleration, maxForwardAcceleration);
 1203    float maxNormalAcceleration = _rotaryWingThreat.CalculateMaxNormalAcceleration();
 1204    normalAcceleration = Vector3.ClampMagnitude(normalAcceleration, maxNormalAcceleration);
 1205    expectedAcceleration = forwardAcceleration + normalAcceleration;
 206
 1207    Assert.AreEqual(expectedAcceleration.magnitude, accelerationInput.magnitude, 0.1f,
 208                    "Acceleration magnitude should match expected.");
 1209    Assert.AreEqual(expectedAcceleration.normalized, accelerationInput.normalized,
 210                    "Acceleration direction should be towards waypoint.");
 1211  }
 212
 213  [Test]
 1214  public void AttackBehavior_LoadedCorrectly() {
 1215    try {
 1216      AttackBehavior attackBehavior =
 217          GetPrivateField<AttackBehavior>(_fixedWingThreat, "_attackBehavior");
 1218      Assert.IsNotNull(attackBehavior, "Attack behavior should not be null.");
 1219      Assert.AreEqual("Test Direct Attack", attackBehavior.Name);
 1220      Assert.AreEqual(Configs.AttackType.DirectAttack, attackBehavior.Type);
 221
 1222      Assert.IsTrue(attackBehavior is DirectAttackBehavior,
 223                    "Attack behavior should be a DirectAttackBehavior.");
 1224      DirectAttackBehavior directAttackBehavior = (DirectAttackBehavior)attackBehavior;
 225
 1226      Assert.IsNotNull(attackBehavior.FlightPlan, "Flight plan should not be null.");
 1227      Assert.AreEqual(Configs.AttackBehaviorConfig.Types.FlightPlanType.DistanceToTarget,
 228                      attackBehavior.FlightPlan.Type);
 229
 1230      List<Waypoint> waypoints = attackBehavior.FlightPlan.Waypoints;
 1231      Assert.IsNotNull(waypoints, "Waypoints should not be null.");
 1232      Assert.AreEqual(2, waypoints.Count, "There should be 2 waypoints.");
 233
 1234      Assert.AreEqual(10000f, waypoints[0].Distance);
 1235      Assert.AreEqual(500f, waypoints[0].Altitude);
 1236      Assert.AreEqual(Configs.Power.Mil, waypoints[0].Power);
 237
 1238      Assert.AreEqual(5000f, waypoints[1].Distance);
 1239      Assert.AreEqual(100f, waypoints[1].Altitude);
 1240      Assert.AreEqual(Configs.Power.Max, waypoints[1].Power);
 241
 1242      GameObject.DestroyImmediate(_simManager.gameObject);
 1243    } catch (AssertionException e) {
 0244      throw new AssertionException(
 245          e.Message + "\n" + "This test likely failed because you have edited " +
 246          "the test string at the top of the test. Please update the test with the new values.\n" +
 247          "If you need to change the test values, please update the test string at the top of the test.");
 248    }
 1249  }
 250}