mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 02:44:02 +00:00
KartaView's server filters by upload date only, so SINCE goes by it throughout for KartaView: the lines (as before), the photo a click opens and the cones, the cut-off taken as its UTC day as KartaView's startDate (passesKartaViewFilter). Providers may declare sinceBasis: 'upload' (validated); while one is lit the panel shows "KartaView: by upload date" under the SINCE slider, read out with it. The gate checks the note, and step 13's picks get 60 s on a loaded machine. Co-Authored-By: Claude Opus 5.5 <[email protected]>
126 lines
3.6 KiB
JavaScript
126 lines
3.6 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { filtersOf, requiresKeyIdFor, validateProviders } from './registry.js';
|
|
|
|
const def = (overrides = {}) => ({
|
|
id: 'mapillary',
|
|
name: 'Mapillary',
|
|
label: 'MAPILLARY',
|
|
requiresKeyId: 'mapillary',
|
|
pickPrefix: 'mly:',
|
|
colors: { coverage: '#05cb63' },
|
|
credit: { html: 'Mapillary' },
|
|
create: () => ({}),
|
|
...overrides,
|
|
});
|
|
|
|
test('a valid list is frozen in registration order', () => {
|
|
const list = validateProviders([
|
|
def(),
|
|
def({ id: 'panoramax', pickPrefix: 'pnx:', requiresKeyId: null }),
|
|
]);
|
|
assert.ok(Object.isFrozen(list));
|
|
assert.deepEqual(
|
|
list.map((p) => p.id),
|
|
['mapillary', 'panoramax'],
|
|
);
|
|
});
|
|
|
|
test('an empty provider list is valid and has no key requirement', () => {
|
|
assert.deepEqual(validateProviders([]), []);
|
|
assert.ok(Object.isFrozen(validateProviders([])));
|
|
assert.equal(requiresKeyIdFor([]), null);
|
|
});
|
|
|
|
test('non-arrays, duplicate ids and malformed ids are rejected', () => {
|
|
assert.throws(() => validateProviders(null), /array/);
|
|
assert.throws(() => validateProviders([def(), def()]), /Duplicate/);
|
|
assert.throws(() => validateProviders([def({ id: 'Bad Id' })]), /slug/);
|
|
});
|
|
|
|
test('every required field is checked by name', () => {
|
|
for (const key of [
|
|
'name',
|
|
'label',
|
|
'pickPrefix',
|
|
'colors',
|
|
'credit',
|
|
'create',
|
|
])
|
|
assert.throws(
|
|
() => validateProviders([def({ [key]: undefined })]),
|
|
new RegExp(`lacks ${key}`),
|
|
key,
|
|
);
|
|
assert.throws(() => validateProviders([def({ create: 1 })]), /create/);
|
|
assert.throws(() => validateProviders([def({ credit: {} })]), /credit/);
|
|
assert.throws(
|
|
() => validateProviders([def({ colors: { pano: '#f0f' } })]),
|
|
/coverage colour/,
|
|
);
|
|
assert.throws(
|
|
() => validateProviders([def({ pickPrefix: '' })]),
|
|
/pick prefix/,
|
|
);
|
|
});
|
|
|
|
test('overlapping pick prefixes are rejected either way round', () => {
|
|
assert.throws(
|
|
() => validateProviders([def(), def({ id: 'other', pickPrefix: 'mly:x' })]),
|
|
/overlaps/,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
validateProviders([def({ pickPrefix: 'mly:x' }), def({ id: 'other' })]),
|
|
/overlaps/,
|
|
);
|
|
assert.doesNotThrow(() =>
|
|
validateProviders([def(), def({ id: 'other', pickPrefix: 'ml:' })]),
|
|
);
|
|
});
|
|
|
|
test('requiresKeyIdFor is the shared key, or null once providers differ', () => {
|
|
assert.equal(requiresKeyIdFor([def()]), 'mapillary');
|
|
assert.equal(
|
|
requiresKeyIdFor([def(), def({ id: 'b', pickPrefix: 'b:' })]),
|
|
'mapillary',
|
|
);
|
|
assert.equal(
|
|
requiresKeyIdFor([
|
|
def(),
|
|
def({ id: 'b', pickPrefix: 'b:', requiresKeyId: null }),
|
|
]),
|
|
null,
|
|
);
|
|
assert.equal(
|
|
requiresKeyIdFor([
|
|
def(),
|
|
def({ id: 'b', pickPrefix: 'b:', requiresKeyId: 'google-maps' }),
|
|
]),
|
|
null,
|
|
);
|
|
assert.equal(requiresKeyIdFor([def({ requiresKeyId: null })]), null);
|
|
});
|
|
|
|
test('a provider may narrow the filters it honours and pick a view-cone marker', () => {
|
|
assert.deepEqual(filtersOf(def()), ['pano', 'since'], 'both by default');
|
|
const narrowed = def({
|
|
filters: [],
|
|
marker: { kind: 'view-cone', color: '#4285f4' },
|
|
});
|
|
assert.deepEqual(filtersOf(validateProviders([narrowed])[0]), []);
|
|
assert.throws(
|
|
() => validateProviders([def({ filters: ['colour'] })]),
|
|
/filters must list pano or since/,
|
|
);
|
|
assert.throws(
|
|
() => validateProviders([def({ marker: { kind: 'pegman' } })]),
|
|
/marker must be/,
|
|
);
|
|
validateProviders([def({ sinceBasis: 'upload' })]);
|
|
assert.throws(
|
|
() => validateProviders([def({ sinceBasis: 'shot' })]),
|
|
/sinceBasis must be 'capture' or 'upload'/,
|
|
);
|
|
});
|