[ADD] application: command registry tested whole, remedy on tour removal
Every command of the registry has an accepted, a refused and, when it admits one, a no-effect example. In reading mode or on a blocked plan nothing is written; in writing mode one journal entry precedes the state, undo restores the charge, a refusal writes nothing and names its remedy unless it is on the admitted null-remedy list. Removing a reserved person from a tour now offers « Retirer la réservation ». The invariant checker runs on each retouch, at opening and after undo, redo and revert. Checked: 2673 node tests, from the index alone. --- FR --- [ADD] application : registre des commandes éprouvé en entier, remède Chaque commande du registre a un exemple accepté, un refusé et, quand elle en admet un, un sans effet. En lecture ou sur un plan bloqué rien ne s'écrit ; en écriture une entrée de journal précède l'état, défaire rend la charge, un refus n'écrit rien et nomme son remède, hors de la liste des remèdes nuls admis. Retirer d'un tour une personne réservée propose désormais « Retirer la réservation ». Le vérificateur d'invariants s'appelle à chaque retouche, à l'ouverture, après défaire, refaire et revenir. Vérifié : 2673 épreuves node, depuis l'index seul. Assisted-by: Claude Opus 5.5
This commit is contained in:
parent
4b442ded14
commit
819a3853e5
3 changed files with 1098 additions and 9 deletions
|
|
@ -435,18 +435,37 @@ function violationsNouvelles(charge, precedent, suivant) {
|
|||
}
|
||||
|
||||
// La charge suivante d'une retouche, ou INVARIANT_VIOLE quand elle ajoute
|
||||
// une violation au retenu reçu. Le versement en réserve des personnes que le
|
||||
// plan n'assied pas (reduireAuxAssises, versLaReserveAffichee) n'en ajoute
|
||||
// une violation au retenu reçu, son remède celui que remedeDe(violations)
|
||||
// rend, null par défaut. Le versement en réserve des personnes que le plan
|
||||
// n'assied pas (reduireAuxAssises, versLaReserveAffichee) n'en ajoute
|
||||
// aucune : l'affichage assied d'abord, à leur table, les personnes qu'elle
|
||||
// réserve, et une capacité ne descend jamais sous ses réservations (§ 6.2).
|
||||
function retouche(charge, suivante) {
|
||||
function retouche(charge, suivante, remedeDe = () => null) {
|
||||
const violations = violationsNouvelles(charge, charge.retenu, suivante.retenu);
|
||||
if (violations.length > 0) {
|
||||
throw refus('INVARIANT_VIOLE', { proposition: charge.retenu.proposition, violations });
|
||||
throw refus('INVARIANT_VIOLE', { proposition: charge.retenu.proposition, violations }, remedeDe(violations));
|
||||
}
|
||||
return suivante;
|
||||
}
|
||||
|
||||
// Le remède d'un retrait du tour que la réservation de la personne à sa
|
||||
// table interdit : le retrait de cette réservation, la première dans l'ordre
|
||||
// canonique qui tient la personne à la table de la violation au tour, « tous
|
||||
// les tours » avant « ce tour ». null quand aucune violation RESERVATION ne
|
||||
// nomme la personne.
|
||||
function remedeDuRetrait(charge, participant, tour, violations) {
|
||||
const violation = violations.find((v) => v.code === 'RESERVATION' && v.participant === participant);
|
||||
if (violation === undefined) return null;
|
||||
const [tenue] = charge.reservations
|
||||
.filter((r) => r.participant === participant && r.table === violation.table && (r.portee === 'tous' || r.tour === tour))
|
||||
.sort(ordreDesReservations);
|
||||
if (tenue === undefined) return null;
|
||||
return {
|
||||
commande: 'retirerReservation',
|
||||
arguments: { participant, table: tenue.table, portee: tenue.portee, tour: tenue.tour },
|
||||
};
|
||||
}
|
||||
|
||||
// Le numéro de la table où le retenu place id à ce tour, null en réserve,
|
||||
// hors du retenu, ou à une table que la charge n'a plus.
|
||||
function numeroDuLieu(charge, tour, id) {
|
||||
|
|
@ -677,7 +696,9 @@ function echangerDansRetenu(charge, { tour, a, b } = {}) {
|
|||
* tour donné et attend dans la réserve de ce tour ; sa chaise se libère.
|
||||
* Une personne que le plan du tour ne montre pas assise (placeDe) — en
|
||||
* réserve, hors du retenu, à une table que la charge n'a plus ou à un rang
|
||||
* au-delà de sa capacité courante — refuse SANS_EFFET.
|
||||
* au-delà de sa capacité courante — refuse SANS_EFFET. Une personne que sa
|
||||
* réservation tient à cette table refuse INVARIANT_VIOLE, remède le retrait
|
||||
* de cette réservation.
|
||||
*/
|
||||
function retirerDuTour(charge, { tour, participant } = {}) {
|
||||
exigerModifiable(charge);
|
||||
|
|
@ -696,7 +717,7 @@ function retirerDuTour(charge, { tour, participant } = {}) {
|
|||
oter(suivante.retenu, tour, participant);
|
||||
enReserve(suivante.retenu, tour, participant);
|
||||
return {
|
||||
charge: retouche(charge, suivante),
|
||||
charge: retouche(charge, suivante, (violations) => remedeDuRetrait(charge, participant, tour, violations)),
|
||||
libelle: libelle('ENTREE_RETIRER_DU_TOUR', { personne: nomAffiche(personne), numero, tour }),
|
||||
avertissements: [],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -728,19 +728,31 @@ describe('commandes des places : le retenu et la dérive (§ 9, § 4.4)', () =>
|
|||
});
|
||||
|
||||
describe('commandes des places : le vérificateur d’invariants du retenu (§ 14.12, § 14.15)', () => {
|
||||
test('retirer du tour une personne réservée à sa table : INVARIANT_VIOLE, les seules violations nouvelles, sans écriture', () => {
|
||||
test('retirer du tour une personne réservée à sa table : INVARIANT_VIOLE, les seules violations nouvelles, remède le retrait de la réservation', () => {
|
||||
// Le retenu reçu porte déjà une violation : 7, réservé à la table 4 au
|
||||
// tour 2, y est assis à la table 7 ; elle n'entre pas dans le refus.
|
||||
const charge = figer(chargeRetenue({ reservations: [resa(4, 5, null, 1), resa(7, 5, null, 2)] }));
|
||||
refuse(() => executer('retirerDuTour', charge, { tour: 1, participant: 4 }), 'INVARIANT_VIOLE', {
|
||||
const leve = refuse(() => executer('retirerDuTour', charge, { tour: 1, participant: 4 }), 'INVARIANT_VIOLE', {
|
||||
proposition: 1,
|
||||
violations: [{ code: 'RESERVATION', participant: 4, table: 5, tour: 1 }],
|
||||
remede: null,
|
||||
remede: { commande: 'retirerReservation', arguments: { participant: 4, table: 5, portee: 'tour', tour: 1 } },
|
||||
});
|
||||
// Le remède lève le refus : la réservation retirée, le retrait passe.
|
||||
const { commande, arguments: argumentsDuRemede } = leve.details.remede;
|
||||
const { charge: sansReservation } = executer(commande, charge, argumentsDuRemede);
|
||||
const { charge: retire } = executer('retirerDuTour', sansReservation, { tour: 1, participant: 4 });
|
||||
assert.deepEqual(reserveDe(retire, 1), [4]);
|
||||
const { charge: apres } = executer('retirerDuTour', charge, { tour: 1, participant: 5 });
|
||||
assert.deepEqual(reserveDe(apres, 1), [5]);
|
||||
});
|
||||
|
||||
test('retirer du tour une personne réservée « tous les tours » à sa table : le remède désigne cette réservation', () => {
|
||||
const charge = figer(chargeRetenue({ reservations: [resa(4, 5, null)] }));
|
||||
refuse(() => executer('retirerDuTour', charge, { tour: 1, participant: 4 }), 'INVARIANT_VIOLE', {
|
||||
remede: { commande: 'retirerReservation', arguments: { participant: 4, table: 5, portee: 'tous', tour: null } },
|
||||
});
|
||||
});
|
||||
|
||||
test('une violation déjà présente, celle d’une dérive, ne bloque pas la retouche suivante', () => {
|
||||
const charge = chargeRetenue({ reservations: [resa(4, 8, null, 1)] });
|
||||
charge.participants.push(personne(13));
|
||||
|
|
|
|||
1056
src/application/registre.test.js
Normal file
1056
src/application/registre.test.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue