test(engine): share the rectangle, L-shape and arc-part fixtures

Engine tests drew the same rectangle, square, L-shape and arc part in
private helpers across the Expander, golden-layout, fill-stack and
fixed-strategy tests. They now use TestDrawingFactory; files whose
helper had its own default size keep a one-line wrapper for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-11-01 10:44:36 -05:00
1 parent e271580f62
commit a5e219008e
11 files changed
+78 -178

No files matched your search

@@ -1,6 +1,7 @@
using OpenNest.CNC;
using OpenNest.Converters;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Tests.Jobs;
using OpenNest.Geometry;
using Xunit;
@@ -10,16 +11,8 @@ public class ExpanderCutoffDeltaTests
{
private static Plate Sheet() => new(new Size(30, 30)) { EdgeSpacing = new Spacing(0, 0) };
private static Program Rectangle(double width = 2, double height = 2)
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(width, 0);
program.LineTo(width, height);
program.LineTo(0, height);
program.LineTo(0, 0);
return program;
}
private static Program Rectangle(double width = 2, double height = 2) =>
TestDrawingFactory.Rectangle(width, height);
private static Part Add(Plate plate, Program program, double x, double y)
{
@@ -1,5 +1,6 @@
using OpenNest.CNC;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Tests.Jobs;
using OpenNest.Geometry;
using Xunit;
@@ -7,17 +8,6 @@ namespace OpenNest.Engine.Tests.Fill;
public class ExpanderCutoffQuadrantTests
{
private static Program Square()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(2, 0);
program.LineTo(2, 2);
program.LineTo(0, 2);
program.LineTo(0, 0);
return program;
}
public static IEnumerable<object[]> Cases()
{
foreach (var quadrant in new[] { 1, 2, 3, 4 })
@@ -42,8 +32,9 @@ public class ExpanderCutoffQuadrantTests
quadrant == 3 || quadrant == 4 ? -80 : 0);
var anchorPose = origin + new Vector(30, 30);
var moverPose = anchorPose + (verticalMotion ? new Vector(0, -3) : new Vector(-3, 0));
var anchor = new Part(new Drawing("anchor", Square()), anchorPose);
var mover = new Part(new Drawing("mover", Square()), moverPose);
var anchor = new Part(
new Drawing("anchor", TestDrawingFactory.Rectangle(2, 2)), anchorPose);
var mover = new Part(new Drawing("mover", TestDrawingFactory.Rectangle(2, 2)), moverPose);
plate.Parts.Add(anchor);
plate.Parts.Add(mover);
@@ -2,6 +2,7 @@ using System.Collections.Generic;
using OpenNest.CNC;
using OpenNest.Converters;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Tests.Jobs;
using OpenNest.Geometry;
using Xunit;
@@ -14,17 +15,6 @@ public class ExpanderFinalQualityTests
private static Program Disk(double radius) =>
ConvertGeometry.ToProgram(new List<Entity> { new Circle(0, 0, radius) });
private static Program Rectangle(double width, double height)
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(width, 0);
program.LineTo(width, height);
program.LineTo(0, height);
program.LineTo(0, 0);
return program;
}
private static Part Add(Plate plate, Program program, double x, double y)
{
var part = new Part(new Drawing("neutral", program), new Vector(x, y));
@@ -56,7 +46,7 @@ public class ExpanderFinalQualityTests
{
var plate = Sheet();
Add(plate, Disk(2), 10, 6);
var mover = Add(plate, Rectangle(1, 1), 12, 5.5);
var mover = Add(plate, TestDrawingFactory.Rectangle(1, 1), 12, 5.5);
var result = Expander.Separate(new List<Part> { mover }, plate, spacing: 1);
Assert.True(result.Converged, $"curved contact pinned: {result.Violations.Count} violations");
Assert.True(result.Positions[0].X >= 13 - 1e-3);
@@ -79,7 +69,7 @@ public class ExpanderFinalQualityTests
program.LineTo(0, 6 * k);
program.LineTo(0, 0);
Add(plate, program, 10, 5);
var mover = Add(plate, Rectangle(2 * k, 2 * k), 10 + k, 5 + 3 * k);
var mover = Add(plate, TestDrawingFactory.Rectangle(2 * k, 2 * k), 10 + k, 5 + 3 * k);
// Left finger [10,10.0002] × [5.0002,5.0006] intersects the
// mover [10.0001,10.0003] × [5.0003,5.0005] in positive area.
var result = Expander.Separate(new List<Part> { mover }, plate, 0);
@@ -92,8 +82,8 @@ public class ExpanderFinalQualityTests
public void Expand_RemoteRegeneratedCutoff_MustNotPinUnrelatedGrowth()
{
var plate = Sheet();
var anchor = Add(plate, Rectangle(2, 2), 1, 4);
var mover = Add(plate, Rectangle(2, 2), 4, 4);
var anchor = Add(plate, TestDrawingFactory.Rectangle(2, 2), 1, 4);
var mover = Add(plate, TestDrawingFactory.Rectangle(2, 2), 4, 4);
plate.CutOffs.Add(new CutOff(new Vector(0, 10), CutOffAxis.Horizontal));
var settings = new CutOffSettings();
plate.RegenerateCutOffs(settings);
@@ -114,8 +104,8 @@ public class ExpanderFinalQualityTests
public void Expand_RegeneratedCutoffBlocksCrossingEvenWithClearFarEndpoint()
{
var plate = new Plate(new Size(20, 30)) { EdgeSpacing = new Spacing(0, 0) };
var anchor = Add(plate, Rectangle(2, 2), 1, 1);
var mover = Add(plate, Rectangle(2, 2), 1, 6);
var anchor = Add(plate, TestDrawingFactory.Rectangle(2, 2), 1, 1);
var mover = Add(plate, TestDrawingFactory.Rectangle(2, 2), 1, 6);
plate.CutOffs.Add(new CutOff(new Vector(0, 10), CutOffAxis.Horizontal));
var settings = new CutOffSettings();
plate.RegenerateCutOffs(settings);
@@ -134,8 +124,8 @@ public class ExpanderFinalQualityTests
public void Expand_OutsideUnchangedMover_MustNotReturnUnqualifiedSuccess()
{
var plate = Sheet();
var anchor = Add(plate, Rectangle(2, 2), 1, 4);
var mover = Add(plate, Rectangle(2, 2), 35, 4);
var anchor = Add(plate, TestDrawingFactory.Rectangle(2, 2), 1, 4);
var mover = Add(plate, TestDrawingFactory.Rectangle(2, 2), 35, 4);
var result = Expander.Expand(new List<Part> { anchor, mover }, plate,
new Expander.Options { MaxSpacing = 3 });
@@ -1,5 +1,6 @@
using OpenNest.CNC;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Tests.Jobs;
using OpenNest.Geometry;
using Xunit;
@@ -7,17 +8,6 @@ namespace OpenNest.Engine.Tests.Fill;
public class ExpanderIntersectingOpenPathTests
{
private static Program Square()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(2, 0);
program.LineTo(2, 2);
program.LineTo(0, 2);
program.LineTo(0, 0);
return program;
}
public static IEnumerable<object[]> Cases()
{
foreach (var quadrant in new[] { 1, 2, 3, 4 })
@@ -40,8 +30,8 @@ public class ExpanderIntersectingOpenPathTests
};
var expectedA = origin + Swap(40, 40);
var expectedB = origin + Swap(43, 40);
var anchor = new Part(new Drawing("anchor", Square()), expectedA);
var mover = new Part(new Drawing("mover", Square()), expectedB);
var anchor = new Part(new Drawing("anchor", TestDrawingFactory.Rectangle(2, 2)), expectedA);
var mover = new Part(new Drawing("mover", TestDrawingFactory.Rectangle(2, 2)), expectedB);
plate.Parts.Add(anchor);
plate.Parts.Add(mover);
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using OpenNest.CNC;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Tests.Jobs;
using OpenNest.Geometry;
using Xunit;
@@ -8,20 +9,10 @@ namespace OpenNest.Engine.Tests.Fill;
public class ExpanderQualityReviewTests
{
private static Program Rectangle(double width, double height)
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(width, 0);
program.LineTo(width, height);
program.LineTo(0, height);
program.LineTo(0, 0);
return program;
}
private static Part AddSquare(Plate plate, double x, double y, double size)
{
var part = new Part(new Drawing("neutral", Rectangle(size, size)), new Vector(x, y));
var part = new Part(
new Drawing("neutral", TestDrawingFactory.Rectangle(size, size)), new Vector(x, y));
plate.Parts.Add(part);
return part;
}
@@ -54,7 +45,7 @@ public class ExpanderQualityReviewTests
{
var plate = MakePlate(30);
plate.ClampZones.Add(new ClampZone("tiny", new Box(5, 5, 1e-5, 1e-5)));
var frameProgram = Rectangle(10, 10);
var frameProgram = TestDrawingFactory.Rectangle(10, 10);
frameProgram.MoveTo(4, 4);
frameProgram.LineTo(6, 4);
frameProgram.LineTo(6, 6);
@@ -1,5 +1,6 @@
using OpenNest.CNC;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Tests.Jobs;
using OpenNest.Geometry;
using Xunit;
@@ -7,17 +8,6 @@ namespace OpenNest.Engine.Tests.Fill;
public class ExpanderRemoteObliquePathTests
{
private static Program Square()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(2, 0);
program.LineTo(2, 2);
program.LineTo(0, 2);
program.LineTo(0, 0);
return program;
}
public static IEnumerable<object[]> Cases()
{
foreach (var quadrant in new[] { 1, 2, 3, 4 })
@@ -42,8 +32,9 @@ public class ExpanderRemoteObliquePathTests
};
var anchorPose = origin + Swap(40, 40);
var moverPose = origin + Swap(43, 40);
var anchor = new Part(new Drawing("anchor", Square()), anchorPose);
var mover = new Part(new Drawing("mover", Square()), moverPose);
var anchor = new Part(
new Drawing("anchor", TestDrawingFactory.Rectangle(2, 2)), anchorPose);
var mover = new Part(new Drawing("mover", TestDrawingFactory.Rectangle(2, 2)), moverPose);
plate.Parts.Add(anchor);
plate.Parts.Add(mover);
if (cutoff)
+3 -10
View File
@@ -4,6 +4,7 @@ using System.Linq;
using System.Threading;
using OpenNest.CNC;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Tests.Jobs;
using OpenNest.Geometry;
using Xunit;
@@ -15,16 +16,8 @@ namespace OpenNest.Engine.Tests.Fill;
/// </summary>
public class ExpanderTests
{
private static Program Rectangle(double width = 4, double length = 4)
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(width, 0);
program.LineTo(width, length);
program.LineTo(0, length);
program.LineTo(0, 0);
return program;
}
private static Program Rectangle(double width = 4, double length = 4) =>
TestDrawingFactory.Rectangle(width, length);
private static Part AddSquare(Plate plate, double x, double y, double size = 4)
{
@@ -34,19 +34,6 @@ namespace OpenNest.Engine.Tests.Jobs;
/// </remarks>
public class FillStackCharacterizationTests
{
private static Program LShape()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(6, 0);
program.LineTo(6, 4);
program.LineTo(3, 4);
program.LineTo(3, 2);
program.LineTo(0, 2);
program.LineTo(0, 0);
return program;
}
/// <summary>6x4 block with a 2x2 notch cut into the middle of its top edge.</summary>
private static Program Notched()
{
@@ -63,18 +50,6 @@ public class FillStackCharacterizationTests
return program;
}
/// <summary>D-shape: 3x5 block closed by a semicircular arc.</summary>
private static Program ArcPart()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(3, 0);
program.ArcTo(3, 5, 3, 2.5, RotationType.CCW);
program.LineTo(0, 5);
program.LineTo(0, 0);
return program;
}
/// <summary>
/// 46 x 3 bar with a stepped end: irregular, and too long for the 48 x 28 work area at all
/// but the sweep angles near 0 and 180 degrees, so only those prove productive and get learned.
@@ -112,9 +87,9 @@ public class FillStackCharacterizationTests
private static Program Shape(string name) =>
name switch
{
"lshape" => LShape(),
"lshape" => TestDrawingFactory.LShape(),
"notched" => Notched(),
"arc" => ArcPart(),
"arc" => TestDrawingFactory.ArcPart(),
"bar" => LongBar(),
"chevron" => Chevron(),
_ => TestDrawingFactory.Rectangle(4, 3),
@@ -259,9 +234,9 @@ public class FillStackCharacterizationTests
/// </summary>
private static List<NestItem> MixedItems() =>
[
new() { Drawing = new Drawing("lshape", LShape()), Quantity = 14 },
new() { Drawing = new Drawing("lshape", TestDrawingFactory.LShape()), Quantity = 14 },
new() { Drawing = new Drawing("notched", Notched()), Quantity = 9 },
new() { Drawing = new Drawing("arc", ArcPart()), Quantity = 11 },
new() { Drawing = new Drawing("arc", TestDrawingFactory.ArcPart()), Quantity = 11 },
new() { Drawing = new Drawing("rect", TestDrawingFactory.Rectangle(4, 3)), Quantity = 1 },
];
@@ -354,7 +329,11 @@ public class FillStackCharacterizationTests
{
var plate = MakeClampedPlate();
// A quantity close to a full sheet makes clamp-dropped copies trigger refills.
var item = new NestItem { Drawing = new Drawing("lshape", LShape()), Quantity = 40 };
var item = new NestItem
{
Drawing = new Drawing("lshape", TestDrawingFactory.LShape()),
Quantity = 40,
};
return Layout(
PlateFillService.FillItem(
strategy,
@@ -58,19 +58,6 @@ public class FixedStrategyNestingEngineTests
Assert.Throws<ArgumentException>(() => new FixedStrategyNestingEngine(" "));
}
private static Program LShape()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(6, 0);
program.LineTo(6, 4);
program.LineTo(3, 4);
program.LineTo(3, 2);
program.LineTo(0, 2);
program.LineTo(0, 0);
return program;
}
public static TheoryData<string, string, double, int> LockedRotationCases =>
new()
{
@@ -99,7 +86,7 @@ public class FixedStrategyNestingEngineTests
"rect-6x4" => TestDrawingFactory.Rectangle(6, 4),
"rect-20x3" => TestDrawingFactory.Rectangle(20, 3),
"rect-3x20" => TestDrawingFactory.Rectangle(3, 20),
_ => LShape(),
_ => TestDrawingFactory.LShape(),
};
var part = new NestJobPart(
shape,
+12 -43
View File
@@ -29,41 +29,6 @@ public class GoldenLayoutTests
{
private const double PoseTolerance = 1e-9;
private static Program Rect(double width, double length)
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(width, 0);
program.LineTo(width, length);
program.LineTo(0, length);
program.LineTo(0, 0);
return program;
}
private static Program LShape()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(6, 0);
program.LineTo(6, 4);
program.LineTo(3, 4);
program.LineTo(3, 2);
program.LineTo(0, 2);
program.LineTo(0, 0);
return program;
}
private static Program ArcPart()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(3, 0);
program.ArcTo(3, 5, 3, 2.5, RotationType.CCW);
program.LineTo(0, 5);
program.LineTo(0, 0);
return program;
}
private static NestJobPart Part(string id, Program program, int quantity) =>
new(id, PartGeometrySnapshot.FromProgram(program), quantity);
@@ -72,10 +37,10 @@ public class GoldenLayoutTests
new(
new[]
{
Part("rect-a", Rect(6, 4), 8),
Part("rect-b", Rect(4, 3), 6),
Part("lshape", LShape(), 3),
Part("arc", ArcPart(), 3),
Part("rect-a", TestDrawingFactory.Rectangle(6, 4), 8),
Part("rect-b", TestDrawingFactory.Rectangle(4, 3), 6),
Part("lshape", TestDrawingFactory.LShape(), 3),
Part("arc", TestDrawingFactory.ArcPart(), 3),
},
new[] { new NestPlateStock("stock", new Size(30, 50), 5, 1, new Spacing(1, 1, 1, 1)) },
new NestJobOptions(strategy)
@@ -86,9 +51,9 @@ public class GoldenLayoutTests
new(
new[]
{
Part("rect-a", Rect(6, 4), 5),
Part("rect-b", Rect(4, 3), 4),
Part("rect-c", Rect(2, 7), 3),
Part("rect-a", TestDrawingFactory.Rectangle(6, 4), 5),
Part("rect-b", TestDrawingFactory.Rectangle(4, 3), 4),
Part("rect-c", TestDrawingFactory.Rectangle(2, 7), 3),
},
new[] { new NestPlateStock("stock", new Size(30, 50), 4, 1, new Spacing(1, 1, 1, 1)) },
new NestJobOptions("Strip")
@@ -339,7 +304,11 @@ public class GoldenLayoutTests
private static NestJob ProgressJob() =>
new(
new[] { Part("a", Rect(6, 4), 5), Part("b", Rect(4, 3), 4) },
new[]
{
Part("a", TestDrawingFactory.Rectangle(6, 4), 5),
Part("b", TestDrawingFactory.Rectangle(4, 3), 4),
},
new[]
{
new NestPlateStock("small", new Size(14, 14), 4, 1, new Spacing(1, 1, 1, 1)),
@@ -14,4 +14,30 @@ internal static class TestDrawingFactory
program.LineTo(0, 0);
return program;
}
/// <summary>A 6 x 4 L: a 6 x 2 base with a 3 x 2 block on its right half.</summary>
public static Program LShape()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(6, 0);
program.LineTo(6, 4);
program.LineTo(3, 4);
program.LineTo(3, 2);
program.LineTo(0, 2);
program.LineTo(0, 0);
return program;
}
/// <summary>D-shape: a 3 x 5 block closed on the right by a semicircular arc.</summary>
public static Program ArcPart()
{
var program = new Program();
program.MoveTo(0, 0);
program.LineTo(3, 0);
program.ArcTo(3, 5, 3, 2.5, RotationType.CCW);
program.LineTo(0, 5);
program.LineTo(0, 0);
return program;
}
}