diff --git a/README.md b/README.md index 4cb14d3..d3807d6 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Renders a syntactically valid 30-digit SIDC with `milsymbol` and returns SVG plu ## Coverage -Rendering coverage follows the installed `milsymbol` package. The curated semantic set includes a few common land-unit examples such as friendly infantry platoon, hostile infantry platoon, armor platoon, artillery platoon, reconnaissance platoon, and infantry company. +Rendering coverage follows the installed `milsymbol` package. The curated semantic set includes common, verified examples across land units, air, sea surface, sea subsurface, land equipment, land installations, and control measures. Examples include infantry platoons and companies, fighter and rotary-wing aircraft, UAVs, destroyers, frigates, merchant ships, submarines, unmanned underwater vehicles, tanks, armored personnel carriers, bases, airports, checkpoints, and waypoints. Image-based reverse lookup is intentionally deferred. diff --git a/src/data/catalog/air.ts b/src/data/catalog/air.ts new file mode 100644 index 0000000..97fba42 --- /dev/null +++ b/src/data/catalog/air.ts @@ -0,0 +1,61 @@ +import type { CuratedSymbol } from "./types.js"; + +export const airSymbols = [ + { + sidc: "130301000011010400000000000000", + name: "Friendly Air Fighter Aircraft", + aliases: [ + "friendly fighter", + "friendly fighter aircraft", + "friend fighter jet", + "blue fighter aircraft" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "air", + affiliation: "friend", + status: "present", + domain: "air", + entity: "aircraft", + entityType: "fighter" + } + }, + { + sidc: "130301000011020000000000000000", + name: "Friendly Air Rotary-Wing Aircraft", + aliases: [ + "friendly rotary wing aircraft", + "friendly helicopter", + "friend helicopter", + "blue rotary wing aircraft" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "air", + affiliation: "friend", + status: "present", + domain: "air", + entity: "aircraft", + entityType: "rotary wing" + } + }, + { + sidc: "130601000011030000000000000000", + name: "Hostile Air Unmanned Aerial Vehicle", + aliases: [ + "hostile uav", + "enemy uav", + "enemy drone", + "red unmanned aerial vehicle" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "air", + affiliation: "hostile", + status: "present", + domain: "air", + entity: "aircraft", + entityType: "unmanned aerial vehicle" + } + } +] as const satisfies readonly CuratedSymbol[]; diff --git a/src/data/catalog/control-measures.ts b/src/data/catalog/control-measures.ts new file mode 100644 index 0000000..60621b4 --- /dev/null +++ b/src/data/catalog/control-measures.ts @@ -0,0 +1,42 @@ +import type { CuratedSymbol } from "./types.js"; + +export const controlMeasureSymbols = [ + { + sidc: "130325000013030000000000000000", + name: "Friendly Control Measure Checkpoint", + aliases: [ + "friendly checkpoint", + "friend checkpoint", + "blue checkpoint", + "control measure checkpoint" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "control measure", + affiliation: "friend", + status: "present", + domain: "control measure", + entity: "command and control point", + entityType: "checkpoint" + } + }, + { + sidc: "130325000013180000000000000000", + name: "Friendly Control Measure Waypoint", + aliases: [ + "friendly waypoint", + "friend waypoint", + "blue waypoint", + "control measure waypoint" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "control measure", + affiliation: "friend", + status: "present", + domain: "control measure", + entity: "command and control point", + entityType: "waypoint" + } + } +] as const satisfies readonly CuratedSymbol[]; diff --git a/src/data/catalog/index.ts b/src/data/catalog/index.ts new file mode 100644 index 0000000..891a5e5 --- /dev/null +++ b/src/data/catalog/index.ts @@ -0,0 +1,20 @@ +import { airSymbols } from "./air.js"; +import { controlMeasureSymbols } from "./control-measures.js"; +import { landEquipmentSymbols } from "./land-equipment.js"; +import { landInstallationSymbols } from "./land-installations.js"; +import { landUnitSymbols } from "./land-units.js"; +import { seaSubsurfaceSymbols } from "./sea-subsurface.js"; +import { seaSurfaceSymbols } from "./sea-surface.js"; +import type { CuratedSymbol } from "./types.js"; + +export type { CuratedSymbol, SymbolParts } from "./types.js"; + +export const curatedSymbols = [ + ...landUnitSymbols, + ...airSymbols, + ...seaSurfaceSymbols, + ...seaSubsurfaceSymbols, + ...landEquipmentSymbols, + ...landInstallationSymbols, + ...controlMeasureSymbols +] as const satisfies readonly CuratedSymbol[]; diff --git a/src/data/catalog/land-equipment.ts b/src/data/catalog/land-equipment.ts new file mode 100644 index 0000000..b80b9fa --- /dev/null +++ b/src/data/catalog/land-equipment.ts @@ -0,0 +1,40 @@ +import type { CuratedSymbol } from "./types.js"; + +export const landEquipmentSymbols = [ + { + sidc: "130315000012020000000000000000", + name: "Friendly Land Equipment Tank", + aliases: [ + "friendly tank", + "friend tank", + "blue tank", + "land equipment tank" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land equipment", + affiliation: "friend", + status: "present", + domain: "land equipment", + entity: "tank" + } + }, + { + sidc: "130315000012010300000000000000", + name: "Friendly Land Equipment Armored Personnel Carrier", + aliases: [ + "friendly armored personnel carrier", + "friendly armoured personnel carrier", + "friend apc", + "blue apc" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land equipment", + affiliation: "friend", + status: "present", + domain: "land equipment", + entity: "armored personnel carrier" + } + } +] as const satisfies readonly CuratedSymbol[]; diff --git a/src/data/catalog/land-installations.ts b/src/data/catalog/land-installations.ts new file mode 100644 index 0000000..8120d73 --- /dev/null +++ b/src/data/catalog/land-installations.ts @@ -0,0 +1,42 @@ +import type { CuratedSymbol } from "./types.js"; + +export const landInstallationSymbols = [ + { + sidc: "130320000012080200000000000000", + name: "Friendly Land Installation Base", + aliases: [ + "friendly base", + "friendly military base", + "friend base", + "blue military base" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land installation", + affiliation: "friend", + status: "present", + domain: "land installation", + entity: "military infrastructure", + entityType: "base" + } + }, + { + sidc: "130320000012080300000000000000", + name: "Friendly Land Installation Airport", + aliases: [ + "friendly airport", + "friendly airfield", + "friend airport", + "land installation airport" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land installation", + affiliation: "friend", + status: "present", + domain: "land installation", + entity: "military infrastructure", + entityType: "airport" + } + } +] as const satisfies readonly CuratedSymbol[]; diff --git a/src/data/catalog/land-units.ts b/src/data/catalog/land-units.ts new file mode 100644 index 0000000..2dfcc68 --- /dev/null +++ b/src/data/catalog/land-units.ts @@ -0,0 +1,119 @@ +import type { CuratedSymbol } from "./types.js"; + +export const landUnitSymbols = [ + { + sidc: "130310001412110000000000000000", + name: "Friendly Land Unit Infantry Platoon", + aliases: [ + "friendly infantry platoon", + "friend infantry platoon", + "blue infantry platoon", + "land infantry platoon" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land unit", + affiliation: "friend", + status: "present", + domain: "land", + entity: "infantry", + echelon: "platoon" + } + }, + { + sidc: "130310001512110000000000000000", + name: "Friendly Land Unit Infantry Company", + aliases: [ + "friendly infantry company", + "friend infantry company", + "blue infantry company", + "land infantry company" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land unit", + affiliation: "friend", + status: "present", + domain: "land", + entity: "infantry", + echelon: "company" + } + }, + { + sidc: "130610001412110000000000000000", + name: "Hostile Land Unit Infantry Platoon", + aliases: [ + "hostile infantry platoon", + "enemy infantry platoon", + "red infantry platoon", + "land infantry platoon hostile" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land unit", + affiliation: "hostile", + status: "present", + domain: "land", + entity: "infantry", + echelon: "platoon" + } + }, + { + sidc: "130310001412050000000000000000", + name: "Friendly Land Unit Armor Platoon", + aliases: [ + "friendly armor platoon", + "friendly armoured platoon", + "friend tank platoon", + "blue armor platoon" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land unit", + affiliation: "friend", + status: "present", + domain: "land", + entity: "armor", + entityType: "tank", + echelon: "platoon" + } + }, + { + sidc: "130310001413030000000000000000", + name: "Friendly Land Unit Artillery Platoon", + aliases: [ + "friendly artillery platoon", + "friend field artillery platoon", + "blue artillery platoon", + "land artillery platoon" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land unit", + affiliation: "friend", + status: "present", + domain: "land", + entity: "artillery", + echelon: "platoon" + } + }, + { + sidc: "130310001412130000000000000000", + name: "Friendly Land Unit Reconnaissance Platoon", + aliases: [ + "friendly reconnaissance platoon", + "friend recon platoon", + "blue reconnaissance platoon", + "land recon platoon" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "land unit", + affiliation: "friend", + status: "present", + domain: "land", + entity: "reconnaissance", + echelon: "platoon" + } + } +] as const satisfies readonly CuratedSymbol[]; diff --git a/src/data/catalog/sea-subsurface.ts b/src/data/catalog/sea-subsurface.ts new file mode 100644 index 0000000..4730627 --- /dev/null +++ b/src/data/catalog/sea-subsurface.ts @@ -0,0 +1,40 @@ +import type { CuratedSymbol } from "./types.js"; + +export const seaSubsurfaceSymbols = [ + { + sidc: "130635000011010000000000000000", + name: "Hostile Sea Subsurface Submarine", + aliases: [ + "hostile submarine", + "enemy submarine", + "red submarine", + "sea subsurface submarine" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "sea subsurface", + affiliation: "hostile", + status: "present", + domain: "sea subsurface", + entity: "submarine" + } + }, + { + sidc: "130335000011040000000000000000", + name: "Friendly Sea Subsurface Unmanned Underwater Vehicle", + aliases: [ + "friendly unmanned underwater vehicle", + "friendly uuv", + "friend uuv", + "blue underwater drone" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "sea subsurface", + affiliation: "friend", + status: "present", + domain: "sea subsurface", + entity: "unmanned underwater vehicle" + } + } +] as const satisfies readonly CuratedSymbol[]; diff --git a/src/data/catalog/sea-surface.ts b/src/data/catalog/sea-surface.ts new file mode 100644 index 0000000..210ea51 --- /dev/null +++ b/src/data/catalog/sea-surface.ts @@ -0,0 +1,61 @@ +import type { CuratedSymbol } from "./types.js"; + +export const seaSurfaceSymbols = [ + { + sidc: "130330000012020300000000000000", + name: "Friendly Sea Surface Destroyer", + aliases: [ + "friendly destroyer", + "friend destroyer", + "blue destroyer", + "surface combatant destroyer" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "sea surface", + affiliation: "friend", + status: "present", + domain: "sea surface", + entity: "surface combatant", + entityType: "destroyer" + } + }, + { + sidc: "130330000012020400000000000000", + name: "Friendly Sea Surface Frigate", + aliases: [ + "friendly frigate", + "friend frigate", + "blue frigate", + "surface combatant frigate" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "sea surface", + affiliation: "friend", + status: "present", + domain: "sea surface", + entity: "surface combatant", + entityType: "frigate" + } + }, + { + sidc: "130430000014010000000000000000", + name: "Neutral Sea Surface Merchant Ship", + aliases: [ + "neutral merchant ship", + "merchant ship general", + "sea surface merchant ship", + "civilian merchant ship" + ], + parts: { + standard: "MIL-STD-2525D/APP-6D", + symbolSet: "sea surface", + affiliation: "neutral", + status: "present", + domain: "sea surface", + entity: "merchant ship", + entityType: "general" + } + } +] as const satisfies readonly CuratedSymbol[]; diff --git a/src/data/catalog/types.ts b/src/data/catalog/types.ts new file mode 100644 index 0000000..0bb6366 --- /dev/null +++ b/src/data/catalog/types.ts @@ -0,0 +1,18 @@ +export type SymbolParts = { + standard: "MIL-STD-2525D/APP-6D"; + symbolSet: string; + affiliation: string; + status: string; + domain: string; + entity: string; + entityType?: string; + entitySubtype?: string; + echelon?: string; +}; + +export type CuratedSymbol = { + sidc: string; + name: string; + aliases: readonly string[]; + parts: SymbolParts; +}; diff --git a/src/data/symbols.ts b/src/data/symbols.ts index 1d28f6a..b77d306 100644 --- a/src/data/symbols.ts +++ b/src/data/symbols.ts @@ -1,136 +1,2 @@ -export type SymbolParts = { - standard: "MIL-STD-2525D/APP-6D"; - symbolSet: string; - affiliation: string; - status: string; - domain: string; - entity: string; - entityType?: string; - entitySubtype?: string; - echelon?: string; -}; - -export type CuratedSymbol = { - sidc: string; - name: string; - aliases: readonly string[]; - parts: SymbolParts; -}; - -export const curatedSymbols = [ - { - sidc: "130310001412110000000000000000", - name: "Friendly Land Unit Infantry Platoon", - aliases: [ - "friendly infantry platoon", - "friend infantry platoon", - "blue infantry platoon", - "land infantry platoon" - ], - parts: { - standard: "MIL-STD-2525D/APP-6D", - symbolSet: "land unit", - affiliation: "friend", - status: "present", - domain: "land", - entity: "infantry", - echelon: "platoon" - } - }, - { - sidc: "130310001512110000000000000000", - name: "Friendly Land Unit Infantry Company", - aliases: [ - "friendly infantry company", - "friend infantry company", - "blue infantry company", - "land infantry company" - ], - parts: { - standard: "MIL-STD-2525D/APP-6D", - symbolSet: "land unit", - affiliation: "friend", - status: "present", - domain: "land", - entity: "infantry", - echelon: "company" - } - }, - { - sidc: "130610001412110000000000000000", - name: "Hostile Land Unit Infantry Platoon", - aliases: [ - "hostile infantry platoon", - "enemy infantry platoon", - "red infantry platoon", - "land infantry platoon hostile" - ], - parts: { - standard: "MIL-STD-2525D/APP-6D", - symbolSet: "land unit", - affiliation: "hostile", - status: "present", - domain: "land", - entity: "infantry", - echelon: "platoon" - } - }, - { - sidc: "130310001412050000000000000000", - name: "Friendly Land Unit Armor Platoon", - aliases: [ - "friendly armor platoon", - "friendly armoured platoon", - "friend tank platoon", - "blue armor platoon" - ], - parts: { - standard: "MIL-STD-2525D/APP-6D", - symbolSet: "land unit", - affiliation: "friend", - status: "present", - domain: "land", - entity: "armor", - entityType: "tank", - echelon: "platoon" - } - }, - { - sidc: "130310001413030000000000000000", - name: "Friendly Land Unit Artillery Platoon", - aliases: [ - "friendly artillery platoon", - "friend field artillery platoon", - "blue artillery platoon", - "land artillery platoon" - ], - parts: { - standard: "MIL-STD-2525D/APP-6D", - symbolSet: "land unit", - affiliation: "friend", - status: "present", - domain: "land", - entity: "artillery", - echelon: "platoon" - } - }, - { - sidc: "130310001412130000000000000000", - name: "Friendly Land Unit Reconnaissance Platoon", - aliases: [ - "friendly reconnaissance platoon", - "friend recon platoon", - "blue reconnaissance platoon", - "land recon platoon" - ], - parts: { - standard: "MIL-STD-2525D/APP-6D", - symbolSet: "land unit", - affiliation: "friend", - status: "present", - domain: "land", - entity: "reconnaissance", - echelon: "platoon" - } - } -] as const satisfies readonly CuratedSymbol[]; +export { curatedSymbols } from "./catalog/index.js"; +export type { CuratedSymbol, SymbolParts } from "./catalog/index.js"; diff --git a/test/sidc-kit.test.mjs b/test/sidc-kit.test.mjs index 1f9aabc..efaef70 100644 --- a/test/sidc-kit.test.mjs +++ b/test/sidc-kit.test.mjs @@ -8,16 +8,64 @@ import { renderSymbol, searchSymbols } from "../dist/index.js"; +import { curatedSymbols } from "../dist/data/catalog/index.js"; const infantryPlatoonSidc = "130310001412110000000000000000"; const infantryCompanySidc = "130310001512110000000000000000"; const armorPlatoonSidc = "130310001412050000000000000000"; const artilleryPlatoonSidc = "130310001413030000000000000000"; const reconnaissancePlatoonSidc = "130310001412130000000000000000"; +const friendlyAirFighterSidc = "130301000011010400000000000000"; +const friendlyAirRotaryWingSidc = "130301000011020000000000000000"; +const hostileAirUavSidc = "130601000011030000000000000000"; +const friendlySeaDestroyerSidc = "130330000012020300000000000000"; +const friendlySeaFrigateSidc = "130330000012020400000000000000"; +const neutralMerchantShipSidc = "130430000014010000000000000000"; +const hostileSubmarineSidc = "130635000011010000000000000000"; +const friendlyUuvSidc = "130335000011040000000000000000"; +const friendlyTankSidc = "130315000012020000000000000000"; +const friendlyApcSidc = "130315000012010300000000000000"; +const friendlyBaseSidc = "130320000012080200000000000000"; +const friendlyAirportSidc = "130320000012080300000000000000"; +const friendlyCheckpointSidc = "130325000013030000000000000000"; +const friendlyWaypointSidc = "130325000013180000000000000000"; const nonCuratedRenderableSidc = "130410001412110000000000000000"; const unknownDimensionFallbackSidc = "000000000000000000000000000000"; const invalidIconFallbackSidc = "999999999999999999999999999999"; +const expandedCatalogSidcs = [ + friendlyAirFighterSidc, + friendlyAirRotaryWingSidc, + hostileAirUavSidc, + friendlySeaDestroyerSidc, + friendlySeaFrigateSidc, + neutralMerchantShipSidc, + hostileSubmarineSidc, + friendlyUuvSidc, + friendlyTankSidc, + friendlyApcSidc, + friendlyBaseSidc, + friendlyAirportSidc, + friendlyCheckpointSidc, + friendlyWaypointSidc +]; + +function buildInputFor(parts) { + const input = { + affiliation: parts.affiliation, + domain: parts.domain, + entity: parts.entity + }; + + for (const key of ["entityType", "entitySubtype", "echelon"]) { + if (parts[key]) { + input[key] = parts[key]; + } + } + + return input; +} + test("renderSymbol returns SVG for a known SIDC", () => { const result = renderSymbol(infantryPlatoonSidc, { size: 40 }); @@ -36,6 +84,35 @@ test("renderSymbol returns SVG for a non-curated SIDC supported by milsymbol", ( assert.match(result.svg, /<\/svg>$/); }); +test("renderSymbol returns SVG for expanded curated SIDCs", () => { + for (const sidc of expandedCatalogSidcs) { + const result = renderSymbol(sidc, { size: 40 }); + + assert.equal(result.sidc, sidc); + assert.match(result.svg, /^$/); + } +}); + +test("all curated catalog entries round-trip through public APIs", () => { + for (const symbol of curatedSymbols) { + const rendered = renderSymbol(symbol.sidc, { size: 32 }); + assert.match(rendered.svg, /^$/); + + const explanation = explainSidc(symbol.sidc); + assert.equal(explanation.name, symbol.name); + assert.deepEqual(explanation.parts, symbol.parts); + + assert.ok( + searchSymbols(symbol.name, { limit: curatedSymbols.length }).some((result) => result.sidc === symbol.sidc), + `Expected searchSymbols to find ${symbol.name}` + ); + + assert.equal(buildSidc(buildInputFor(symbol.parts)), symbol.sidc); + } +}); + test("renderSymbol rejects unsupported 30-digit SIDCs instead of returning fallback SVG", () => { for (const sidc of [unknownDimensionFallbackSidc, invalidIconFallbackSidc]) { assert.throws( @@ -59,6 +136,24 @@ test("explainSidc returns expected curated parts", () => { assert.equal(result.parts.echelon, "platoon"); }); +test("explainSidc returns expanded curated parts", () => { + const merchantShip = explainSidc(neutralMerchantShipSidc); + assert.equal(merchantShip.coverage, "curated"); + assert.equal(merchantShip.name, "Neutral Sea Surface Merchant Ship"); + assert.equal(merchantShip.parts.affiliation, "neutral"); + assert.equal(merchantShip.parts.symbolSet, "sea surface"); + assert.equal(merchantShip.parts.domain, "sea surface"); + assert.equal(merchantShip.parts.entity, "merchant ship"); + assert.equal(merchantShip.parts.entityType, "general"); + + const checkpoint = explainSidc(friendlyCheckpointSidc); + assert.equal(checkpoint.name, "Friendly Control Measure Checkpoint"); + assert.equal(checkpoint.parts.symbolSet, "control measure"); + assert.equal(checkpoint.parts.domain, "control measure"); + assert.equal(checkpoint.parts.entity, "command and control point"); + assert.equal(checkpoint.parts.entityType, "checkpoint"); +}); + test("explainSidc remains limited to curated SIDCs", () => { assert.throws( () => explainSidc(nonCuratedRenderableSidc), @@ -74,6 +169,13 @@ test("searchSymbols finds symbols by natural-language alias", () => { assert.ok(results[0].score > 0); }); +test("searchSymbols finds expanded symbols by natural-language aliases", () => { + assert.equal(searchSymbols("enemy drone")[0]?.sidc, hostileAirUavSidc); + assert.equal(searchSymbols("surface combatant destroyer")[0]?.sidc, friendlySeaDestroyerSidc); + assert.equal(searchSymbols("military base")[0]?.sidc, friendlyBaseSidc); + assert.equal(searchSymbols("control measure waypoint")[0]?.sidc, friendlyWaypointSidc); +}); + test("buildSidc creates the expected known SIDC from structured parts", () => { assert.equal( buildSidc({ @@ -86,6 +188,70 @@ test("buildSidc creates the expected known SIDC from structured parts", () => { ); }); +test("buildSidc creates expanded curated SIDCs from structured parts", () => { + assert.equal( + buildSidc({ + affiliation: "friend", + domain: "air", + entity: "aircraft", + entityType: "fighter" + }), + friendlyAirFighterSidc + ); + assert.equal( + buildSidc({ + affiliation: "hostile", + domain: "air", + entity: "aircraft", + entityType: "unmanned aerial vehicle" + }), + hostileAirUavSidc + ); + assert.equal( + buildSidc({ + affiliation: "friend", + domain: "sea surface", + entity: "surface combatant", + entityType: "frigate" + }), + friendlySeaFrigateSidc + ); + assert.equal( + buildSidc({ + affiliation: "hostile", + domain: "sea subsurface", + entity: "submarine" + }), + hostileSubmarineSidc + ); + assert.equal( + buildSidc({ + affiliation: "friend", + domain: "land equipment", + entity: "tank" + }), + friendlyTankSidc + ); + assert.equal( + buildSidc({ + affiliation: "friend", + domain: "land installation", + entity: "military infrastructure", + entityType: "airport" + }), + friendlyAirportSidc + ); + assert.equal( + buildSidc({ + affiliation: "friend", + domain: "control measure", + entity: "command and control point", + entityType: "checkpoint" + }), + friendlyCheckpointSidc + ); +}); + test("buildSidc uses the correct field positions for land-unit fixtures", () => { assert.equal( buildSidc({