using System; using System.Collections.Generic; using System.IO; 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 { /// 边界场景测试 public class EdgeCaseTests : IDisposable { private readonly string _testDir; private readonly IScenarioService _scenario; private readonly SQLite.SQLiteConnection _db; private string _taskId = string.Empty; public EdgeCaseTests() { _testDir = Path.Combine(Path.GetTempPath(), $"cd_edge_{Guid.NewGuid():N}"); var paths = new TestPathProvider(_testDir); var dbm = new DatabaseManager(paths); _db = dbm.OpenMainDb(); foreach (var a in DefaultAmmunition.GetAll()) _db.Insert(a); _scenario = new ScenarioService( new SimTaskRepository(_db), new CombatSceneRepository(_db), new ControlZoneRepository(_db), new TargetConfigRepository(_db), new EquipmentDeploymentRepository(_db), new CloudDispersalRepository(_db), new RoutePlanRepository(_db), new WaypointRepository(_db)); } public void Dispose() { _db?.Close(); if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true); } [Fact] public void EmptyDeployment_EngineRunsWithoutCrash() { var task = _scenario.CreateTask("空部署", ""); _taskId = task.Id; _scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0 }); _scenario.SaveTarget(_taskId, new TargetConfig { GroupId = "default", TargetType = (int)TargetType.Piston, Quantity = 1, TypicalSpeed = 100, TypicalAltitude = 300, }); _scenario.SaveDeployment(_taskId, new List()); _scenario.SaveCloudDispersal(_taskId, new CloudDispersal()); _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 300, PosZ = 0 }, new Waypoint { PosX = 1000, PosY = 300, PosZ = 0 }, }); var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)), new DamageModelRouter(), new TestPathProvider(_testDir)); engine.Initialize(_taskId); engine.TimeScale = 4f; for (int i = 0; i < 500; i++) { var r = engine.Tick(1f / 20f); if (r.State == SimulationState.Completed) break; } engine.Stop(); Assert.Equal(DroneStatus.ReachedTarget, engine.Drones[0].Status); } [Fact] public void ExtremeWind_DroneStillFlies() { var task = _scenario.CreateTask("飓风", ""); _taskId = task.Id; _scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 30, // 最大风速 WindDirection = (int)WindDirection.E, }); _scenario.SaveTarget(_taskId, new TargetConfig { GroupId = "default", TargetType = (int)TargetType.Piston, Quantity = 1, TypicalSpeed = 600, // 高速对抗强风 }); _scenario.SaveDeployment(_taskId, new List()); _scenario.SaveCloudDispersal(_taskId, new CloudDispersal()); _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 300, PosZ = 0 }, new Waypoint { PosX = 5000, PosY = 300, PosZ = 0 }, }); var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)), new DamageModelRouter(), new TestPathProvider(_testDir)); engine.Initialize(_taskId); engine.TimeScale = 4f; for (int i = 0; i < 500; i++) { var r = engine.Tick(1f / 20f); if (r.State == SimulationState.Completed) break; } engine.Stop(); // 强风下应偏移到东方(+X) Assert.True(engine.Drones[0].PosX > 0); } [Fact] public void LongRoute_CompletesWithoutError() { var task = _scenario.CreateTask("超长航路", ""); _taskId = task.Id; _scenario.SaveScene(_taskId, new CombatScene { WindSpeed = 0 }); _scenario.SaveTarget(_taskId, new TargetConfig { GroupId = "default", TargetType = (int)TargetType.HighSpeed, Quantity = 1, TypicalSpeed = 500, }); _scenario.SaveDeployment(_taskId, new List()); _scenario.SaveCloudDispersal(_taskId, new CloudDispersal()); // 500 km/h, 100km 航程 _scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 500, PosZ = 0 }, new Waypoint { PosX = 100000, PosY = 500, PosZ = 0 }, }); var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)), new DamageModelRouter(), new TestPathProvider(_testDir)); engine.Initialize(_taskId); engine.TimeScale = 4f; for (int i = 0; i < 5000; i++) { var r = engine.Tick(1f / 20f); if (r.State == SimulationState.Completed) break; } engine.Stop(); Assert.Equal(DroneStatus.ReachedTarget, engine.Drones[0].Status); } } }