Files
OpenNest/OpenNest.Tests/Data/SetReleaseTextTests.cs
T
ajandClaude Opus 5.5 54b15cff19 feat(releases): release library drawings on their own beside sets
Operators want to release a few loose drawings without first building a
set for them. The release record gains a `drawings` list (drawingId,
quantity, joined drawingName) and nest items with no `setId` carry those
drawings' quantities, so grouping, merging and undo stay one path.

Schema v11 adds release_drawings and rebuilds release_nest_items with a
nullable setId (SQLite cannot drop NOT NULL), keeping every row. The
query gains `drawingId=`; a server from before this refuses that unknown
parameter with 400, which the client turns into ServerTooOldException.
SetReleaseSession asks before building anything, because the release is
posted only after its nests are saved and an old server would refuse it
then.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 11:54:30 -04:00

156 lines
6.8 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 Origin_NamesDrawingsOnTheirOwn_BesideSetsOrAlone()
{
SetReleaseDrawing Loose(string name, int quantity) => new() { DrawingName = name, Quantity = quantity };
var set = new SetReleaseLine { SetName = "Synthetic kit", SetRevision = 3, Quantity = 2 };
Assert.Equal("Released from drawing 'SYN-A' ×4",
SetReleaseText.Origin(new SetReleaseRecord { Drawings = new[] { Loose("SYN-A", 4) } }));
Assert.Equal("Released from set 'Synthetic kit' revision 3 ×2 and drawings 'SYN-A' ×4 and 'SYN-B' ×1",
SetReleaseText.Origin(new SetReleaseRecord { Sets = new[] { set }, Drawings = new[] { Loose("SYN-A", 4), Loose("SYN-B", 1) } }));
Assert.Equal("drawings 'A' ×1, 'B' ×2 and 'C' ×3",
SetReleaseText.Drawings(new[] { Loose("A", 1), Loose("B", 2), Loose("C", 3) }));
Assert.Equal("4 drawings", SetReleaseText.Drawings(Enumerable.Range(1, 4).Select(i => Loose("D" + i, i)).ToList()));
}
[Theory]
[InlineData(SetReleaseNestKind.Created, null, "Created")]
[InlineData(SetReleaseNestKind.Created, SetReleaseNestUndo.Deleted, "Created; undo deleted it")]
[InlineData(SetReleaseNestKind.Merged, null, "Merged (revision 3 → 4)")]
[InlineData(SetReleaseNestKind.Merged, SetReleaseNestUndo.Restored, "Merged (revision 3 → 4); undo restored revision 3")]
[InlineData(SetReleaseNestKind.Merged, SetReleaseNestUndo.Skipped, "Merged (revision 3 → 4); undo left it as it was")]
public void Change_SaysWhatTheReleaseAndItsUndoDid(SetReleaseNestKind kind, SetReleaseNestUndo? undo, string expected)
{
var nest = new SetReleaseNest
{
Kind = kind,
RevisionBefore = kind == SetReleaseNestKind.Merged ? 3 : null,
RevisionAfter = kind == SetReleaseNestKind.Merged ? 4 : 1,
Undo = undo,
};
Assert.Equal(expected, SetReleaseText.Change(nest));
}
[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));
}
}