mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-07-26 06:42:32 +00:00
_resolveFreeCam() (keys/drum) and _freeCamFor() (highway_3d) guarded the panel map lookup with only `i != null`, so a non-integer / negative / string index from panelIndexFor() could resolve an unintended or inherited property (e.g. map['toString']) instead of cleanly falling back to the global camera. Gate the index on `Number.isInteger(i) && i >= 0` before `map[i]`, matching the hardening already applied in _bgPanelKey(). Extend the resolver tests with float/string (prototype-key) cases. Behavior change only for malformed indices. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Kris Anderson <topkoa@gmail.com>
79 lines
3.5 KiB
JavaScript
79 lines
3.5 KiB
JavaScript
// Camera Director bridge resolver tests: per-panel select, global fallback,
|
|
// null-when-absent, throw-safety, and the splitscreen global-name alias. Loads
|
|
// screen.js in a bare vm window and exercises the __test exports (no DOM/WebGL).
|
|
const { test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const vm = require('node:vm');
|
|
|
|
function load() {
|
|
const window = {
|
|
console,
|
|
location: { protocol: 'http:', host: 'localhost' },
|
|
slopsmith: {},
|
|
};
|
|
window.window = window;
|
|
window.globalThis = window;
|
|
const context = vm.createContext(window);
|
|
const src = fs.readFileSync(path.join(__dirname, '..', 'screen.js'), 'utf8');
|
|
vm.runInContext(src, context, { filename: 'screen.js' });
|
|
return { window, __test: window.slopsmithViz_drum_highway_3d.__test };
|
|
}
|
|
|
|
test('_resolveFreeCam: per-panel camera under splitscreen', () => {
|
|
const { __test } = load();
|
|
const c0 = {}, c1 = {};
|
|
const ss = { panelIndexFor: (c) => (c === c0 ? 0 : 1) };
|
|
const map = { 0: { id: 'p0' }, 1: { id: 'p1' } };
|
|
assert.equal(__test._resolveFreeCam(c0, ss, map, { id: 'g' }).id, 'p0');
|
|
assert.equal(__test._resolveFreeCam(c1, ss, map, { id: 'g' }).id, 'p1');
|
|
});
|
|
|
|
test('_resolveFreeCam: falls back to global when there is no panel map', () => {
|
|
const { __test } = load();
|
|
const g = { id: 'global' };
|
|
assert.equal(__test._resolveFreeCam({}, { panelIndexFor: () => 0 }, null, g), g);
|
|
});
|
|
|
|
test('_resolveFreeCam: falls back to global when the panel has no map entry', () => {
|
|
const { __test } = load();
|
|
const g = { id: 'global' };
|
|
const ss = { panelIndexFor: () => 3 }; // index 3 absent from map
|
|
assert.equal(__test._resolveFreeCam({}, ss, { 0: {} }, g), g);
|
|
});
|
|
|
|
test('_resolveFreeCam: null when Camera Director is absent (no global)', () => {
|
|
const { __test } = load();
|
|
assert.equal(__test._resolveFreeCam({}, null, null, null), null);
|
|
assert.equal(__test._resolveFreeCam({}, { panelIndexFor: () => 0 }, {}, undefined), null);
|
|
});
|
|
|
|
test('_resolveFreeCam: throw-safe on panelIndexFor → falls back to global', () => {
|
|
const { __test } = load();
|
|
const g = { id: 'global' };
|
|
const ss = { panelIndexFor: () => { throw new Error('boom'); } };
|
|
assert.equal(__test._resolveFreeCam({}, ss, { 0: {} }, g), g);
|
|
});
|
|
|
|
test('_resolveFreeCam: NaN/negative/float/string index → falls back to global', () => {
|
|
const { __test } = load();
|
|
const g = { id: 'global' };
|
|
assert.equal(__test._resolveFreeCam({}, { panelIndexFor: () => NaN }, { 0: {} }, g), g);
|
|
assert.equal(__test._resolveFreeCam({}, { panelIndexFor: () => -1 }, { 0: {} }, g), g);
|
|
assert.equal(__test._resolveFreeCam({}, { panelIndexFor: () => 0.5 }, { 0: {} }, g), g);
|
|
// A string/prototype key must not resolve an inherited property (e.g. toString).
|
|
assert.equal(__test._resolveFreeCam({}, { panelIndexFor: () => 'toString' }, {}, g), g);
|
|
});
|
|
|
|
test('_ssApi: null when neither global set; slopsmith alias; feedBack canonical wins', () => {
|
|
const { window, __test } = load();
|
|
assert.equal(__test._ssApi(), null);
|
|
const legacy = { panelIndexFor: () => 0 };
|
|
window.slopsmithSplitscreen = legacy;
|
|
assert.equal(__test._ssApi(), legacy); // legacy alias picked up
|
|
const current = { panelIndexFor: () => 1 };
|
|
window.feedBackSplitscreen = current;
|
|
assert.equal(__test._ssApi(), current); // canonical name takes precedence
|
|
});
|