gestion_table_tournante_libre/src/application/diagnostic.test.js
Mathieu Benoit 626159db5f [ADD] interface: diagnostic — what a configuration makes unavoidable
Before generating, the operator must know what no plan can avoid: the
encounters a table size forces, the conflicts when every table holds
colleagues, the anchors that impose a return. The engine's diagnosis is
turned into sentences with their figures and their remedies, shown in its
section and, compact, beside the plan, whose banner states the floors
when every table is in conflict (§ 7.5).
Checked: 2425 node and 413 browser tests.

--- FR ---

[ADD] interface : diagnostic — ce qu'une configuration rend inévitable

Avant de générer, l'opérateur doit savoir ce qu'aucun plan n'évite : les
rencontres qu'une taille de table impose, les conflits quand chaque table
réunit des collègues, les ancrages qui imposent un retour. Le diagnostic du
moteur devient des phrases, avec leurs chiffres et leurs remèdes, montrées
dans sa section et, en compact, à côté du plan, dont le bandeau énonce les
planchers quand toutes les tables sont en conflit (§ 7.5).
Vérifié : 2425 node et 413 navigateur.

Assisted-by: Claude Opus 5.5
2026-10-07 09:41:51 -04:00

83 lines
3.9 KiB
JavaScript

// © 2026 TechnoLibre (http://www.technolibre.ca)
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
// Épreuves du diagnostic d'une charge (§ 5.6, § 15.3) : la valeur rendue est
// celle de diagnostiquer sur la configuration de la charge, sollicitée une
// seconde fois (§ 19.1) ; une configuration qui ne se normalise pas rend son
// code et ses détails, sans lever. Les noms d'épreuve sont inventés.
import assert from 'node:assert/strict';
import { describe, test } from '../../test/lanceur.js';
import { texteLivre } from '../demo/livrees.js';
import { diagnostiquer } from '../moteur/diagnostic.js';
import { ErreurConfiguration } from '../moteur/erreurs.js';
import { normaliser } from '../moteur/configuration.js';
import { serialiser } from '../stockage/canonique.js';
import { analyser, configurationDepuisCharge, creerCharge } from '../stockage/document.js';
import { VERSION } from '../version.genere.js';
import { diagnostiquerCharge } from './diagnostic.js';
const chargeDemo = (cle) => analyser(texteLivre(cle)).charge;
// La petite démonstration où quatre personnes portent une réservation de
// portée « tous les tours », sans siège, à la table 1, de 3 places.
function quatreReserveesSurTrois() {
const charge = chargeDemo('petite');
charge.reservations = [1, 2, 3, 4].map((participant) => ({ participant, table: 1, siege: null, portee: 'tous', tour: null }));
return charge;
}
describe('diagnostiquerCharge', () => {
test('petite démonstration : le diagnostic de sa configuration, erreur null', () => {
const charge = chargeDemo('petite');
const rendu = diagnostiquerCharge(charge);
assert.deepEqual(rendu, { diagnostic: diagnostiquer(configurationDepuisCharge(charge)), erreur: null });
assert.ok(rendu.diagnostic.plafondAPriori.repartition.length > 0);
});
test('petite démonstration au conflit inévitable : le plancher du groupe de 5', () => {
const charge = chargeDemo('petite-conflit');
const { diagnostic, erreur } = diagnostiquerCharge(charge);
assert.equal(erreur, null);
assert.equal(diagnostic.collisions.length, 1);
assert.deepEqual(diagnostic, diagnostiquer(configurationDepuisCharge(charge)));
});
test('quatre réservées sur une table de 3 : analyser admet, normaliser refuse ; le code rendu, sans lever', () => {
const charge = quatreReserveesSurTrois();
// Le fichier qui la porte se relit : la charge est admise par le stockage.
const relue = analyser(serialiser(charge, { revision: 1, produitVersion: VERSION.affichee })).charge;
assert.equal(relue.reservations.length, 4);
let attendue = null;
try {
normaliser(configurationDepuisCharge(relue));
} catch (erreur) {
assert.ok(erreur instanceof ErreurConfiguration);
attendue = erreur;
}
assert.notEqual(attendue, null);
const rendu = diagnostiquerCharge(relue);
assert.deepEqual(rendu, { diagnostic: null, erreur: { code: 'SURRESERVATION', details: attendue.details } });
assert.equal(rendu.erreur.code, attendue.code);
});
test('un événement neuf, sans participant ni table : un diagnostic, aucune erreur', () => {
const charge = creerCharge({ id: 'evt-neuf', nom: 'Club des Merles', siegesParDefaut: 8, tours: 4 });
const { diagnostic, erreur } = diagnostiquerCharge(charge);
assert.equal(erreur, null);
assert.deepEqual(diagnostic, diagnostiquer(configurationDepuisCharge(charge)));
});
test('une erreur qui n\u{2019}est pas une ErreurConfiguration remonte', () => {
const charge = chargeDemo('petite');
charge.tables = null;
assert.throws(() => diagnostiquerCharge(charge), TypeError);
});
test('la charge reçue ne change pas', () => {
const charge = quatreReserveesSurTrois();
const avant = structuredClone(charge);
diagnostiquerCharge(charge);
diagnostiquerCharge(chargeDemo('grande'));
assert.deepEqual(charge, avant);
});
});