refactoring and tests

This commit is contained in:
vcoppe committed 2026-10-09 08:58:00 +02:00
1 parent 3bb553d6b5
commit da9abbae5e
45 files changed
+3558 -1564

No files matched your search

+51
View File
@@ -0,0 +1,51 @@
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import {
getHighwayColor,
getSlopeColor,
getSurfaceColor,
highwayColors,
surfaceColors,
} from './colors';
describe('colors of the OSM data', () => {
it('has the color of a surface, or the one of the missing ones', () => {
assert.equal(getSurfaceColor('asphalt'), surfaceColors.asphalt);
assert.equal(getSurfaceColor('grass'), '#61b55c');
assert.equal(getSurfaceColor('something new'), surfaceColors.missing);
assert.equal(getSurfaceColor(''), surfaceColors.missing);
});
it('has the color of a highway, or the one of the missing ones', () => {
assert.equal(getHighwayColor('motorway', undefined, undefined), highwayColors.motorway);
assert.equal(getHighwayColor('path', undefined, undefined), highwayColors.path);
assert.equal(getHighwayColor('something new', undefined, undefined), highwayColors.missing);
});
});
describe('slope colors', () => {
const hue = (color: string) => Number(/hsl\(([-\d.e]+),/.exec(color)![1]);
const lightness = (color: string) => Number(/,([\d.]+)%\)$/.exec(color)![1]);
it('is yellow on the flat, redder uphill and greener downhill, symmetrically', () => {
const flat = getSlopeColor(0);
assert.equal(hue(flat), 60);
assert.equal(lightness(flat), 90);
// steeper is further from the flat color, in both directions
assert.ok(hue(getSlopeColor(10)) < 60);
assert.ok(hue(getSlopeColor(-10)) > 60);
assert.ok(lightness(getSlopeColor(10)) < 90);
assert.ok(hue(getSlopeColor(20)) < hue(getSlopeColor(10)));
const up = getSlopeColor(7);
const down = getSlopeColor(-7);
assert.ok(Math.abs(hue(up) + hue(down) - 120) < 1e-9);
assert.ok(Math.abs(lightness(up) - lightness(down)) < 1e-9);
});
it('does not go further than 20 %', () => {
assert.equal(getSlopeColor(20), getSlopeColor(35));
assert.equal(getSlopeColor(1000), getSlopeColor(20));
assert.equal(getSlopeColor(-20), getSlopeColor(-55));
assert.notEqual(getSlopeColor(19), getSlopeColor(20));
});
});
+103
View File
@@ -0,0 +1,103 @@
// The layers are plain data, which the settings and the menus rely on being consistent.
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import {
basemaps,
basemapTree,
defaultBasemap,
defaultBasemapTree,
defaultOpacities,
defaultOverlays,
defaultOverlayTree,
defaultOverpassQueries,
defaultOverpassTree,
defaultTerrainSource,
overlays,
overlayTree,
overpassQueryData,
overpassTree,
terrainSources,
type LayerTreeType,
} from './layers';
import { getLayers } from '$lib/components/map/layer-control/utils';
const leaves = (tree: LayerTreeType) => Object.keys(getLayers(tree));
describe('layers', () => {
it('has a basemap and an overlay for every leaf of their trees', () => {
for (const id of leaves(basemapTree)) assert.ok(id in basemaps, `basemap ${id}`);
for (const id of leaves(overlayTree)) assert.ok(id in overlays, `overlay ${id}`);
for (const id of leaves(overpassTree)) assert.ok(id in overpassQueryData, `query ${id}`);
});
it('offers every layer and every query in its trees', () => {
const missingFrom = (ids: string[], tree: LayerTreeType) => {
const offered = new Set(leaves(tree));
return ids.filter((id) => !offered.has(id));
};
const basemapIds = Object.keys(basemaps);
assert.deepEqual(missingFrom(basemapIds, basemapTree), [], 'basemapTree');
assert.deepEqual(missingFrom(basemapIds, defaultBasemapTree), [], 'defaultBasemapTree');
const overlayIds = Object.keys(overlays);
assert.deepEqual(missingFrom(overlayIds, overlayTree), [], 'overlayTree');
assert.deepEqual(missingFrom(overlayIds, defaultOverlayTree), [], 'defaultOverlayTree');
const queryIds = Object.keys(overpassQueryData);
assert.deepEqual(missingFrom(queryIds, overpassTree), [], 'overpassTree');
assert.deepEqual(missingFrom(queryIds, defaultOverpassTree), [], 'defaultOverpassTree');
assert.deepEqual(
missingFrom(queryIds, defaultOverpassQueries),
[],
'defaultOverpassQueries'
);
});
it('only offers by default what exists', () => {
assert.ok(defaultBasemap in basemaps);
for (const id of leaves(defaultBasemapTree)) assert.ok(id in basemaps, `basemap ${id}`);
for (const id of leaves(defaultOverlayTree)) assert.ok(id in overlays, `overlay ${id}`);
for (const id of leaves(defaultOverpassTree)) assert.ok(id in overpassQueryData, `${id}`);
for (const id of leaves(defaultOverlays)) assert.ok(id in overlays, `overlay ${id}`);
for (const id of leaves(defaultOverpassQueries)) {
assert.ok(id in overpassQueryData, `query ${id}`);
}
assert.ok(defaultTerrainSource in terrainSources);
});
it('has the default selections inside the default trees', () => {
const inTree = (selection: LayerTreeType, tree: LayerTreeType) => {
const offered = new Set(leaves(tree));
for (const id of leaves(selection)) assert.ok(offered.has(id), `${id}`);
};
inTree(defaultOverlays, defaultOverlayTree);
inTree(defaultOverpassQueries, defaultOverpassTree);
});
it('has the default tree inside the whole tree', () => {
const all = new Set(leaves(basemapTree));
for (const id of leaves(defaultBasemapTree)) assert.ok(all.has(id), `${id}`);
});
it('has no id used by two leaves of a tree', () => {
for (const tree of [basemapTree, overlayTree, overpassTree, defaultBasemapTree]) {
const ids: string[] = [];
const walk = (node: LayerTreeType) =>
Object.entries(node).forEach(([id, value]) =>
typeof value === 'boolean' ? ids.push(id) : walk(value)
);
walk(tree);
assert.equal(new Set(ids).size, ids.length);
}
});
it('has opacities between 0 and 1, for overlays', () => {
for (const [id, opacity] of Object.entries(defaultOpacities)) {
assert.ok(opacity >= 0 && opacity <= 1, id);
}
});
it('has the queries it needs', () => {
for (const [id, data] of Object.entries(overpassQueryData)) {
assert.ok(Object.keys(data).length > 0, id);
}
});
});