109 lines
5.2 KiB
C#
109 lines
5.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using TrajectoryPlanningVisualization;
|
|
|
|
namespace TrajectoryPlanningVisualizationVerificationHost;
|
|
|
|
internal static class ContractChecks
|
|
{
|
|
public static void Run()
|
|
{
|
|
CopiesCollectionsAndRejectsNonFiniteNumbers();
|
|
StoresOccupancyAsDefensiveCompactBits();
|
|
ExposesImmutableSnapshotContracts();
|
|
DocumentsPublicSafetyAndLifecycleBoundary();
|
|
}
|
|
|
|
private static void CopiesCollectionsAndRejectsNonFiniteNumbers()
|
|
{
|
|
var points = new List<VisualizationPoint> { 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<ArgumentOutOfRangeException>(
|
|
() => new VisualizationPoint(double.NaN, 0d), "point rejects NaN");
|
|
Verification.Throws<ArgumentOutOfRangeException>(
|
|
() => new VisualizationPose(0d, 0d, double.PositiveInfinity), "pose rejects infinity");
|
|
Verification.Throws<ArgumentOutOfRangeException>(
|
|
() => new VisualizationBounds(0d, 1d, 0d, double.NaN), "bounds rejects NaN");
|
|
Verification.Throws<ArgumentException>(
|
|
() => 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<ArgumentException>(
|
|
() => 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<VisualizationPolyline>(),
|
|
Array.Empty<VisualizationMarker>(),
|
|
Array.Empty<VisualizationDirectionSegment>(),
|
|
Array.Empty<VisualizationConfigurationGroup>());
|
|
var dynamicSnapshot = new PlanningVisualizationDynamicSnapshot(
|
|
1L,
|
|
DateTimeOffset.UtcNow,
|
|
"运行中",
|
|
0,
|
|
"forward",
|
|
new VisualizationPose(0d, 0d, 0d),
|
|
Array.Empty<VisualizationPolyline>(),
|
|
Array.Empty<VisualizationMarker>(),
|
|
Array.Empty<VisualizationChart>(),
|
|
Array.Empty<VisualizationValue>(),
|
|
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");
|
|
}
|
|
}
|
|
|
|
private static void DocumentsPublicSafetyAndLifecycleBoundary()
|
|
{
|
|
string readmePath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory,
|
|
"..", "..", "..", "..", "..", "TrajectoryPlanningVisualization", "README.md"));
|
|
string readme = File.ReadAllText(readmePath);
|
|
|
|
Verification.True(readme.Contains("OBSERVE_ONLY"), "README documents observe-only boundary");
|
|
Verification.True(readme.Contains("127.0.0.1"), "README documents loopback boundary");
|
|
Verification.True(readme.Contains("capacity 1"), "README documents latest-frame capacity");
|
|
Verification.True(readme.Contains("60"), "README documents default history limit");
|
|
Verification.True(readme.Contains("10 Hz"), "README documents default refresh rate");
|
|
Verification.True(readme.Contains("j[i]"), "README documents jerk interval semantics");
|
|
Verification.True(readme.Contains("末点后无时间区间"), "README documents jerk terminal explanation");
|
|
Verification.True(readme.Contains("PlanningVisualizationSessionInfo info = visualization.Start(staticSnapshot);"),
|
|
"README documents Start example");
|
|
Verification.True(readme.Contains("visualization.Publish(dynamicSnapshot);"), "README documents Publish example");
|
|
Verification.True(readme.Contains("visualization.Stop();"), "README documents Stop example");
|
|
}
|
|
}
|