CounterDroneBackend/test/unit/CounterDrone.Core.Tests/DroneEntityTests.cs
tian 070167f572 fix: 编队偏移持久化到航点 + yLanes=Quantity + 云Z展开
- DroneEntity: 偏移写入克隆航点List而非位置字段
- Planner: 车道数=无人机数, laneSpacingZ=LateralSpacing
- 200m间距: 33发, 2/3击毁, 第三架hp=0.10边缘效应
2026-06-13 15:03:44 +08:00

135 lines
5.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.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 alt, float speed)
{
return new List<Waypoint>
{
new() { PosX = fromX, PosY = alt, PosZ = 0, Altitude = alt, Speed = speed },
new() { PosX = toX, PosY = alt, PosZ = 0, Altitude = alt, Speed = speed },
};
}
[Fact]
public void InitialPosition_IsFirstWaypoint()
{
var drone = new DroneEntity("d1", "g1", CreateConfig(),
CreateRoute(100, 500, 300, 120), 0, 50, 0, 0, FormationMode.Single);
Assert.Equal(100, drone.PosX, 1);
Assert.Equal(300, drone.PosY, 1);
}
[Fact]
public void Update_MovesTowardTarget()
{
var drone = new DroneEntity("d1", "g1", CreateConfig(),
CreateRoute(0, 1000, 300, 120), 0, 50, 0, 0, FormationMode.Single);
float prevX = drone.PosX;
drone.Update(1f, 0, WindDirection.N);
Assert.True(drone.PosX > prevX);
}
[Fact]
public void Update_ReachesTarget_StatusChanges()
{
var drone = new DroneEntity("d1", "g1", CreateConfig(360),
CreateRoute(0, 100, 300, 360), 0, 50, 0, 0, FormationMode.Single);
drone.Update(2f, 0, WindDirection.N);
Assert.Equal(DroneStatus.ReachedTarget, drone.Status);
}
[Fact]
public void Damage_ReducesHp()
{
var drone = new DroneEntity("d1", "g1", CreateConfig(),
CreateRoute(0, 100, 300, 60), 0, 50, 0, 0, FormationMode.Single);
drone.ApplyDamage(0.4f);
Assert.Equal(0.6f, drone.Hp, 0.01f);
}
[Fact]
public void Damage_ExceedingHp_Destroys()
{
var drone = new DroneEntity("d1", "g1", CreateConfig(),
CreateRoute(0, 100, 300, 60), 0, 50, 0, 0, FormationMode.Single);
drone.ApplyDamage(1.5f);
Assert.True(drone.Hp <= 0);
Assert.Equal(DroneStatus.Destroyed, drone.Status);
}
[Fact]
public void Wind_AffectsPosition()
{
var drone = new DroneEntity("d1", "g1", CreateConfig(),
CreateRoute(0, 1000, 300, 60), 0, 50, 0, 0, FormationMode.Single);
float xBefore = drone.PosX;
drone.Update(1f, 20f, WindDirection.E);
Assert.True(drone.PosX > xBefore + 15f);
}
[Fact]
public void Formation_Lateral_ZOffsetsDiffer()
{
var route = CreateRoute(0, 100, 300, 60);
var d0 = new DroneEntity("d0", "g1", CreateConfig(), route, 0, 50, 0, 0, FormationMode.Formation);
var d1 = new DroneEntity("d1", "g1", CreateConfig(), route, 1, 50, 0, 0, FormationMode.Formation);
var d2 = new DroneEntity("d2", "g1", CreateConfig(), route, 2, 50, 0, 0, FormationMode.Formation);
// 起始Z不同
Assert.NotEqual(d0.PosZ, d1.PosZ);
Assert.NotEqual(d1.PosZ, d2.PosZ);
// 航点Z不同偏移持久化到航点
Assert.NotEqual(d0.Route[0].PosZ, d1.Route[0].PosZ);
Assert.NotEqual(d0.Route[1].PosZ, d1.Route[1].PosZ);
}
[Fact]
public void Formation_Longitudinal_XOffsetsDiffer()
{
var route = CreateRoute(0, 100, 300, 60);
var d0 = new DroneEntity("d0", "g1", CreateConfig(), route, 0, 0, 0, 100, FormationMode.Formation);
var d1 = new DroneEntity("d1", "g1", CreateConfig(), route, 0, 0, 1, 100, FormationMode.Formation);
Assert.NotEqual(d0.PosX, d1.PosX);
}
[Fact]
public void Formation_Mixed_2x2()
{
var route = CreateRoute(0, 100, 300, 60);
var d0 = new DroneEntity("d0", "g1", CreateConfig(), route, 0, 50, 0, 100, FormationMode.Formation);
var d1 = new DroneEntity("d1", "g1", CreateConfig(), route, 1, 50, 0, 100, FormationMode.Formation);
var d2 = new DroneEntity("d2", "g1", CreateConfig(), route, 0, 50, 1, 100, FormationMode.Formation);
var d3 = new DroneEntity("d3", "g1", CreateConfig(), route, 1, 50, 1, 100, FormationMode.Formation);
Assert.NotEqual(d0.PosZ, d1.PosZ); // lateral
Assert.NotEqual(d0.PosX, d2.PosX); // longitudinal
}
[Fact]
public void Swarm_ProducesRandomOffsets()
{
var route = CreateRoute(0, 100, 300, 60);
var d0 = new DroneEntity("d0", "g1", CreateConfig(), route, 0, 30, 0, 0, FormationMode.Swarm);
var d1 = new DroneEntity("d1", "g1", CreateConfig(), route, 1, 30, 0, 0, FormationMode.Swarm);
Assert.True(d0.PosX != d1.PosX || d0.PosZ != d1.PosZ);
}
}
}