From 11c8124674e6830df392cf0e9f1abceb78f9a8d3 Mon Sep 17 00:00:00 2001 From: grokbot_ty Date: Tue, 15 Sep 2026 03:20:17 +0000 Subject: [PATCH] test(capture): expect tip-trimmed every-6in width stations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ty UAT: width min/max must describe bulk, not tips. Pin L=48 tapered case (7 interior stations, no tip endpoints), uniform mid-board count, and L≤12 empty/zero fallback before the sampleWidths change lands. --- frontend/src/measure/measure.test.ts | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 frontend/src/measure/measure.test.ts diff --git a/frontend/src/measure/measure.test.ts b/frontend/src/measure/measure.test.ts new file mode 100644 index 0000000..9a9ba57 --- /dev/null +++ b/frontend/src/measure/measure.test.ts @@ -0,0 +1,58 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { minAreaRect, orientedRect } from '../geometry/rect.ts'; +import { measure } from './measure.ts'; + +// Uniform slab, 10 px/in: full W×H canvas, axis +x via minAreaRect angle 0. +function uniform(W: number, H: number) { + const bitset = new Uint8Array(W * H).fill(1); + const box = orientedRect(minAreaRect(bitset, W, H)!, 0); + return { bitset, box, slabPx: W * H }; +} + +// Tapered slab, 10 px/in: tips under 6 in and past L−6 in are `tipPx` wide +// (centered), the bulk is full canvas height. +function tapered(W: number, H: number, lengthEighths: number, tipPx: number) { + const inIn = W / 10; + const bitset = new Uint8Array(W * H); + const half = tipPx / 2; + for (let x = 0; x < W; x++) { + const p = x / 10; + const w = p < 6 || p > inIn - 6 ? tipPx : H; + for (let y = (H - w) / 2; y < (H + w) / 2; y++) bitset[y * W + x] = 1; + } + const box = orientedRect(minAreaRect(bitset, W, H)!, 0); + return { bitset, box, slabPx: bitset.reduce((a, c) => a + c, 0), lengthEighths }; +} + +test('tapered 48in slab: min/max reflect the bulk, tips excluded', () => { + const { bitset, box, slabPx, lengthEighths } = tapered(480, 100, 384, 20); // tips 2in, bulk 10in + const m = measure(bitset, 480, 100, box, lengthEighths, 8, slabPx); + assert.equal(m.widths.every6In.length, 7, `stations ${m.widths.every6In.length} (6..42in)`); + for (const e of m.widths.every6In) { + assert.ok(e >= 76 && e <= 84, `station ${e / 8}in must be bulk (~10in)`); + } + assert.ok(m.widths.min >= 76 && m.widths.min <= 84, `min ${m.widths.min / 8}in`); + assert.ok(m.widths.max >= 76 && m.widths.max <= 84, `max ${m.widths.max / 8}in`); +}); + +test('uniform slab: interior stations keep the full width', () => { + const { bitset, box, slabPx } = uniform(480, 100); + const m = measure(bitset, 480, 100, box, 384, 8, slabPx); + assert.equal(m.widths.every6In.length, 7); + for (const e of m.widths.every6In) { + assert.ok(e >= 72 && e <= 104, `station ${e / 8}in`); + } +}); + +test('short slab L=12in: no interior stations, widths are empty/zero', () => { + const { bitset, box, slabPx } = uniform(120, 100); + const m = measure(bitset, 120, 100, box, 96, 8, slabPx); + assert.deepEqual(m.widths, { min: 0, max: 0, avg: 0, every6In: [] }); +}); + +test('short slab L=10in: no interior stations, widths are empty/zero', () => { + const { bitset, box, slabPx } = uniform(100, 100); + const m = measure(bitset, 100, 100, box, 80, 8, slabPx); + assert.deepEqual(m.widths, { min: 0, max: 0, avg: 0, every6In: [] }); +});