fix(io): keep the clamp rail when its saved removal time is invalid

A negative removalMinutes in a saved nest made the ClampRail constructor
throw, so the reader dropped the whole rail and every sheet lost its
removed-clamp state and time. An invalid value now falls back to the
default five minutes, like a missing one.

PM 6ded8ac4-84fd-4e8b-9a3b-6f41e494542c item (b)
This commit is contained in:
aj committed 2026-10-13 18:15:49 -04:00
1 parent 53db543d6b
commit 65754957cc
2 files changed
+31 -7

No files matched your search

@@ -286,6 +286,29 @@ public class ClampRailPersistenceTests
Assert.Equal(keepsRemoval, plate.ClampRail != null);
}
// PM 6ded8ac4 (b): an invalid removal time falls back to the default instead of
// dropping the rail and every sheet's removal state with it.
[Theory]
[InlineData("-1")]
[InlineData("\"x\"")]
public void InvalidRemovalMinutesFallBackToTheDefault(string minutes)
{
var tampered = RewriteNestJson(RemovedClamp3Nest(), text =>
{
var root = JsonNode.Parse(text)!;
root["plateDefaults"]!["clampRail"]!["removalMinutes"] = JsonNode.Parse(minutes);
return root.ToJsonString();
});
var reopened = new NestReader(tampered).Read();
Assert.NotNull(reopened.PlateDefaults.ClampRail);
Assert.Equal(ClampRail.DefaultRemovalMinutes, reopened.PlateDefaults.ClampRail.RemovalMinutes);
var plate = Assert.Single(reopened.Plates);
Assert.Equal(new[] { "clamp-3" }, plate.RemovedClamps);
Assert.NotNull(plate.ClampRail);
}
/// <summary>Removes a named property wherever it appears in the document, simulating a
/// key an older writer never emitted. Rebuilds via <see cref="JsonNode"/> so the result
/// is always valid JSON regardless of whether the property was first, last or only one
+8 -7
View File
@@ -330,7 +330,7 @@ namespace OpenNest.IO
/// <summary>
/// The saved machine clamp rail, or null when absent, empty or malformed (a bad rail
/// is ignored rather than failing the nest; each plate's saved zones still load). A
/// missing removal-minutes value falls back to <see cref="ClampRail.DefaultRemovalMinutes"/>.
/// missing or invalid removal-minutes value falls back to <see cref="ClampRail.DefaultRemovalMinutes"/>.
/// </summary>
private static ClampRail ReadClampRail(ClampRailDto dto)
{
@@ -338,12 +338,13 @@ namespace OpenNest.IO
return null;
try
{
return new ClampRail(
dto.Width,
dto.Depth,
dto.Centers,
dto.RemovalMinutes ?? ClampRail.DefaultRemovalMinutes
);
// An invalid removal time (negative or not finite) falls back to the default
// rather than dropping the rail, which would also discard every sheet's
// removed-clamp state.
var minutes = dto.RemovalMinutes is double m && double.IsFinite(m) && m >= 0
? m
: ClampRail.DefaultRemovalMinutes;
return new ClampRail(dto.Width, dto.Depth, dto.Centers, minutes);
}
catch (ArgumentException)
{