Files
gods-eye-view/src/data/contactMatch.test.mjs
T

119 lines
5.5 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {
CONTACT_MATCH_TIER,
canonicalizeContactId,
contactMatchWins,
rankContactMatch,
} from './contactMatch.js';
/**
* Voice resolves a spoken or model-supplied identity against the loaded fleet.
* Ranking callsign and registration together let a registration that happened
* to equal another contact's callsign win on `Map` insertion order, so the same
* query could follow a different aircraft between polls. These pin the
* precedence and the separator-insensitive registration comparison.
*/
test('separators and case fall out of an identity comparison', () => {
assert.equal(canonicalizeContactId('G-ABCD'), 'GABCD');
assert.equal(canonicalizeContactId('gabcd'), 'GABCD');
assert.equal(canonicalizeContactId('05-8152'), '058152');
assert.equal(canonicalizeContactId('N123AB'), 'N123AB');
assert.equal(canonicalizeContactId(null), '');
assert.equal(canonicalizeContactId(' '), '');
});
test('hex outranks every softer match', () => {
assert.equal(
rankContactMatch({ query: 'ae7f01', hex: 'ae7f01', callsign: 'RCH451' }),
CONTACT_MATCH_TIER.HEX_EXACT,
);
// A hex query must not be out-competed by a substring hit elsewhere.
assert.equal(
rankContactMatch({ query: 'ae7f01', hex: 'bbb999', callsign: 'AE7F01X' }),
CONTACT_MATCH_TIER.CALLSIGN_PREFIX,
);
});
test('an exact callsign beats an exact registration, whatever the feed order', () => {
const asCallsign = rankContactMatch({ query: '6606', hex: 'aaa111', callsign: '6606' });
const asRegistration = rankContactMatch({ query: '6606', hex: 'bbb222', registration: '6606' });
assert.equal(asCallsign, CONTACT_MATCH_TIER.CALLSIGN_EXACT);
assert.equal(asRegistration, CONTACT_MATCH_TIER.REGISTRATION_EXACT);
assert.ok(
asCallsign < asRegistration,
'the callsign contract must not depend on which contact the feed listed first',
);
});
test('a registration matches in the form the operator says it', () => {
const hyphenated = { hex: 'aaa111', registration: 'G-ABCD' };
assert.equal(rankContactMatch({ query: 'GABCD', ...hyphenated }), CONTACT_MATCH_TIER.REGISTRATION_EXACT);
assert.equal(rankContactMatch({ query: 'g-abcd', ...hyphenated }), CONTACT_MATCH_TIER.REGISTRATION_EXACT);
const military = { hex: 'ae7f01', registration: '05-8152' };
assert.equal(rankContactMatch({ query: '058152', ...military }), CONTACT_MATCH_TIER.REGISTRATION_EXACT);
assert.equal(rankContactMatch({ query: '05-8152', ...military }), CONTACT_MATCH_TIER.REGISTRATION_EXACT);
});
test('a civilian N-number resolves in every form it is written or spoken', () => {
const civilian = { hex: 'a1b2c3', registration: 'N123AB' };
assert.equal(rankContactMatch({ query: 'N123AB', ...civilian }), CONTACT_MATCH_TIER.REGISTRATION_EXACT);
assert.equal(rankContactMatch({ query: 'n-123ab', ...civilian }), CONTACT_MATCH_TIER.REGISTRATION_EXACT);
assert.equal(rankContactMatch({ query: 'n123', ...civilian }), CONTACT_MATCH_TIER.REGISTRATION_PREFIX);
assert.equal(rankContactMatch({ query: '123ab', ...civilian }), CONTACT_MATCH_TIER.REGISTRATION_SUBSTRING);
});
test('prefix beats substring, and callsign beats registration at equal strength', () => {
assert.equal(
rankContactMatch({ query: 'swa', hex: 'a1', callsign: 'SWA123' }),
CONTACT_MATCH_TIER.CALLSIGN_PREFIX,
);
assert.equal(
rankContactMatch({ query: '123', hex: 'a1', callsign: 'SWA123' }),
CONTACT_MATCH_TIER.CALLSIGN_SUBSTRING,
);
// Same contact, both fields hit: the callsign tier is the one reported.
assert.equal(
rankContactMatch({ query: 'n12', hex: 'a1', callsign: 'N12X', registration: 'N123AB' }),
CONTACT_MATCH_TIER.CALLSIGN_PREFIX,
);
});
test('nothing matches an empty or unknown query', () => {
assert.equal(rankContactMatch({ query: '', hex: 'a1', callsign: 'SWA123' }), CONTACT_MATCH_TIER.NONE);
assert.equal(rankContactMatch({ query: ' ', hex: 'a1', callsign: 'SWA123' }), CONTACT_MATCH_TIER.NONE);
assert.equal(rankContactMatch({ query: 'zzz', hex: 'a1', callsign: 'SWA123' }), CONTACT_MATCH_TIER.NONE);
// A contact with no identity at all cannot be matched by a non-empty query.
assert.equal(rankContactMatch({ query: 'zzz', hex: '' }), CONTACT_MATCH_TIER.NONE);
});
test('a same-tier tie resolves the same way every time', () => {
// Two contacts whose registrations both match at the same strength. Without
// a stable key the winner is upstream Map order, so the same spoken query
// could follow a different aircraft between polls.
const a = { tier: CONTACT_MATCH_TIER.REGISTRATION_PREFIX, id: 'bbb222' };
const b = { tier: CONTACT_MATCH_TIER.REGISTRATION_PREFIX, id: 'aaa111' };
assert.equal(contactMatchWins(b, a), true, 'the lower hex takes over');
assert.equal(contactMatchWins(a, b), false, 'and the higher hex never displaces it');
});
test('a stronger tier always beats a weaker one, whichever arrived first', () => {
const exact = { tier: CONTACT_MATCH_TIER.CALLSIGN_EXACT, id: 'zzz999' };
const prefix = { tier: CONTACT_MATCH_TIER.REGISTRATION_PREFIX, id: 'aaa111' };
assert.equal(contactMatchWins(exact, prefix), true, 'tier outranks the tiebreak key');
assert.equal(contactMatchWins(prefix, exact), false);
});
test('a non-match never becomes the best match', () => {
assert.equal(contactMatchWins({ tier: CONTACT_MATCH_TIER.NONE, id: 'aaa111' }, null), false);
assert.equal(
contactMatchWins(
{ tier: CONTACT_MATCH_TIER.NONE, id: 'aaa111' },
{ tier: CONTACT_MATCH_TIER.CALLSIGN_EXACT, id: 'zzz999' },
),
false,
);
});