import { describe, expect, it } from 'vitest'; import { COUNTRY_CODES, UNMAPPED_COUNTRY_NAMES, countryToIso3, iso3ToName, isKnownUnmapped, lookupCountry, normalizeCountryName } from '../src/country-codes.js'; import dbCountries from '../src/fixtures/trial-countries.json' with { type: 'json' }; describe('countryToIso3', () => { it('maps the ClinicalTrials.gov v2 short names', () => { expect(countryToIso3('United States')).toBe('USA'); expect(countryToIso3('South Korea')).toBe('KOR'); expect(countryToIso3('Turkey (Türkiye)')).toBe('TUR'); expect(countryToIso3('Russia')).toBe('RUS'); expect(countryToIso3('Vietnam')).toBe('VNM'); expect(countryToIso3('Reunion')).toBe('REU'); expect(countryToIso3('Palestinian Territories')).toBe('PSE'); expect(countryToIso3('The Bahamas')).toBe('BHS'); expect(countryToIso3('Burma')).toBe('MMR'); expect(countryToIso3('Côte d’Ivoire')).toBe('CIV'); // curly apostrophe as stored in the DB }); it('maps the legacy ISO-style long names', () => { expect(countryToIso3('Korea, Republic of')).toBe('KOR'); expect(countryToIso3('Russian Federation')).toBe('RUS'); expect(countryToIso3('Iran, Islamic Republic of')).toBe('IRN'); expect(countryToIso3('Viet Nam')).toBe('VNM'); expect(countryToIso3('Réunion')).toBe('REU'); expect(countryToIso3('Palestinian Territory, occupied')).toBe('PSE'); expect(countryToIso3('Türkiye')).toBe('TUR'); expect(countryToIso3('Czechia')).toBe('CZE'); expect(countryToIso3('Hong Kong')).toBe('HKG'); expect(countryToIso3('Macao')).toBe('MAC'); expect(countryToIso3('Taiwan')).toBe('TWN'); }); it('is case/whitespace insensitive and accepts ISO3 itself', () => { expect(countryToIso3(' united states ')).toBe('USA'); expect(countryToIso3('usa')).toBe('USA'); expect(countryToIso3('FRA')).toBe('FRA'); }); it('returns null for dissolved states, empty and unknown strings', () => { expect(countryToIso3('Former Serbia and Montenegro')).toBeNull(); expect(countryToIso3('Former Yugoslavia')).toBeNull(); expect(countryToIso3('Netherlands Antilles')).toBeNull(); expect(countryToIso3('')).toBeNull(); expect(countryToIso3(null)).toBeNull(); expect(countryToIso3('Atlantis')).toBeNull(); expect(isKnownUnmapped('Serbia and Montenegro')).toBe(true); expect(isKnownUnmapped('Atlantis')).toBe(false); }); it('exposes display names', () => { expect(iso3ToName('KOR')).toBe('South Korea'); expect(iso3ToName('ZZZ')).toBe('ZZZ'); expect(lookupCountry('Viet Nam')).toEqual({ iso3: 'VNM', name: 'Vietnam', aliases: ['Viet Nam'] }); expect(normalizeCountryName(" Côte d’Ivoire ")).toBe("côte d'ivoire"); }); }); describe('COUNTRY_CODES table', () => { it('has unique ISO3 codes and unique normalized names/aliases', () => { const codes = COUNTRY_CODES.map((c) => c.iso3); expect(new Set(codes).size).toBe(codes.length); for (const c of codes) expect(c).toMatch(/^[A-Z]{3}$/); const names = COUNTRY_CODES.flatMap((c) => [c.name, ...(c.aliases ?? [])]).map(normalizeCountryName); const dupes = names.filter((n, i) => names.indexOf(n) !== i); expect(dupes).toEqual([]); }); it('resolves every distinct country currently in trial_locations, or lists it as UNMAPPED', () => { const missing = (dbCountries as string[]).filter((n) => countryToIso3(n) === null && !isKnownUnmapped(n)); expect(missing).toEqual([]); // Sanity: the fixture is the real export (≈ 180 names), not an empty file. expect((dbCountries as string[]).length).toBeGreaterThan(150); // Explicitly unmapped names never resolve (a mapping added later must remove them from UNMAPPED). for (const u of UNMAPPED_COUNTRY_NAMES) expect(countryToIso3(u)).toBeNull(); }); });