Files
OpenNest/scripts/ReleaseSmoke/Program.cs
T
aj 5af44b251c feat(engine): make Default choose between Irregular and Rectangles per job
Default is the engine every front end uses when none is named. It now runs
Irregular, then Rectangles, checks both layouts with NestLayoutCheck and keeps
the best: valid first, then fewest unplaced parts, then lowest salvage-credited
cost; ties keep Irregular. A candidate that throws or returns nothing is
skipped, cancellation stops the search, and only the chosen layout's plate
commits are reported. Neither engine wins every job in the lane benchmarks,
and Rectangles adds little time while also covering Irregular's invalid
layouts.

The registry lists Default first and no longer maps the name to Fill; fill
strategy callers still read Default as Fill. A future circle/ring engine joins
as another candidate.
2026-10-06 12:26:10 -04:00

55 lines
2.4 KiB
C#

using System.Reflection;
using System.Runtime.Loader;
try
{
if (args.Length != 1)
throw new ArgumentException("Usage: ReleaseSmoke <extracted-package-directory>");
var package = Path.GetFullPath(args[0]);
// No project references: resolve against the extracted release, never the build tree.
AssemblyLoadContext.Default.Resolving += (_, name) =>
{
var path = Path.Combine(package, name.Name + ".dll");
return File.Exists(path) ? AssemblyLoadContext.Default.LoadFromAssemblyPath(path) : null;
};
var engineAssemblyPath = Path.Combine(package, "OpenNest.Engine.dll");
var engineAssembly = Assembly.LoadFrom(engineAssemblyPath);
var registry = engineAssembly.GetType("OpenNest.Engine.Jobs.NestingEngineRegistry", true)!;
var create = registry.GetMethod("Create")!;
// Every built-in engine the desktop offers must instantiate from the packaged assembly.
string[] expected = ["Default", "Rectangles", "Irregular", "StockLadder", "Fill", "Strip", "Vertical Remnant", "Horizontal Remnant"];
foreach (var name in expected)
{
var engine = create.Invoke(null, [name])!;
if (!string.Equals(engine.GetType().Assembly.Location, engineAssemblyPath, StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException($"Engine {name} was not loaded from the release package.");
Console.WriteLine($"PASS: {name} instantiated from {engineAssemblyPath}");
}
// A selection saved before the engines were renamed must still resolve.
var resolved = registry.GetMethod("ResolveName")!.Invoke(null, ["Opus55NestingEngine"]);
if (!Equals(resolved, "Irregular"))
throw new InvalidOperationException($"Legacy selection Opus55NestingEngine resolved to '{resolved}', expected Irregular.");
Console.WriteLine("PASS: legacy selection Opus55NestingEngine resolves to Irregular");
// Failure case: an unknown engine must be rejected, so a broken registry cannot pass silently.
try
{
create.Invoke(null, ["ReleaseSmokeMissingEngine"]);
throw new InvalidOperationException("Unknown engine name was accepted.");
}
catch (TargetInvocationException exception) when (exception.InnerException is NotSupportedException)
{
Console.WriteLine("PASS: unknown engine name rejected");
}
return 0;
}
catch (Exception exception)
{
Console.Error.WriteLine(exception);
return 1;
}