From 315d36a36af6d011d8ddcfe772cd661c3b7f2708 Mon Sep 17 00:00:00 2001 From: codex Date: Fri, 7 Aug 2026 08:42:34 +0300 Subject: [PATCH] test: cover p-rec-annot line-number list planning --- .../PRecAnnot.Core/LineNumberListPlanner.cs | 19 ++++++++++++++ .../LineNumberListPlannerTests.cs | 25 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/LineNumberListPlanner.cs create mode 100644 Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/LineNumberListPlannerTests.cs diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/LineNumberListPlanner.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/LineNumberListPlanner.cs new file mode 100644 index 0000000..17bd5b4 --- /dev/null +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/LineNumberListPlanner.cs @@ -0,0 +1,19 @@ +using System.Security.Cryptography; +using System.Text; +using PRecAnnot.Abstractions; + +namespace PRecAnnot.Core; + +public static class LineNumberListPlanner +{ + public static LineNumberListApplyPreflight Build(AnnotationPoint position, double rotation, IEnumerable rows) + { + var ordered = rows.OrderBy(row => row.MarkerNumber).ToArray(); + if (ordered.Length == 0) throw new ArgumentException("LINE_NUMBER_LIST_EMPTY", nameof(rows)); + if (ordered.Any(row => string.IsNullOrWhiteSpace(row.StableId) || string.IsNullOrWhiteSpace(row.Text))) throw new ArgumentException("LINE_NUMBER_LIST_ROW_INVALID", nameof(rows)); + if (ordered.Select(row => row.MarkerNumber).Distinct().Count() != ordered.Length) throw new ArgumentException("LINE_NUMBER_LIST_DUPLICATE_MARKER_NUMBER", nameof(rows)); + var key = string.Join("|", ordered.Select(row => $"{row.MarkerNumber}:{row.StableId}")); + var digest = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(key))).ToLowerInvariant(); + return new($"ln-list:{digest}", position, rotation, ordered); + } +} diff --git a/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/LineNumberListPlannerTests.cs b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/LineNumberListPlannerTests.cs new file mode 100644 index 0000000..b7a6de8 --- /dev/null +++ b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/LineNumberListPlannerTests.cs @@ -0,0 +1,25 @@ +using PRecAnnot.Abstractions; +using PRecAnnot.Core; + +namespace PRecAnnot.Core.Tests; + +public sealed class LineNumberListPlannerTests +{ + [Fact] + public void ProducesStableOwnershipAndMarkerOrder() + { + var second = new LineNumberApplyPreflight("b", 2, "L-2", new(1, 1), 0, "L", "S"); + var first = new LineNumberApplyPreflight("a", 1, "L-1", new(0, 0), 0, "L", "S"); + var result = LineNumberListPlanner.Build(new(5, 6), 1.5, [second, first]); + Assert.Equal(new[] { 1, 2 }, result.Rows.Select(row => row.MarkerNumber)); + Assert.Equal(result.StableId, LineNumberListPlanner.Build(new(99, 0), 0, [first, second]).StableId); + } + + [Fact] + public void RejectsDuplicateMarkerNumbers() + { + var one = new LineNumberApplyPreflight("a", 1, "L-1", new(), 0, "L", "S"); + var duplicate = one with { StableId = "b" }; + Assert.Throws(() => LineNumberListPlanner.Build(new(), 0, [one, duplicate])); + } +}