mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
Test that a late Nepal boundary after cancel leaves the live locator scene alone on both engines
This commit is contained in:
1 parent
dae4011604
commit
1c09c90e13
1 file changed
+193
@@ -0,0 +1,193 @@
|
||||
// Edge cases from docs/migration/planet-separation/layers.md
|
||||
// (bhote-koshi-locator): a boundary that resolves late, after its request was
|
||||
// cancelled, does not change the live scene; both engines show the same area
|
||||
// and the same target.
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import * as Cesium from 'cesium';
|
||||
import { createBhoteKoshiLocatorLayer } from './bhoteKoshiLocator.js';
|
||||
|
||||
const STALE_RING = [
|
||||
[10, 10],
|
||||
[11, 10],
|
||||
[11, 11],
|
||||
[10, 11],
|
||||
];
|
||||
const LIVE_RING = [
|
||||
[80, 26],
|
||||
[88, 26],
|
||||
[88, 30],
|
||||
[80, 30],
|
||||
];
|
||||
|
||||
function deferred() {
|
||||
let resolve;
|
||||
const promise = new Promise((done) => (resolve = done));
|
||||
return { promise, resolve };
|
||||
}
|
||||
|
||||
/** A locator on one engine; `shown()` is the data source the scene draws. */
|
||||
function locator(engine) {
|
||||
const lookups = [];
|
||||
const renders = [];
|
||||
const publications = [];
|
||||
const shown = new Set();
|
||||
const overlayHost = {
|
||||
setEntries: (sourceId, entries) => publications.push(entries),
|
||||
clearSource() {},
|
||||
};
|
||||
const viewer = {
|
||||
creditDisplay: { addStaticCredit() {}, removeStaticCredit() {} },
|
||||
dataSources: {
|
||||
add: (source) => shown.add(source),
|
||||
remove: (source) => shown.delete(source),
|
||||
},
|
||||
};
|
||||
const navara = {
|
||||
kind: 'navara',
|
||||
render: { request: (reason) => renders.push(reason) },
|
||||
credits: { add() {}, remove() {} },
|
||||
};
|
||||
const layer = createBhoteKoshiLocatorLayer({
|
||||
boundaryResolver: (signal) => {
|
||||
const lookup = deferred();
|
||||
lookups.push({ signal, ...lookup });
|
||||
return lookup.promise;
|
||||
},
|
||||
createNativeRenderer: (_engine, dataSource) => {
|
||||
shown.add(dataSource);
|
||||
return { destroy: () => shown.delete(dataSource) };
|
||||
},
|
||||
requestRender: (reason) => renders.push(reason),
|
||||
overlayHost,
|
||||
scheduleFrame: () => 1,
|
||||
cancelFrame() {},
|
||||
scheduleDelay: () => 1,
|
||||
cancelDelay() {},
|
||||
});
|
||||
const scene = engine === 'cesium' ? viewer : null;
|
||||
layer.attachRenderer(scene, {
|
||||
engine: engine === 'navara' ? navara : null,
|
||||
});
|
||||
return {
|
||||
layer,
|
||||
scene,
|
||||
lookups,
|
||||
renders,
|
||||
publications,
|
||||
shown: () => [...shown],
|
||||
};
|
||||
}
|
||||
|
||||
/** The drawn area as degree pairs, and the drawn targets. */
|
||||
function drawn(source) {
|
||||
const entities = source.entities.values;
|
||||
const fill = source.entities.getById('nepal-border-fill');
|
||||
const area = fill
|
||||
? fill.polygon.hierarchy.getValue().positions.map((position) => {
|
||||
const c = Cesium.Cartographic.fromCartesian(position);
|
||||
return [
|
||||
Math.round(Cesium.Math.toDegrees(c.longitude)),
|
||||
Math.round(Cesium.Math.toDegrees(c.latitude)),
|
||||
];
|
||||
})
|
||||
: null;
|
||||
return { area, ids: entities.map((entity) => entity.id).sort() };
|
||||
}
|
||||
|
||||
for (const engine of ['cesium', 'navara']) {
|
||||
test(`edge:bhote-koshi-locator: a boundary resolving after cancel leaves the live ${engine} scene alone`, async () => {
|
||||
const h = locator(engine);
|
||||
const cancelled = h.layer.enable(h.scene);
|
||||
await h.layer.disable();
|
||||
const live = h.layer.enable(h.scene);
|
||||
assert.equal(h.lookups.length, 2);
|
||||
h.lookups[1].resolve({ ring: LIVE_RING });
|
||||
assert.equal(await live, true);
|
||||
|
||||
const [source] = h.shown();
|
||||
assert.equal(h.shown().length, 1);
|
||||
const before = drawn(source);
|
||||
const publications = h.publications.length;
|
||||
const renders = h.renders.length;
|
||||
|
||||
h.lookups[0].resolve({ ring: STALE_RING });
|
||||
await assert.rejects(cancelled, (error) => error?.name === 'AbortError');
|
||||
|
||||
assert.deepEqual(h.shown(), [source], 'the live source stays drawn');
|
||||
assert.deepEqual(drawn(source), before);
|
||||
assert.deepEqual(before.area, LIVE_RING);
|
||||
assert.equal(h.publications.length, publications, 'no late callouts');
|
||||
assert.equal(h.renders.length, renders, 'no late frame request');
|
||||
assert.equal(h.layer.getStats().status, 'nominal');
|
||||
await h.layer.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
test('edge:bhote-koshi-locator: both engines draw the same area and the same target', async () => {
|
||||
const result = {};
|
||||
for (const engine of ['cesium', 'navara']) {
|
||||
const h = locator(engine);
|
||||
const enabling = h.layer.enable(h.scene);
|
||||
h.lookups[0].resolve({ ring: LIVE_RING });
|
||||
await enabling;
|
||||
const [source] = h.shown();
|
||||
result[engine] = {
|
||||
...drawn(source),
|
||||
callouts: h.publications.at(-1).map(({ id, position }) => ({
|
||||
id,
|
||||
position: Cesium.Cartesian3.clone(position),
|
||||
})),
|
||||
};
|
||||
await h.layer.destroy();
|
||||
}
|
||||
assert.deepEqual(result.navara, result.cesium);
|
||||
assert.deepEqual(result.cesium.area, LIVE_RING);
|
||||
assert.ok(result.cesium.ids.includes('bhote-koshi-incident-halo'));
|
||||
assert.deepEqual(
|
||||
result.cesium.callouts.map(({ id }) => id),
|
||||
['nepal-context-callout', 'bhote-koshi-incident-callout'],
|
||||
);
|
||||
});
|
||||
|
||||
test('edge:bhote-koshi-locator: an engine swap while the boundary resolves lands it on the new engine only', async () => {
|
||||
const shown = { cesium: new Set(), navara: new Set() };
|
||||
const lookup = deferred();
|
||||
const layer = createBhoteKoshiLocatorLayer({
|
||||
boundaryResolver: () => lookup.promise,
|
||||
createNativeRenderer: (_engine, dataSource) => {
|
||||
shown.navara.add(dataSource);
|
||||
return { destroy: () => shown.navara.delete(dataSource) };
|
||||
},
|
||||
requestRender() {},
|
||||
overlayHost: { setEntries() {}, clearSource() {} },
|
||||
scheduleFrame: () => 1,
|
||||
cancelFrame() {},
|
||||
scheduleDelay: () => 1,
|
||||
cancelDelay() {},
|
||||
});
|
||||
const viewer = {
|
||||
creditDisplay: { addStaticCredit() {}, removeStaticCredit() {} },
|
||||
dataSources: {
|
||||
add: (source) => shown.cesium.add(source),
|
||||
remove: (source) => shown.cesium.delete(source),
|
||||
},
|
||||
};
|
||||
layer.attachRenderer(viewer);
|
||||
const enabling = layer.enable(viewer);
|
||||
layer.detachRenderer();
|
||||
layer.attachRenderer(null, {
|
||||
engine: {
|
||||
kind: 'navara',
|
||||
render: { request() {} },
|
||||
credits: { add() {}, remove() {} },
|
||||
},
|
||||
});
|
||||
lookup.resolve({ ring: LIVE_RING });
|
||||
assert.equal(await enabling, true);
|
||||
assert.equal(shown.cesium.size, 0, 'nothing left on the released scene');
|
||||
assert.equal(shown.navara.size, 1);
|
||||
assert.deepEqual(drawn([...shown.navara][0]).area, LIVE_RING);
|
||||
await layer.destroy();
|
||||
assert.equal(shown.navara.size, 0);
|
||||
});
|
||||
Reference in new issue
Block a user