← back to Charge And Explore
backend/test/stop-score.test.ts
70 lines
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import {
routeConvenience,
chargerQuality,
scoreStop,
STOP_SCORE_WEIGHTS,
type StopScoreComponents,
} from "../src/core/stop-score.ts";
const perfect: StopScoreComponents = {
route: 100,
charger: 100,
amenity: 100,
timeFit: 100,
nighttime: 100,
walkability: 100,
basicNeeds: 100,
};
describe("routeConvenience", () => {
it("is 100 at zero detour and decays with detour", () => {
assert.equal(Math.round(routeConvenience(0)), 100);
assert.ok(routeConvenience(5) > routeConvenience(20));
});
it("never goes negative", () => {
assert.ok(routeConvenience(1000) >= 0);
});
});
describe("stop score weights", () => {
it("weights sum to 1.0", () => {
const sum = Object.values(STOP_SCORE_WEIGHTS).reduce((a, b) => a + b, 0);
assert.ok(Math.abs(sum - 1) < 1e-9, `weights sum to ${sum}`);
});
});
describe("chargerQuality", () => {
it("stays within 0–100 and rewards power most", () => {
const highPower = chargerQuality({ power: 100, stalls: 0, reliability: 0, dynamicAvailability: 0 });
const highAvail = chargerQuality({ power: 0, stalls: 0, reliability: 0, dynamicAvailability: 100 });
assert.ok(highPower > highAvail);
assert.ok(highPower <= 100);
});
});
describe("scoreStop", () => {
it("a perfect stop scores 100", () => {
assert.equal(scoreStop(perfect, 1).score, 100);
});
it("a zeroed stop scores 0", () => {
const zero = { ...perfect };
(Object.keys(zero) as (keyof StopScoreComponents)[]).forEach((k) => (zero[k] = 0));
assert.equal(scoreStop(zero, 1).score, 0);
});
it("labels confidence from data completeness", () => {
assert.equal(scoreStop(perfect, 0.9).confidence, "high");
assert.equal(scoreStop(perfect, 0.6).confidence, "limited");
assert.equal(scoreStop(perfect, 0.2).confidence, "low");
});
it("clamps out-of-range component inputs", () => {
const over = { ...perfect, charger: 999 };
assert.ok(scoreStop(over, 1).score <= 100);
});
});