diff --git a/OpenNest.Tests/CincinnatiCIFiber/CIFiberSampleRegressionTests.cs b/OpenNest.Tests/CincinnatiCIFiber/CIFiberSampleRegressionTests.cs index 66ac9b6a..069a4f61 100644 --- a/OpenNest.Tests/CincinnatiCIFiber/CIFiberSampleRegressionTests.cs +++ b/OpenNest.Tests/CincinnatiCIFiber/CIFiberSampleRegressionTests.cs @@ -20,6 +20,11 @@ namespace OpenNest.Tests.CincinnatiCIFiber; /// 12992-4SS nest (same part + layout as the sample NC) and compares contour /// counts, macro counts and perimeter geometry with 12992-4SS_NEST.nc. /// +/// Each placed part in the fixture carries the sample's own pierce, lead-in +/// and cut moves as its saved cutting program (not locked). Posting those +/// saved programs must reproduce the sample move for move; the other tests +/// replace them with OpenNest's own lead-ins first. +/// /// The fixture lives outside the repository (/srv/shared). Configure it in /// OpenNest.Tests/test-config.json: /// { "CIFiberSampleNcPath": "/srv/shared/.../12992-4SS_NEST.nc", @@ -48,10 +53,11 @@ public class CIFiberSampleRegressionTests var plate = nest.Plates[0]; plate.CuttingParameters = new CuttingParameters { - // The sample cuts clean holes with a short perpendicular linear - // lead (pierce ~0.079 outside the contour), including the circles - // (ArcCircleLeadIn). TF5200 13.2.4.1 requires a LINEAR first - // motion block after G41/G42, so holes must have linear leads. + // OpenNest's own short perpendicular linear leads, including the + // circles (ArcCircleLeadIn). TF5200 13.2.4.1 requires a LINEAR + // first motion block after G41/G42, so holes must have linear + // leads. (The sample itself pierces holes at their centre and + // uses 0.125 in perimeter leads; see the saved-lead-in test.) InternalLeadIn = new LineLeadIn { Length = 0.075, ApproachAngle = 90 }, ExternalLeadIn = new LineLeadIn { Length = 0.075, ApproachAngle = 90 }, ArcCircleLeadIn = new LineLeadIn { Length = 0.075, ApproachAngle = 90 }, @@ -96,6 +102,49 @@ public class CIFiberSampleRegressionTests return result; } + /// + /// The program body from the restart label through the last part: every + /// line except the per-part source-path comment, which names the + /// original CAM part file. + /// + private static List ProgramBody(string nc) + { + var lines = nc.Replace("\r\n", "\n").Split('\n').ToList(); + var start = lines.IndexOf("N0:"); + var end = lines.LastIndexOf("( PART END )"); + Assert.True(start >= 0 && end > start, "No N0: ... ( PART END ) body found"); + return lines + .Skip(start) + .Take(end - start + 1) + .Where(line => !line.StartsWith("( PART:", StringComparison.Ordinal)) + .ToList(); + } + + [SkippableFact] + public void Post_ReconstructedNest_SavedSampleLeadIns_ReproduceSampleProgram() + { + var fixture = ResolveFixture(); + Skip.If(fixture == null, "CI Fiber fixtures not configured in test-config.json"); + + // Post the saved programs as they are: no lead-in assignment. + var reader = new NestReader(fixture.Value.Nest); + var nest = reader.Read(); + Assert.Empty(reader.Warnings); + Assert.All(nest.Plates.SelectMany(plate => plate.Parts), part => Assert.True(part.HasManualLeadIns)); + + var expected = ProgramBody(File.ReadAllText(fixture.Value.Nc)); + var actual = ProgramBody(PostNest(nest)); + + // Pierce points, L2/L4 macro, G41/G42 side, lead-ins and every cut + // move line up with the machine program exactly. + Assert.Equal(expected.Count, actual.Count); + for (var i = 0; i < expected.Count; i++) + Assert.True( + expected[i] == actual[i], + $"Line {i} after N0: differs: sample '{expected[i]}', posted '{actual[i]}'" + ); + } + [SkippableFact] public void Post_ReconstructedNest_IsIdenticalAfterSavedLeadInsReload() { diff --git a/docs/cincinnati-ci-fiber-post-output.md b/docs/cincinnati-ci-fiber-post-output.md index aff3bb86..73eb4f1b 100644 --- a/docs/cincinnati-ci-fiber-post-output.md +++ b/docs/cincinnati-ci-fiber-post-output.md @@ -100,7 +100,13 @@ validated and saved only when OK is pressed. cover a square with a hole, kerf side for either winding, coordinate transforms/formatting, lead-in rejection, cut-off sequencing and output, table bounds, suppression/scribe handling, and -multi-sheet output in both modes. Run: +multi-sheet output in both modes. +[Sample regression tests](../OpenNest.Tests/CincinnatiCIFiber/CIFiberSampleRegressionTests.cs) +post a nest rebuilt from a Cincinnati machine sample, whose parts carry the +sample's own pierce, lead-in and cut moves. Posted unchanged, the program body +must match the sample line for line (macro, G41/G42 side, lead-ins and cuts). +The fixture stays outside the repository and the tests skip when +`test-config.json` does not point at it. Run: ```sh dotnet test OpenNest.Tests/OpenNest.Tests.csproj --filter FullyQualifiedName~CincinnatiCIFiber