From 48368e0fe85f021b5c11a9f0f3f178d04f4e0b44 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Sat, 13 Jun 2026 19:09:29 +0800 Subject: [PATCH] =?UTF-8?q?test:=20DamageAssessment=205=E9=A1=B9=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95=E9=AA=8C=E8=AF=81=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E7=A7=AF=E5=88=86=E6=AD=A3=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 单云穿心/两云相邻/9云链/两云有间隙/两点跨云 --- .../DamageAssessmentTests.cs | 79 +++++++++++++++++++ .../KinematicsTests.cs | 49 ++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 test/unit/CounterDrone.Core.Tests/DamageAssessmentTests.cs diff --git a/test/unit/CounterDrone.Core.Tests/DamageAssessmentTests.cs b/test/unit/CounterDrone.Core.Tests/DamageAssessmentTests.cs new file mode 100644 index 0000000..6280eff --- /dev/null +++ b/test/unit/CounterDrone.Core.Tests/DamageAssessmentTests.cs @@ -0,0 +1,79 @@ +using System; +using CounterDrone.Core.Algorithms; +using Xunit; + +namespace CounterDrone.Core.Tests +{ + public class DamageAssessmentTests + { + [Fact] + public void SingleSegment_ThroughCenter_DiameterExposure() + { + // 无人机穿过球心:路径=2R + float len = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 20, 0, 0, 20); + Assert.Equal(40, len, 1); + } + + [Fact] + public void TwoAdjacentClouds_FullCoverage() + { + // 20段×4m步长=80m,经过R=20的两朵相邻云(中心在20和60) + float total = 0; + float prevX = 0; + for (int s = 0; s < 20; s++) + { + float nextX = prevX + 4; + total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, 20, 0, 0, 20); + total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, 60, 0, 0, 20); + prevX = nextX; + } + // 每朵云直径40m,两朵共80m + Assert.True(Math.Abs(total - 80f) < 1f, $"total={total:F2}, expected=80"); + } + + [Fact] + public void NineCloudChain_CoverageMatchesTheory() + { + // 9朵云,间距40m,R=20m,无人机段长22.2m(55.6m/s×0.4s) + float[] cloudX = { 9840, 9880, 9920, 9960, 10000, 10040, 10080, 10120, 10160 }; + float radius = 20; + float total = 0; + float prevX = 9800; + for (int t = 0; t < 20; t++) + { + float nextX = prevX + 22.22f; + foreach (float cx in cloudX) + total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, cx, 0, 0, radius); + prevX = nextX; + } + // 理论: 9×40m = 360m + Assert.True(Math.Abs(total - 360f) < 10f, $"total={total:F1}, expected=360"); + } + [Fact] + public void TwoCloudsWithGap_GapYieldsNoExposure() + { + // 两朵云中心在20和80, R=20: 云1=[0,40], 云2=[60,100], 间隙=[40,60] + float total = 0; + float prevX = 0; + for (int s = 0; s < 25; s++) // 100m / 4m = 25段 + { + float nextX = prevX + 4; + total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, 20, 0, 0, 20); + total += DamageAssessment.PathInSphere(prevX, 0, 0, nextX, 0, 0, 80, 0, 0, 20); + prevX = nextX; + } + // 每朵云直径40m,两朵共80m,间隙无暴露 + Assert.True(Math.Abs(total - 80f) < 1f, $"total={total:F2}, expected=80"); + } + [Fact] + public void TwoPointsInDifferentClouds_GapExcluded() + { + // 两朵云R=10, 边间距50: 云1中心(0), 云2中心(70) + // 两点: 云1内(0)→云2内(70) + float len1 = DamageAssessment.PathInSphere(0, 0, 0, 70, 0, 0, 0, 0, 0, 10); + float len2 = DamageAssessment.PathInSphere(0, 0, 0, 70, 0, 0, 70, 0, 0, 10); + float total = len1 + len2; + Assert.True(Math.Abs(total - 20f) < 1f, $"total={total:F2}, expected=20 (10+10)"); + } + } +} diff --git a/test/unit/CounterDrone.Core.Tests/KinematicsTests.cs b/test/unit/CounterDrone.Core.Tests/KinematicsTests.cs index 0ec8222..ced0ad5 100644 --- a/test/unit/CounterDrone.Core.Tests/KinematicsTests.cs +++ b/test/unit/CounterDrone.Core.Tests/KinematicsTests.cs @@ -134,5 +134,54 @@ namespace CounterDrone.Core.Tests var vertices = new (float X, float Z)[] { (0, 0), (10, 0), (10, 10), (0, 10) }; Assert.False(Kinematics.PointInPolygon(20, 5, vertices)); } + [Fact] + public void PathInSphere_CenterPass_ReturnsFullDiameter() + { + // 无人机穿过球心: 路径长度 = 2R + float len = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 20, 0, 0, 20); + Assert.Equal(40, len, 1); + } + + [Fact] + public void PathInSphere_EdgePass_ReturnsCorrectChord() + { + // 从(0)→(40), 球心(30), R=20: 进入t=0.25(x=10), 段尾在球内(t=1,x=40), 路径=30m + float len = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 30, 0, 0, 20); + Assert.True(System.Math.Abs(len - 30f) < 1f, $"len={len:F2}"); + } + + [Fact] + public void PathInSphere_Miss_ReturnsZero() + { + float len = DamageAssessment.PathInSphere(0, 0, 0, 10, 0, 0, 50, 0, 0, 20); + Assert.Equal(0, len, 1); + } + + [Fact] + public void PathInSphere_PartialEntry_ReturnsCorrectSegment() + { + // 从球外(0)到球内(20), R=20, 球心(30): 进入点在10, 段长=10 + float len = DamageAssessment.PathInSphere(0, 0, 0, 20, 0, 0, 30, 0, 0, 20); + Assert.True(System.Math.Abs(len - 10f) < 1f, $"len={len:F2}"); + } + [Fact] + public void PathInSphere_TwoClouds_AccumulatesCorrectly() + { + // 一段经过两个云: (0→100), 云1(20,R20), 云2(80,R20) + float len1 = DamageAssessment.PathInSphere(0, 0, 0, 100, 0, 0, 20, 0, 0, 20); + float len2 = DamageAssessment.PathInSphere(0, 0, 0, 100, 0, 0, 80, 0, 0, 20); + Assert.True(System.Math.Abs(len1 - 40f) < 1f, $"cloud1 len={len1:F2}"); + Assert.True(System.Math.Abs(len2 - 40f) < 1f, $"cloud2 len={len2:F2}"); + } + [Fact] + public void PathInSphere_AdjacentClouds_SumCorrectly() + { + // 无人机从云1中心(0)到云2中心(40),两云R=20,间距=40(边碰边) + // 两个云在段内路径:云1=20m(中心→右边缘), 云2=20m(左边缘→中心) + float len1 = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 0, 0, 0, 20); + float len2 = DamageAssessment.PathInSphere(0, 0, 0, 40, 0, 0, 40, 0, 0, 20); + float total = len1 + len2; + Assert.True(System.Math.Abs(total - 40f) < 1f, $"total={total:F2} (cloud1={len1:F2} + cloud2={len2:F2})"); + } } }