mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
The existing "route that fits" case used 199 steps, which is how the off-by-one went unnoticed. Folds the docs note into the existing cap sentence and makes the changelog entry specific.
227 lines
6.5 KiB
JavaScript
227 lines
6.5 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
ROUTE_STEPS_MAX,
|
|
formatRouteDistance,
|
|
formatRouteDuration,
|
|
instructionFor,
|
|
normalizeOsrmSteps,
|
|
roadLabel,
|
|
} from './routeSteps.js';
|
|
|
|
test('instructions read like a navigator, one sentence per OSRM maneuver', () => {
|
|
assert.equal(
|
|
instructionFor({ type: 'depart', name: 'Kaivokatu' }),
|
|
'Head out on Kaivokatu',
|
|
);
|
|
assert.equal(instructionFor({ type: 'depart' }), 'Head out');
|
|
assert.equal(
|
|
instructionFor({
|
|
type: 'new name',
|
|
modifier: 'straight',
|
|
name: 'Simonkatu',
|
|
}),
|
|
'Continue onto Simonkatu',
|
|
);
|
|
assert.equal(
|
|
instructionFor({
|
|
type: 'end of road',
|
|
modifier: 'left',
|
|
name: 'Annankatu',
|
|
}),
|
|
'At the end of the road, turn left onto Annankatu',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'turn', modifier: 'right', name: 'Kansakoulukatu' }),
|
|
'Turn right onto Kansakoulukatu',
|
|
);
|
|
assert.equal(
|
|
instructionFor({
|
|
type: 'turn',
|
|
modifier: 'slight left',
|
|
name: 'Ring I',
|
|
ref: 'Kt 50',
|
|
}),
|
|
'Turn slightly left onto Ring I (Kt 50)',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'turn', modifier: 'uturn' }),
|
|
'Make a U-turn',
|
|
);
|
|
assert.equal(
|
|
instructionFor({
|
|
type: 'roundabout',
|
|
modifier: 'right',
|
|
exit: 2,
|
|
name: 'Malminrinne',
|
|
}),
|
|
'At the roundabout, take the 2nd exit onto Malminrinne',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'rotary', exit: 1 }),
|
|
'At the roundabout, take the 1st exit',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'roundabout', exit: 11 }),
|
|
'At the roundabout, take the 11th exit',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'fork', modifier: 'slight right', ref: 'E12' }),
|
|
'Keep slightly right at the fork onto E12',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'off ramp', modifier: 'right', name: 'Turunväylä' }),
|
|
'Take the exit on the right onto Turunväylä',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'on ramp', modifier: 'left' }),
|
|
'Take the ramp on the left',
|
|
);
|
|
assert.equal(
|
|
instructionFor({
|
|
type: 'merge',
|
|
modifier: 'slight left',
|
|
name: 'Länsiväylä',
|
|
}),
|
|
'Merge slightly left onto Länsiväylä',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'arrive', modifier: 'right' }),
|
|
'Arrive at your destination, on the right',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'arrive' }),
|
|
'Arrive at your destination',
|
|
);
|
|
assert.equal(
|
|
instructionFor({ type: 'made-up', name: 'X' }),
|
|
'Continue onto X',
|
|
);
|
|
assert.equal(instructionFor(null), 'Continue');
|
|
});
|
|
|
|
test('road label prefers "Name (Ref)" and never repeats a ref already in the name', () => {
|
|
assert.equal(roadLabel({ name: 'Ring I', ref: 'Kt 50' }), 'Ring I (Kt 50)');
|
|
assert.equal(
|
|
roadLabel({ name: 'E12 Turunväylä', ref: 'E12' }),
|
|
'E12 Turunväylä',
|
|
);
|
|
assert.equal(roadLabel({ ref: 'E12' }), 'E12');
|
|
assert.equal(roadLabel({}), '');
|
|
});
|
|
|
|
test('normalizeOsrmSteps flattens legs, folds roundabout exits, and drops steps without a location', () => {
|
|
const route = {
|
|
legs: [
|
|
{
|
|
steps: [
|
|
{
|
|
maneuver: { type: 'depart', location: [24.9384, 60.1699] },
|
|
name: 'Kaivokatu',
|
|
distance: 8.3,
|
|
duration: 1.3,
|
|
},
|
|
{
|
|
maneuver: {
|
|
type: 'roundabout',
|
|
modifier: 'right',
|
|
exit: 2,
|
|
location: [24.9313, 60.1675],
|
|
},
|
|
name: '',
|
|
distance: 34.7,
|
|
duration: 7.3,
|
|
},
|
|
{
|
|
maneuver: {
|
|
type: 'exit roundabout',
|
|
modifier: 'slight right',
|
|
exit: 2,
|
|
location: [24.931, 60.1674],
|
|
},
|
|
name: 'Malminrinne',
|
|
distance: 100.8,
|
|
duration: 17.1,
|
|
},
|
|
{
|
|
maneuver: { type: 'turn', modifier: 'left' },
|
|
name: 'Nowhere',
|
|
distance: 5,
|
|
duration: 1,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
steps: [
|
|
{
|
|
maneuver: {
|
|
type: 'arrive',
|
|
modifier: 'left',
|
|
location: [24.6559, 60.2055],
|
|
},
|
|
name: 'Kirkkojärventie',
|
|
distance: 0,
|
|
duration: 0,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
};
|
|
const { steps, truncated } = normalizeOsrmSteps(route);
|
|
assert.equal(truncated, false, 'a short route is complete');
|
|
assert.deepEqual(
|
|
steps.map((s) => s.type),
|
|
['depart', 'roundabout', 'arrive'],
|
|
);
|
|
assert.equal(steps[1].distanceM, 136);
|
|
assert.equal(steps[1].durationS, 24);
|
|
assert.equal(
|
|
steps[1].instruction,
|
|
'At the roundabout, take the 2nd exit onto Malminrinne',
|
|
);
|
|
assert.deepEqual(
|
|
steps.map((s) => s.index),
|
|
[0, 1, 2],
|
|
);
|
|
assert.equal(steps[2].instruction, 'Arrive at your destination, on the left');
|
|
assert.equal(steps[0].lon, 24.9384);
|
|
assert.equal(steps[0].lat, 60.1699);
|
|
assert.deepEqual(normalizeOsrmSteps(null), { steps: [], truncated: false });
|
|
assert.deepEqual(normalizeOsrmSteps({ legs: [{ steps: null }] }), {
|
|
steps: [],
|
|
truncated: false,
|
|
});
|
|
});
|
|
|
|
test('the step list is capped, and the cap is reported rather than hidden', () => {
|
|
const many = Array.from({ length: ROUTE_STEPS_MAX + 50 }, (_, i) => ({
|
|
maneuver: { type: 'turn', modifier: 'left', location: [i * 0.001, 0.5] },
|
|
name: `Street ${i}`,
|
|
distance: 10,
|
|
duration: 2,
|
|
}));
|
|
const cut = normalizeOsrmSteps({ legs: [{ steps: many }] });
|
|
assert.equal(cut.steps.length, ROUTE_STEPS_MAX);
|
|
// The arrival step is among the ones dropped; a caller that is not told so
|
|
// would present a route that simply stops in the middle of a road.
|
|
assert.equal(cut.truncated, true);
|
|
const exact = normalizeOsrmSteps({
|
|
legs: [{ steps: many.slice(0, ROUTE_STEPS_MAX) }],
|
|
});
|
|
assert.equal(exact.steps.length, ROUTE_STEPS_MAX);
|
|
assert.equal(exact.truncated, false, 'a route that fits is not cut');
|
|
});
|
|
|
|
test('distance and duration formatting', () => {
|
|
assert.equal(formatRouteDistance(8), '8 m');
|
|
assert.equal(formatRouteDistance(846), '850 m');
|
|
assert.equal(formatRouteDistance(1234), '1.2 km');
|
|
assert.equal(formatRouteDistance(21479), '21 km');
|
|
assert.equal(formatRouteDistance(-1), '');
|
|
assert.equal(formatRouteDuration(40), '40 s');
|
|
assert.equal(formatRouteDuration(1478), '25 min');
|
|
assert.equal(formatRouteDuration(3900), '1 h 5 min');
|
|
assert.equal(formatRouteDuration(7200), '2 h');
|
|
assert.equal(formatRouteDuration(NaN), '');
|
|
});
|