- IScenarioService 新增 GetDefenseRecommendation(scenarioId) - ScenarioService 构造函数加可选 IPathProvider + IDefensePlanner - DefenseRecommendation / RecommendOption 返回类型 - 前端调用获取最佳抛撒参数 → 用户一键应用写入 CloudDispersal - 去掉 Critical(省弹药到 50% 概率,无决策价值) - Unity ScenarioManager 桥接 + 构造注入 planner - 对接文档加推荐用法示例 - 265 测试通过(+3 推荐),Unity 编译通过
98 lines
3.9 KiB
C#
98 lines
3.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using CounterDrone.Core;
|
|
using CounterDrone.Core.Algorithms;
|
|
using CounterDrone.Core.Models;
|
|
using CounterDrone.Core.Repository;
|
|
using CounterDrone.Core.Services;
|
|
using SQLite;
|
|
using Xunit;
|
|
|
|
namespace CounterDrone.Core.Tests
|
|
{
|
|
public class DefenseRecommendationTests : IDisposable
|
|
{
|
|
private readonly string _testDir;
|
|
private readonly IPathProvider _paths;
|
|
private readonly SQLiteConnection _db;
|
|
private readonly ScenarioService _scenario;
|
|
private string _scenarioId = string.Empty;
|
|
|
|
public DefenseRecommendationTests()
|
|
{
|
|
_testDir = Path.Combine(Path.GetTempPath(), $"cd_rec_{Guid.NewGuid():N}");
|
|
_paths = new TestPathProvider(_testDir);
|
|
var dbm = new DatabaseManager(_paths);
|
|
_db = dbm.OpenMainDb();
|
|
|
|
var planner = new DefensePlanner(
|
|
DefaultData.Load(_paths).Ammunition,
|
|
PlannerConfig.Load(_paths));
|
|
_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),
|
|
_paths, planner);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_db?.Close();
|
|
if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetDefenseRecommendation_PresetScenario_ReturnsBest()
|
|
{
|
|
// 用预设想定
|
|
var results = _scenario.SearchScenarios("活塞", null, null, 1, 10);
|
|
Assert.True(results.TotalCount > 0, "预设想定未找到");
|
|
_scenarioId = results.Items[0].Id;
|
|
|
|
var rec = _scenario.GetDefenseRecommendation(_scenarioId);
|
|
|
|
Assert.True(rec.Success, $"推荐失败: {rec.Summary}");
|
|
Assert.True(rec.Best.SalvoRounds > 0, "最佳方案弹药数应 > 0");
|
|
Assert.True(rec.Best.EstimatedProbability > 0, "最佳方案概率应 > 0");
|
|
Assert.NotEmpty(rec.Summary);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetDefenseRecommendation_NoFireUnits_ReturnsFailure()
|
|
{
|
|
// 创建无火力单元的想定
|
|
var sc = _scenario.CreateScenario("无防御测试", "");
|
|
_scenarioId = sc.Id;
|
|
_scenario.SaveScene(_scenarioId, new CombatScene { WindSpeed = 0, Visibility = 10000 });
|
|
_scenario.SaveScenarioDrone(_scenarioId, TestData.CreateScenarioDrone("default", 1));
|
|
_scenario.SaveRoute(_scenarioId, "default", new RoutePlan { FormationMode = (int)FormationMode.Single },
|
|
new List<Waypoint> {
|
|
new() { PosX = 0, PosY = 500, PosZ = 0, Speed = 200 },
|
|
new() { PosX = 10000, PosY = 500, PosZ = 0, Speed = 200 },
|
|
});
|
|
_scenario.SaveCloudDispersal(_scenarioId, new CloudDispersal { AerosolType = (int)AerosolType.InertGas });
|
|
|
|
var rec = _scenario.GetDefenseRecommendation(_scenarioId);
|
|
|
|
Assert.False(rec.Success);
|
|
Assert.Contains("火力单元", rec.Summary);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetDefenseRecommendation_NoPlanner_Throws()
|
|
{
|
|
// 不传 planner 的 ScenarioService
|
|
var svcNoPlanner = 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));
|
|
|
|
Assert.Throws<InvalidOperationException>(() => svcNoPlanner.GetDefenseRecommendation("any"));
|
|
}
|
|
}
|
|
}
|