// © 2026 TechnoLibre (http://www.technolibre.ca) // License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) // Épreuves du mécanisme de traduction (§ 14.6) : une clé absente lève et se // nomme, une clé de deux tables lève à la création, les clés s'énumèrent // triées, une entrée en compose une autre, et la langue témoin encadre le // résultat entier de t d'une seule paire de marques. Les tables d'épreuve sont // inventées. import assert from 'node:assert/strict'; import { describe, test } from '../../test/lanceur.js'; import { MARQUE_TEMOIN, creerTraduction } from './traduction.js'; const { ouverture: O, fermeture: F } = MARQUE_TEMOIN; const TABLE_A = new Map([ ['essai.vide', '\u{2014}'], ['essai.salut', ({ nom }) => `Bonjour ${nom}`], ['essai.compose', ({ nom }, texte) => `${texte('essai.salut', { nom })}, ${texte('essai.vide')}`], ]); const TABLE_B = new Map([ ['AUTRE_CODE', () => 'Un code d’essai.'], ['autre.libelle', 'Un libellé'], ]); describe('traduction : le mécanisme (§ 14.6)', () => { test('les deux marques de la langue témoin sont U+2045 et U+2046, et figées', () => { assert.equal(O, '\u{2045}'); assert.equal(F, '\u{2046}'); assert.ok(Object.isFrozen(MARQUE_TEMOIN)); }); test('une clé absente lève RangeError, et le message nomme la clé ; jamais la clé brute, jamais une chaîne vide', () => { const { t } = creerTraduction([TABLE_A]); assert.throws(() => t('essai.inconnue'), (erreur) => { assert.ok(erreur instanceof RangeError); assert.match(erreur.message, /essai\.inconnue/); return true; }); assert.throws(() => t(undefined), RangeError); assert.throws(() => t('constructor'), RangeError); }); test('une clé portée par deux tables lève à la création, et se nomme', () => { const doublon = new Map([['essai.salut', 'Salut']]); assert.throws(() => creerTraduction([TABLE_A, doublon]), (erreur) => { assert.ok(erreur instanceof RangeError); assert.match(erreur.message, /essai\.salut/); return true; }); }); test('cles() énumère toutes les clés des tables, triées par unités UTF-16', () => { const { cles } = creerTraduction([TABLE_A, TABLE_B]); const attendues = ['AUTRE_CODE', 'autre.libelle', 'essai.compose', 'essai.salut', 'essai.vide']; assert.equal(cles().length, 5); assert.deepEqual(cles(), attendues); }); test('une chaîne se rend telle quelle, une fonction reçoit ses détails, et une entrée en compose une autre par texte', () => { const { t, langue } = creerTraduction([TABLE_A, TABLE_B]); assert.equal(langue, 'fr'); assert.equal(t('autre.libelle'), 'Un libellé'); assert.equal(t('essai.salut', { nom: 'Iris Ombrelle' }), 'Bonjour Iris Ombrelle'); assert.equal(t('essai.compose', { nom: 'Théo Pervenche' }), 'Bonjour Théo Pervenche, \u{2014}'); assert.equal(t('AUTRE_CODE'), 'Un code d’essai.'); }); test("une fonction appelée sans détails en reçoit un objet vide ; une entrée qui ne rend pas une chaîne lève", () => { const table = new Map([ ['essai.details', (details) => `${Object.keys(details).length}`], ['essai.nombre', () => 3], ]); const { t } = creerTraduction([table]); assert.equal(t('essai.details'), '0'); assert.equal(t('essai.details', null), '0'); assert.throws(() => t('essai.nombre'), TypeError); }); test("une table qui n'est pas une Map, une entrée ni chaîne ni fonction, une langue inconnue lèvent à la création", () => { assert.throws(() => creerTraduction([{ 'essai.objet': 'x' }]), TypeError); assert.throws(() => creerTraduction([new Map([['essai.nombre', 4]])]), TypeError); assert.throws(() => creerTraduction([TABLE_A], { langue: 'en' }), RangeError); }); }); describe('traduction : la langue témoin (§ 14.6)', () => { test('t encadre son résultat de la marque, une fois', () => { const { t, langue } = creerTraduction([TABLE_A, TABLE_B], { langue: 'temoin' }); assert.equal(langue, 'temoin'); assert.equal(t('essai.vide'), `${O}\u{2014}${F}`); assert.equal(t('autre.libelle'), `${O}Un libellé${F}`); }); test('une fonction de détails est décorée sur son résultat entier', () => { const { t } = creerTraduction([TABLE_A], { langue: 'temoin' }); assert.equal(t('essai.salut', { nom: 'Ondine Lacasse' }), `${O}Bonjour Ondine Lacasse${F}`); }); test("une composition ne porte qu'une paire de marques : texte compose en français", () => { const { t } = creerTraduction([TABLE_A], { langue: 'temoin' }); const rendu = t('essai.compose', { nom: 'Grisaille' }); assert.equal(rendu, `${O}Bonjour Grisaille, \u{2014}${F}`); assert.equal(rendu.split(O).length - 1, 1); assert.equal(rendu.split(F).length - 1, 1); }); test('une clé absente lève en langue témoin comme en français', () => { const { t } = creerTraduction([TABLE_A], { langue: 'temoin' }); assert.throws(() => t('essai.inconnue'), RangeError); }); });