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 _scenarioId = 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(); _scenario = new ScenarioService( new ScenarioRepository(_db), new CombatSceneRepository(_db), new ControlZoneRepository(_db), new ScenarioDroneRepository(_db), new ScenarioUnitRepository(_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 scenario = _scenario.CreateScenario("空部署", ""); _scenarioId = scenario.Id; _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0 }); _scenario.SaveScenarioDrone(_scenarioId, TestData.CreateScenarioDrone("default", 1)); _scenario.SaveDeployment(_scenarioId, new List()); _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal()); _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 300, PosZ = 0, Speed = 100 }, new Waypoint { PosX = 1000, PosY = 300, PosZ = 0, Speed = 100 }, }); var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)), new DamageModelRouter(), new TestPathProvider(_testDir), new DefensePlanner(TestData.Ammo, TestPlannerConfig.Instance)); engine.Initialize(_scenarioId); 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 scenario = _scenario.CreateScenario("飓风", ""); _scenarioId = scenario.Id; _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 30, // 最大风速 WindDirection = (int)WindDirection.E, }); _scenario.SaveScenarioDrone(_scenarioId, TestData.CreateScenarioDrone("default", 1)); _scenario.SaveDeployment(_scenarioId, new List()); _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal()); _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 300, PosZ = 0, Speed = 600 }, new Waypoint { PosX = 5000, PosY = 300, PosZ = 0, Speed = 600 }, }); var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)), new DamageModelRouter(), new TestPathProvider(_testDir), new DefensePlanner(TestData.Ammo, TestPlannerConfig.Instance)); engine.Initialize(_scenarioId); 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 scenario = _scenario.CreateScenario("超长航路", ""); _scenarioId = scenario.Id; _scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0 }); _scenario.SaveScenarioDrone(_scenarioId, TestData.CreateScenarioDrone("default", 1)); _scenario.SaveDeployment(_scenarioId, new List()); _scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal()); // 500 km/h, 100km 航程 _scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single }, new List { new Waypoint { PosX = 0, PosY = 500, PosZ = 0, Speed = 500 }, new Waypoint { PosX = 100000, PosY = 500, PosZ = 0, Speed = 500 }, }); var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)), new DamageModelRouter(), new TestPathProvider(_testDir), new DefensePlanner(TestData.Ammo, TestPlannerConfig.Instance)); engine.Initialize(_scenarioId); 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); } } }