mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
199 lines
5.7 KiB
JavaScript
199 lines
5.7 KiB
JavaScript
// COORDINATE PARSING — what the search box accepts as a coordinate, and what it
|
|
// refuses. A refusal hands the text to the geocoders; a wrong accept flies the
|
|
// operator somewhere they never asked for and looks like success, so every
|
|
// malformed and ambiguous form below is pinned.
|
|
//
|
|
// Run with: npm test
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
parseCoordinateQuery,
|
|
formatCoordinateLabel,
|
|
} from './coordinateParser.js';
|
|
|
|
test('a plain decimal pair is latitude then longitude', () => {
|
|
assert.deepEqual(parseCoordinateQuery('43.1731, -79.0384'), {
|
|
lat: 43.1731,
|
|
lon: -79.0384,
|
|
label: '43.1731° N, 79.0384° W',
|
|
});
|
|
assert.deepEqual(parseCoordinateQuery('43.1731,-79.0384')?.lat, 43.1731);
|
|
assert.deepEqual(
|
|
parseCoordinateQuery(' 43.1731 ; -79.0384 ')?.lon,
|
|
-79.0384,
|
|
);
|
|
assert.deepEqual(parseCoordinateQuery('43.1731 -79.0384')?.lon, -79.0384);
|
|
assert.deepEqual(parseCoordinateQuery('0, 0'), {
|
|
lat: 0,
|
|
lon: 0,
|
|
label: '0.0000° N, 0.0000° E',
|
|
});
|
|
assert.deepEqual(parseCoordinateQuery('-33.8568, 151.2153')?.lat, -33.8568);
|
|
assert.deepEqual(parseCoordinateQuery('30, -97')?.lat, 30);
|
|
assert.deepEqual(parseCoordinateQuery('.5, -.25')?.lon, -0.25);
|
|
});
|
|
|
|
test('hemisphere letters fix the axis, in either order', () => {
|
|
assert.deepEqual(parseCoordinateQuery('N 40, W 74'), {
|
|
lat: 40,
|
|
lon: -74,
|
|
label: '40.0000° N, 74.0000° W',
|
|
});
|
|
// The reviewer's case: written longitude-first, it must not read as latitude.
|
|
assert.deepEqual(parseCoordinateQuery('W 40, N 74'), {
|
|
lat: 74,
|
|
lon: -40,
|
|
label: '74.0000° N, 40.0000° W',
|
|
});
|
|
assert.deepEqual(parseCoordinateQuery('40N, 74W')?.lon, -74);
|
|
assert.deepEqual(parseCoordinateQuery('74w, 40n'), {
|
|
lat: 40,
|
|
lon: -74,
|
|
label: '40.0000° N, 74.0000° W',
|
|
});
|
|
assert.deepEqual(parseCoordinateQuery('40° N, 74° W')?.lat, 40);
|
|
// One letter is enough: it fixes its own axis, the other takes what is left.
|
|
assert.deepEqual(parseCoordinateQuery('40 N, -74')?.lon, -74);
|
|
assert.deepEqual(parseCoordinateQuery('-74, 40 N'), {
|
|
lat: 40,
|
|
lon: -74,
|
|
label: '40.0000° N, 74.0000° W',
|
|
});
|
|
});
|
|
|
|
test('malformed and ambiguous coordinates are refused, never guessed', () => {
|
|
for (const query of [
|
|
// The reviewer's case: trailing text must not be discarded.
|
|
'12junk, 34oops',
|
|
'12junk,34',
|
|
'43.1731, -79.0384x',
|
|
'abc, def',
|
|
'Paris',
|
|
'New York, NY',
|
|
'',
|
|
' ',
|
|
',',
|
|
'40',
|
|
'40,',
|
|
', 74',
|
|
'40, 74, 12',
|
|
'40.0.0, 74',
|
|
'1e3, 5',
|
|
'0x40, 74',
|
|
'40 74 12',
|
|
// Two letters naming the same axis leaves the other axis unstated.
|
|
'N 40, N 74',
|
|
'E 40, W 74',
|
|
'S 40, 40 S',
|
|
// A sign and a letter both claim the direction.
|
|
'-40N, 74W',
|
|
'N -40, W 74',
|
|
// Two letters on one component.
|
|
'N40W, 74',
|
|
// Out of range.
|
|
'91, 0',
|
|
'-90.1, 0',
|
|
'0, 181',
|
|
'0, -180.5',
|
|
'N 100, W 74',
|
|
// Degrees/minutes/seconds is out of scope and must fall through, not
|
|
// be read as a decimal pair.
|
|
'40°26\'46"N, 79°58\'56"W',
|
|
'40 26 46, 79 58 56',
|
|
// A grid reference is out of scope too.
|
|
'33UXP0500444998',
|
|
]) {
|
|
assert.equal(
|
|
parseCoordinateQuery(query),
|
|
null,
|
|
`${JSON.stringify(query)} must be refused`,
|
|
);
|
|
}
|
|
});
|
|
|
|
test('non-strings are refused without throwing', () => {
|
|
for (const query of [null, undefined, 42, {}, [], ['40', '74']])
|
|
assert.equal(parseCoordinateQuery(query), null);
|
|
});
|
|
|
|
test('the label reads the way a coordinate is written', () => {
|
|
assert.equal(
|
|
formatCoordinateLabel(43.1731, -79.0384),
|
|
'43.1731° N, 79.0384° W',
|
|
);
|
|
assert.equal(
|
|
formatCoordinateLabel(-33.8568, 151.2153),
|
|
'33.8568° S, 151.2153° E',
|
|
);
|
|
assert.equal(formatCoordinateLabel(0, 0), '0.0000° N, 0.0000° E');
|
|
});
|
|
|
|
test('the poles and the dateline are inside the accepted range', () => {
|
|
assert.deepEqual(parseCoordinateQuery('90, 180')?.lat, 90);
|
|
assert.deepEqual(parseCoordinateQuery('-90, -180')?.lon, -180);
|
|
});
|
|
|
|
test('two-dimensional WGS84 geo URIs resolve to the same decimal coordinate', () => {
|
|
for (const query of [
|
|
'geo:39.7392,-104.9903',
|
|
'geo:39.7392,-104.9903;crs=wgs84',
|
|
' GEO:39.7392,-104.9903;CRS=WGS84 ',
|
|
]) {
|
|
assert.deepEqual(parseCoordinateQuery(query), {
|
|
lat: 39.7392,
|
|
lon: -104.9903,
|
|
label: '39.7392° N, 104.9903° W',
|
|
});
|
|
}
|
|
for (const [query, decimal] of [
|
|
['geo:0,0', '0,0'],
|
|
['geo:-33.8568,151.2153', '-33.8568,151.2153'],
|
|
['geo:90,180', '90,180'],
|
|
['geo:-90,-180;crs=wgs84', '-90,-180'],
|
|
['geo:09,007', '9,7'],
|
|
['geo:-0,-0', '-0,-0'],
|
|
]) {
|
|
assert.deepEqual(
|
|
parseCoordinateQuery(query),
|
|
parseCoordinateQuery(decimal),
|
|
);
|
|
}
|
|
});
|
|
|
|
test('malformed or unsupported geo URIs are refused without losing their meaning', () => {
|
|
for (const query of [
|
|
'geo:',
|
|
'geo:39.7392',
|
|
'geo:,104.9903',
|
|
'geo:39.7392,,104.9903',
|
|
'geo:39.7392,-104.9903,',
|
|
'geo:91,0',
|
|
'geo:-90.1,0',
|
|
'geo:0,181',
|
|
'geo:0,-180.1',
|
|
'geo:000,0',
|
|
'geo:0,0000',
|
|
'geo:+39.7392,-104.9903',
|
|
'geo:.5,-.25',
|
|
'geo:1e1,2',
|
|
'geo:NaN,0',
|
|
'geo:Infinity,0',
|
|
'geo:39.7392, -104.9903',
|
|
'geo:39.7392;-104.9903',
|
|
'geo:39.7392N,104.9903W',
|
|
'geo:39.7392,-104.9903,1600',
|
|
'geo:39.7392,-104.9903;u=10',
|
|
'geo:39.7392,-104.9903;crs=unknown',
|
|
'geo:39.7392,-104.9903;crs=wgs84;crs=wgs84',
|
|
'geo:39.7392,-104.9903;crs=wgs84;u=0',
|
|
'geo:39.7392,-104.9903;custom=value',
|
|
'geo:0,0?q=39.7392,-104.9903(Denver)',
|
|
'geo:39.7392,-104.9903#Denver',
|
|
'geo:39.7392,-104.9903 trailing text',
|
|
'geo://39.7392,-104.9903',
|
|
'https://example.com/geo:39.7392,-104.9903',
|
|
]) {
|
|
assert.equal(parseCoordinateQuery(query), null, query);
|
|
}
|
|
});
|