mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
93 lines
3.7 KiB
JavaScript
93 lines
3.7 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFile } from 'node:fs/promises';
|
|
import {
|
|
PDF_COMPASS_PATHS,
|
|
PDF_COMPASS_VIEWBOX_SIZE,
|
|
pdfCompassOps,
|
|
pdfCompassTransform,
|
|
} from '../test-build/pdf/pdf-compass.js';
|
|
|
|
const EXPECTED_PATHS = [
|
|
'M20.82,15.31h0L10.46,9c-.46-.26-1.11.37-.86.84l6.15,10.56,10.56,6.15a.66.66,0,0,0,.84-.86Zm-4,4,3-3,4.55,7.44Z',
|
|
'M18,2A16,16,0,1,0,34,18,16,16,0,0,0,18,2Zm1,29.95V29.53H17v2.42A14,14,0,0,1,4.05,19H6.47V17H4.05A14,14,0,0,1,17,4.05V6.47h2V4.05A14,14,0,0,1,31.95,17H29.53v2h2.42A14,14,0,0,1,19,31.95Z',
|
|
];
|
|
|
|
const apply = (matrix, x, y) => [
|
|
matrix.a * x + matrix.c * y + matrix.e,
|
|
matrix.b * x + matrix.d * y + matrix.f,
|
|
];
|
|
|
|
const closeTo = (actual, expected) => {
|
|
assert.ok(Math.abs(actual - expected) < 1e-10, `${actual} != ${expected}`);
|
|
};
|
|
|
|
test('compass keeps the two canonical Clarity paths pinned to the reviewed commit', () => {
|
|
assert.deepEqual(PDF_COMPASS_PATHS, EXPECTED_PATHS);
|
|
assert.equal(PDF_COMPASS_VIEWBOX_SIZE, 36);
|
|
});
|
|
|
|
test('compass transform preserves its center, size and cardinal north semantics', () => {
|
|
const center = [120, 80];
|
|
const cardinal = [
|
|
{ northDeg: 0, direction: [0, -1] },
|
|
{ northDeg: 90, direction: [1, 0] },
|
|
{ northDeg: 180, direction: [0, 1] },
|
|
{ northDeg: 270, direction: [-1, 0] },
|
|
];
|
|
for (const { northDeg, direction } of cardinal) {
|
|
const matrix = pdfCompassTransform({ centerX: center[0], centerY: center[1], size: 36, northDeg });
|
|
const transformedCenter = apply(matrix, 18, 18);
|
|
closeTo(transformedCenter[0], center[0]);
|
|
closeTo(transformedCenter[1], center[1]);
|
|
|
|
// The canonical diagonal from (18,18) to (17,17) is the needle's north axis.
|
|
const transformedNorth = apply(matrix, 17, 17);
|
|
const dx = transformedNorth[0] - center[0];
|
|
const dy = transformedNorth[1] - center[1];
|
|
closeTo(dx / Math.SQRT2, direction[0]);
|
|
closeTo(dy / Math.SQRT2, direction[1]);
|
|
}
|
|
});
|
|
|
|
test('compass operations are finite, deterministic and normalize equivalent angles', () => {
|
|
const placement = { centerX: 70, centerY: 45, size: 24, northDeg: -90 };
|
|
const first = pdfCompassOps(placement);
|
|
const second = pdfCompassOps({ ...placement, northDeg: 270 });
|
|
assert.deepEqual(first, second);
|
|
assert.ok(first.length > 20);
|
|
assert.equal(first.filter((entry) => entry.op === 'Z').length, 4);
|
|
for (const entry of first) {
|
|
for (const value of Object.values(entry).filter((item) => typeof item === 'number')) {
|
|
assert.ok(Number.isFinite(value));
|
|
}
|
|
}
|
|
assert.deepEqual(
|
|
pdfCompassTransform({ centerX: 0, centerY: 0, size: 18, northDeg: 360 }),
|
|
pdfCompassTransform({ centerX: 0, centerY: 0, size: 18, northDeg: 0 }),
|
|
);
|
|
});
|
|
|
|
test('compass rejects non-finite placement and non-positive sizes', () => {
|
|
assert.throws(
|
|
() => pdfCompassTransform({ centerX: 0, centerY: 0, size: 0, northDeg: 0 }),
|
|
{ name: 'RangeError' },
|
|
);
|
|
assert.throws(
|
|
() => pdfCompassTransform({ centerX: Number.NaN, centerY: 0, size: 10, northDeg: 0 }),
|
|
{ name: 'RangeError' },
|
|
);
|
|
});
|
|
|
|
test('tracked notice preserves Clarity source, commit and MIT attribution', async () => {
|
|
const notice = await readFile(new URL('../THIRD_PARTY_NOTICES.md', import.meta.url), 'utf8');
|
|
const shippedNotice = await readFile(
|
|
new URL('../custom_components/houseplan/THIRD_PARTY_NOTICES.md', import.meta.url), 'utf8',
|
|
);
|
|
assert.match(notice, /bf6bdd0dd3f247f1a320d44d13fecdeda18c071c/);
|
|
assert.match(notice, /Copyright \(c\) 2018 VMware, Inc\./);
|
|
assert.match(notice, /MIT License/);
|
|
assert.match(notice, /copies or substantial portions of the Software/);
|
|
assert.equal(shippedNotice, notice, 'the HACS zip ships the exact reviewed notice');
|
|
});
|