using System.Collections.Generic; using CounterDrone.Core; using CounterDrone.Core.Algorithms; using CounterDrone.Core.Models; using CounterDrone.Core.Repository; using CounterDrone.Core.Services; using CounterDrone.Core.Simulation; using Xunit; namespace CounterDrone.Core.Tests { /// 诊断 BuildFireSchedule 是否生成正确计划 public class FireScheduleDiagnostics { private static readonly List TestAmmo = new() { new AmmunitionSpec { AerosolType = (int)AerosolType.InertGas, InitialRadius = 50, CoreDensity = 1.0, DispersionRateBase = 5, MaxRadius = 200, MaxDuration = 60 }, new AmmunitionSpec { AerosolType = (int)AerosolType.ActiveMaterial, InitialRadius = 30, CoreDensity = 2.0, DispersionRateBase = 3, MaxRadius = 150, MaxDuration = 45 }, }; [Fact] public void BuildFireSchedule_WithRecommendation_ProducesEvents() { // 模拟:活塞无人机威胁 → 算法推荐 → 发射计划 var threat = new ThreatProfile { Environment = new CombatScene { WindSpeed = 3 }, Targets = new List { new TargetConfig { TargetType = (int)TargetType.Piston, PowerType = (int)PowerType.Piston, Quantity = 1, TypicalSpeed = 200 }, }, Route = new RoutePlan { FormationMode = (int)FormationMode.Single }, Waypoints = new List { new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 }, new Waypoint { PosX = 20000, PosY = 500, PosZ = 0, Speed = 200 }, }, }; var rec = new DefaultDefenseAdvisor(TestAmmo).Recommend(threat); // 检查推荐 Assert.True(rec.Best.RecommendedCloud.RecommendedTiming > 0, $"推荐时机={rec.Best.RecommendedCloud.RecommendedTiming}"); Assert.NotEmpty(rec.Best.Platforms); // 模拟持久化后读取 var cloud = rec.Best.RecommendedCloud; var equips = new List(); foreach (var p in rec.Best.Platforms) equips.Add(new EquipmentDeployment { EquipmentRole = (int)EquipmentRole.LaunchPlatform, Quantity = p.Quantity, PositionX = p.Position.X, PositionY = p.Position.Y, PositionZ = p.Position.Z, AerosolType = (int)rec.Best.RecommendedAerosolType, MunitionCount = p.MunitionCount, Cooldown = 5, MuzzleVelocity = 800, }); // 手动调用 BuildFireSchedule 同样的逻辑 var schedule = new List(); if (cloud.RecommendedTiming.HasValue && cloud.RecommendedTiming.Value > 0) { foreach (var p in equips) { var muzzleV = (float)(p.MuzzleVelocity ?? 800); var dx = (float)cloud.PositionX - (float)p.PositionX; var dz = (float)cloud.PositionZ - (float)p.PositionZ; var dist = (float)System.Math.Sqrt(dx * dx + dz * dz); var flightTime = dist / muzzleV; var fireTime = (float)cloud.RecommendedTiming.Value - flightTime; if (fireTime < 0) fireTime = 0.1f; schedule.Add(new FireEvent { FireTime = fireTime, PlatformIndex = 0, TargetX = (float)cloud.PositionX, TargetY = (float)cloud.PositionY, TargetZ = (float)cloud.PositionZ, MuzzleVelocity = muzzleV, }); } } Assert.NotEmpty(schedule); Assert.True(schedule[0].FireTime > 0); Assert.Equal((float)cloud.PositionX, schedule[0].TargetX); } } }