From 35d7248da08076b266483a1f3ee37aa5a71162f1 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Mon, 9 Mar 2026 21:06:43 -0400 Subject: [PATCH] refactor: move OpenNest.Test to separate test data repo Test code and fixture data now live together in the OpenNest.Test repo at git.thecozycat.net/aj/OpenNest.Test.git. Co-Authored-By: Claude Opus 4.6 --- OpenNest.Test/FillTests.cs | 71 ---------------------- OpenNest.Test/OpenNest.Test.csproj | 24 -------- OpenNest.Test/RemnantFillTests.cs | 97 ------------------------------ OpenNest.Test/TestData.cs | 72 ---------------------- OpenNest.sln | 14 ----- 5 files changed, 278 deletions(-) delete mode 100644 OpenNest.Test/FillTests.cs delete mode 100644 OpenNest.Test/OpenNest.Test.csproj delete mode 100644 OpenNest.Test/RemnantFillTests.cs delete mode 100644 OpenNest.Test/TestData.cs diff --git a/OpenNest.Test/FillTests.cs b/OpenNest.Test/FillTests.cs deleted file mode 100644 index 3199893..0000000 --- a/OpenNest.Test/FillTests.cs +++ /dev/null @@ -1,71 +0,0 @@ -using OpenNest.Geometry; -using Xunit; -using Xunit.Abstractions; - -namespace OpenNest.Test; - -public class FillTests -{ - private readonly ITestOutputHelper _output; - - public FillTests(ITestOutputHelper output) - { - _output = output; - } - - [SkippableFact] - [Trait("Category", "Fill")] - public void N0308_008_HingePlate_FillsAtLeast75() - { - Skip.IfNot(TestData.IsAvailable, TestData.SkipReason); - - var nest = TestData.LoadNest("N0308-008.zip"); - var hinge = nest.Drawings.First(d => d.Name.Contains("HINGE PLATE #2")); - var plate = TestData.CleanPlateFrom(nest.Plates[0]); - - var engine = new NestEngine(plate); - var sw = System.Diagnostics.Stopwatch.StartNew(); - engine.Fill(new NestItem { Drawing = hinge, Quantity = 0 }); - sw.Stop(); - - _output.WriteLine($"Parts: {plate.Parts.Count} | Time: {sw.ElapsedMilliseconds}ms"); - - Assert.True(plate.Parts.Count >= 75, - $"Expected >= 75 parts, got {plate.Parts.Count}"); - AssertNoOverlaps(plate.Parts.ToList()); - } - - [SkippableFact] - [Trait("Category", "Fill")] - public void RemainderStripRefill_30pcs_FillsAtLeast32() - { - Skip.IfNot(TestData.IsAvailable, TestData.SkipReason); - - var nest = TestData.LoadNest("30pcs Fill.zip"); - var drawing = nest.Drawings.First(); - var plate = TestData.CleanPlateFrom(nest.Plates[0]); - - var engine = new NestEngine(plate); - var sw = System.Diagnostics.Stopwatch.StartNew(); - engine.Fill(new NestItem { Drawing = drawing, Quantity = 0 }); - sw.Stop(); - - _output.WriteLine($"Parts: {plate.Parts.Count} | Time: {sw.ElapsedMilliseconds}ms"); - - Assert.True(plate.Parts.Count >= 32, - $"Expected >= 32 parts, got {plate.Parts.Count}"); - AssertNoOverlaps(plate.Parts.ToList()); - } - - private void AssertNoOverlaps(List parts) - { - for (var i = 0; i < parts.Count; i++) - { - for (var j = i + 1; j < parts.Count; j++) - { - if (parts[i].Intersects(parts[j], out _)) - Assert.Fail($"Overlap detected: part [{i}] vs [{j}]"); - } - } - } -} diff --git a/OpenNest.Test/OpenNest.Test.csproj b/OpenNest.Test/OpenNest.Test.csproj deleted file mode 100644 index 14f45d1..0000000 --- a/OpenNest.Test/OpenNest.Test.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net8.0-windows - enable - enable - false - true - - - - - - - - - - - - - - - - diff --git a/OpenNest.Test/RemnantFillTests.cs b/OpenNest.Test/RemnantFillTests.cs deleted file mode 100644 index c19a329..0000000 --- a/OpenNest.Test/RemnantFillTests.cs +++ /dev/null @@ -1,97 +0,0 @@ -using OpenNest.Geometry; -using Xunit; -using Xunit.Abstractions; - -namespace OpenNest.Test; - -public class RemnantFillTests -{ - private readonly ITestOutputHelper _output; - - public RemnantFillTests(ITestOutputHelper output) - { - _output = output; - } - - [SkippableFact] - [Trait("Category", "Remnant")] - public void N0308_017_PT02_RemnantFillsAtLeast10() - { - Skip.IfNot(TestData.IsAvailable, TestData.SkipReason); - - var nest = TestData.LoadNest("N0308-017.zip"); - var plate = nest.Plates[0]; - var pt02 = nest.Drawings.First(d => d.Name.Contains("PT02")); - var remnant = plate.GetRemnants()[0]; - - _output.WriteLine($"Remnant: ({remnant.X:F2},{remnant.Y:F2}) {remnant.Width:F2}x{remnant.Height:F2}"); - - var countBefore = plate.Parts.Count; - var engine = new NestEngine(plate); - var sw = System.Diagnostics.Stopwatch.StartNew(); - engine.Fill(new NestItem { Drawing = pt02, Quantity = 0 }, remnant); - sw.Stop(); - - var added = plate.Parts.Count - countBefore; - _output.WriteLine($"Added: {added} parts | Time: {sw.ElapsedMilliseconds}ms"); - - Assert.True(added >= 10, $"Expected >= 10 parts in remnant, got {added}"); - - var newParts = plate.Parts.Skip(countBefore).ToList(); - AssertNoOverlaps(newParts); - AssertNoCrossOverlaps(plate.Parts.Take(countBefore).ToList(), newParts); - } - - [SkippableFact] - [Trait("Category", "Remnant")] - public void N0308_008_HingePlate_RemnantFillsAtLeast8() - { - Skip.IfNot(TestData.IsAvailable, TestData.SkipReason); - - var nest = TestData.LoadNest("N0308-008.zip"); - var plate = nest.Plates[0]; - var hinge = nest.Drawings.First(d => d.Name.Contains("HINGE PLATE #2")); - var remnants = plate.GetRemnants(); - - _output.WriteLine($"Remnant 0: ({remnants[0].X:F2},{remnants[0].Y:F2}) {remnants[0].Width:F2}x{remnants[0].Height:F2}"); - - var countBefore = plate.Parts.Count; - var engine = new NestEngine(plate); - var sw = System.Diagnostics.Stopwatch.StartNew(); - engine.Fill(new NestItem { Drawing = hinge, Quantity = 0 }, remnants[0]); - sw.Stop(); - - var added = plate.Parts.Count - countBefore; - _output.WriteLine($"Added: {added} parts | Time: {sw.ElapsedMilliseconds}ms"); - - Assert.True(added >= 8, $"Expected >= 8 parts in remnant, got {added}"); - - var newParts = plate.Parts.Skip(countBefore).ToList(); - AssertNoOverlaps(newParts); - AssertNoCrossOverlaps(plate.Parts.Take(countBefore).ToList(), newParts); - } - - private void AssertNoOverlaps(List parts) - { - for (var i = 0; i < parts.Count; i++) - { - for (var j = i + 1; j < parts.Count; j++) - { - if (parts[i].Intersects(parts[j], out _)) - Assert.Fail($"Overlap detected: part [{i}] vs [{j}]"); - } - } - } - - private void AssertNoCrossOverlaps(List existing, List added) - { - for (var i = 0; i < existing.Count; i++) - { - for (var j = 0; j < added.Count; j++) - { - if (existing[i].Intersects(added[j], out _)) - Assert.Fail($"Cross-overlap: existing [{i}] vs added [{j}]"); - } - } - } -} diff --git a/OpenNest.Test/TestData.cs b/OpenNest.Test/TestData.cs deleted file mode 100644 index abb4439..0000000 --- a/OpenNest.Test/TestData.cs +++ /dev/null @@ -1,72 +0,0 @@ -using OpenNest.IO; - -namespace OpenNest.Test; - -public static class TestData -{ - private static readonly string? BasePath = ResolveBasePath(); - - public static bool IsAvailable => BasePath != null; - - public static string SkipReason => - "Test data not found. Set OPENNEST_TEST_DATA env var or clone " + - "https://git.thecozycat.net/aj/OpenNest.Test.git to ../OpenNest.Test.Data/"; - - public static string GetPath(string filename) - { - if (BasePath == null) - throw new InvalidOperationException(SkipReason); - - var path = Path.Combine(BasePath, filename); - - if (!File.Exists(path)) - throw new FileNotFoundException($"Test fixture not found: {path}"); - - return path; - } - - public static Nest LoadNest(string filename) - { - var reader = new NestReader(GetPath(filename)); - return reader.Read(); - } - - public static Plate CleanPlateFrom(Plate reference) - { - var plate = new Plate(); - plate.Size = reference.Size; - plate.PartSpacing = reference.PartSpacing; - plate.EdgeSpacing = reference.EdgeSpacing; - plate.Quadrant = reference.Quadrant; - return plate; - } - - private static string? ResolveBasePath() - { - // 1. Environment variable - var envPath = Environment.GetEnvironmentVariable("OPENNEST_TEST_DATA"); - - if (!string.IsNullOrEmpty(envPath) && Directory.Exists(envPath)) - return envPath; - - // 2. Sibling directory (../OpenNest.Test.Data/ relative to solution root) - var dir = AppContext.BaseDirectory; - - // Walk up from bin/Debug/net8.0-windows to find the solution root. - for (var i = 0; i < 6; i++) - { - var parent = Directory.GetParent(dir); - - if (parent == null) - break; - - dir = parent.FullName; - var candidate = Path.Combine(dir, "OpenNest.Test.Data"); - - if (Directory.Exists(candidate)) - return candidate; - } - - return null; - } -} diff --git a/OpenNest.sln b/OpenNest.sln index f591b6f..42a267c 100644 --- a/OpenNest.sln +++ b/OpenNest.sln @@ -15,8 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenNest.IO", "OpenNest.IO\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenNest.Mcp", "OpenNest.Mcp\OpenNest.Mcp.csproj", "{61CC6F65-8B70-408A-B49A-F4E5F34FFD01}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenNest.Test", "OpenNest.Test\OpenNest.Test.csproj", "{59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -99,18 +97,6 @@ Global {61CC6F65-8B70-408A-B49A-F4E5F34FFD01}.Release|x64.Build.0 = Release|Any CPU {61CC6F65-8B70-408A-B49A-F4E5F34FFD01}.Release|x86.ActiveCfg = Release|Any CPU {61CC6F65-8B70-408A-B49A-F4E5F34FFD01}.Release|x86.Build.0 = Release|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Debug|x64.ActiveCfg = Debug|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Debug|x64.Build.0 = Debug|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Debug|x86.ActiveCfg = Debug|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Debug|x86.Build.0 = Debug|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Release|Any CPU.Build.0 = Release|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Release|x64.ActiveCfg = Release|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Release|x64.Build.0 = Release|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Release|x86.ActiveCfg = Release|Any CPU - {59F071B4-4CFD-43E8-A8CE-7594CC2C5AD0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE