Planner no longer has god-view. It assumes threats enter from detection boundary (unified info network earliest detection point), not route start. Core: DetectionCalculator (EO attenuated by Visibility, radar/IR unaffected; earliest detection via segment-circle intersection). EquipmentDeployment: drop DetectionRadius, add RadarRange/EORange/IRange/DetectionAccuracy. FireUnit detection fields activated in BuildFireUnits. IDefensePlanner.Plan adds 4th param detectionSources. Engine: BuildDetectionSources merges standalone detectors + fire-unit self-detection into unified list, passed to planner. Fix: Solve robustness when GenerateFireEventsAt returns empty (detection boundary too late to intercept). Tests 193 to 208 (+15). 0 warnings.
97 lines
3.2 KiB
C#
97 lines
3.2 KiB
C#
using System;
|
||
using System.IO;
|
||
using CounterDrone.Core.Algorithms;
|
||
using CounterDrone.Core.Models;
|
||
using Xunit;
|
||
|
||
namespace CounterDrone.Core.Tests
|
||
{
|
||
public class PlannerConfigTests : IDisposable
|
||
{
|
||
private readonly string _testDir;
|
||
|
||
public PlannerConfigTests()
|
||
{
|
||
_testDir = Path.Combine(Path.GetTempPath(), $"cd_cfg_{Guid.NewGuid():N}");
|
||
Directory.CreateDirectory(_testDir);
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
if (Directory.Exists(_testDir)) Directory.Delete(_testDir, true);
|
||
}
|
||
|
||
private void WriteConfig(string json)
|
||
=> File.WriteAllText(Path.Combine(_testDir, "planner_config.json"), json);
|
||
|
||
private static readonly string ValidJson = @"
|
||
{
|
||
""CloudOverlapRatio"": 0.2,
|
||
""CriticalProbabilityThreshold"": 0.5,
|
||
""MaxInterceptProbability"": 0.95,
|
||
""TypeCoefficient"": {
|
||
""HighSpeed"": 4.0, ""FixedWing"": 2.0, ""Piston"": 2.0,
|
||
""Rotor"": 1.0, ""Electric"": 1.0
|
||
},
|
||
""AmmoMatch"": {
|
||
""Electric"": ""InertGas"", ""Piston"": ""InertGas"", ""Jet"": ""ActiveMaterial""
|
||
},
|
||
""DefaultDetectionAccuracy"": 50.0
|
||
}";
|
||
|
||
[Fact]
|
||
public void Load_ValidJson_ReturnsAllFields()
|
||
{
|
||
WriteConfig(ValidJson);
|
||
var cfg = PlannerConfig.Load(_testDir);
|
||
Assert.Equal(0.2f, cfg.CloudOverlapRatio);
|
||
Assert.Equal(0.5f, cfg.CriticalProbabilityThreshold);
|
||
Assert.Equal(0.95f, cfg.MaxInterceptProbability);
|
||
Assert.Equal(4.0f, cfg.TypeCoefficient[TargetType.HighSpeed]);
|
||
Assert.Equal(AerosolType.InertGas, cfg.AmmoMatch[PowerType.Piston]);
|
||
Assert.Equal(AerosolType.ActiveMaterial, cfg.AmmoMatch[PowerType.Jet]);
|
||
}
|
||
|
||
[Fact]
|
||
public void Load_MissingFile_Throws()
|
||
{
|
||
// 不写文件
|
||
Assert.Throws<FileNotFoundException>(() => PlannerConfig.Load(_testDir));
|
||
}
|
||
|
||
[Fact]
|
||
public void Load_MissingField_Throws()
|
||
{
|
||
// 缺 CriticalProbabilityThreshold
|
||
WriteConfig(@"{ ""CloudOverlapRatio"": 0.2, ""MaxInterceptProbability"": 0.95,
|
||
""TypeCoefficient"": {""Piston"": 2.0}, ""AmmoMatch"": {""Piston"": ""InertGas""} }");
|
||
Assert.Throws<InvalidDataException>(() => PlannerConfig.Load(_testDir));
|
||
}
|
||
|
||
[Fact]
|
||
public void Load_OverlapOutOfRange_Throws()
|
||
{
|
||
// CloudOverlapRatio = 1.0 非法(必须 < 1)
|
||
var bad = ValidJson.Replace("0.2", "1.0");
|
||
WriteConfig(bad);
|
||
Assert.Throws<InvalidDataException>(() => PlannerConfig.Load(_testDir));
|
||
}
|
||
|
||
[Fact]
|
||
public void Load_EmptyDataRoot_Throws()
|
||
{
|
||
Assert.Throws<ArgumentException>(() => PlannerConfig.Load(""));
|
||
}
|
||
|
||
[Fact]
|
||
public void Load_EnumParsedFromString()
|
||
{
|
||
// 验证枚举用字符串(非数字)也能正确解析
|
||
WriteConfig(ValidJson);
|
||
var cfg = PlannerConfig.Load(_testDir);
|
||
Assert.Equal(1.0f, cfg.TypeCoefficient[TargetType.Rotor]);
|
||
Assert.Equal(AerosolType.InertGas, cfg.AmmoMatch[PowerType.Electric]);
|
||
}
|
||
}
|
||
}
|