gestion_table_tournante_libre/src/csv/normalisation.test.js

111 lines
5 KiB
JavaScript
Raw Normal View History

// © 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));
});
});