feat(gate-b): Gate B mask + BDFT + length axis (#21–#23) #31
@@ -0,0 +1,37 @@
|
||||
/** TECH-SPEC §8 TV-3 numeric fixture (client-authoritative sqft input). */
|
||||
export function tv3Fixture(): {
|
||||
lengthIn: number;
|
||||
thicknessIn: number;
|
||||
sqft: number;
|
||||
expectedBdft: number;
|
||||
} {
|
||||
return {
|
||||
lengthIn: 96,
|
||||
thicknessIn: 1.5,
|
||||
sqft: 0.64,
|
||||
expectedBdft: 0.96,
|
||||
};
|
||||
}
|
||||
|
||||
/** TECH-SPEC §8 TV-10 rounding vectors. */
|
||||
export function tv10Fixture(): {
|
||||
lengthRaw: number;
|
||||
lengthExpected: number;
|
||||
sqftRaw: number;
|
||||
sqftExpected: number;
|
||||
bdftRaw: number;
|
||||
bdftExpected: number;
|
||||
priceRaw: number;
|
||||
priceExpected: number;
|
||||
} {
|
||||
return {
|
||||
lengthRaw: 96.04,
|
||||
lengthExpected: 96,
|
||||
sqftRaw: 0.641,
|
||||
sqftExpected: 0.64,
|
||||
bdftRaw: 11.525,
|
||||
bdftExpected: 11.53,
|
||||
priceRaw: 12.345,
|
||||
priceExpected: 12.35,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
computeBdft,
|
||||
roundBdft,
|
||||
roundLengthIn,
|
||||
roundPrice,
|
||||
roundSqft,
|
||||
} from "../lib/pipeline/units.js";
|
||||
import { tv3Fixture, tv10Fixture } from "./fixtures/units.js";
|
||||
|
||||
describe("TV-3 Scale, sqft, bdft", () => {
|
||||
it("bdft = sqft × thickness_in with no divide-by-12", () => {
|
||||
const { lengthIn, thicknessIn, sqft, expectedBdft } = tv3Fixture();
|
||||
const bdft = computeBdft(sqft, thicknessIn);
|
||||
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
case: "TV-3",
|
||||
lengthIn,
|
||||
thicknessIn,
|
||||
sqft,
|
||||
bdft,
|
||||
expectedBdft,
|
||||
identity_1sqft_1in: computeBdft(1, 1),
|
||||
}),
|
||||
);
|
||||
|
||||
expect(bdft).toBe(expectedBdft);
|
||||
expect(bdft).toBe(0.96);
|
||||
expect(computeBdft(1, 1)).toBe(1);
|
||||
expect(bdft).not.toBeCloseTo((sqft * thicknessIn) / 12, 5);
|
||||
});
|
||||
|
||||
it("bdft is monotonic in thickness and sqft", () => {
|
||||
const baseSqft = 0.64;
|
||||
const baseThick = 1.5;
|
||||
expect(computeBdft(baseSqft, baseThick + 0.125)).toBeGreaterThan(
|
||||
computeBdft(baseSqft, baseThick),
|
||||
);
|
||||
expect(computeBdft(baseSqft + 0.01, baseThick)).toBeGreaterThan(
|
||||
computeBdft(baseSqft, baseThick),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("TV-10 Rounding", () => {
|
||||
it("half-up / nearest-step matches TECH-SPEC vectors", () => {
|
||||
const fx = tv10Fixture();
|
||||
|
||||
const length = roundLengthIn(fx.lengthRaw);
|
||||
const sqft = roundSqft(fx.sqftRaw);
|
||||
const bdft = roundBdft(fx.bdftRaw);
|
||||
const price = roundPrice(fx.priceRaw);
|
||||
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
case: "TV-10",
|
||||
length: { raw: fx.lengthRaw, rounded: length, expected: fx.lengthExpected },
|
||||
sqft: { raw: fx.sqftRaw, rounded: sqft, expected: fx.sqftExpected },
|
||||
bdft: { raw: fx.bdftRaw, rounded: bdft, expected: fx.bdftExpected },
|
||||
price: { raw: fx.priceRaw, rounded: price, expected: fx.priceExpected },
|
||||
}),
|
||||
);
|
||||
|
||||
expect(length).toBe(fx.lengthExpected);
|
||||
expect(sqft).toBe(fx.sqftExpected);
|
||||
expect(bdft).toBe(fx.bdftExpected);
|
||||
expect(price).toBe(fx.priceExpected);
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./constants.js";
|
||||
export * from "./types.js";
|
||||
export * from "./mask.js";
|
||||
export * from "./units.js";
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
AREA_DECIMALS,
|
||||
BDFT_DECIMALS,
|
||||
INCH_STEP,
|
||||
PRICE_DECIMALS,
|
||||
} from "./constants.js";
|
||||
|
||||
/** Half-up at .5 (away from zero). */
|
||||
export function roundHalfUp(value: number, decimals: number): number {
|
||||
if (!Number.isFinite(value)) {
|
||||
return value;
|
||||
}
|
||||
const factor = 10 ** decimals;
|
||||
const scaled = Math.abs(value) * factor;
|
||||
const rounded = Math.floor(scaled + 0.5) / factor;
|
||||
return value < 0 ? -rounded : rounded;
|
||||
}
|
||||
|
||||
/** Nearest INCH_STEP (1/8"). */
|
||||
export function roundLengthIn(lengthIn: number): number {
|
||||
return Math.round(lengthIn / INCH_STEP) * INCH_STEP;
|
||||
}
|
||||
|
||||
export function roundSqft(sqft: number): number {
|
||||
return roundHalfUp(sqft, AREA_DECIMALS);
|
||||
}
|
||||
|
||||
export function roundBdft(bdft: number): number {
|
||||
return roundHalfUp(bdft, BDFT_DECIMALS);
|
||||
}
|
||||
|
||||
export function roundPrice(price: number): number {
|
||||
return roundHalfUp(price, PRICE_DECIMALS);
|
||||
}
|
||||
|
||||
/** bdft = sqft × thickness_in. No divide-by-12. */
|
||||
export function computeBdft(sqft: number, thicknessIn: number): number {
|
||||
return roundBdft(sqft * thicknessIn);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
RUN v2.1.9 /workspace/gitea-atd/Ty_Tech/SlabUploader/frontend
|
||||
|
||||
stdout | src/__tests__/tv3-tv10-units.test.ts > TV-3 Scale, sqft, bdft > bdft = sqft × thickness_in with no divide-by-12
|
||||
{"case":"TV-3","lengthIn":96,"thicknessIn":1.5,"sqft":0.64,"bdft":0.96,"expectedBdft":0.96,"identity_1sqft_1in":1}
|
||||
|
||||
stdout | src/__tests__/tv3-tv10-units.test.ts > TV-10 Rounding > half-up / nearest-step matches TECH-SPEC vectors
|
||||
{"case":"TV-10","length":{"raw":96.04,"rounded":96,"expected":96},"sqft":{"raw":0.641,"rounded":0.64,"expected":0.64},"bdft":{"raw":11.525,"rounded":11.53,"expected":11.53},"price":{"raw":12.345,"rounded":12.35,"expected":12.35}}
|
||||
|
||||
✓ src/__tests__/tv3-tv10-units.test.ts (3 tests) 7ms
|
||||
|
||||
Test Files 1 passed (1)
|
||||
Tests 3 passed (3)
|
||||
Start at 06:02:02
|
||||
Duration 377ms (transform 61ms, setup 0ms, collect 63ms, tests 7ms, environment 0ms, prepare 67ms)
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
RUN v2.1.9 /workspace/gitea-atd/Ty_Tech/SlabUploader/frontend
|
||||
|
||||
❯ src/__tests__/tv3-tv10-units.test.ts (0 test)
|
||||
|
||||
⎯⎯⎯⎯⎯⎯ Failed Suites 1 ⎯⎯⎯⎯⎯⎯⎯
|
||||
|
||||
FAIL src/__tests__/tv3-tv10-units.test.ts [ src/__tests__/tv3-tv10-units.test.ts ]
|
||||
Error: Failed to load url ../lib/pipeline/units.js (resolved id: ../lib/pipeline/units.js) in /workspace/gitea-atd/Ty_Tech/SlabUploader/frontend/src/__tests__/tv3-tv10-units.test.ts. Does the file exist?
|
||||
❯ loadAndTransform node_modules/vite/dist/node/chunks/dep-BK3b2jBa.js:51969:17
|
||||
|
||||
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
|
||||
|
||||
Test Files 1 failed (1)
|
||||
Tests no tests
|
||||
Start at 06:01:33
|
||||
Duration 344ms (transform 42ms, setup 0ms, collect 0ms, tests 0ms, environment 0ms, prepare 69ms)
|
||||
|
||||
Reference in New Issue
Block a user