111 lines
5 KiB
JavaScript
111 lines
5 KiB
JavaScript
|
|
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|||
|
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|||
|
|
|
|||
|
|
// Épreuves des clés de comparaison (§ 10.1) : la clé normalisée, que
|
|||
|
|
// partagent la réconciliation des appartenances et la clé de doublon, et la
|
|||
|
|
// clé d'en-tête, qui en dérive. Les lettres décomposées et les blancs autres
|
|||
|
|
// que l'espace s'écrivent par leur point de code : un éditeur qui recompose
|
|||
|
|
// une lettre ou remplace un caractère invisible changerait l'épreuve sans
|
|||
|
|
// qu'elle le montre.
|
|||
|
|
import assert from 'node:assert/strict';
|
|||
|
|
import { describe, test } from '../../test/lanceur.js';
|
|||
|
|
import { cleEntete, cleNormalisee } from './normalisation.js';
|
|||
|
|
|
|||
|
|
describe('cleNormalisee (§ 10.1)', () => {
|
|||
|
|
test('la casse et les accents sont ignorés', () => {
|
|||
|
|
for (const texte of ['Coopérative Bleue', 'COOPÉRATIVE BLEUE', 'coopérative bleue', 'Cooperative Bleue']) {
|
|||
|
|
assert.equal(cleNormalisee(texte), 'cooperative bleue', texte);
|
|||
|
|
}
|
|||
|
|
assert.equal(cleNormalisee('Ça gèle à Noël, où ?'), 'ca gele a noel, ou ?');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('une lettre accentuée, composée ou décomposée, donne la même clé', () => {
|
|||
|
|
const composee = 'Th\u{E9}o';
|
|||
|
|
const decomposee = 'The\u{301}o';
|
|||
|
|
assert.notEqual(composee, decomposee);
|
|||
|
|
assert.equal(cleNormalisee(composee), 'theo');
|
|||
|
|
assert.equal(cleNormalisee(decomposee), 'theo');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('toute marque combinante est retirée, pas seulement les accents du français', () => {
|
|||
|
|
// Cédille, rond en chef, tréma, double accent aigu, ogonek, puis un
|
|||
|
|
// cercle englobant, marque combinante qui n'est pas un accent.
|
|||
|
|
assert.equal(cleNormalisee('Gar\u{E7}on'), 'garcon');
|
|||
|
|
assert.equal(cleNormalisee('\u{C5}ngstr\u{F6}m'), 'angstrom');
|
|||
|
|
assert.equal(cleNormalisee('\u{150}rs\u{105}'), 'orsa');
|
|||
|
|
assert.equal(cleNormalisee('a\u{20DD}b'), 'ab');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('la décomposition est canonique : une ligature ou une lettre sans décomposition reste', () => {
|
|||
|
|
assert.equal(cleNormalisee('\u{152}uvre'), '\u{153}uvre');
|
|||
|
|
assert.equal(cleNormalisee('\u{FB01}n'), '\u{FB01}n');
|
|||
|
|
assert.equal(cleNormalisee('\u{141}ukasz'), '\u{142}ukasz');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('les blancs se réduisent à une espace, les bouts retirés', () => {
|
|||
|
|
assert.equal(cleNormalisee(' cooperative bleue '), 'cooperative bleue');
|
|||
|
|
assert.equal(cleNormalisee('club\tdes\u{A0}merles\r\nnord'), 'club des merles nord');
|
|||
|
|
assert.equal(cleNormalisee('\u{202F}chorale\u{3000}du\u{2009}givre\u{FEFF}'), 'chorale du givre');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test("le trait d'union, le trait de soulignement et l'espace restent : seule la clé d'en-tête les retire", () => {
|
|||
|
|
// La réconciliation des appartenances et la clé de doublon comparent par
|
|||
|
|
// cette clé : « Club-des-Merles » et « Club des Merles » y restent deux.
|
|||
|
|
assert.equal(cleNormalisee('Club-des-Merles'), 'club-des-merles');
|
|||
|
|
assert.equal(cleNormalisee('Club_des_Merles'), 'club_des_merles');
|
|||
|
|
assert.equal(cleNormalisee('Clubdes Merles'), 'clubdes merles');
|
|||
|
|
assert.notEqual(cleNormalisee('Val-Brume'), cleNormalisee('Val Brume'));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('un texte vide ou blanc donne la clé vide', () => {
|
|||
|
|
for (const texte of ['', ' ', '\t\r\n', '\u{A0}\u{3000}\u{202F}']) {
|
|||
|
|
assert.equal(cleNormalisee(texte), '', JSON.stringify(texte));
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('les minuscules ne suivent aucune langue', () => {
|
|||
|
|
// Une minuscule turque ferait de I un ı sans point.
|
|||
|
|
assert.equal(cleNormalisee('IRIS'), 'iris');
|
|||
|
|
// I à point suscrit : le point est une marque, retirée.
|
|||
|
|
assert.equal(cleNormalisee('\u{130}LE'), 'ile');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('la clé est un point fixe : la normaliser de nouveau ne la change pas', () => {
|
|||
|
|
for (const texte of ['Coopérative Bleue', ' The\u{301}o PERVENCHE ', '\u{130}LE', 'a\u{20DD}b', '\u{152}UVRE']) {
|
|||
|
|
const cle = cleNormalisee(texte);
|
|||
|
|
assert.equal(cleNormalisee(cle), cle, texte);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
describe('cleEntete (§ 10.1)', () => {
|
|||
|
|
test('sans égard à la casse, aux accents, aux espaces, à « _ » ni à « - »', () => {
|
|||
|
|
const cas = [
|
|||
|
|
['NOM', 'nom'],
|
|||
|
|
[' Prénom ', 'prenom'],
|
|||
|
|
['Équipe', 'equipe'],
|
|||
|
|
['Rôle', 'role'],
|
|||
|
|
['E X C L U', 'exclu'],
|
|||
|
|
['titre_pressenti', 'titrepressenti'],
|
|||
|
|
['Titre-Pressenti', 'titrepressenti'],
|
|||
|
|
['titre pressenti', 'titrepressenti'],
|
|||
|
|
['titre\u{A0}_\u{9}pressenti', 'titrepressenti'],
|
|||
|
|
[' Ti_tre--Pres sen-ti ', 'titrepressenti'],
|
|||
|
|
];
|
|||
|
|
assert.deepEqual(
|
|||
|
|
cas.map(([entete]) => cleEntete(entete)),
|
|||
|
|
cas.map(([, cle]) => cle),
|
|||
|
|
);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('seuls les blancs, « _ » et « - » sont retirés', () => {
|
|||
|
|
assert.equal(cleEntete('titre.pressenti'), 'titre.pressenti');
|
|||
|
|
assert.equal(cleEntete('nom/prenom'), 'nom/prenom');
|
|||
|
|
assert.equal(cleEntete('titre\u{2013}pressenti'), 'titre\u{2013}pressenti');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('un en-tête vide ou fait de blancs, de « _ » et de « - » donne la clé vide', () => {
|
|||
|
|
for (const entete of ['', ' ', '_-_', ' - ']) assert.equal(cleEntete(entete), '', JSON.stringify(entete));
|
|||
|
|
});
|
|||
|
|
});
|