mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-27 07:11:06 -04:00
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>
156 lines
6.8 KiB
C#
156 lines
6.8 KiB
C#
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));
|
||
}
|
||
}
|