Files
OpenNest/OpenNest.IO.Tests/NestWriterAtomicSaveTests.cs
ajandClaude Opus 5.5 d29f919aa2 fix(io): save nests safely and reopen them with their cut-off settings
Reopening a nest regenerated its cut-offs with built-in defaults (no
overtravel, a different minimum segment) rather than the machine's
settings it was made with, so a nest saved, reopened and posted could
cut scrap that never separates. Plates now record the settings their
cut-offs were last generated with, and files carry them; older files
still load with the defaults.

Saving over a nest file truncated it before writing, so any failure
part way lost the only good copy, and the error reached the user as an
unhandled exception after the save path had already changed. Nest and
settings files are now written beside the target and swapped in, and a
failed save is reported with the old file left intact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 09:51:11 -05:00

49 lines
1.7 KiB
C#

namespace OpenNest.IO.Tests;
/// <summary>
/// Saving over a nest file must never leave it truncated: a write that fails part way keeps
/// the previously saved nest.
/// </summary>
public class NestWriterAtomicSaveTests : IDisposable
{
private readonly string directory = Path.Combine(Path.GetTempPath(), "opennest-atomic-save-" + Guid.NewGuid());
public NestWriterAtomicSaveTests() => Directory.CreateDirectory(directory);
public void Dispose() => Directory.Delete(directory, recursive: true);
[Fact]
public void FailedWrite_KeepsThePreviousFile()
{
var path = Path.Combine(directory, "job.nest");
var nest = new Nest("Good");
var drawing = TestDrawings.Square();
nest.Drawings.Add(drawing);
var plate = new Plate(48, 96);
plate.Parts.Add(new Part(drawing));
nest.Plates.Add(plate);
Assert.True(new NestWriter(nest).Write(path));
var saved = File.ReadAllBytes(path);
// JSON has no NaN, so serializing this plate throws part way through the archive.
nest.Plates[0].PartSpacing = double.NaN;
Assert.ThrowsAny<Exception>(() => new NestWriter(nest).Write(path));
Assert.Equal(saved, File.ReadAllBytes(path));
Assert.Equal(new[] { path }, Directory.GetFiles(directory));
}
[Fact]
public void Write_ReplacesAnExistingFile()
{
var path = Path.Combine(directory, "job.nest");
File.WriteAllText(path, "old");
Assert.True(new NestWriter(new Nest("New")).Write(path));
using var stream = File.OpenRead(path);
Assert.Equal("New", new NestReader(stream).Read().Name);
Assert.Equal(new[] { path }, Directory.GetFiles(directory));
}
}