using System; using System.Collections.Generic; using System.Reflection; using TrajectoryPlanningVisualization; namespace TrajectoryPlanningVisualizationVerificationHost; internal static class ContractChecks { public static void Run() { CopiesCollectionsAndRejectsNonFiniteNumbers(); StoresOccupancyAsDefensiveCompactBits(); ExposesImmutableSnapshotContracts(); } private static void CopiesCollectionsAndRejectsNonFiniteNumbers() { var points = new List { new VisualizationPoint(1d, 2d) }; var series = new VisualizationSeries("current", "当前轨迹", VisualizationLineStyle.Solid, points); points[0] = new VisualizationPoint(9d, 9d); Verification.NearlyEqual(1d, series.Points[0].X, "series copies points"); Verification.Throws( () => new VisualizationPoint(double.NaN, 0d), "point rejects NaN"); Verification.Throws( () => new VisualizationPose(0d, 0d, double.PositiveInfinity), "pose rejects infinity"); Verification.Throws( () => new VisualizationBounds(0d, 1d, 0d, double.NaN), "bounds rejects NaN"); Verification.Throws( () => new VisualizationSeries("invalid", "无效", VisualizationLineStyle.Solid, new VisualizationPoint[] { null! }), "series rejects null point"); } private static void StoresOccupancyAsDefensiveCompactBits() { byte[] bits = { 0x01 }; var grid = new VisualizationOccupancyGrid(new VisualizationBounds(0d, 1d, 0d, 1d), 0.5d, rows: 2, columns: 2, bits); bits[0] = 0x00; Verification.Equal("AQ==", grid.OccupancyBitsBase64, "occupancy grid copies compact bits"); Verification.Throws( () => new VisualizationOccupancyGrid(new VisualizationBounds(0d, 1d, 0d, 1d), 0.5d, rows: 2, columns: 2, new byte[2]), "occupancy grid validates bit length"); } private static void ExposesImmutableSnapshotContracts() { var staticSnapshot = new PlanningVisualizationStaticSnapshot( "会话", new VisualizationBounds(0d, 1d, 0d, 1d), null, Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty()); var dynamicSnapshot = new PlanningVisualizationDynamicSnapshot( 1L, DateTimeOffset.UtcNow, "运行中", 0, "forward", new VisualizationPose(0d, 0d, 0d), Array.Empty(), Array.Empty(), Array.Empty(), Array.Empty(), new VisualizationCycleSummary(1L, DateTimeOffset.UtcNow, "成功", true, 1d, 0, "forward", "rolling", "none", null, null, "")); Verification.True(staticSnapshot.StaticPolylines.GetType().Name.Contains("ReadOnlyCollection"), "static snapshot uses read-only collection"); Verification.True(dynamicSnapshot.Charts.GetType().Name.Contains("ReadOnlyCollection"), "dynamic snapshot uses read-only collection"); AssertNoSetters(typeof(PlanningVisualizationStaticSnapshot)); AssertNoSetters(typeof(PlanningVisualizationDynamicSnapshot)); } private static void AssertNoSetters(Type type) { foreach (PropertyInfo property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { Verification.True(property.SetMethod == null, type.Name + " exposes no property setters"); } } }