// power.test.js — node test for the pure power module. // Run: node power.test.js (must print "power.test.js: ALL PASS") var assert = require('assert'); var P = require('./power.js'); var passed = 0; function eq(got, want, msg) { assert.strictEqual(got, want, msg); passed++; } function deep(got, want, msg) { assert.deepStrictEqual(got, want, msg); passed++; } function ok(cond, msg) { assert(cond, msg); passed++; } // --- normalizePercent ------------------------------------------------------ eq(P.normalizePercent(0.42), 42, 'fraction 0..1 -> percent'); eq(P.normalizePercent(73), 73, 'already-percent passes through'); eq(P.normalizePercent(1), 100, '1.0 -> 100'); eq(P.normalizePercent(null), 0, 'null -> 0'); eq(P.normalizePercent(99.6), 100, 'rounds'); // --- minutesToLabel -------------------------------------------------------- eq(P.minutesToLabel(0), 'unknown', 'zero seconds unknown'); eq(P.minutesToLabel(2700), '45m', '45 minutes'); eq(P.minutesToLabel(7200), '2h', 'exact hours drop minutes'); eq(P.minutesToLabel(4800), '1h 20m', 'hours and minutes'); eq(P.minutesToLabel(-50), 'unknown', 'negative clamps to unknown'); // --- cleanState ------------------------------------------------------------ eq(P.cleanState('Fully charged'), 'full', 'fully charged -> full'); eq(P.cleanState('Discharging'), 'discharging', 'lowercased'); eq(P.cleanState('Pending charge'), 'pendingcharge', 'spaces stripped'); eq(P.cleanState(null), 'unknown', 'null -> unknown'); // --- batteryRole ----------------------------------------------------------- eq(P.batteryRole(8), 'error', 'critical'); eq(P.batteryRole(10), 'error', 'boundary 10'); eq(P.batteryRole(20), 'warning', 'low'); eq(P.batteryRole(25), 'warning', 'boundary 25'); eq(P.batteryRole(60), 'ui.accent', 'healthy'); // --- timeEstimateLabel ----------------------------------------------------- eq(P.timeEstimateLabel('Charging', 3600, 0), '1h', 'charging uses time-to-full'); eq(P.timeEstimateLabel('Discharging', 0, 5400), '1h 30m', 'discharging uses time-to-empty'); // --- isLowPower ------------------------------------------------------------ eq(P.isLowPower('Discharging'), true, 'discharging is low power'); eq(P.isLowPower('Pending discharge'), true, 'pending discharge is low power'); eq(P.isLowPower('Charging'), false, 'charging is not'); eq(P.isLowPower('Fully charged'), false, 'full is not'); // --- hasMainBattery -------------------------------------------------------- eq(P.hasMainBattery({ percent: 0, state: 'unknown', timeEstimate: 'unknown', health: -1 }), false, 'desktop display device placeholder is not a main battery'); eq(P.hasMainBattery({ percent: 72, state: 'charging', timeEstimate: '1h', health: 91 }), true, 'real laptop battery is a main battery'); eq(P.hasMainBattery({ percent: 0, state: 'discharging', timeEstimate: 'unknown', health: -1 }), true, 'reported discharging state is a main battery even at zero percent'); // --- requiresConfirmation -------------------------------------------------- eq(P.requiresConfirmation('poweroff'), true, 'poweroff confirms'); eq(P.requiresConfirmation('reboot'), true, 'reboot confirms'); eq(P.requiresConfirmation('logout'), true, 'logout confirms'); eq(P.requiresConfirmation('suspend'), false, 'suspend is recoverable, no confirm'); eq(P.requiresConfirmation('lock'), false, 'lock no confirm'); eq(P.requiresConfirmation('monitor-off'), false, 'monitor-off no confirm'); // --- actionPlan: the routing table (the safety-critical part) -------------- deep(P.actionPlan('lock'), { via: 'lock' }, 'lock routes to lockService'); deep(P.actionPlan('monitor-off'), { via: 'niri', args: ['power-off-monitors'] }, 'monitor-off via niri'); deep(P.actionPlan('monitor-on'), { via: 'niri', args: ['power-on-monitors'] }, 'monitor-on via niri'); deep(P.actionPlan('logout'), { via: 'niri', args: ['quit', '--skip-confirmation'] }, 'logout = niri quit, skip its prompt'); deep(P.actionPlan('suspend'), { via: 'exec', argv: ['systemctl', 'suspend'] }, 'suspend = systemctl suspend'); deep(P.actionPlan('reboot'), { via: 'exec', argv: ['systemctl', 'reboot'] }, 'reboot = systemctl reboot'); deep(P.actionPlan('poweroff'), { via: 'exec', argv: ['systemctl', 'poweroff'] }, 'poweroff = systemctl poweroff'); deep(P.actionPlan('bogus'), { via: 'none' }, 'unknown action does nothing'); // argv/args must be discrete tokens, never a single shell string ok(Array.isArray(P.actionPlan('poweroff').argv) && P.actionPlan('poweroff').argv.length === 2, 'poweroff argv is token array (no shell injection)'); // every advertised session action has a real plan (no silent no-ops) P.SESSION_ACTIONS.forEach(function (a) { ok(P.actionPlan(a).via !== 'none', 'session action "' + a + '" has a real route'); }); // --- actionLabel ----------------------------------------------------------- eq(P.actionLabel('monitor-off'), 'mon off', 'monitor-off label'); eq(P.actionLabel('poweroff'), 'power', 'poweroff label'); eq(P.actionLabel('lock'), 'lock', 'passthrough label'); console.log(passed + ' assertions passed'); console.log('power.test.js: ALL PASS');