mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
185 lines
5.6 KiB
JavaScript
185 lines
5.6 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { createApplicationOperations } from './operations.js';
|
|
|
|
function requests(terrain, boundaries = { query: async () => [] }) {
|
|
return {
|
|
terrain,
|
|
boundaries,
|
|
regional: { getBrief: async () => ({}) },
|
|
weather: { getConditions: async () => ({}) },
|
|
summary: { summarize: async () => ({}) },
|
|
};
|
|
}
|
|
|
|
test('surface cache and stack listeners belong to the supplied application lifetime', async (t) => {
|
|
const a = new AbortController();
|
|
const b = new AbortController();
|
|
t.after(() => {
|
|
a.abort();
|
|
b.abort();
|
|
});
|
|
const target = new EventTarget();
|
|
let calls = 0;
|
|
const first = createApplicationOperations({
|
|
signal: a.signal,
|
|
eventTarget: target,
|
|
requests: requests({
|
|
async getHeights(points) {
|
|
calls++;
|
|
return points.map(() => ({ ellipsoid: 123 }));
|
|
},
|
|
}),
|
|
});
|
|
const second = createApplicationOperations({
|
|
signal: b.signal,
|
|
eventTarget: target,
|
|
requests: requests({
|
|
async getHeights(points) {
|
|
return points.map(() => ({ ellipsoid: 456 }));
|
|
},
|
|
}),
|
|
});
|
|
const point = { lat: 30, lon: -97 };
|
|
await first.surface.terrain.resolveEllipsoidalGround([point]);
|
|
await first.surface.terrain.resolveEllipsoidalGround([point]);
|
|
await second.surface.terrain.resolveEllipsoidalGround([point]);
|
|
assert.equal(calls, 1);
|
|
assert.equal(first.surface.groundFloor.cachedGroundFloor(30, -97), 123);
|
|
assert.equal(second.surface.groundFloor.cachedGroundFloor(30, -97), 456);
|
|
target.dispatchEvent(
|
|
new CustomEvent('gev:map-stack-changed', {
|
|
detail: { activeId: 'esri-imagery' },
|
|
}),
|
|
);
|
|
assert.equal(first.surface.groundFloor.meshFloorPreferred(), false);
|
|
a.abort();
|
|
assert.equal(first.surface.terrain.cachedEllipsoidalGround(30, -97), null);
|
|
target.dispatchEvent(
|
|
new CustomEvent('gev:map-stack-changed', {
|
|
detail: { activeId: 'photoreal' },
|
|
}),
|
|
);
|
|
assert.equal(
|
|
first.surface.groundFloor.meshFloorPreferred(),
|
|
false,
|
|
'disposed listener cannot update the old owner',
|
|
);
|
|
assert.equal(second.surface.groundFloor.meshFloorPreferred(), true);
|
|
});
|
|
|
|
test('a terrain reply after application abort cannot refill the cache or become a fallback', async () => {
|
|
const lifetime = new AbortController();
|
|
let respond;
|
|
let receivedSignal;
|
|
const operations = createApplicationOperations({
|
|
signal: lifetime.signal,
|
|
eventTarget: null,
|
|
requests: requests({
|
|
getHeights(_points, { signal }) {
|
|
receivedSignal = signal;
|
|
return new Promise((resolve) => {
|
|
respond = resolve;
|
|
});
|
|
},
|
|
}),
|
|
});
|
|
const pending = operations.surface.terrain.resolveEllipsoidalGround([
|
|
{ lat: 30, lon: -97 },
|
|
]);
|
|
lifetime.abort();
|
|
respond([{ ellipsoid: 123 }]);
|
|
await assert.rejects(pending, { name: 'AbortError' });
|
|
assert.equal(receivedSignal.aborted, true);
|
|
assert.equal(
|
|
operations.surface.terrain.cachedEllipsoidalGround(30, -97),
|
|
null,
|
|
);
|
|
});
|
|
|
|
test('annotation lookup and cached outlines use the supplied source independently', async (t) => {
|
|
const priorWindow = globalThis.window;
|
|
globalThis.window = { setTimeout, clearTimeout };
|
|
const a = new AbortController();
|
|
const b = new AbortController();
|
|
t.after(() => {
|
|
a.abort();
|
|
b.abort();
|
|
if (priorWindow === undefined) delete globalThis.window;
|
|
else globalThis.window = priorWindow;
|
|
});
|
|
const calls = [0, 0];
|
|
const make = (signal, index) =>
|
|
createApplicationOperations({
|
|
signal,
|
|
eventTarget: null,
|
|
requests: requests(
|
|
{ getHeights: async () => [] },
|
|
{
|
|
query: async () => {
|
|
calls[index]++;
|
|
const delta = index * 0.0001;
|
|
return [
|
|
{
|
|
type: 'way',
|
|
id: index + 1,
|
|
tags: { building: 'yes', name: 'Source fixture hall' },
|
|
geometry: [
|
|
{ lat: 30 - 0.0001, lon: -97 - 0.0001 + delta },
|
|
{ lat: 30 - 0.0001, lon: -97 + 0.0001 + delta },
|
|
{ lat: 30 + 0.0001, lon: -97 + 0.0001 + delta },
|
|
{ lat: 30 + 0.0001, lon: -97 - 0.0001 + delta },
|
|
{ lat: 30 - 0.0001, lon: -97 - 0.0001 + delta },
|
|
],
|
|
},
|
|
];
|
|
},
|
|
},
|
|
),
|
|
});
|
|
const first = make(a.signal, 0);
|
|
const second = make(b.signal, 1);
|
|
const query = {
|
|
viewer: {},
|
|
target: 'Source fixture hall',
|
|
latitude: 30,
|
|
longitude: -97,
|
|
footprint: true,
|
|
entityKind: 'building',
|
|
};
|
|
const resultA = await first.annotationResolver.resolveAnnotationTarget(query);
|
|
const resultB =
|
|
await second.annotationResolver.resolveAnnotationTarget(query);
|
|
assert.ok(resultA.ring?.length >= 4);
|
|
assert.ok(resultB.ring?.length >= 4);
|
|
assert.notDeepEqual(resultA.ring, resultB.ring);
|
|
const before = calls[0];
|
|
const cached = await first.annotationResolver.resolveAnnotationTarget(query);
|
|
assert.deepEqual(cached.ring, resultA.ring);
|
|
assert.equal(calls[0], before);
|
|
a.abort();
|
|
await assert.rejects(
|
|
first.annotationResolver.resolveAnnotationTarget(query),
|
|
{ name: 'AbortError' },
|
|
);
|
|
});
|
|
|
|
test('invalid feature adapters fail before surface listeners are installed', () => {
|
|
let installed = 0;
|
|
assert.throws(
|
|
() =>
|
|
createApplicationOperations({
|
|
signal: new AbortController().signal,
|
|
requests: { ...requests({ getHeights: async () => [] }), features: {} },
|
|
eventTarget: {
|
|
addEventListener() {
|
|
installed++;
|
|
},
|
|
removeEventListener() {},
|
|
},
|
|
}),
|
|
/Missing feature operation/,
|
|
);
|
|
assert.equal(installed, 0);
|
|
});
|