mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
263 lines
7.6 KiB
JavaScript
263 lines
7.6 KiB
JavaScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { FEATURE_SOURCE_METHODS } from '../sources/featureSource.js';
|
|
import { createAnnotationResolver } from './resolver.js';
|
|
|
|
function featureSource(overrides = {}) {
|
|
const source = {};
|
|
for (const method of FEATURE_SOURCE_METHODS)
|
|
source[method] = async () => null;
|
|
return Object.assign(source, overrides);
|
|
}
|
|
|
|
// A state-typed place outside every bundled boundary, so the admin-boundary
|
|
// feature lookup (not the bundled packs) answers.
|
|
const offPackGeocode = {
|
|
async geocode() {
|
|
return {
|
|
place: {
|
|
lat: 0.5,
|
|
lng: -150.5,
|
|
label: 'Atlantis',
|
|
name: 'Atlantis',
|
|
types: ['administrative_area_level_1', 'political'],
|
|
},
|
|
};
|
|
},
|
|
};
|
|
|
|
function geocoderFor(place) {
|
|
const calls = [];
|
|
return {
|
|
calls,
|
|
async geocode(query) {
|
|
calls.push(query);
|
|
return { place };
|
|
},
|
|
};
|
|
}
|
|
|
|
test('region ring: Natural Earth names resolve without a geocoder', async () => {
|
|
const { resolveRegionRingForQuery } = createAnnotationResolver({
|
|
featureSource: featureSource(),
|
|
});
|
|
for (const name of ['Gulf of Mexico', 'the Alps']) {
|
|
const region = await resolveRegionRingForQuery(name);
|
|
assert.ok(region?.ring?.length >= 3, `${name} resolves to a ring`);
|
|
assert.equal(region.source, 'natural-earth');
|
|
assert.equal(region.error, undefined);
|
|
}
|
|
});
|
|
|
|
test('region ring: duplicate natural names need a containing geocoded anchor', async () => {
|
|
const { resolveRegionRingForQuery } = createAnnotationResolver({
|
|
featureSource: featureSource(),
|
|
});
|
|
const miss = geocoderFor(null);
|
|
assert.equal(
|
|
await resolveRegionRingForQuery('Cordillera Oriental', undefined, miss),
|
|
null,
|
|
);
|
|
assert.deepEqual(miss.calls, ['Cordillera Oriental']);
|
|
|
|
const inside = geocoderFor({
|
|
lat: 5,
|
|
lng: -73,
|
|
label: 'Cordillera Oriental',
|
|
name: 'Cordillera Oriental',
|
|
types: ['natural_feature'],
|
|
});
|
|
const region = await resolveRegionRingForQuery(
|
|
'Cordillera Oriental',
|
|
undefined,
|
|
inside,
|
|
);
|
|
assert.equal(region?.source, 'natural-earth');
|
|
assert.equal(region.name, 'Cordillera Oriental');
|
|
assert.ok(region.ring.length >= 8);
|
|
assert.deepEqual(inside.calls, ['Cordillera Oriental']);
|
|
});
|
|
|
|
test('region ring: outside and overlapping geocoded natural anchors stay unresolved', async () => {
|
|
const { resolveRegionRingForQuery } = createAnnotationResolver({
|
|
featureSource: featureSource(),
|
|
});
|
|
for (const [name, lat, lng] of [
|
|
['Cordillera Oriental', 30.27, -97.74],
|
|
['Canadian Shield', 45.6336, -74.86493],
|
|
]) {
|
|
const geocoder = geocoderFor({
|
|
lat,
|
|
lng,
|
|
label: name,
|
|
name,
|
|
types: ['natural_feature'],
|
|
});
|
|
assert.equal(
|
|
await resolveRegionRingForQuery(name, undefined, geocoder),
|
|
null,
|
|
);
|
|
assert.deepEqual(geocoder.calls, [name]);
|
|
}
|
|
});
|
|
|
|
test('region ring: geocoded administrative scope wins over duplicate natural geography', async () => {
|
|
const lookups = [];
|
|
const { resolveRegionRingForQuery } = createAnnotationResolver({
|
|
featureSource: featureSource({
|
|
getAdministrativeAreas: async (point) => {
|
|
lookups.push(point);
|
|
return [];
|
|
},
|
|
}),
|
|
});
|
|
const geo = geocoderFor({
|
|
lat: 5,
|
|
lng: -73,
|
|
label: 'Cordillera Oriental',
|
|
name: 'Cordillera Oriental',
|
|
types: ['locality'],
|
|
});
|
|
const resolved = await resolveRegionRingForQuery(
|
|
'Cordillera Oriental',
|
|
undefined,
|
|
geo,
|
|
);
|
|
assert.equal(
|
|
resolved,
|
|
null,
|
|
'an unavailable city boundary is not a natural-region outline',
|
|
);
|
|
assert.deepEqual(lookups, [{ lat: 5, lon: -73 }]);
|
|
assert.deepEqual(geo.calls, ['Cordillera Oriental']);
|
|
});
|
|
|
|
test('region ring: cancellation during bundled lookup and geocode never returns a region', async () => {
|
|
const { resolveRegionRingForQuery } = createAnnotationResolver({
|
|
featureSource: featureSource(),
|
|
});
|
|
const controller = new AbortController();
|
|
const pending = resolveRegionRingForQuery('the Alps', controller.signal);
|
|
controller.abort();
|
|
await assert.rejects(pending, { name: 'AbortError' });
|
|
|
|
const later = new AbortController();
|
|
await assert.rejects(
|
|
resolveRegionRingForQuery('Cordillera Oriental', later.signal, {
|
|
async geocode() {
|
|
later.abort();
|
|
return { place: null };
|
|
},
|
|
}),
|
|
{ name: 'AbortError' },
|
|
);
|
|
});
|
|
|
|
test('region ring: a slow admin-boundary lookup returns region-timeout within the budget', async () => {
|
|
let adminSignal;
|
|
let release;
|
|
let lookupStarted;
|
|
const { resolveRegionRingForQuery } = createAnnotationResolver({
|
|
featureSource: featureSource({
|
|
getAdministrativeAreas(_point, { signal }) {
|
|
lookupStarted = Date.now();
|
|
adminSignal = signal;
|
|
return new Promise((resolve) => {
|
|
release = resolve;
|
|
});
|
|
},
|
|
}),
|
|
});
|
|
const region = await resolveRegionRingForQuery(
|
|
'Atlantis',
|
|
undefined,
|
|
offPackGeocode,
|
|
{ budgetMs: 50 },
|
|
);
|
|
assert.deepEqual(region, {
|
|
name: 'Atlantis',
|
|
ring: null,
|
|
error: 'region-timeout',
|
|
});
|
|
// Timed from the boundary lookup, so the bundled pack scans before it do not
|
|
// count. Under the 3 s default budget, so an ignored budgetMs still fails.
|
|
assert.ok(
|
|
Date.now() - lookupStarted < 2_000,
|
|
'returns at the budget, not the lookup',
|
|
);
|
|
// The lookup is left running so it can fill the boundary cache.
|
|
assert.equal(adminSignal?.aborted ?? false, false);
|
|
release(null);
|
|
});
|
|
|
|
test('region ring: an unbounded budget waits for the lookup', async () => {
|
|
const { resolveRegionRingForQuery } = createAnnotationResolver({
|
|
featureSource: featureSource({
|
|
getAdministrativeAreas: () =>
|
|
new Promise((resolve) => setTimeout(() => resolve(null), 30)),
|
|
}),
|
|
});
|
|
const region = await resolveRegionRingForQuery(
|
|
'Atlantis',
|
|
undefined,
|
|
offPackGeocode,
|
|
{ budgetMs: Infinity },
|
|
);
|
|
assert.equal(region, null);
|
|
});
|
|
|
|
test('region ring: bundled states and counties resolve without a geocoder', async () => {
|
|
const lookups = [];
|
|
const { resolveRegionRingForQuery } = createAnnotationResolver({
|
|
featureSource: featureSource({
|
|
getAdministrativeAreas: async () => {
|
|
lookups.push('admin');
|
|
return null;
|
|
},
|
|
}),
|
|
});
|
|
const geocoder = geocoderFor(null);
|
|
for (const [query, name] of [
|
|
['Texas', 'Texas'],
|
|
['Bavaria', 'Bavaria'],
|
|
['Travis County, Texas', 'Travis County'],
|
|
]) {
|
|
const region = await resolveRegionRingForQuery(query, undefined, geocoder);
|
|
assert.equal(region?.name, name, query);
|
|
assert.equal(region.source, 'bundled-admin');
|
|
assert.ok(region.ring.length >= 8, `${query} has a real ring`);
|
|
}
|
|
assert.deepEqual(geocoder.calls, [], 'no geocoding');
|
|
assert.deepEqual(lookups, [], 'no boundary lookups');
|
|
});
|
|
|
|
test('region ring: a geocoder-typed state resolves from the bundled pack', async () => {
|
|
const lookups = [];
|
|
const { resolveRegionRingForQuery } = createAnnotationResolver({
|
|
featureSource: featureSource({
|
|
getAdministrativeAreas: async () => {
|
|
lookups.push('admin');
|
|
return null;
|
|
},
|
|
}),
|
|
});
|
|
// "Georgia" alone is also a country, so the words don't settle it; the
|
|
// geocoder's state type and point inside the US state do.
|
|
const geocoder = geocoderFor({
|
|
lat: 32.16,
|
|
lng: -82.9,
|
|
label: 'Georgia, USA',
|
|
name: 'Georgia',
|
|
types: ['administrative_area_level_1', 'political'],
|
|
});
|
|
const region = await resolveRegionRingForQuery(
|
|
'Georgia',
|
|
undefined,
|
|
geocoder,
|
|
);
|
|
assert.equal(region?.name, 'Georgia');
|
|
assert.ok(region.ring.length >= 8);
|
|
assert.deepEqual(geocoder.calls, ['Georgia']);
|
|
assert.deepEqual(lookups, [], 'no boundary lookups');
|
|
});
|