diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f897079a..1634c5bd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,9 @@ - Street Level counts unique tiles before ranking so overlapping dateline halves in polar views do not waste slots in the 16-tile overview budget. +- Directions no longer shows a truncation notice for a route with exactly 200 + turns, and a roundabout at the 200th turn keeps its exit distance. + - Weather records keep missing conditions unknown and refuse summaries without a measured temperature. - Tool string length validation counts Unicode characters correctly, including characters outside the basic multilingual plane. diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 7376cd2a6..de34656f6 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -3403,9 +3403,10 @@ rate limit from the routing service is reported as one instead of as "no route found". `src/data/routeSteps.js` turns OSRM maneuver type / modifier / exit / road name into one plain-English sentence per decision, folding `exit roundabout` steps into the roundabout they leave, and caps one route at -200 maneuvers — a route past that cap is reported as cut off, in the row -summary and as the last line of the list, because the arrival step is among -the ones dropped. +200 maneuvers — a route with more is reported as cut off, in the row summary +and as the last line of the list, because the arrival step is among the ones +dropped. A route of exactly 200 is complete, and a roundabout exit after the +200th keeps folding into it. A step's card opens from its dot on the globe or from its line in the list, and the list covers every step including departure and arrival, which have no dot. diff --git a/src/data/route-cap-truthfulness.test.mjs b/src/data/route-cap-truthfulness.test.mjs new file mode 100644 index 000000000..7d5d80153 --- /dev/null +++ b/src/data/route-cap-truthfulness.test.mjs @@ -0,0 +1,24 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { normalizeOsrmSteps, ROUTE_STEPS_MAX } from './routeSteps.js'; +const step = (type) => ({ + maneuver: { type, location: [10, 20] }, + distance: 10, + duration: 1, +}); +test('exact-cap routes remain complete and boundary exits retain their distance', () => { + const steps = Array.from({ length: ROUTE_STEPS_MAX }, () => step('turn')); + assert.equal(normalizeOsrmSteps({ legs: [{ steps }] }).truncated, false); + assert.equal( + normalizeOsrmSteps({ legs: [{ steps: [...steps, step('turn')] }] }) + .truncated, + true, + ); + steps[steps.length - 1] = step('roundabout'); + const result = normalizeOsrmSteps({ + legs: [{ steps: [...steps, step('exit roundabout')] }], + }); + assert.equal(result.truncated, false); + assert.equal(result.steps.length, ROUTE_STEPS_MAX); + assert.equal(result.steps.at(-1).distanceM, 20); +}); diff --git a/src/data/routeSteps.js b/src/data/routeSteps.js index 5ee11602a..e3144bdf7 100644 --- a/src/data/routeSteps.js +++ b/src/data/routeSteps.js @@ -185,9 +185,9 @@ export function normalizeOsrmSteps(route) { } continue; } + if (out.length >= ROUTE_STEPS_MAX) return { steps: out, truncated: true }; step.instruction = instructionFor(step); out.push(step); - if (out.length >= ROUTE_STEPS_MAX) return { steps: out, truncated: true }; } } return { steps: out, truncated: false }; diff --git a/src/data/routeSteps.test.mjs b/src/data/routeSteps.test.mjs index a3c8cf227..6bf74dd08 100644 --- a/src/data/routeSteps.test.mjs +++ b/src/data/routeSteps.test.mjs @@ -206,9 +206,9 @@ test('the step list is capped, and the cap is reported rather than hidden', () = // 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 - 1) }], + legs: [{ steps: many.slice(0, ROUTE_STEPS_MAX) }], }); - assert.equal(exact.steps.length, ROUTE_STEPS_MAX - 1); + assert.equal(exact.steps.length, ROUTE_STEPS_MAX); assert.equal(exact.truncated, false, 'a route that fits is not cut'); });