using Flyshot.Core.Planning.Sampling; namespace Flyshot.Core.Tests; /// /// 验证 J519 实发重采样器在离线导出和运行时下发之间保持一致的时间轴语义。 /// public sealed class J519SendTrajectorySamplerTests { /// /// 验证 speed_ratio 只缩放轨迹时间,物理发送时间仍按固定伺服周期推进。 /// [Fact] public void SampleDenseJointTrajectory_MapsSendTimeToScaledTrajectoryTimeAndDegrees() { var denseTrajectory = new[] { new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, new[] { 0.008, Math.PI / 2.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, new[] { 0.016, Math.PI, 0.0, 0.0, 0.0, 0.0, 0.0 } }; var samples = J519SendTrajectorySampler.SampleDenseJointTrajectory( denseTrajectory, durationSeconds: 0.016, servoPeriodSeconds: 0.008, speedRatio: 0.5); Assert.Equal(5, samples.Count); Assert.Equal(0, samples[0].SampleIndex); Assert.Equal(0.0, samples[0].SendTime, precision: 6); Assert.Equal(0.0, samples[0].TrajectoryTime, precision: 6); Assert.Equal(0.0, samples[0].JointsDegrees[0], precision: 6); Assert.Equal(1, samples[1].SampleIndex); Assert.Equal(0.008, samples[1].SendTime, precision: 6); Assert.Equal(0.004, samples[1].TrajectoryTime, precision: 6); Assert.Equal(45.0, samples[1].JointsDegrees[0], precision: 6); Assert.Equal(4, samples[^1].SampleIndex); Assert.Equal(0.032, samples[^1].SendTime, precision: 6); Assert.Equal(0.016, samples[^1].TrajectoryTime, precision: 6); Assert.Equal(180.0, samples[^1].JointsDegrees[0], precision: 6); } /// /// 验证空稠密轨迹会直接暴露为调用错误,避免生成无意义下发点。 /// [Fact] public void SampleDenseJointTrajectory_RejectsEmptyDenseTrajectory() { var exception = Assert.Throws(() => J519SendTrajectorySampler.SampleDenseJointTrajectory( Array.Empty>(), durationSeconds: 0.016, servoPeriodSeconds: 0.008, speedRatio: 1.0)); Assert.Contains("稠密关节轨迹为空", exception.Message); } /// /// 验证非法 speed_ratio 会在公共入口统一拦截。 /// [Theory] [InlineData(0.0)] [InlineData(double.NaN)] [InlineData(double.PositiveInfinity)] public void SampleDenseJointTrajectory_RejectsInvalidSpeedRatio(double speedRatio) { var denseTrajectory = new[] { new[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 } }; Assert.Throws(() => J519SendTrajectorySampler.SampleDenseJointTrajectory( denseTrajectory, durationSeconds: 0.0, servoPeriodSeconds: 0.008, speedRatio: speedRatio)); } /// /// 验证公共诊断行格式与既有 ActualSendTiming 文件保持一致。 /// [Fact] public void BuildTimingRow_UsesLegacyActualSendColumnOrder() { var row = J519SendTrajectorySampler.BuildTimingRow(new J519SendSample( sampleIndex: 2, sendTime: 0.016, trajectoryTime: 0.008, speedRatio: 0.5, jointsDegrees: [90.0, 0.0, 0.0, 0.0, 0.0, 0.0])); Assert.Equal([2.0, 0.016, 0.008, 0.5], row); } }