New nests now load plate defaults from %APPDATA%/OpenNest/defaults.json instead of a .nstdot nest template: - Tools > Nest Defaults... edits the file directly (new dialog). - Tools > Save Current Plate as Defaults captures the active plate with no dialog (visible when a nest is open). - New_Click no longer unzips a template; a corrupt defaults file warns once per session and falls back to built-in values. - First run converts an existing NestTemplatePath .nstdot to defaults.json and clears the legacy setting (kept readable on a failed conversion); the setting itself stays, marked legacy. - Save As no longer offers the .nstdot filter; SaveTemplate removed. - BomImportForm and OptionsForm template plumbing removed in favor of the shared NestDefaults store.
210 lines
6.4 KiB
C#
210 lines
6.4 KiB
C#
using OpenNest.Data;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.Tests.Data;
|
|
|
|
public class NestDefaultsTests : IDisposable
|
|
{
|
|
private readonly string _testDir;
|
|
private readonly string _path;
|
|
|
|
public NestDefaultsTests()
|
|
{
|
|
_testDir = Path.Combine(Path.GetTempPath(), "OpenNestTests", Guid.NewGuid().ToString());
|
|
Directory.CreateDirectory(_testDir);
|
|
_path = Path.Combine(_testDir, "defaults.json");
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (Directory.Exists(_testDir))
|
|
Directory.Delete(_testDir, true);
|
|
}
|
|
|
|
[Fact]
|
|
public void Save_ThenLoad_RoundTrips()
|
|
{
|
|
var original = new NestDefaults
|
|
{
|
|
Units = Units.Millimeters,
|
|
Size = new Size(1220, 2440),
|
|
Quadrant = 3,
|
|
PartSpacing = 2.5,
|
|
EdgeSpacing = new Spacing(1.5, 3, 1.5, 3),
|
|
};
|
|
|
|
original.Save(_path);
|
|
var loaded = NestDefaults.Load(_path, out var status);
|
|
|
|
Assert.Equal(NestDefaultsStatus.Ok, status);
|
|
Assert.Equal(Units.Millimeters, loaded.Units);
|
|
Assert.Equal(original.Size, loaded.Size);
|
|
Assert.Equal(3, loaded.Quadrant);
|
|
Assert.Equal(2.5, loaded.PartSpacing);
|
|
Assert.Equal(original.EdgeSpacing.Left, loaded.EdgeSpacing.Left);
|
|
Assert.Equal(original.EdgeSpacing.Bottom, loaded.EdgeSpacing.Bottom);
|
|
Assert.Equal(original.EdgeSpacing.Right, loaded.EdgeSpacing.Right);
|
|
Assert.Equal(original.EdgeSpacing.Top, loaded.EdgeSpacing.Top);
|
|
}
|
|
|
|
[Fact]
|
|
public void Save_CreatesMissingDirectory()
|
|
{
|
|
var nested = Path.Combine(_testDir, "nested", "defaults.json");
|
|
new NestDefaults().Save(nested);
|
|
Assert.True(File.Exists(nested));
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_MissingFile_ReturnsFallback()
|
|
{
|
|
var loaded = NestDefaults.Load(_path, out var status);
|
|
|
|
Assert.Equal(NestDefaultsStatus.Missing, status);
|
|
AssertFallback(loaded);
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_CorruptJson_ReturnsFallbackButReportsInvalid()
|
|
{
|
|
File.WriteAllText(_path, "{ this is not json");
|
|
|
|
var loaded = NestDefaults.Load(_path, out var status);
|
|
|
|
Assert.Equal(NestDefaultsStatus.Invalid, status);
|
|
AssertFallback(loaded);
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_PartialFile_MergesPerField()
|
|
{
|
|
File.WriteAllText(_path, """{ "units": "millimeters", "partSpacing": 4 }""");
|
|
|
|
var loaded = NestDefaults.Load(_path, out var status);
|
|
|
|
Assert.Equal(NestDefaultsStatus.Ok, status);
|
|
Assert.Equal(Units.Millimeters, loaded.Units);
|
|
Assert.Equal(4, loaded.PartSpacing);
|
|
// Untouched fields keep fallback values.
|
|
Assert.Equal(new Size(100, 100), loaded.Size);
|
|
Assert.Equal(1, loaded.Quadrant);
|
|
Assert.Equal(new Spacing(1, 1, 1, 1), loaded.EdgeSpacing);
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_OutOfRangeValues_FallBackPerField()
|
|
{
|
|
File.WriteAllText(
|
|
_path,
|
|
"""
|
|
{
|
|
"units": "furlongs",
|
|
"size": { "width": -50, "length": 100 },
|
|
"quadrant": 9,
|
|
"partSpacing": -1,
|
|
"edgeSpacing": { "left": 1, "bottom": -2, "right": 1, "top": 1 }
|
|
}
|
|
"""
|
|
);
|
|
|
|
var loaded = NestDefaults.Load(_path, out var status);
|
|
|
|
// The file parses; only the invalid values fall back, so no warning.
|
|
Assert.Equal(NestDefaultsStatus.Ok, status);
|
|
Assert.Equal(Units.Inches, loaded.Units);
|
|
Assert.Equal(new Size(100, 100), loaded.Size);
|
|
Assert.Equal(1, loaded.Quadrant);
|
|
Assert.Equal(1, loaded.PartSpacing);
|
|
Assert.Equal(new Spacing(1, 1, 1, 1), loaded.EdgeSpacing);
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_NonFiniteValues_FallBack()
|
|
{
|
|
File.WriteAllText(_path, """{ "partSpacing": 1e400 }""");
|
|
|
|
var loaded = NestDefaults.Load(_path);
|
|
|
|
// 1e400 deserializes to Infinity, which is rejected.
|
|
Assert.Equal(1, loaded.PartSpacing);
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_UnknownFieldsAndFutureVersion_Ignored()
|
|
{
|
|
File.WriteAllText(
|
|
_path,
|
|
"""
|
|
{
|
|
"version": 2,
|
|
"units": "inches",
|
|
"partSpacing": 2,
|
|
"futureFeature": { "enabled": true },
|
|
"material": { "name": "steel" }
|
|
}
|
|
"""
|
|
);
|
|
|
|
var loaded = NestDefaults.Load(_path, out var status);
|
|
|
|
Assert.Equal(NestDefaultsStatus.Ok, status);
|
|
Assert.Equal(2, loaded.PartSpacing);
|
|
}
|
|
|
|
[Fact]
|
|
public void FromNest_CapturesUnitsAndPlateDefaults()
|
|
{
|
|
var nest = new Nest
|
|
{
|
|
Units = Units.Millimeters,
|
|
};
|
|
nest.PlateDefaults.Size = new Size(60, 120);
|
|
nest.PlateDefaults.Quadrant = 2;
|
|
nest.PlateDefaults.PartSpacing = 0.5;
|
|
nest.PlateDefaults.EdgeSpacing = new Spacing(2, 2, 2, 2);
|
|
|
|
var captured = NestDefaults.FromNest(nest);
|
|
|
|
Assert.Equal(Units.Millimeters, captured.Units);
|
|
Assert.Equal(new Size(60, 120), captured.Size);
|
|
Assert.Equal(2, captured.Quadrant);
|
|
Assert.Equal(0.5, captured.PartSpacing);
|
|
Assert.Equal(new Spacing(2, 2, 2, 2), captured.EdgeSpacing);
|
|
}
|
|
|
|
[Fact]
|
|
public void ApplyTo_SetsUnitsAndPlateDefaults_AndDoesNotAliasSourceNest()
|
|
{
|
|
var source = new Nest();
|
|
source.PlateDefaults.Size = new Size(48, 96);
|
|
source.PlateDefaults.EdgeSpacing = new Spacing(1.25, 1.25, 1.25, 1.25);
|
|
var defaults = NestDefaults.FromNest(source);
|
|
|
|
// Mutating the source nest afterwards must not change the capture.
|
|
source.PlateDefaults.Size = new Size(1, 1);
|
|
source.PlateDefaults.EdgeSpacing = new Spacing(9, 9, 9, 9);
|
|
|
|
var target = new Nest();
|
|
defaults.ApplyTo(target);
|
|
|
|
Assert.Equal(new Size(48, 96), target.PlateDefaults.Size);
|
|
Assert.Equal(
|
|
new Spacing(1.25, 1.25, 1.25, 1.25),
|
|
target.PlateDefaults.EdgeSpacing
|
|
);
|
|
|
|
// And the applied target owns its own values too.
|
|
target.PlateDefaults.Size = new Size(2, 2);
|
|
Assert.Equal(new Size(48, 96), defaults.Size);
|
|
}
|
|
|
|
private static void AssertFallback(NestDefaults loaded)
|
|
{
|
|
Assert.Equal(Units.Inches, loaded.Units);
|
|
Assert.Equal(new Size(100, 100), loaded.Size);
|
|
Assert.Equal(1, loaded.Quadrant);
|
|
Assert.Equal(1, loaded.PartSpacing);
|
|
Assert.Equal(new Spacing(1, 1, 1, 1), loaded.EdgeSpacing);
|
|
}
|
|
}
|