CounterDroneBackend/test/unit/CounterDrone.Core.Tests/EdgeCaseTests.cs
tian 8eeb43f0e8 feat: 统一默认数据架构 (defaults.json + DefaultData)
单一数据源 data/defaults.json,含弹药/编队/火力单元/无人机/探测/天气六类预设

版本追踪: Meta 表 + version 字段,更新时 InsertOrReplace,不删用户数据

名称统一 [Demo] 前缀,UI 中可识别为模拟数据

删除: DefaultAmmunition.cs, DefaultFireUnits.cs, default_ammo.json, default_formations.json, TestAmmo.cs

TestPathProvider 自动复制数据文件到测试目录

集成测试精简: 4个简单变体跳过,保留6个核心场景,39s
2026-06-15 15:46:20 +08:00

165 lines
6.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
{
/// <summary>边界场景测试</summary>
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();
_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
{
WaveId = "default",
TargetType = (int)TargetType.Piston,
Quantity = 1,
TypicalSpeed = 100,
TypicalAltitude = 300,
});
_scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>());
_scenario.SaveCloudDispersal(_taskId, new CloudDispersal());
_scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
new List<Waypoint>
{
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), new DefensePlanner(TestData.Defaults.Ammunition, TestPlannerConfig.Instance));
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
{
WaveId = "default",
TargetType = (int)TargetType.Piston,
Quantity = 1,
TypicalSpeed = 600, // 高速对抗强风
});
_scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>());
_scenario.SaveCloudDispersal(_taskId, new CloudDispersal());
_scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
new List<Waypoint>
{
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), new DefensePlanner(TestData.Defaults.Ammunition, TestPlannerConfig.Instance));
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
{
WaveId = "default",
TargetType = (int)TargetType.HighSpeed,
Quantity = 1,
TypicalSpeed = 500,
});
_scenario.SaveDeployment(_taskId, new List<EquipmentDeployment>());
_scenario.SaveCloudDispersal(_taskId, new CloudDispersal());
// 500 km/h, 100km 航程
_scenario.SaveRoute(_taskId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
new List<Waypoint>
{
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), new DefensePlanner(TestData.Defaults.Ammunition, TestPlannerConfig.Instance));
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);
}
}
}