Distinguer scénario, dessin et couleurs sur chaque livre
Le rôle vit sur le LIEN livre-auteur, jamais sur l'auteur : le même auteur scénarise un album et dessine le suivant, et il ne doit pas exister en deux fiches pour autant — ce que l'index unique sur la clé de regroupement interdit de toute façon. Les rôles se retrouvent par clé d'auteur résolue et non par position : ResoudreAsync écarte les noms vides et fusionne les variantes, donc sa liste peut être plus courte que la saisie. Piège traité : le champ des noms reconstruit la liste à chaque frappe. Decouper reprend les rôles connus en rapprochant sur la forme normalisée, sans quoi corriger une faute de frappe les effacerait tous. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -390,6 +390,74 @@ public class ServiceCatalogueTests : IDisposable
|
||||
Assert.Equal(["Germinal"], nonPrecises.Select(l => l.Titre));
|
||||
}
|
||||
|
||||
// ── Rôles des auteurs : ils vivent sur le LIEN, pas sur la personne ──────
|
||||
|
||||
[Fact]
|
||||
public async Task Les_roles_sont_enregistres_par_livre_et_pas_par_personne()
|
||||
{
|
||||
var bd = Saisie("Le Horla", format: Format.Physique);
|
||||
bd.TypeDocument = TypeDocument.BandeDessinee;
|
||||
bd.Auteurs =
|
||||
[
|
||||
new AuteurSaisi("Guy de Maupassant", RoleAuteur.Scenario),
|
||||
new AuteurSaisi("Guillaume Sorel", RoleAuteur.Dessin),
|
||||
];
|
||||
|
||||
var premier = (await _service.CreerAsync(bd, "mathieu")).Livre!;
|
||||
|
||||
// Le MÊME dessinateur, scénariste ailleurs : une seule fiche d'auteur, deux rôles.
|
||||
var autre = Saisie("Autre album");
|
||||
autre.Auteurs = [new AuteurSaisi("Guillaume Sorel", RoleAuteur.Scenario)];
|
||||
var second = (await _service.CreerAsync(autre, "mathieu", confirmerDoublon: true)).Livre!;
|
||||
|
||||
Assert.Equal(
|
||||
[RoleAuteur.Scenario, RoleAuteur.Dessin],
|
||||
premier.Auteurs.Select(a => a.Role));
|
||||
|
||||
Assert.Equal(RoleAuteur.Scenario, second.Auteurs.Single().Role);
|
||||
Assert.Equal(2, await _db.Auteurs.CountAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Un_livre_sans_role_precise_reste_non_precise()
|
||||
{
|
||||
var livre = (await _service.CreerAsync(Saisie("Germinal", "Émile Zola"), "mathieu")).Livre!;
|
||||
|
||||
Assert.Equal(RoleAuteur.NonPrecise, livre.Auteurs.Single().Role);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Le_role_suit_lauteur_meme_si_son_nom_est_ecrit_autrement()
|
||||
{
|
||||
var saisie = Saisie("Le Horla");
|
||||
saisie.Auteurs =
|
||||
[
|
||||
// Variante sûre d'un auteur déjà connu : le serveur la rapproche, et le rôle doit
|
||||
// suivre la fiche RÉSOLUE, pas la position dans la saisie.
|
||||
new AuteurSaisi("Maupassant, Guy de", RoleAuteur.Scenario),
|
||||
];
|
||||
|
||||
await _service.CreerAsync(Saisie("Bel-Ami", "Guy de Maupassant"), "mathieu");
|
||||
var livre = (await _service.CreerAsync(saisie, "mathieu")).Livre!;
|
||||
|
||||
Assert.Single(await _db.Auteurs.ToListAsync());
|
||||
Assert.Equal(RoleAuteur.Scenario, livre.Auteurs.Single().Role);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Modifier_un_livre_change_le_role_sans_toucher_a_lauteur()
|
||||
{
|
||||
var saisie = Saisie("Le Horla");
|
||||
saisie.Auteurs = [new AuteurSaisi("Guillaume Sorel", RoleAuteur.Dessin)];
|
||||
var cree = (await _service.CreerAsync(saisie, "mathieu")).Livre!;
|
||||
|
||||
saisie.Auteurs = [new AuteurSaisi("Guillaume Sorel", RoleAuteur.Couleurs)];
|
||||
var modifie = (await _service.ModifierAsync(cree.Id, saisie, "mathieu")).Livre!;
|
||||
|
||||
Assert.Equal(RoleAuteur.Couleurs, modifie.Auteurs.Single().Role);
|
||||
Assert.Single(await _db.Auteurs.ToListAsync());
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Doublons : un AVERTISSEMENT, jamais un refus. Posséder deux exemplaires est légitime —
|
||||
// on garde le sien et on prête l'autre — et l'ISBN est facultatif, donc il ne peut pas
|
||||
|
||||
Reference in New Issue
Block a user