Files
OpenNest/OpenNest.Tests/Diagnostics/OverlapHoverPagesTests.cs
T
ajandClaude Opus 5.5 f0d84e041c test: share the circle, square, rectangle and contour fixtures
Cutting-planning, diagnostics and fill tests drew the same circles,
squares, clockwise rectangles, closed polygons, rounded rectangles and
right-midpoint rectangle contours in private helpers. They now use
TestHelpers; files whose helper had its own default size keep a
one-line wrapper for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 10:50:50 -05:00

122 lines
5.1 KiB
C#

using System.Globalization;
using OpenNest.CNC;
using OpenNest.Diagnostics;
using OpenNest.Geometry;
using static OpenNest.Tests.TestHelpers;
namespace OpenNest.Tests.Diagnostics;
public class OverlapHoverPagesTests
{
[Fact]
public void CrowdedCoincidentPairsRemainAccessibleInOrderWithinEveryPageBudget()
{
var parts = Enumerable.Range(1, 12).Select(i => MakeSquarePart($"part-{i}")).ToArray();
var report = PlateOverlapAnalyzer.Analyze(parts);
var pairs = OverlapPairPresentation.HitTest(report.Pairs.Reverse(), p => p, new Vector(2, 2), 96);
var text = string.Join("\n\n", pairs.Select(p => OverlapPairPresentation.Details(p, Units.Millimeters, CultureInfo.InvariantCulture)));
var pages = OverlapHoverPages.Create(text, pairs.Count, 10, 45, s => s.Length);
Assert.True(pages.PageCount > 1);
Assert.False(pages.NeedsLargerViewport);
var displayed = ReadAll(pages, 10, 45);
Assert.Equal(text.Replace("\n", ""), displayed);
Assert.Contains("Pair 11/12: part-11 / part-12", displayed);
Assert.Contains("Shared area ≈ 16 mm²", displayed);
Assert.Contains("Marker: (2, 2) mm", displayed);
Assert.Equal(pages.PageCount - 1, pages.PageIndex);
Assert.Contains($"Page {pages.PageCount}/{pages.PageCount}", string.Join("", pages.NavigationLines));
Assert.Contains("66 pairs", string.Join("", pages.NavigationLines));
Assert.Contains("PgUp/PgDn", string.Join("", pages.NavigationLines));
}
[Theory]
[InlineData(8, 12)]
[InlineData(4, 40)]
public void OneDetailWithLongUnbrokenNamesPagesWithoutDroppingText(int rows, int width)
{
var name = string.Concat(Enumerable.Repeat("veryLongName😀e\u0301", 30));
var pair = Assert.Single(PlateOverlapAnalyzer.Analyze(
new[] { MakeSquarePart(name), MakeSquarePart("tail") }).Pairs);
var text = OverlapPairPresentation.Details(pair, Units.Inches, CultureInfo.InvariantCulture);
var pages = OverlapHoverPages.Create(text, 1, rows, width, s => new StringInfo(s).LengthInTextElements);
Assert.True(pages.PageCount > 1);
Assert.False(pages.NeedsLargerViewport);
Assert.Equal(text.Replace("\n", ""), ReadAll(pages, rows, width, s => new StringInfo(s).LengthInTextElements));
Assert.All(AllLines(text, rows, width), line =>
{
Assert.False(line.Length > 0 && char.IsLowSurrogate(line[0]));
Assert.False(line.StartsWith("\u0301"));
});
}
[Fact]
public void NavigationClampsAtBothEndsAndNewHoverStartsAtFirstPage()
{
const string text = "one\ntwo\nthree\nfour\nfive\nsix";
var pages = OverlapHoverPages.Create(text, 2, 4, 40, s => s.Length);
Assert.True(pages.PageCount > 1);
pages.MovePage(int.MaxValue);
Assert.Equal(pages.PageCount - 1, pages.PageIndex);
pages.MovePage(1);
Assert.Equal(pages.PageCount - 1, pages.PageIndex);
pages.MovePage(int.MinValue);
Assert.Equal(0, pages.PageIndex);
pages.MovePage(-1);
Assert.Equal(0, pages.PageIndex);
pages.MovePage(1);
Assert.Equal(0, OverlapHoverPages.Create(text, 2, 4, 40, s => s.Length).PageIndex);
}
[Fact]
public void FittingDetailsDoNotSpendSpaceOnNavigation()
{
var pages = OverlapHoverPages.Create("Pair 1/2\narea\ncentroid", 1, 3, 40, s => s.Length);
Assert.Equal(1, pages.PageCount);
Assert.Empty(pages.NavigationLines);
Assert.Equal(new[] { "Pair 1/2", "area", "centroid" }, pages.Lines);
pages.MovePage(1);
Assert.Equal(0, pages.PageIndex);
}
[Theory]
[InlineData(0, 40)]
[InlineData(3, 0)]
[InlineData(1, 5)]
[InlineData(4, 0.5)]
public void ImpossibleViewportExplicitlyRequestsMoreSpaceInsteadOfDroppingDetails(int rows, double width)
{
var pages = OverlapHoverPages.Create("Pair 1/2\narea\ncentroid", 1, rows, width, s => s.Length);
Assert.True(pages.NeedsLargerViewport);
Assert.Empty(pages.Lines);
Assert.Equal(0, pages.PageCount);
}
private static string ReadAll(OverlapHoverPages pages, int rows, double width, Func<string, double>? measure = null)
{
measure ??= s => s.Length;
var content = new List<string>();
for (var index = 0; index < pages.PageCount; index++)
{
Assert.Equal(index, pages.PageIndex);
Assert.InRange(pages.Lines.Count + pages.NavigationLines.Count, 1, rows);
Assert.All(pages.Lines.Concat(pages.NavigationLines), line => Assert.InRange(measure(line), 0, width));
content.AddRange(pages.Lines);
pages.MovePage(1);
}
return string.Concat(content);
}
private static IEnumerable<string> AllLines(string text, int rows, int width)
{
var pages = OverlapHoverPages.Create(text, 1, rows, width, s => new StringInfo(s).LengthInTextElements);
for (var i = 0; i < pages.PageCount; i++)
{
foreach (var line in pages.Lines)
yield return line;
pages.MovePage(1);
}
}
}