125 lines
4.5 KiB
C#
125 lines
4.5 KiB
C#
using System.Collections.Generic;
|
|
using CounterDrone.Core.Models;
|
|
using CounterDrone.Core.Simulation;
|
|
using Xunit;
|
|
|
|
namespace CounterDrone.Core.Tests
|
|
{
|
|
public class DroneEntityTests
|
|
{
|
|
private TargetConfig CreateConfig(float speed = 120, float altitude = 300)
|
|
{
|
|
return new TargetConfig
|
|
{
|
|
TargetType = (int)TargetType.Piston,
|
|
PowerType = (int)PowerType.Piston,
|
|
TypicalSpeed = speed,
|
|
TypicalAltitude = altitude,
|
|
Wingspan = 2.5,
|
|
Quantity = 1,
|
|
};
|
|
}
|
|
|
|
private List<Waypoint> CreateRoute(float fromX, float toX, float altitude, float speed)
|
|
{
|
|
return new List<Waypoint>
|
|
{
|
|
new Waypoint { PosX = fromX, PosY = altitude, PosZ = 0, Altitude = altitude, Speed = speed },
|
|
new Waypoint { PosX = toX, PosY = altitude, PosZ = 0, Altitude = altitude, Speed = speed },
|
|
};
|
|
}
|
|
|
|
[Fact]
|
|
public void InitialPosition_IsFirstWaypoint()
|
|
{
|
|
var route = CreateRoute(100, 500, 300, 120);
|
|
var drone = new DroneEntity("d1", "g1", CreateConfig(), route, 0, 50, FormationMode.Single);
|
|
|
|
Assert.Equal(100, drone.PosX, 1);
|
|
Assert.Equal(300, drone.PosY, 1); // 高度 = waypoint.PosY
|
|
}
|
|
|
|
[Fact]
|
|
public void Update_MovesTowardTarget()
|
|
{
|
|
var route = CreateRoute(0, 1000, 300, 120);
|
|
var drone = new DroneEntity("d1", "g1", CreateConfig(), route, 0, 50, FormationMode.Single);
|
|
|
|
float prevX = drone.PosX;
|
|
drone.Update(1f, 0, WindDirection.N);
|
|
|
|
Assert.True(drone.PosX > prevX, "无人机应向目标移动");
|
|
}
|
|
|
|
[Fact]
|
|
public void Update_ReachesTarget_StatusChanges()
|
|
{
|
|
var route = CreateRoute(0, 100, 300, 360); // 360 km/h = 100 m/s
|
|
var drone = new DroneEntity("d1", "g1", CreateConfig(360), route, 0, 50, FormationMode.Single);
|
|
|
|
// 100m 距离, 100m/s 速度, 1s 后应到达
|
|
drone.Update(2f, 0, WindDirection.N);
|
|
|
|
Assert.Equal(DroneStatus.ReachedTarget, drone.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public void ApplyDamage_ReducesHp()
|
|
{
|
|
var drone = new DroneEntity("d1", "g1", CreateConfig(),
|
|
CreateRoute(0, 100, 300, 60), 0, 50, FormationMode.Single);
|
|
|
|
drone.ApplyDamage(0.4f);
|
|
Assert.Equal(0.6f, drone.Hp, 0.01f);
|
|
Assert.Equal(DroneStatus.Flying, drone.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public void ApplyDamage_ExceedingHp_DestroysDrone()
|
|
{
|
|
var drone = new DroneEntity("d1", "g1", CreateConfig(),
|
|
CreateRoute(0, 100, 300, 60), 0, 50, FormationMode.Single);
|
|
|
|
drone.ApplyDamage(1.5f);
|
|
Assert.True(drone.Hp <= 0);
|
|
Assert.Equal(DroneStatus.Destroyed, drone.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public void Formation_YOffsetsDiffer()
|
|
{
|
|
var route = CreateRoute(0, 100, 300, 60);
|
|
var d0 = new DroneEntity("d0", "g1", CreateConfig(), route, 0, 50, FormationMode.Formation);
|
|
var d1 = new DroneEntity("d1", "g1", CreateConfig(), route, 1, 50, FormationMode.Formation);
|
|
|
|
Assert.NotEqual(d0.PosY, d1.PosY);
|
|
}
|
|
|
|
[Fact]
|
|
public void Swarm_ProducesRandomOffsets()
|
|
{
|
|
var route = CreateRoute(0, 100, 300, 60);
|
|
var d0 = new DroneEntity("d0", "g1", CreateConfig(), route, 0, 50, FormationMode.Swarm);
|
|
var d1 = new DroneEntity("d1", "g1", CreateConfig(), route, 1, 50, FormationMode.Swarm);
|
|
var d2 = new DroneEntity("d2", "g1", CreateConfig(), route, 2, 50, FormationMode.Swarm);
|
|
|
|
// 蜂群模式:三架无人机位置应各不相同
|
|
Assert.True(d0.PosX != d1.PosX || d0.PosY != d1.PosY, "蜂群应有位置差异");
|
|
Assert.True(d1.PosX != d2.PosX || d1.PosY != d2.PosY, "蜂群应有位置差异");
|
|
}
|
|
|
|
[Fact]
|
|
public void Wind_AffectsPosition()
|
|
{
|
|
var route = CreateRoute(0, 1000, 300, 60);
|
|
var drone = new DroneEntity("d1", "g1", CreateConfig(), route, 0, 50, FormationMode.Single);
|
|
|
|
float xBefore = drone.PosX;
|
|
drone.Update(1f, 20f, WindDirection.E); // 东风 20m/s
|
|
|
|
// 东风 → +X 方向偏移
|
|
Assert.True(drone.PosX > xBefore + 15f, "东风应显著增加 X 位移");
|
|
}
|
|
}
|
|
}
|