增加了单元测试框架,重构了告警器模型,增加了告警器配置,编写了新增告警器的单元测试

This commit is contained in:
Tian jianyong 2024-11-19 16:57:57 +08:00
parent 3f02f52074
commit af702cbbda
18 changed files with 1354 additions and 313 deletions

View File

@ -4,8 +4,19 @@
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>9.0</LangVersion>
<ImplicitUsings>disable</ImplicitUsings>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
</PropertyGroup>
<ItemGroup>
<Compile Remove="obj\**" />
<Compile Remove="src\Tests\**" />
<EmbeddedResource Remove="obj\**" />
<EmbeddedResource Remove="src\Tests\**" />
<None Remove="obj\**" />
<None Remove="src\Tests\**" />
</ItemGroup>
</Project>

View File

@ -1,29 +1,33 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ActiveProtect", "ActiveProtect.csproj", "{7F47A2C7-1087-440B-82F7-A1BF50D30A1B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7F47A2C7-1087-440B-82F7-A1BF50D30A1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F47A2C7-1087-440B-82F7-A1BF50D30A1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F47A2C7-1087-440B-82F7-A1BF50D30A1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F47A2C7-1087-440B-82F7-A1BF50D30A1B}.Release|Any CPU.Build.0 = Release|Any CPU
{644AFA6F-7DEE-4438-85C3-1D380B052E3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{644AFA6F-7DEE-4438-85C3-1D380B052E3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{644AFA6F-7DEE-4438-85C3-1D380B052E3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{644AFA6F-7DEE-4438-85C3-1D380B052E3D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {73773200-50D4-40ED-803B-FC16B131FFD2}
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActiveProtect", "ActiveProtect.csproj", "{7138CDD4-EC75-4803-8050-D72A32B381CA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{88B204F0-6636-4265-ACFB-52D889A56413}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActiveProtect.Tests", "src\Tests\ActiveProtect.Tests.csproj", "{55F5BDBE-025D-465B-BB34-2262369715BB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7138CDD4-EC75-4803-8050-D72A32B381CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7138CDD4-EC75-4803-8050-D72A32B381CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7138CDD4-EC75-4803-8050-D72A32B381CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7138CDD4-EC75-4803-8050-D72A32B381CA}.Release|Any CPU.Build.0 = Release|Any CPU
{55F5BDBE-025D-465B-BB34-2262369715BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55F5BDBE-025D-465B-BB34-2262369715BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55F5BDBE-025D-465B-BB34-2262369715BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55F5BDBE-025D-465B-BB34-2262369715BB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{55F5BDBE-025D-465B-BB34-2262369715BB} = {88B204F0-6636-4265-ACFB-52D889A56413}
EndGlobalSection
EndGlobal

View File

@ -1,51 +0,0 @@
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Models
{
/// <summary>
/// 红外告警器类,用于检测红外辐射并发出警报
/// </summary>
public class InfraredWarner : WarnerBase
{
/// <summary>
/// 红外告警器灵敏度阈值
/// </summary>
private readonly double sensitivityThreshold;
public InfraredWarner(string id, Vector3D position, Orientation orientation,
ISimulationManager manager, string tankId, double warningDuration, double sensitivityThreshold)
: base(id, position, orientation, manager, tankId, warningDuration)
{
this.sensitivityThreshold = sensitivityThreshold;
SimulationManager.SubscribeToEvent<InfraredDetectionEvent>(OnInfraredDetection);
}
private void OnInfraredDetection(InfraredDetectionEvent evt)
{
if (evt?.TargetId == TankId && evt.Intensity >= sensitivityThreshold)
{
StartWarning();
}
}
public override string GetWarningStatus()
{
return $"红外告警器 {Id}:\n" +
$" 告警状态: {(IsWarning ? "" : "")}\n" +
$" 告警持续时间: {CurrentWarningTime:F2}/{WarningDuration:F2}";
}
public override void Activate()
{
base.Activate();
SimulationManager.SubscribeToEvent<InfraredDetectionEvent>(OnInfraredDetection);
}
public override void Deactivate()
{
base.Deactivate();
SimulationManager.UnsubscribeFromEvent<InfraredDetectionEvent>(OnInfraredDetection);
}
}
}

View File

@ -1,160 +0,0 @@
using ActiveProtect.Simulation;
using System;
using ActiveProtect.Utility;
namespace ActiveProtect.Models
{
/// <summary>
/// 激光告警器类,用于检测激光照射并发出警报
/// </summary>
public class LaserWarner : SimulationElement
{
/// <summary>
/// 是否正在发出警报
/// </summary>
public bool IsAlarming { get; private set; }
/// <summary>
/// 警报持续时间(秒)
/// </summary>
private readonly double alarmDuration;
/// <summary>
/// 当前警报计时器
/// </summary>
private double alarmTimer = 0;
/// <summary>
/// 被监视实体的ID
/// </summary>
public string MonitoredEntityId { get; private set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="id">激光告警器ID</param>
/// <param name="position">初始位置</param>
/// <param name="orientation">初始朝向</param>
/// <param name="simulationManager">仿真管理器</param>
/// <param name="monitoredEntityId">被监视实体的ID</param>
/// <param name="config">激光告警器配置</param>
public LaserWarner(string id, Vector3D position, Orientation orientation, ISimulationManager simulationManager, string monitoredEntityId, LaserWarnerConfig config)
: base(id, position, orientation, 0, simulationManager)
{
MonitoredEntityId = monitoredEntityId;
IsAlarming = false;
alarmDuration = config.AlarmDuration;
base.SimulationManager.SubscribeToEvent<LaserIlluminationStartEvent>(OnLaserIlluminationStart);
base.SimulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
}
/// <summary>
/// 更新激光告警器状态
/// </summary>
/// <param name="deltaTime">时间步长</param>
public override void Update(double deltaTime)
{
if (!IsActive) return;
var tank = SimulationManager.GetEntityById(MonitoredEntityId) as Tank;
if (tank != null)
{
Position = tank.Position;
Orientation = tank.Orientation;
}
if (IsAlarming)
{
alarmTimer += deltaTime;
if (alarmTimer >= alarmDuration)
{
StopAlarm();
}
}
}
/// <summary>
/// 处理激光照射事件
/// </summary>
/// <param name="evt">激光照射事件</param>
private void OnLaserIlluminationStart(LaserIlluminationStartEvent evt)
{
if (evt?.Target != null && evt.Target.Id == MonitoredEntityId)
{
TriggerAlarm();
}
}
/// <summary>
/// 处理激光照射停止事件
/// </summary>
/// <param name="evt">激光照射停止事件</param>
private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt)
{
if (evt?.Target != null && evt.Target.Id == MonitoredEntityId)
{
StopAlarm();
}
}
/// <summary>
/// 触发警报
/// </summary>
public void TriggerAlarm()
{
if (!IsAlarming)
{
IsAlarming = true;
alarmTimer = 0;
PublishEvent(new LaserWarnerAlarmEvent() { TargetId = MonitoredEntityId });
Console.WriteLine($"激光告警器 {Id} 发出警报!");
}
}
/// <summary>
/// 停止警报
/// </summary>
public void StopAlarm()
{
if (IsAlarming)
{
IsAlarming = false;
alarmTimer = 0;
PublishEvent(new LaserWarnerAlarmStopEvent() { TargetId = MonitoredEntityId });
Console.WriteLine($"激光告警器 {Id} 停止警报");
}
}
/// <summary>
/// 获取激光告警器状态信息
/// </summary>
/// <returns>状态信息字符串</returns>
public override string GetStatus()
{
return $"激光告警器 {Id}:\n" +
$" 监视实体: {MonitoredEntityId}\n" +
$" 警报状态: {(IsAlarming ? "" : "")}\n" +
$" 警报持续时间: {(IsAlarming ? alarmTimer : 0):F2}/{alarmDuration:F2}";
}
/// <summary>
/// 激活激光告警器
/// </summary>
public override void Activate()
{
base.Activate();
SimulationManager.SubscribeToEvent<LaserIlluminationStartEvent>(OnLaserIlluminationStart);
SimulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
}
/// <summary>
/// 停用激光告警器
/// </summary>
public override void Deactivate()
{
base.Deactivate();
SimulationManager.UnsubscribeFromEvent<LaserIlluminationStartEvent>(OnLaserIlluminationStart);
SimulationManager.UnsubscribeFromEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
}
}
}

View File

@ -1,62 +0,0 @@
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Models
{
/// <summary>
/// 毫米波告警器类,用于检测毫米波辐射并发出警报
/// </summary>
public class MillimeterWaveWarner : WarnerBase
{
/// <summary>
/// 毫米波告警器灵敏度阈值
/// </summary>
private readonly double sensitivityThreshold;
/// <summary>
/// 频率范围GHz
/// </summary>
private readonly (double Min, double Max) frequencyRange;
public MillimeterWaveWarner(string id, Vector3D position, Orientation orientation,
ISimulationManager manager, string tankId, double warningDuration,
double sensitivityThreshold, (double Min, double Max) frequencyRange)
: base(id, position, orientation, manager, tankId, warningDuration)
{
this.sensitivityThreshold = sensitivityThreshold;
this.frequencyRange = frequencyRange;
SimulationManager.SubscribeToEvent<MillimeterWaveDetectionEvent>(OnMillimeterWaveDetection);
}
private void OnMillimeterWaveDetection(MillimeterWaveDetectionEvent evt)
{
if (evt?.TargetId == TankId &&
evt.Intensity >= sensitivityThreshold &&
evt.Frequency >= frequencyRange.Min &&
evt.Frequency <= frequencyRange.Max)
{
StartWarning();
}
}
public override string GetWarningStatus()
{
return $"毫米波告警器 {Id}:\n" +
$" 告警状态: {(IsWarning ? "" : "")}\n" +
$" 告警持续时间: {CurrentWarningTime:F2}/{WarningDuration:F2}\n" +
$" 频率范围: {frequencyRange.Min}-{frequencyRange.Max} GHz";
}
public override void Activate()
{
base.Activate();
SimulationManager.SubscribeToEvent<MillimeterWaveDetectionEvent>(OnMillimeterWaveDetection);
}
public override void Deactivate()
{
base.Deactivate();
SimulationManager.UnsubscribeFromEvent<MillimeterWaveDetectionEvent>(OnMillimeterWaveDetection);
}
}
}

View File

@ -0,0 +1,71 @@
using System;
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Models
{
/// <summary>
/// 红外告警器类,用于检测红外辐射并发出警报
/// </summary>
public class InfraredWarner : WarnerBase
{
private readonly double _sensitivityThreshold;
private readonly double _wavelengthMin;
private readonly double _wavelengthMax;
public InfraredWarner(string id, Vector3D position, Orientation orientation,
ISimulationManager manager, string tankId, InfraredWarnerConfig config)
: base(id, position, orientation, manager, tankId, config.SensitivityThreshold,
(config.WavelengthMin, config.WavelengthMax), config.AlarmDuration)
{
_sensitivityThreshold = config.SensitivityThreshold;
_wavelengthMin = config.WavelengthMin;
_wavelengthMax = config.WavelengthMax;
SimulationManager.SubscribeToEvent<InfraredDetectionEvent>(OnInfraredDetection);
}
private void OnInfraredDetection(InfraredDetectionEvent evt)
{
if (evt?.TargetId == TankId && evt.Intensity >= _sensitivityThreshold)
{
StartWarning();
}
}
public override string GetWarningStatus()
{
return $"红外告警器 {Id}:\n" +
$" 告警状态: {(IsWarning ? "" : "")}\n" +
$" 告警持续时间: {CurrentWarningTime:F2}/{WarningDuration:F2}\n" +
$" 波长范围: {_wavelengthMin:F2}-{_wavelengthMax:F2}微米";
}
public override void Update(double deltaTime)
{
base.Update(deltaTime);
if (IsWarning && IsActive)
{
// 发布告警事件
SimulationManager.PublishEvent(new InfraredWarnerAlarmEvent
{
SenderId = Id,
Timestamp = SimulationManager.CurrentTime,
TargetId = TankId
});
}
}
public override void Activate()
{
base.Activate();
SimulationManager.SubscribeToEvent<InfraredDetectionEvent>(OnInfraredDetection);
}
public override void Deactivate()
{
base.Deactivate();
SimulationManager.UnsubscribeFromEvent<InfraredDetectionEvent>(OnInfraredDetection);
}
}
}

View File

@ -0,0 +1,94 @@
using System;
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Models
{
/// <summary>
/// 激光告警器类,用于检测激光照射并发出警报
/// </summary>
public class LaserWarner : WarnerBase
{
/// <summary>
/// 构造函数
/// </summary>
public LaserWarner(string id, Vector3D position, Orientation orientation,
ISimulationManager manager, string tankId, LaserWarnerConfig config)
: base(id, position, orientation, manager, tankId, config.SensitivityThreshold,
(config.WavelengthMin, config.WavelengthMax), config.AlarmDuration)
{
SimulationManager.SubscribeToEvent<LaserIlluminationStartEvent>(OnLaserIlluminationStart);
SimulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
}
/// <summary>
/// 处理激光照射事件
/// </summary>
private void OnLaserIlluminationStart(LaserIlluminationStartEvent evt)
{
// 添加日志以帮助调试
Console.WriteLine($"收到激光照射事件: TargetId={evt?.Target?.Id}, ExpectedId={TankId}");
if (evt?.Target != null && evt.Target.Id == TankId)
{
Console.WriteLine("开始告警");
StartWarning();
}
}
/// <summary>
/// 处理激光照射停止事件
/// </summary>
private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt)
{
// 添加日志以帮助调试
Console.WriteLine($"收到激光照射停止事件: TargetId={evt?.Target?.Id}, ExpectedId={TankId}");
if (evt?.Target != null && evt.Target.Id == TankId)
{
Console.WriteLine("停止告警");
StopWarning();
}
}
/// <summary>
/// 获取告警状态信息
/// </summary>
public override string GetWarningStatus()
{
return $"激光告警器 {Id}:\n" +
$" 告警状态: {(IsWarning ? "" : "")}\n" +
$" 告警持续时间: {CurrentWarningTime:F2}/{WarningDuration:F2}";
}
public override void Activate()
{
base.Activate();
SimulationManager.SubscribeToEvent<LaserIlluminationStartEvent>(OnLaserIlluminationStart);
SimulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
}
public override void Deactivate()
{
base.Deactivate();
SimulationManager.UnsubscribeFromEvent<LaserIlluminationStartEvent>(OnLaserIlluminationStart);
SimulationManager.UnsubscribeFromEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
}
public override void Update(double deltaTime)
{
base.Update(deltaTime);
if (IsWarning)
{
// 发布告警事件
SimulationManager.PublishEvent(new LaserWarnerAlarmEvent
{
SenderId = Id,
Timestamp = SimulationManager.CurrentTime,
TargetId = TankId
});
}
}
}
}

View File

@ -0,0 +1,75 @@
using System;
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Models
{
/// <summary>
/// 毫米波告警器类,用于检测毫米波辐射并发出警报
/// </summary>
public class MillimeterWaveWarner : WarnerBase
{
private readonly double _sensitivityThreshold;
private readonly double _wavelengthMin;
private readonly double _wavelengthMax;
public MillimeterWaveWarner(string id, Vector3D position, Orientation orientation,
ISimulationManager manager, string tankId, MillimeterWaveWarnerConfig config)
: base(id, position, orientation, manager, tankId, config.SensitivityThreshold,
(config.WavelengthMin, config.WavelengthMax), config.AlarmDuration)
{
_sensitivityThreshold = config.SensitivityThreshold;
_wavelengthMin = config.WavelengthMin;
_wavelengthMax = config.WavelengthMax;
SimulationManager.SubscribeToEvent<MillimeterWaveDetectionEvent>(OnMillimeterWaveDetection);
}
private void OnMillimeterWaveDetection(MillimeterWaveDetectionEvent evt)
{
if (evt?.TargetId == TankId &&
evt.Intensity >= _sensitivityThreshold &&
evt.Frequency >= _wavelengthMin &&
evt.Frequency <= _wavelengthMax)
{
StartWarning();
}
}
public override string GetWarningStatus()
{
return $"毫米波告警器 {Id}:\n" +
$" 告警状态: {(IsWarning ? "" : "")}\n" +
$" 告警持续时间: {CurrentWarningTime:F2}/{WarningDuration:F2}\n" +
$" 频率范围: {_wavelengthMin:F2}-{_wavelengthMax:F2}GHz";
}
public override void Update(double deltaTime)
{
base.Update(deltaTime);
if (IsWarning && IsActive)
{
// 发布告警事件
SimulationManager.PublishEvent(new MillimeterWaveWarnerAlarmEvent
{
SenderId = Id,
Timestamp = SimulationManager.CurrentTime,
TargetId = TankId,
DetectedFrequency = (_wavelengthMin + _wavelengthMax) / 2 // 使用中心频率
});
}
}
public override void Activate()
{
base.Activate();
SimulationManager.SubscribeToEvent<MillimeterWaveDetectionEvent>(OnMillimeterWaveDetection);
}
public override void Deactivate()
{
base.Deactivate();
SimulationManager.UnsubscribeFromEvent<MillimeterWaveDetectionEvent>(OnMillimeterWaveDetection);
}
}
}

View File

@ -1,3 +1,4 @@
using System;
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
@ -8,22 +9,24 @@ namespace ActiveProtect.Models
/// </summary>
public class UltravioletWarner : WarnerBase
{
/// <summary>
/// 紫外告警器灵敏度阈值
/// </summary>
private readonly double sensitivityThreshold;
private readonly double _sensitivityThreshold;
private readonly double _wavelengthMin;
private readonly double _wavelengthMax;
public UltravioletWarner(string id, Vector3D position, Orientation orientation,
ISimulationManager manager, string tankId, double warningDuration, double sensitivityThreshold)
: base(id, position, orientation, manager, tankId, warningDuration)
ISimulationManager manager, string tankId, UltravioletWarnerConfig config)
: base(id, position, orientation, manager, tankId, config.SensitivityThreshold,
(config.WavelengthMin, config.WavelengthMax), config.AlarmDuration)
{
this.sensitivityThreshold = sensitivityThreshold;
_sensitivityThreshold = config.SensitivityThreshold;
_wavelengthMin = config.WavelengthMin;
_wavelengthMax = config.WavelengthMax;
SimulationManager.SubscribeToEvent<UltravioletDetectionEvent>(OnUltravioletDetection);
}
private void OnUltravioletDetection(UltravioletDetectionEvent evt)
{
if (evt?.TargetId == TankId && evt.Intensity >= sensitivityThreshold)
if (evt?.TargetId == TankId && evt.Intensity >= _sensitivityThreshold)
{
StartWarning();
}
@ -33,7 +36,24 @@ namespace ActiveProtect.Models
{
return $"紫外告警器 {Id}:\n" +
$" 告警状态: {(IsWarning ? "" : "")}\n" +
$" 告警持续时间: {CurrentWarningTime:F2}/{WarningDuration:F2}";
$" 告警持续时间: {CurrentWarningTime:F2}/{WarningDuration:F2}\n" +
$" 波长范围: {_wavelengthMin:F2}-{_wavelengthMax:F2}纳米";
}
public override void Update(double deltaTime)
{
base.Update(deltaTime);
if (IsWarning && IsActive)
{
// 发布告警事件
SimulationManager.PublishEvent(new UltravioletWarnerAlarmEvent
{
SenderId = Id,
Timestamp = SimulationManager.CurrentTime,
TargetId = TankId
});
}
}
public override void Activate()

View File

@ -14,6 +14,16 @@ namespace ActiveProtect.Models
/// </summary>
public bool IsWarning { get; protected set; }
/// <summary>
/// 告警灵敏度阈值
/// </summary>
protected double SensitivityThreshold { get; set; }
/// <summary>
/// 告警频率范围
/// </summary>
protected (double Min, double Max) FrequencyRange { get; set; }
/// <summary>
/// 告警持续时间(秒)
/// </summary>
@ -30,10 +40,12 @@ namespace ActiveProtect.Models
protected string TankId { get; set; }
protected WarnerBase(string id, Vector3D position, Orientation orientation,
ISimulationManager manager, string tankId, double warningDuration)
ISimulationManager manager, string tankId, double sensitivityThreshold, (double Min, double Max) frequencyRange, double warningDuration)
: base(id, position, orientation, 0, manager)
{
TankId = tankId;
SensitivityThreshold = sensitivityThreshold;
FrequencyRange = frequencyRange;
WarningDuration = warningDuration;
CurrentWarningTime = 0;
IsWarning = false;

View File

@ -165,18 +165,165 @@ namespace ActiveProtect.Simulation
/// </summary>
public string Id { get; set; }
/// <summary>
/// 告警灵敏度阈值
/// </summary>
public double SensitivityThreshold { get; set; }
/// <summary>
/// 警报持续时间(秒)
/// </summary>
public double AlarmDuration { get; set; }
/// <summary>
/// 最小波长(纳米)
/// </summary>
public double WavelengthMin { get; set; }
/// <summary>
/// 最大波长(纳米)
/// </summary>
public double WavelengthMax { get; set; }
/// <summary>
/// 构造函数,设置默认值
/// </summary>
public LaserWarnerConfig()
{
Id = "";
SensitivityThreshold = 0;
AlarmDuration = 5.0; // 默认警报持续5秒
WavelengthMin = 0;
WavelengthMax = 0;
}
}
/// <summary>
/// 紫外线告警器配置类
/// </summary>
public class UltravioletWarnerConfig
{
/// <summary>
/// 紫外线告警器ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 告警灵敏度阈值
/// </summary>
public double SensitivityThreshold { get; set; }
/// <summary>
/// 警报持续时间(秒)
/// </summary>
public double AlarmDuration { get; set; }
/// <summary>
/// 波长范围(纳米)
/// </summary>
public double WavelengthMin { get; set; }
/// <summary>
/// 最大波长(纳米)
/// </summary>
public double WavelengthMax { get; set; }
/// <summary>
/// 构造函数,设置默认值
/// </summary>
public UltravioletWarnerConfig()
{
Id = "";
SensitivityThreshold = 0;
AlarmDuration = 5.0; // 默认警报持续5秒
WavelengthMin = 0;
WavelengthMax = 0;
}
}
/// <summary>
/// 红外告警器配置类
/// </summary>
public class InfraredWarnerConfig
{
/// <summary>
/// 红外告警器ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 告警灵敏度阈值
/// </summary>
public double SensitivityThreshold { get; set; }
/// <summary>
/// 警报持续时间(秒)
/// </summary>
public double AlarmDuration { get; set; }
/// <summary>
/// 最小波长(纳米)
/// </summary>
public double WavelengthMin { get; set; }
/// <summary>
/// 最大波长(纳米)
/// </summary>
public double WavelengthMax { get; set; }
/// <summary>
/// 构造函数,设置默认值
/// </summary>
public InfraredWarnerConfig()
{
Id = "";
SensitivityThreshold = 0;
AlarmDuration = 5.0; // 默认警报持续5秒
WavelengthMin = 0;
WavelengthMax = 0;
}
}
/// <summary>
/// 毫米波告警器配置类
/// </summary>
public class MillimeterWaveWarnerConfig
{
/// <summary>
/// 毫米波告警器ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 告警灵敏度阈值
/// </summary>
public double SensitivityThreshold { get; set; }
/// <summary>
/// 警报持续时间(秒)
/// </summary>
public double AlarmDuration { get; set; }
/// <summary>
/// 波长范围(纳米)
/// </summary>
public double WavelengthMin { get; set; }
/// <summary>
/// 最大波长(纳米)
/// </summary>
public double WavelengthMax { get; set; }
/// <summary>
/// 构造函数,设置默认值
/// </summary>
public MillimeterWaveWarnerConfig()
{
Id = "";
SensitivityThreshold = 0;
AlarmDuration = 5.0; // 默认警报持续5秒
WavelengthMin = 0;
WavelengthMax = 0;
}
}

View File

@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>9.0</LangVersion>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Moq" Version="4.18.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\ActiveProtect.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Remove="obj\**" />
<EmbeddedResource Remove="obj\**" />
<None Remove="obj\**" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,167 @@
using Xunit;
using Moq;
using System;
using System.Linq;
using ActiveProtect.Models;
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Tests.Unit.Models.Jammer
{
public class InfraredJammerTests : IDisposable
{
private readonly Mock<ISimulationManager> _mockSimManager;
private readonly InfraredJammer _jammer;
private readonly string _jammerId = "TestJammer";
private readonly string _tankId = "TestTank";
public InfraredJammerTests()
{
// 设置测试环境
_mockSimManager = new Mock<ISimulationManager>();
_mockSimManager.Setup(m => m.CurrentTime).Returns(0.0);
// 设置事件发布
_mockSimManager.Setup(m => m.PublishEvent(It.IsAny<SimulationEvent>()));
_jammer = new InfraredJammer(
_jammerId,
new Vector3D(0, 0, 0),
new Orientation(),
_mockSimManager.Object,
_tankId,
maxJammingPower: 1000.0,
initialJammingPower: 400.0,
powerIncreaseRate: 100.0,
maxCooldownTime: 5.0,
wavelengthRange: (3.0, 5.0)
);
}
public void Dispose()
{
// 清理资源
_jammer.Deactivate();
}
[Fact]
public void Constructor_InitializesCorrectly()
{
Assert.Equal(_jammerId, _jammer.Id);
Assert.False(_jammer.IsJamming);
Assert.Equal(400.0, _jammer.CurrentJammingPower);
}
[Fact]
public void StartJamming_WhenNotJamming_StartsJamming()
{
// Act
_jammer.StartJamming();
// Assert
Assert.True(_jammer.IsJamming);
}
[Fact]
public void StopJamming_WhenJamming_StopsAndEntersCooldown()
{
// Arrange
_jammer.StartJamming();
// Act
_jammer.StopJamming();
// Assert
Assert.False(_jammer.IsJamming);
Assert.Equal(400.0, _jammer.CurrentJammingPower); // 重置为初始功率
}
[Theory]
[InlineData(1.0, 500.0)] // 1秒后功率增加100
[InlineData(2.0, 600.0)] // 2秒后功率增加200
[InlineData(10.0, 1000.0)] // 10秒后达到最大功率1000
public void Update_WhenJamming_IncreasesPowerCorrectly(double deltaTime, double expectedPower)
{
// Arrange
_jammer.StartJamming();
_jammer.Activate(); // 确保激活状态
// Act
_jammer.Update(deltaTime);
// Assert
Assert.Equal(expectedPower, _jammer.CurrentJammingPower, 1); // 允许1瓦特的误差
}
[Fact]
public void OnInfraredWarnerAlarm_StartsJamming()
{
// Arrange
Action<InfraredWarnerAlarmEvent>? eventHandler = null;
_mockSimManager.Setup(m => m.SubscribeToEvent(It.IsAny<Action<InfraredWarnerAlarmEvent>>()))
.Callback<Action<InfraredWarnerAlarmEvent>>(handler => eventHandler = handler);
// 激活干扰器以触发事件订阅
_jammer.Activate();
// 确保事件处理程序被设置
Assert.NotNull(eventHandler);
// Act
eventHandler?.Invoke(new InfraredWarnerAlarmEvent { TargetId = _tankId });
// Assert
Assert.True(_jammer.IsJamming);
}
[Fact]
public void Update_PublishesJammingEvent()
{
// Arrange
_jammer.StartJamming();
_jammer.Activate();
// Act
_jammer.Update(1.0);
// Assert
_mockSimManager.Verify(m => m.PublishEvent(It.Is<InfraredJammingEvent>(e =>
e.TargetId == _tankId &&
Math.Abs(e.JammingPower - 500.0) < 1 &&
e.WavelengthMin == 3.0 &&
e.WavelengthMax == 5.0
)), Times.Once);
}
[Fact]
public void GetJammingStatus_ReturnsCorrectFormat()
{
// Arrange
_jammer.StartJamming();
// Act
string status = _jammer.GetJammingStatus();
// Assert
Assert.Contains("红外干扰器", status);
Assert.Contains("干扰中", status);
Assert.Contains("400.00/1000.00", status);
Assert.Contains("3.00-5.00微米", status);
}
[Fact]
public void Deactivate_UnsubscribesFromEvents()
{
// Act
_jammer.Deactivate();
// Assert
_mockSimManager.Verify(
m => m.UnsubscribeFromEvent<InfraredWarnerAlarmEvent>(It.IsAny<Action<InfraredWarnerAlarmEvent>>()),
Times.Once);
_mockSimManager.Verify(
m => m.UnsubscribeFromEvent<InfraredWarnerAlarmStopEvent>(It.IsAny<Action<InfraredWarnerAlarmStopEvent>>()),
Times.Once);
}
}
}

View File

@ -0,0 +1,161 @@
using Xunit;
using Moq;
using System;
using ActiveProtect.Models;
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Tests.Unit.Models.Warner
{
public class InfraredWarnerTests : IDisposable
{
private readonly Mock<ISimulationManager> _mockSimManager;
private readonly InfraredWarner _warner;
private readonly string _warnerId = "TestInfraredWarner";
private readonly string _tankId = "TestTank";
private readonly InfraredWarnerConfig _config;
public InfraredWarnerTests()
{
_mockSimManager = new Mock<ISimulationManager>();
_mockSimManager.Setup(m => m.CurrentTime).Returns(0.0);
_mockSimManager.Setup(m => m.PublishEvent(It.IsAny<SimulationEvent>()));
_config = new InfraredWarnerConfig
{
AlarmDuration = 5.0,
SensitivityThreshold = 0.1,
WavelengthMin = 3.0,
WavelengthMax = 5.0
};
_warner = new InfraredWarner(
_warnerId,
new Vector3D(0, 0, 0),
new Orientation(0, 0, 0),
_mockSimManager.Object,
_tankId,
_config
);
}
public void Dispose()
{
_warner.Deactivate();
}
[Fact]
public void Constructor_InitializesCorrectly()
{
Assert.Equal(_warnerId, _warner.Id);
Assert.False(_warner.IsWarning);
}
[Fact]
public void StartWarning_WhenNotWarning_StartsWarning()
{
// Act
_warner.StartWarning();
// Assert
Assert.True(_warner.IsWarning);
}
[Fact]
public void StopWarning_WhenWarning_StopsWarning()
{
// Arrange
_warner.StartWarning();
// Act
_warner.StopWarning();
// Assert
Assert.False(_warner.IsWarning);
}
[Fact]
public void Update_WhenWarningTimeExceeded_StopsWarning()
{
// Arrange
_warner.Activate();
_warner.StartWarning();
// Act
_warner.Update(6.0); // 超过警报持续时间
// Assert
Assert.False(_warner.IsWarning);
}
[Theory]
[InlineData(0.2, true)] // 高于阈值,应该触发
[InlineData(0.05, false)] // 低于阈值,不应该触发
public void OnInfraredDetection_RespondsToIntensityThreshold(double intensity, bool shouldTrigger)
{
// Arrange
Action<InfraredDetectionEvent>? eventHandler = null;
_mockSimManager.Setup(m => m.SubscribeToEvent(It.IsAny<Action<InfraredDetectionEvent>>()))
.Callback<Action<InfraredDetectionEvent>>(handler => eventHandler = handler);
_warner.Activate();
Assert.NotNull(eventHandler);
var detectionEvent = new InfraredDetectionEvent
{
TargetId = _tankId,
Intensity = intensity
};
// Act
eventHandler?.Invoke(detectionEvent);
// Assert
Assert.Equal(shouldTrigger, _warner.IsWarning);
}
[Fact]
public void GetWarningStatus_ReturnsCorrectFormat()
{
// Arrange
_warner.StartWarning();
// Act
string status = _warner.GetWarningStatus();
// Assert
Assert.Contains("红外告警器", status);
Assert.Contains("告警中", status);
Assert.Contains("3.00-5.00微米", status);
}
[Fact]
public void Update_PublishesWarningEvent_WhenWarning()
{
// Arrange
_warner.StartWarning();
_warner.Activate();
// Act
_warner.Update(1.0);
// Assert
_mockSimManager.Verify(m => m.PublishEvent(It.Is<InfraredWarnerAlarmEvent>(e =>
e.TargetId == _tankId
)), Times.Once);
}
[Fact]
public void Deactivate_UnsubscribesFromEvents()
{
// Act
_warner.Deactivate();
// Assert
_mockSimManager.Verify(
m => m.UnsubscribeFromEvent<InfraredDetectionEvent>(
It.IsAny<Action<InfraredDetectionEvent>>()),
Times.Once);
}
}
}

View File

@ -0,0 +1,204 @@
using Xunit;
using Moq;
using System;
using ActiveProtect.Models;
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Tests.Unit.Models.Warner
{
public class LaserWarnerTests : IDisposable
{
private readonly Mock<ISimulationManager> _mockSimManager;
private readonly LaserWarner _warner;
private readonly string _warnerId = "TestLaserWarner";
private readonly string _tankId = "TestTank";
private readonly LaserWarnerConfig _config;
public LaserWarnerTests()
{
_mockSimManager = new Mock<ISimulationManager>();
_mockSimManager.Setup(m => m.CurrentTime).Returns(0.0);
_mockSimManager.Setup(m => m.PublishEvent(It.IsAny<SimulationEvent>()));
_config = new LaserWarnerConfig
{
AlarmDuration = 5.0,
};
_warner = new LaserWarner(
_warnerId,
new Vector3D(0, 0, 0),
new Orientation(0, 0, 0),
_mockSimManager.Object,
_tankId,
_config
);
}
public void Dispose()
{
_warner.Deactivate();
}
[Fact]
public void Constructor_InitializesCorrectly()
{
Assert.Equal(_warnerId, _warner.Id);
Assert.False(_warner.IsWarning);
}
[Fact]
public void StartWarning_WhenNotWarning_StartsWarning()
{
// Act
_warner.StartWarning();
// Assert
Assert.True(_warner.IsWarning);
}
[Fact]
public void StopWarning_WhenWarning_StopsWarning()
{
// Arrange
_warner.StartWarning();
// Act
_warner.StopWarning();
// Assert
Assert.False(_warner.IsWarning);
}
[Fact]
public void Update_WhenWarningTimeExceeded_StopsWarning()
{
// Arrange
_warner.Activate();
_warner.StartWarning();
// Act
_warner.Update(6.0); // 超过警报持续时间
// Assert
Assert.False(_warner.IsWarning);
}
[Fact]
public void OnLaserIllumination_StartsWarning()
{
// Arrange
Action<LaserIlluminationStartEvent>? eventHandler = null;
_mockSimManager.Setup(m => m.SubscribeToEvent(It.IsAny<Action<LaserIlluminationStartEvent>>()))
.Callback<Action<LaserIlluminationStartEvent>>(handler => eventHandler = handler);
_warner.Activate();
Assert.NotNull(eventHandler);
// 创建一个模拟的目标
var mockTarget = new Mock<SimulationElement>(_tankId,
new Vector3D(0, 0, 0),
new Orientation(0, 0, 0),
0,
_mockSimManager.Object);
// 设置模拟对象的 Id 属性
mockTarget.Setup(t => t.Id).Returns(_tankId);
var illuminationEvent = new LaserIlluminationStartEvent
{
Target = mockTarget.Object,
SenderId = "TestLaser" // 添加发送者ID
};
// Act
eventHandler?.Invoke(illuminationEvent);
// Assert
Assert.True(_warner.IsWarning);
}
[Fact]
public void OnLaserIlluminationStop_StopsWarning()
{
// Arrange
Action<LaserIlluminationStopEvent>? eventHandler = null;
_mockSimManager.Setup(m => m.SubscribeToEvent(It.IsAny<Action<LaserIlluminationStopEvent>>()))
.Callback<Action<LaserIlluminationStopEvent>>(handler => eventHandler = handler);
_warner.Activate();
_warner.StartWarning();
Assert.NotNull(eventHandler);
// 创建一个模拟的目标
var mockTarget = new Mock<SimulationElement>(_tankId,
new Vector3D(0, 0, 0),
new Orientation(0, 0, 0),
0,
_mockSimManager.Object);
// 设置模拟对象的 Id 属性
mockTarget.Setup(t => t.Id).Returns(_tankId);
var illuminationStopEvent = new LaserIlluminationStopEvent
{
Target = mockTarget.Object,
SenderId = "TestLaser" // 添加发送者ID
};
// Act
eventHandler?.Invoke(illuminationStopEvent);
// Assert
Assert.False(_warner.IsWarning);
}
[Fact]
public void GetWarningStatus_ReturnsCorrectFormat()
{
// Arrange
_warner.StartWarning();
// Act
string status = _warner.GetWarningStatus();
// Assert
Assert.Contains("激光告警器", status);
Assert.Contains("告警中", status);
}
[Fact]
public void Update_PublishesWarningEvent_WhenWarning()
{
// Arrange
_warner.StartWarning();
_warner.Activate();
// Act
_warner.Update(1.0);
// Assert
_mockSimManager.Verify(m => m.PublishEvent(It.Is<LaserWarnerAlarmEvent>(e =>
e.TargetId == _tankId
)), Times.Once);
}
[Fact]
public void Deactivate_UnsubscribesFromEvents()
{
// Act
_warner.Deactivate();
// Assert
_mockSimManager.Verify(
m => m.UnsubscribeFromEvent<LaserIlluminationStartEvent>(
It.IsAny<Action<LaserIlluminationStartEvent>>()),
Times.Once);
_mockSimManager.Verify(
m => m.UnsubscribeFromEvent<LaserIlluminationStopEvent>(
It.IsAny<Action<LaserIlluminationStopEvent>>()),
Times.Once);
}
}
}

View File

@ -0,0 +1,150 @@
using Xunit;
using Moq;
using System;
using ActiveProtect.Models;
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Tests.Unit.Models.Warner
{
public class MillimeterWaveWarnerTests : IDisposable
{
private readonly Mock<ISimulationManager> _mockSimManager;
private readonly MillimeterWaveWarner _warner;
private readonly string _warnerId = "TestMMWWarner";
private readonly string _tankId = "TestTank";
private readonly MillimeterWaveWarnerConfig _config;
public MillimeterWaveWarnerTests()
{
_mockSimManager = new Mock<ISimulationManager>();
_mockSimManager.Setup(m => m.CurrentTime).Returns(0.0);
_mockSimManager.Setup(m => m.PublishEvent(It.IsAny<SimulationEvent>()));
_config = new MillimeterWaveWarnerConfig
{
AlarmDuration = 5.0,
SensitivityThreshold = 0.1,
WavelengthMin = 30.0, // 30 GHz
WavelengthMax = 300.0 // 300 GHz
};
_warner = new MillimeterWaveWarner(
_warnerId,
new Vector3D(0, 0, 0),
new Orientation(0, 0, 0),
_mockSimManager.Object,
_tankId,
_config
);
}
public void Dispose()
{
_warner.Deactivate();
}
[Fact]
public void Constructor_InitializesCorrectly()
{
Assert.Equal(_warnerId, _warner.Id);
Assert.False(_warner.IsWarning);
}
[Fact]
public void StartWarning_WhenNotWarning_StartsWarning()
{
// Act
_warner.StartWarning();
// Assert
Assert.True(_warner.IsWarning);
}
[Fact]
public void StopWarning_WhenWarning_StopsWarning()
{
// Arrange
_warner.StartWarning();
// Act
_warner.StopWarning();
// Assert
Assert.False(_warner.IsWarning);
}
[Theory]
[InlineData(0.2, 100.0, true)] // 高于阈值,频率在范围内
[InlineData(0.05, 100.0, false)] // 低于阈值,频率在范围内
[InlineData(0.2, 400.0, false)] // 高于阈值,频率超出范围
public void OnMillimeterWaveDetection_RespondsToThresholds(
double intensity, double frequency, bool shouldTrigger)
{
// Arrange
Action<MillimeterWaveDetectionEvent>? eventHandler = null;
_mockSimManager.Setup(m => m.SubscribeToEvent(It.IsAny<Action<MillimeterWaveDetectionEvent>>()))
.Callback<Action<MillimeterWaveDetectionEvent>>(handler => eventHandler = handler);
_warner.Activate();
Assert.NotNull(eventHandler);
var detectionEvent = new MillimeterWaveDetectionEvent
{
TargetId = _tankId,
Intensity = intensity,
Frequency = frequency
};
// Act
eventHandler?.Invoke(detectionEvent);
// Assert
Assert.Equal(shouldTrigger, _warner.IsWarning);
}
[Fact]
public void GetWarningStatus_ReturnsCorrectFormat()
{
// Arrange
_warner.StartWarning();
// Act
string status = _warner.GetWarningStatus();
// Assert
Assert.Contains("毫米波告警器", status);
Assert.Contains("告警中", status);
Assert.Contains("30.00-300.00GHz", status);
}
[Fact]
public void Update_PublishesWarningEvent_WhenWarning()
{
// Arrange
_warner.StartWarning();
_warner.Activate();
// Act
_warner.Update(1.0);
// Assert
_mockSimManager.Verify(m => m.PublishEvent(It.Is<MillimeterWaveWarnerAlarmEvent>(e =>
e.TargetId == _tankId
)), Times.Once);
}
[Fact]
public void Deactivate_UnsubscribesFromEvents()
{
// Act
_warner.Deactivate();
// Assert
_mockSimManager.Verify(
m => m.UnsubscribeFromEvent<MillimeterWaveDetectionEvent>(
It.IsAny<Action<MillimeterWaveDetectionEvent>>()),
Times.Once);
}
}
}

View File

@ -0,0 +1,161 @@
using Xunit;
using Moq;
using System;
using ActiveProtect.Models;
using ActiveProtect.Simulation;
using ActiveProtect.Utility;
namespace ActiveProtect.Tests.Unit.Models.Warner
{
public class UltravioletWarnerTests : IDisposable
{
private readonly Mock<ISimulationManager> _mockSimManager;
private readonly UltravioletWarner _warner;
private readonly string _warnerId = "TestUVWarner";
private readonly string _tankId = "TestTank";
private readonly UltravioletWarnerConfig _config;
public UltravioletWarnerTests()
{
_mockSimManager = new Mock<ISimulationManager>();
_mockSimManager.Setup(m => m.CurrentTime).Returns(0.0);
_mockSimManager.Setup(m => m.PublishEvent(It.IsAny<SimulationEvent>()));
_config = new UltravioletWarnerConfig
{
AlarmDuration = 5.0,
SensitivityThreshold = 0.1,
WavelengthMin = 200.0,
WavelengthMax = 280.0
};
_warner = new UltravioletWarner(
_warnerId,
new Vector3D(0, 0, 0),
new Orientation(0, 0, 0),
_mockSimManager.Object,
_tankId,
_config
);
}
public void Dispose()
{
_warner.Deactivate();
}
[Fact]
public void Constructor_InitializesCorrectly()
{
Assert.Equal(_warnerId, _warner.Id);
Assert.False(_warner.IsWarning);
}
[Fact]
public void StartWarning_WhenNotWarning_StartsWarning()
{
// Act
_warner.StartWarning();
// Assert
Assert.True(_warner.IsWarning);
}
[Fact]
public void StopWarning_WhenWarning_StopsWarning()
{
// Arrange
_warner.StartWarning();
// Act
_warner.StopWarning();
// Assert
Assert.False(_warner.IsWarning);
}
[Fact]
public void Update_WhenWarningTimeExceeded_StopsWarning()
{
// Arrange
_warner.Activate();
_warner.StartWarning();
// Act
_warner.Update(6.0); // 超过警报持续时间
// Assert
Assert.False(_warner.IsWarning);
}
[Theory]
[InlineData(0.2, true)] // 高于阈值,应该触发
[InlineData(0.05, false)] // 低于阈值,不应该触发
public void OnUltravioletDetection_RespondsToIntensityThreshold(double intensity, bool shouldTrigger)
{
// Arrange
Action<UltravioletDetectionEvent>? eventHandler = null;
_mockSimManager.Setup(m => m.SubscribeToEvent(It.IsAny<Action<UltravioletDetectionEvent>>()))
.Callback<Action<UltravioletDetectionEvent>>(handler => eventHandler = handler);
_warner.Activate();
Assert.NotNull(eventHandler);
var detectionEvent = new UltravioletDetectionEvent
{
TargetId = _tankId,
Intensity = intensity
};
// Act
eventHandler?.Invoke(detectionEvent);
// Assert
Assert.Equal(shouldTrigger, _warner.IsWarning);
}
[Fact]
public void GetWarningStatus_ReturnsCorrectFormat()
{
// Arrange
_warner.StartWarning();
// Act
string status = _warner.GetWarningStatus();
// Assert
Assert.Contains("紫外告警器", status);
Assert.Contains("告警中", status);
Assert.Contains("200.00-280.00纳米", status);
}
[Fact]
public void Update_PublishesWarningEvent_WhenWarning()
{
// Arrange
_warner.StartWarning();
_warner.Activate();
// Act
_warner.Update(1.0);
// Assert
_mockSimManager.Verify(m => m.PublishEvent(It.Is<UltravioletWarnerAlarmEvent>(e =>
e.TargetId == _tankId
)), Times.Once);
}
[Fact]
public void Deactivate_UnsubscribesFromEvents()
{
// Act
_warner.Deactivate();
// Assert
_mockSimManager.Verify(
m => m.UnsubscribeFromEvent<UltravioletDetectionEvent>(
It.IsAny<Action<UltravioletDetectionEvent>>()),
Times.Once);
}
}
}