gestion_table_tournante_libre/src/stockage/systeme_fichiers.test.js
Mathieu Benoit fdaa79ed32 [ADD] storage: file-system interface, failing test double, contract
Storage code receives its file system as a parameter (§ 13.4): one
interface, and here the implementation tests inject. It keeps files in
memory, shares a disk between two instances to replay a restart, and
fails on demand: a refused rename that leaves the target intact, writes
refused from a moment on, a process killed after n writes, a failing
probe, a removable medium. One contract suite, its assertions passed in,
will run unchanged on the Electron and web implementations.

Checked: 87 tests, the contract suite run on the test double.

--- FR ---

[ADD] stockage : interface du système de fichiers, double, contrat

Le code du stockage reçoit son système de fichiers en paramètre
(§ 13.4) : une interface, et ici l'implémentation que les épreuves
injectent. Elle garde les fichiers en mémoire, partage un disque entre
deux instances pour rejouer un redémarrage, et tombe en panne à la
demande : renommage refusé qui laisse la cible intacte, écritures
refusées à partir d'un instant, processus tué après n écritures, sonde
qui échoue, support amovible. Une suite de contrat, ses assertions
reçues en paramètre, servira telle quelle sous Electron et sous web.

Vérifié : 87 épreuves, la suite de contrat jouée sur le double.

Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
2026-10-06 13:12:25 -04:00

84 lines
2.8 KiB
JavaScript

// © 2026 TechnoLibre (http://www.technolibre.ca)
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
// Épreuves du contrôle des chemins relatifs à une racine (§ 13.4, § 14.10) :
// exigerCheminRelatif, que partagent l'implémentation web et celle
// d'épreuve, rend les segments d'un chemin admis, et refuse par
// CHEMIN_REFUSE tout chemin absolu, remontant, ou que Windows lirait
// autrement. Le reste du module est l'interface en JSDoc, que la suite de
// contrat test/contrat_fichiers.js éprouve sur chaque implémentation. Les
// noms d'épreuve sont inventés.
import assert from 'node:assert/strict';
import { describe, test } from '../../test/lanceur.js';
import { ErreurStockage } from './erreurs.js';
import { exigerCheminRelatif } from './systeme_fichiers.js';
// Rend l'erreur que lève la fonction ; échoue quand elle n'en lève pas.
function erreurDe(fonction) {
try {
fonction();
} catch (erreur) {
return erreur;
}
assert.fail('aucune erreur levée');
}
describe('exigerCheminRelatif', () => {
test("rend les segments d'un chemin relatif, et aucun pour la racine", () => {
const cas = [
['', []],
['soiree.gtt.json', ['soiree.gtt.json']],
[
'corbeille/2026-01-02_03-04-05/soiree.gtt.json',
['corbeille', '2026-01-02_03-04-05', 'soiree.gtt.json'],
],
['.gtt-temoin', ['.gtt-temoin']],
['..soiree', ['..soiree']],
[' devant', [' devant']],
['Soir\u{E9}e d\u{2019}\u{E9}t\u{E9}.gtt.json', ['Soir\u{E9}e d\u{2019}\u{E9}t\u{E9}.gtt.json']],
];
for (const [chemin, segments] of cas) assert.deepEqual(exigerCheminRelatif(chemin), segments, chemin);
});
test('refuse un chemin absolu, remontant, ou que Windows lirait autrement : CHEMIN_REFUSE {chemin}', () => {
const refuses = [
// absolus, ou porteurs d'un segment vide
'/x',
'//serveur/partage/x',
'a//b',
'a/',
// remontants ou désignant le dossier courant
'..',
'../x',
'a/../../x',
'.',
'./x',
'a/./b',
// ce que Windows ramène à eux, ou à un autre nom, en retirant points et
// espaces finaux
'...',
'a/.. /x',
'soiree.',
'soiree ',
// lecteur, partage, séparateur de Windows, flux de données secondaire
'C:\\x',
'C:x',
'C:/x',
'\\\\serveur\\partage\\x',
'a\\b',
'soiree.gtt.json:flux',
// caractère nul
'a\u{0}b',
// autre chose qu'une chaîne
null,
undefined,
42,
];
for (const chemin of refuses) {
const erreur = erreurDe(() => exigerCheminRelatif(chemin));
assert.ok(erreur instanceof ErreurStockage, `${String(chemin)} : ${erreur}`);
assert.equal(erreur.code, 'CHEMIN_REFUSE', String(chemin));
assert.deepEqual(erreur.details, { chemin }, String(chemin));
}
});
});