aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-studio/test-columns.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/theme-studio/test-columns.mjs')
-rw-r--r--scripts/theme-studio/test-columns.mjs59
1 files changed, 58 insertions, 1 deletions
diff --git a/scripts/theme-studio/test-columns.mjs b/scripts/theme-studio/test-columns.mjs
index 139860360..a63e5e0e0 100644
--- a/scripts/theme-studio/test-columns.mjs
+++ b/scripts/theme-studio/test-columns.mjs
@@ -5,7 +5,7 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
-import { columnsFromPalette, regenColumn, groundRoleOfEntry, rankByLightness, stepRepointPlan, sortColumns } from './app-core.js';
+import { columnsFromPalette, usedPaletteHexes, paletteUsages, regenColumn, groundRoleOfEntry, rankByLightness, stepRepointPlan, sortColumns } from './app-core.js';
const columnOf = (columns, name) => columns.find(f => f.members.some(m => m.name === name));
@@ -112,6 +112,11 @@ test('groundRoleOfEntry: Boundary - exact ground roles only, not bg-prefix names
assert.equal(groundRoleOfEntry(['#555555', 'ground-1'], ground), 'step');
});
+test('groundRoleOfEntry: Boundary - renamed entries with the ground column id remain steps', () => {
+ const ground = { bg: '#ffffff', fg: '#000000' };
+ assert.equal(groundRoleOfEntry(['#777777', 'renamed-middle', 'ground'], ground), 'step');
+});
+
// --- regenColumn ------------------------------------------------------------
test('regenColumn: Normal - n steps each side plus the base, ordered by offset', () => {
@@ -196,3 +201,55 @@ test('sortColumns: Normal - preserves member order inside a column', () => {
const members = ['#dddddd', '#222222', '#888888'];
assert.deepEqual(sortColumns([column('gray', members)])[0].members.map(m => m.hex), members);
});
+
+// --- regenColumn ground bounds (task: spans stop at bg/fg) -------------------
+const _lum = h => { const n=parseInt(h.slice(1),16),r=(n>>16&255)/255,g=(n>>8&255)/255,b=(n&255)/255; const f=c=>c<=0.03928?c/12.92:((c+0.055)/1.055)**2.4; return 0.2126*f(r)+0.7152*f(g)+0.0722*f(b); };
+
+test('regenColumn: Normal - ground-bounded span stays within the bg/fg endpoints', () => {
+ const bg = '#101010', fg = '#f0f0f0';
+ const members = regenColumn('#67809c', 4, { ground: { bg, fg } }).members;
+ const lo = _lum(bg), hi = _lum(fg);
+ assert.ok(members.every(m => _lum(m.hex) >= lo - 1e-6 && _lum(m.hex) <= hi + 1e-6),
+ 'every generated member sits within [bg, fg] luminance');
+});
+
+test('regenColumn: Boundary - a near-black bg yields no duplicate pure-black tiles', () => {
+ const members = regenColumn('#67809c', 8, { ground: { bg: '#000000', fg: '#ffffff' } }).members;
+ assert.ok(!members.some(m => m.offset !== 0 && (m.hex === '#000000' || m.hex === '#ffffff')),
+ 'pure endpoints are not duplicated as generated steps');
+});
+
+test('regenColumn: Boundary - no ground falls back to the black/white span', () => {
+ assert.equal(regenColumn('#67809c', 2).members.length, 5);
+});
+
+// --- usedPaletteHexes (unused-tile flagging) --------------------------------
+test('usedPaletteHexes: Normal - records ground, syntax-by-hex, ui-by-name, pkg box color', () => {
+ const palette = [['#101010','bg','ground'],['#f0f0f0','fg','ground'],['#67809c','blue','blue'],['#aa3344','red','red'],['#123456','teal','teal']];
+ const used = usedPaletteHexes(palette, { kw: { fg: '#67809c' } }, { region: { bg: 'red' } }, { magit: { m: { box: { color: '#aa3344' } } } }, { bg: '#101010', fg: '#f0f0f0' });
+ assert.ok(used.has('#101010') && used.has('#f0f0f0'), 'ground endpoints are always used');
+ assert.ok(used.has('#67809c'), 'a syntax hex reference is recorded');
+ assert.ok(used.has('#aa3344'), 'a ui name reference resolves to its hex');
+ assert.ok(!used.has('#123456'), 'an unreferenced color is absent');
+});
+
+test('usedPaletteHexes: Boundary - empty maps leave only the ground endpoints', () => {
+ const used = usedPaletteHexes([['#101010','bg','ground'],['#f0f0f0','fg','ground']], {}, {}, {}, { bg: '#101010', fg: '#f0f0f0' });
+ assert.deepEqual([...used].sort(), ['#101010', '#f0f0f0']);
+});
+
+// --- paletteUsages (hover "view area > element") ----------------------------
+test('paletteUsages: Normal - lists area > element for every assignment of the color', () => {
+ const palette = [['#67809c','blue','blue']];
+ const scopes = [
+ { area: 'color/code assignments', faces: { keyword: { fg: '#67809c' }, string: { fg: '#aabbcc' } } },
+ { area: 'ui faces', faces: { region: { bg: 'blue' } } },
+ { area: 'magit', faces: { branch: { fg: '#999999', box: { color: '#67809c' } } } },
+ ];
+ assert.deepEqual(paletteUsages('#67809c', scopes, palette).sort(),
+ ['color/code assignments > keyword', 'magit > branch', 'ui faces > region'].sort());
+});
+
+test('paletteUsages: Boundary - a color used nowhere returns an empty list', () => {
+ assert.deepEqual(paletteUsages('#123456', [{ area: 'ui faces', faces: { region: { bg: '#000000' } } }], []), []);
+});