Files
houseplan-card/test/led-strip-path-cache.test.mjs
T
Matysh 416d2fae71 perf(led): avoid redundant tube and barrier calculations
Preserve exact light fields while culling provably distant occluders,
reusing physical tube paths across camera updates and excluding LED emitter
data from aligned architectural fingerprints. Cover output equivalence,
in-place invalidation, resize tags and hyphenated benchmark chunk hashes.

Issue: #788
User-Visible: yes
2026-10-03 19:18:49 +03:00

89 lines
4.1 KiB
JavaScript

// #788: camera renders reuse tube geometry without freezing live state or edits.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { ledFrameFor, ledStripePath, releaseLed } from '../test-build/led-strip-runtime.js';
import { LED_THICKNESS_D, pathD, visibleStripPath } from '../test-build/led-strip-geometry.js';
const strip = () => ({ id: 'led', marker: 'lamp', points: [[2, 1], [6, 1], [6, 4]] });
const wallFaces = () => ({
faces: [{ a: [0, 1], b: [10, 1] }],
inside: ([x, y]) => x > 0 && x < 10 && y < 1,
epsilon: 1e-5,
});
const fresh = (shape, faces, diameter) => {
const t = LED_THICKNESS_D * diameter;
const path = visibleStripPath(shape.points, faces, t / 2);
return { t, path, d: pathD(path) };
};
test('#788: repeated camera reads skip tube classification and reuse identical SVG geometry', () => {
const shape = strip(), faces = wallFaces();
let classifications = 0;
faces.near = () => { classifications++; return faces.faces; };
const cached = ledStripePath(shape, faces, 4);
assert.equal(classifications, 1);
for (let step = 0; step < 100; step++) assert.equal(ledStripePath(shape, faces, 4), cached);
assert.equal(classifications, 1, 'camera reads must not rerun face classification');
assert.deepEqual(cached, fresh(shape, faces, 4), 'cached outline and hit geometry equal the uncached derivation');
});
test('#788: face context, epsilon, diameter and exact point edits invalidate the tube cache', () => {
const shape = strip();
let faces = wallFaces(), diameter = 4;
let previous = ledStripePath(shape, faces, diameter);
const changed = () => {
const value = ledStripePath(shape, faces, diameter);
assert.notEqual(value, previous);
assert.deepEqual(value, fresh(shape, faces, diameter));
previous = value;
};
diameter = 8;
changed();
faces = null;
changed();
faces = wallFaces();
changed();
faces.epsilon *= 2;
changed();
shape.points[1][0] = 7;
changed();
shape.points = [[1, 2], [8, 2], [8, 5]];
changed();
shape.points.push([9, 6]);
changed();
const replacement = { ...shape, points: shape.points.map((point) => [...point]) };
assert.notEqual(ledStripePath(replacement, faces, diameter), previous, 'same id in a new frame owns a new weak cache key');
});
const ownerFixture = () => ({
isConnected: true,
_renderDevices: [{ id: 'lamp', name: 'Lamp', primary: 'light.led', entities: ['light.led'],
space: 's', marker: { id: 'lamp', binding: 'device:lamp' } }],
_renderPlanHass: { states: { 'light.led': { state: 'on', attributes: {} } } },
_fillColors: { glow_light: { c: '#ffd27b', a: 0.7 } },
_cellCm: 5, _gridPitch: 1000 / 240, _config: { icon_size: 3.4 },
_mode: 'view', _showAll: false,
_pointInRoom: () => false,
});
const spaceFixture = () => ({ id: 's', vb: [0, 0, 1000, 1000], rooms: [],
led_strips: [{ id: 'led', marker: 'lamp', points: [[0.1, 0.1], [0.4, 0.1]] }] });
test('#788: new HA frames keep live state and evict the old frame geometry; disconnect releases it', () => {
const owner = ownerFixture(), space = spaceFixture();
const first = ledFrameFor(owner, space, true);
const firstStrip = first.views[0].strip;
const firstPath = ledStripePath(firstStrip, first.faces, first.d);
assert.equal(ledFrameFor(owner, space, true), first, 'unchanged camera inputs reuse the frame');
assert.equal(ledStripePath(firstStrip, first.faces, first.d), firstPath);
owner._renderPlanHass = { states: { 'light.led': { state: 'off', attributes: {} } } };
const second = ledFrameFor(owner, space, true);
assert.notEqual(second, first);
assert.equal(second.views[0].state, 'off', 'geometry caching must not freeze the device state');
assert.notEqual(ledStripePath(firstStrip, first.faces, first.d), firstPath, 'old frame entry was explicitly evicted');
const secondStrip = second.views[0].strip;
const secondPath = ledStripePath(secondStrip, second.faces, second.d);
assert.deepEqual(secondPath, firstPath, 'state changes preserve the physical tube');
releaseLed(owner);
assert.notEqual(ledStripePath(secondStrip, second.faces, second.d), secondPath, 'disconnect explicitly evicts current frame entries');
});