Archived
docs(engines): template on shared services and a determinism rule
New engines start from the shared test kit (the template's tests are a one-line EngineContractTests subclass) and the host APIs, so they don't re-derive geometry reading, work areas or validator tolerances. BENCH-RULES.md now forbids clocks, unseeded randomness and environment variables from influencing placement (budgets count work; wall time only through the host's cancellation token) and lists the kit as read-only. Build-Engines.ps1 deploys only OpenNest.Engine.* folders, and New-Engine.ps1 -IncludeBuildFiles copies the kit. Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,8 +10,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
<ProjectReference Include="../../Engine.Testing/OpenNest.Engine.Testing.csproj" />
|
||||
<ProjectReference Include="../OpenNest.Engine.__NAME__.csproj" />
|
||||
<!-- The benchmark's NestValidator is the arbiter the engine is scored by. -->
|
||||
<ProjectReference Include="$(OpenNestRoot)OpenNest.Benchmark/OpenNest.Benchmark.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using OpenNest.Engine.Testing;
|
||||
using static OpenNest.Engine.Testing.JobBuilder;
|
||||
using static OpenNest.Engine.Testing.Shapes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenNest.Benchmark;
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Engine.Jobs;
|
||||
using OpenNest.Engine.Jobs.Adapters;
|
||||
@@ -10,7 +12,7 @@ using OpenNest.Geometry;
|
||||
namespace OpenNest.Engine.__NAME__.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Starter acceptance tests. Every layout is checked by the same NestValidator the benchmark
|
||||
/// Starter acceptance tests. Every layout is checked by the shared NestLayoutCheck the benchmark
|
||||
/// scores with, so a passing test means the benchmark will accept the layout. They fail until
|
||||
/// Solve() is implemented; add engine-specific tests alongside them.
|
||||
/// </summary>
|
||||
@@ -30,7 +32,7 @@ public class __NAME__NestingEngineTests
|
||||
|
||||
var result = new __NAME__NestingEngine().Solve(job);
|
||||
|
||||
AssertValid(job, result);
|
||||
LayoutAssert.Valid(job, result);
|
||||
Assert.Equal(NestJobStatus.Complete, result.Status);
|
||||
Assert.Single(result.Plates);
|
||||
Assert.Equal(12, result.Plates[0].Placements.Count);
|
||||
@@ -55,7 +57,7 @@ public class __NAME__NestingEngineTests
|
||||
|
||||
var result = new __NAME__NestingEngine().Solve(job);
|
||||
|
||||
AssertValid(job, result);
|
||||
LayoutAssert.Valid(job, result);
|
||||
Assert.Equal(NestJobStatus.Complete, result.Status);
|
||||
}
|
||||
|
||||
@@ -66,7 +68,7 @@ public class __NAME__NestingEngineTests
|
||||
|
||||
var result = new __NAME__NestingEngine().Solve(job);
|
||||
|
||||
AssertValid(job, result);
|
||||
LayoutAssert.Valid(job, result);
|
||||
Assert.Equal(NestJobStatus.Complete, result.Status);
|
||||
Assert.True(result.Plates.Count > 1);
|
||||
}
|
||||
@@ -81,70 +83,11 @@ public class __NAME__NestingEngineTests
|
||||
|
||||
var result = new __NAME__NestingEngine().Solve(job);
|
||||
|
||||
AssertValid(job, result);
|
||||
LayoutAssert.Valid(job, result);
|
||||
var huge = Assert.Single(result.Fulfillment, f => f.PartId == "huge");
|
||||
Assert.Equal(1, huge.Unplaced);
|
||||
}
|
||||
|
||||
// ---- helpers -------------------------------------------------------------------------
|
||||
|
||||
private static void AssertValid(NestJob job, NestJobResult result)
|
||||
{
|
||||
var materialized = NestResultMaterializer.Materialize(job, result);
|
||||
var runs = materialized.Nest.Plates.Select(plate => (Plate: plate, Parts: plate.Parts.ToList())).ToList();
|
||||
var requirements = job.Parts.ToDictionary<NestJobPart, Drawing, (string Name, int Quantity)>(
|
||||
p => materialized.DrawingsByPartId[p.Id],
|
||||
p => (p.Id, p.Quantity),
|
||||
ReferenceEqualityComparer.Instance
|
||||
);
|
||||
var validation = NestValidator.Validate(runs, requirements);
|
||||
NestValidator.ValidateAgainstJob(job, result, job.Parts.ToDictionary(p => p.Id, p => p.Id), validation);
|
||||
Assert.True(validation.Valid, string.Join(Environment.NewLine, validation.Violations));
|
||||
|
||||
foreach (var f in result.Fulfillment)
|
||||
Assert.Equal(f.Requested, f.Placed + f.Unplaced);
|
||||
}
|
||||
|
||||
private static NestJob Job(NestJobPart[] parts, NestPlateStock[] stock, NestJobOptions? options = null) =>
|
||||
new(parts, stock, options);
|
||||
|
||||
private static NestJobPart Part(string id, Program program, int quantity, RotationPolicy? rotation = null) =>
|
||||
new(id, PartGeometrySnapshot.FromProgram(program), quantity, 0, rotation);
|
||||
|
||||
/// <param name="width">Y extent.</param>
|
||||
/// <param name="length">X extent.</param>
|
||||
private static NestPlateStock Stock(
|
||||
string id,
|
||||
double width,
|
||||
double length,
|
||||
double spacing = 0,
|
||||
Spacing edge = default,
|
||||
int quadrant = 1,
|
||||
int? quantity = null
|
||||
) => new(id, new Size(width, length), quantity, spacing, edge, quadrant);
|
||||
|
||||
private static Program Polyline(params (double X, double Y)[] points)
|
||||
{
|
||||
var program = new Program();
|
||||
program.Codes.Add(new RapidMove(points[0].X, points[0].Y));
|
||||
foreach (var (x, y) in points.Skip(1))
|
||||
program.Codes.Add(new LinearMove(x, y));
|
||||
program.Codes.Add(new LinearMove(points[0].X, points[0].Y));
|
||||
return program;
|
||||
}
|
||||
|
||||
private static Program Rectangle(double w, double h) => Polyline((0, 0), (w, 0), (w, h), (0, h));
|
||||
|
||||
private static Program Triangle(double w, double h) => Polyline((0, 0), (w, 0), (w * 0.3, h));
|
||||
|
||||
private static Program LShape(double w, double h, double t) => Polyline((0, 0), (w, 0), (w, t), (t, t), (t, h), (0, h));
|
||||
|
||||
private static Program Disc(double r)
|
||||
{
|
||||
var program = new Program();
|
||||
program.Codes.Add(new RapidMove(r, 0));
|
||||
program.Codes.Add(new ArcMove(-r, 0, 0, 0, RotationType.CCW));
|
||||
program.Codes.Add(new ArcMove(r, 0, 0, 0, RotationType.CCW));
|
||||
return program;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class __NAME__ContractTests : EngineContractTests<__NAME__NestingEngine> { }
|
||||
|
||||
Reference in New Issue
Block a user