Files
OpenNest/OpenNest.Tests/Data/SetReleaseTextTests.cs
T
ajandClaude Opus 5.5 74203483c5 feat(data): release several sets in one plan and merge groups into draft nests
The release plan now takes several sets, each with its own kit count. A
drawing listed by more than one set becomes one item with the quantities
summed and each set's share kept, so the release can record what every kit
put into every nest. FindDraftsAsync lists the Draft nests of a group's
material through the new nest query filters.

The session can merge a group into a chosen draft instead of making a new
nest. It downloads the draft at the revision it was chosen at, refuses it
unless it is still a Draft of the group's material, thickness, units and cut
type, adds the items, and removes every plate so the whole demand is nested
again. The save is guarded by that revision, so a draft someone saved
meanwhile fails its group instead of being overwritten. An optional renest
step, run before anything is uploaded, will back "Nest after release"; if it
throws, the nest is still released without a layout.

The release record now carries every set line, merged nests with their
revisions before and after, and each set's drawing quantities.
SetReleaseText.UndoRefusal words a refused undo for the release history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 10:25:53 -04:00

122 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using OpenNest.Data;
using OpenNest.Geometry;
namespace OpenNest.Tests.Data;
public class SetReleaseTextTests
{
private static SetReleaseNest Nest(NestStatus status, bool deleted = false, bool joined = true) => new()
{
NestId = Guid.NewGuid(),
MaterialName = "Synthetic Steel",
MaterialGrade = "Grade A",
Thickness = 0.25,
Units = Units.Inches,
CutType = CutType.Waterjet,
Nest = joined ? new NestRecord { Name = "N1", Status = status, Deleted = deleted } : null,
};
[Fact]
public void Progress_CountsCutNestsAndLeavesDeletedOnesOut()
{
Assert.Equal("2 of 3 cut", SetReleaseText.Progress(new SetReleaseRecord
{
Nests = new[] { Nest(NestStatus.HasBeenCut), Nest(NestStatus.HasBeenCut), Nest(NestStatus.Draft) },
}));
Assert.Equal("0 of 1 cut, 2 deleted", SetReleaseText.Progress(new SetReleaseRecord
{
Nests = new[] { Nest(NestStatus.ToBeCut), Nest(NestStatus.HasBeenCut, deleted: true), Nest(NestStatus.Quote, joined: false) },
}));
Assert.Equal("All nests deleted", SetReleaseText.Progress(new SetReleaseRecord
{
Nests = new[] { Nest(NestStatus.Draft, deleted: true), Nest(NestStatus.Draft, deleted: true) },
}));
}
[Fact]
public void NestState_AndGroup_DescribeOneNest()
{
Assert.Equal("To Be Cut", SetReleaseText.NestState(Nest(NestStatus.ToBeCut)));
Assert.Equal("Deleted", SetReleaseText.NestState(Nest(NestStatus.ToBeCut, deleted: true)));
Assert.Equal("Synthetic Steel Grade A 0.25 in waterjet", SetReleaseText.Group(Nest(NestStatus.Draft)));
}
[Fact]
public void Origin_NamesTheSetRevisionMultiplierAndWho()
{
var text = SetReleaseText.Origin(new SetReleaseRecord
{
Sets = new[] { new SetReleaseLine { SetName = "Synthetic kit", SetRevision = 3, Quantity = 2 } },
ReleasedBy = "Synthetic operator",
});
Assert.Equal("Released from set 'Synthetic kit' revision 3 ×2 by Synthetic operator", text);
}
[Fact]
public void UndoRefusal_NamesEachChangedNest_OrSaysItWasUndoneBefore()
{
var conflict = new SetReleaseUndoConflict
{
Reason = SetReleaseUndoRefusal.NestsChanged,
ChangedNests = new[]
{
new NestRecord { Name = "Edited nest", Revision = 5, Status = NestStatus.ToBeCut },
new NestRecord { Name = "Removed nest", Revision = 2, Deleted = true },
},
};
var text = SetReleaseText.UndoRefusal(conflict);
Assert.Contains("- Edited nest: saved since the release (now revision 5, To Be Cut)", text);
Assert.Contains("- Removed nest: deleted since the release", text);
Assert.Equal("This release was already undone.",
SetReleaseText.UndoRefusal(new SetReleaseUndoConflict { Reason = SetReleaseUndoRefusal.AlreadyUndone }));
}
[Fact]
public void Origin_OfAMergeOfSeveralSets_NamesThemAll_AndAnUndo()
{
var nest = Guid.NewGuid();
var release = new SetReleaseRecord
{
Sets = new[]
{
new SetReleaseLine { SetName = "Kit A", SetRevision = 3, Quantity = 2 },
new SetReleaseLine { SetName = "Kit B", SetRevision = 1, Quantity = 1 },
new SetReleaseLine { SetName = "Kit C", SetRevision = 5, Quantity = 4 },
},
Nests = new[] { new SetReleaseNest { NestId = nest, Kind = SetReleaseNestKind.Merged } },
UndoneAt = new DateTime(2026, 10, 21, 9, 0, 0, DateTimeKind.Utc),
};
Assert.Equal("Merged from sets 'Kit A' revision 3 ×2, 'Kit B' revision 1 ×1 and 'Kit C' revision 5 ×4 (undone)",
SetReleaseText.Origin(release, nest));
Assert.StartsWith("Released from sets", SetReleaseText.Origin(release));
Assert.Equal("Undone", SetReleaseText.Progress(release));
}
[Fact]
public void NestDefaults_ConvertedTo_ScalesPlateDefaultsBetweenUnits()
{
var inches = new NestDefaults
{
Units = Units.Inches,
Size = new Size(60, 120),
Quadrant = 3,
PartSpacing = 0.125,
EdgeSpacing = new Spacing(0.5, 0.25, 0.5, 0.25),
};
var millimeters = inches.ConvertedTo(Units.Millimeters);
var back = millimeters.ConvertedTo(Units.Inches);
Assert.Equal((Units.Millimeters, 1524.0, 3048.0, 3, 3.175), (millimeters.Units, millimeters.Size.Width,
millimeters.Size.Length, millimeters.Quadrant, millimeters.PartSpacing));
Assert.Equal((12.7, 6.35, 12.7, 6.35), (millimeters.EdgeSpacing.Left, millimeters.EdgeSpacing.Bottom,
millimeters.EdgeSpacing.Right, millimeters.EdgeSpacing.Top));
Assert.Equal((60.0, 120.0, 0.125), (back.Size.Width, back.Size.Length, back.PartSpacing));
Assert.NotSame(inches, inches.ConvertedTo(Units.Inches));
}
}