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>
94 lines
3.0 KiB
C#
94 lines
3.0 KiB
C#
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.CNC;
|
|
using OpenNest.Engine.Jobs;
|
|
using OpenNest.Engine.Jobs.Adapters;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.Engine.__NAME__.Tests;
|
|
|
|
/// <summary>
|
|
/// 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>
|
|
public class __NAME__NestingEngineTests
|
|
{
|
|
[Fact]
|
|
public void HasPublicParameterlessConstructorForPluginDiscovery()
|
|
{
|
|
var engine = Activator.CreateInstance(typeof(__NAME__NestingEngine));
|
|
Assert.IsAssignableFrom<INestingEngine>(engine);
|
|
}
|
|
|
|
[Fact]
|
|
public void RectanglesFitOnOneSheetWithSpacing()
|
|
{
|
|
var job = Job(new[] { Part("rect", Rectangle(10, 5), 12) }, new[] { Stock("sheet", 48, 96, spacing: 0.25) });
|
|
|
|
var result = new __NAME__NestingEngine().Solve(job);
|
|
|
|
LayoutAssert.Valid(job, result);
|
|
Assert.Equal(NestJobStatus.Complete, result.Status);
|
|
Assert.Single(result.Plates);
|
|
Assert.Equal(12, result.Plates[0].Placements.Count);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(1)]
|
|
[InlineData(2)]
|
|
[InlineData(3)]
|
|
[InlineData(4)]
|
|
public void MixedArcAndConcavePartsAreValidInEveryQuadrant(int quadrant)
|
|
{
|
|
var job = Job(
|
|
new[]
|
|
{
|
|
Part("disc", Disc(3), 10),
|
|
Part("ell", LShape(12, 8, 4), 10),
|
|
Part("tri", Triangle(9, 6), 10),
|
|
},
|
|
new[] { Stock("sheet", 40, 60, spacing: 0.5, edge: new Spacing(0.5, 0.5, 0.5, 0.5), quadrant: quadrant) }
|
|
);
|
|
|
|
var result = new __NAME__NestingEngine().Solve(job);
|
|
|
|
LayoutAssert.Valid(job, result);
|
|
Assert.Equal(NestJobStatus.Complete, result.Status);
|
|
}
|
|
|
|
[Fact]
|
|
public void OverflowSpillsOntoAdditionalSheets()
|
|
{
|
|
var job = Job(new[] { Part("square", Rectangle(10, 10), 30) }, new[] { Stock("sheet", 25, 45, spacing: 0.25) });
|
|
|
|
var result = new __NAME__NestingEngine().Solve(job);
|
|
|
|
LayoutAssert.Valid(job, result);
|
|
Assert.Equal(NestJobStatus.Complete, result.Status);
|
|
Assert.True(result.Plates.Count > 1);
|
|
}
|
|
|
|
[Fact]
|
|
public void PartTooBigForAnySheetIsReportedUnplaced()
|
|
{
|
|
var job = Job(
|
|
new[] { Part("huge", Rectangle(50, 50), 1), Part("small", Rectangle(5, 5), 4) },
|
|
new[] { Stock("sheet", 20, 20, spacing: 0.25) }
|
|
);
|
|
|
|
var result = new __NAME__NestingEngine().Solve(job);
|
|
|
|
LayoutAssert.Valid(job, result);
|
|
var huge = Assert.Single(result.Fulfillment, f => f.PartId == "huge");
|
|
Assert.Equal(1, huge.Unplaced);
|
|
}
|
|
|
|
}
|
|
|
|
public sealed class __NAME__ContractTests : EngineContractTests<__NAME__NestingEngine> { }
|