The new windows-desktop CI job surfaced several tests that had never
actually run on Windows:
- SeparatorPenLifetimeTests expected Control.Disposed to fire only
once; current WinForms re-fires it on every Dispose() call.
- EditNestFocusTraversalTests assumed the Plates tab was selected by
default, which stopped being true once Drawings became the landing
tab; select it explicitly before asserting focus.
- NestReportExportTests asserted an exact plate count that ignored
PlateManager's trailing sentinel plate, and didn't expect the nest
name in the busy-export message.
- AtomicReportFileTests only expected IOException when replacing a
directory target; Windows raises UnauthorizedAccessException instead,
which callers already treat the same way.
Also register a ThreadException handler so an exception inside a
WndProc callback fails the test normally instead of popping a modal
dialog that blocks the desktop.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add OpenNest.Reporting (net8.0, PDFsharp-MigraDoc 6.2.4) with a detached
report snapshot and a PDF writer for an empty/demand-only job or a single
plate layout: Letter portrait summary with vector part thumbnails and a
landscape plate page with a vector sheet diagram, both with Page X of Y.
- Snapshot uses reference identity for document-local R### IDs, recounts
nested quantities from placements x copies with checked wide integers,
excludes cutoffs from accounting, and retains no live domain objects.
- Geometry keeps Cut/Display material paths, drops rapid/scribe/lead paths,
preserves native arcs, holes and intentional tab gaps, and rejects
malformed programs with plate/part identification.
- Open contours and cutoffs are stroked per contour so PDFsharp cannot join
a tab gap to the next contour.
- Bundled DejaVu Sans via a custom resolver (including MigraDoc's error
font); unsupported text fails with the field and code point.
- Layouts beyond this slice (multiple plates, page overflow, labels that
do not fit) fail with NotSupportedException before the destination is
replaced; output is rendered to a temporary sibling and moved atomically.