using System.Collections.Generic; using System.Linq; using CounterDrone.Core.Algorithms; using CounterDrone.Core.Models; using Xunit; namespace CounterDrone.Core.Tests { public class DispersionAdvisorRealityTests { private ThreatProfile CreatePistonThreat(float speed = 200, float length = 20000) { return new ThreatProfile { Environment = new CombatScene { WindSpeed = 3, WindDirection = (int)WindDirection.W }, Targets = new List { new TargetConfig { PowerType = (int)PowerType.Piston, Quantity = 1, TypicalSpeed = speed, TypicalAltitude = 500 }, }, Route = new RoutePlan { FormationMode = (int)FormationMode.Single }, Waypoints = new List { new Waypoint { PosX = 0, PosY = 500, PosZ = 0 }, new Waypoint { PosX = length, PosY = 500, PosZ = 0 }, }, }; } [Fact] public void Piston_200kmh_20km_ProducesReasonableSalvo() { var advisor = new DefaultDefenseAdvisor(DefaultAmmunition.GetAll()); var rec = advisor.Recommend(CreatePistonThreat()); Assert.Equal(AerosolType.InertGas, rec.Best.RecommendedAerosolType); Assert.NotEmpty(rec.Best.FireSchedule); Assert.True(rec.Best.FireSchedule.Count >= 1, $"齐射数={rec.Best.FireSchedule.Count},应≥1"); // 发射计划中的云团位置应在航路范围内且沿航路展开 var positions = rec.Best.FireSchedule.Select(f => f.TargetX).OrderBy(x => x).ToList(); Assert.True(positions.First() > 0, "第一个云团应在航路起点之后"); Assert.True(positions.Last() < 20000, "最后一个云团应在航路终点之前"); Assert.True(positions.Last() - positions.First() > 10, "云团应沿航路展开"); } [Fact] public void Timing_AccountsForExpansion() { var advisor = new DefaultDefenseAdvisor(DefaultAmmunition.GetAll()); var rec = advisor.Recommend(CreatePistonThreat()); var timing = rec.Best.RecommendedCloud.RecommendedTiming!.Value; var halfTime = 20000f / (200f / 3.6f) / 2f; Assert.True(timing < halfTime - 5, $"推荐时机={timing:F1}s 应早于中点={halfTime:F1}s(预留飞行+膨胀时间)"); } } }