Files
mabibli/MaBibli.Tests/NettoyageIsbdTests.cs
T
Mathieu LimonierandClaude Opus 5 6a6d745af4 MaBibli 1.0.0
Gestion de bibliothèque personnelle auto-hébergée : catalogue, prêts,
scan de code-barres, consultation hors-ligne.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 22:36:16 +02:00

166 lines
8.1 KiB
C#

using MaBibli.Api.Services.Isbn;
namespace MaBibli.Tests;
public class NettoyageIsbdTests
{
[Theory]
[InlineData("Germinal / Émile Zola ; préface d'Armand Lanoux", "Germinal")]
[InlineData("Germinal / Émile Zola ; préf., dossier et notes par Colette Becker", "Germinal")]
[InlineData("Le Horla / Guy de Maupassant", "Le Horla")]
public void Titre_coupe_a_la_mention_de_responsabilite(string brut, string attendu)
=> Assert.Equal(attendu, NettoyageIsbd.Titre(brut));
[Theory]
[InlineData("Germinal", "Germinal")]
[InlineData("Le Petit Prince", "Le Petit Prince")]
[InlineData("Introduction to Algorithms", "Introduction to Algorithms")]
// Le sous-titre ISBD (« : ») n'est pas de la ponctuation à retirer : on le garde.
[InlineData("Voyage au bout de la nuit : roman", "Voyage au bout de la nuit : roman")]
// Un « / » sans espaces autour appartient au titre, il ne doit pas servir de coupure.
[InlineData("Entrée/sortie", "Entrée/sortie")]
public void Titre_laisse_passer_ce_qui_est_deja_propre(string brut, string attendu)
=> Assert.Equal(attendu, NettoyageIsbd.Titre(brut));
/// <summary>
/// Cas réel mesuré sur l'ISBN <c>9782749942636</c> : la BnF recolle le nom de l'auteur en
/// fin de titre <b>sans</b> le séparateur ISBD, ce que <see cref="NettoyageIsbd.Titre"/> ne
/// peut donc pas voir.
/// </summary>
[Fact]
public void Titre_retire_le_nom_de_lauteur_colle_en_fin()
{
const string brut = "Le plus grand défi de l'histoire de l'humanité : face à la "
+ "catastrophe écologique et sociale (Nouvelle éd. augmentée) Aurélien Barrau";
var titre = NettoyageIsbd.RetirerAuteurEnFin(brut, ["Aurélien Barrau"]);
Assert.Equal(
"Le plus grand défi de l'histoire de l'humanité : face à la catastrophe écologique "
+ "et sociale (Nouvelle éd. augmentée)",
titre);
}
[Theory]
// Contre-exemple central : le nom est bien là, mais pas en fin de chaîne. On n'y touche pas.
[InlineData("Lettre à Émile Zola", "Guy de Maupassant")]
[InlineData("Émile Zola et son temps", "Émile Zola")]
// Le titre EST le nom de l'auteur (biographie, recueil) : le retirer ne laisserait rien.
[InlineData("Aurélien Barrau", "Aurélien Barrau")]
// Fin de mot fortuite : « Zola » ne doit pas être découpé dans « Gorgonzola ».
[InlineData("Éloge du gorgonzola", "Zola")]
// Auteur inconnu du titre.
[InlineData("Germinal", "Émile Zola")]
public void Titre_ne_mutile_pas_un_nom_legitime(string titre, string auteur)
=> Assert.Equal(titre, NettoyageIsbd.RetirerAuteurEnFin(titre, [auteur]));
[Fact]
public void Titre_tolere_une_difference_daccent_ou_de_casse_sur_le_nom()
=> Assert.Equal(
"Le grand défi",
NettoyageIsbd.RetirerAuteurEnFin("Le grand défi AURELIEN BARRAU", ["Aurélien Barrau"]));
[Fact]
public void Titre_sans_auteur_connu_reste_intact()
{
Assert.Equal("Germinal", NettoyageIsbd.RetirerAuteurEnFin("Germinal", []));
Assert.Equal("Germinal", NettoyageIsbd.RetirerAuteurEnFin("Germinal", [null, " "]));
Assert.Null(NettoyageIsbd.RetirerAuteurEnFin(null, ["Émile Zola"]));
}
[Theory]
[InlineData("Zola, Émile (1840-1902). Auteur du texte", "Émile Zola")]
[InlineData("Saint-Exupéry, Antoine de (1900-1944). Auteur du texte", "Antoine de Saint-Exupéry")]
[InlineData("Maupassant, Guy de (1850-1893). Auteur du texte", "Guy de Maupassant")]
[InlineData("Becker, Colette (1932-....). Éditeur scientifique", "Colette Becker")]
[InlineData("Zola, Émile (1840-1902)", "Émile Zola")]
[InlineData("Zola, Émile. Auteur du texte", "Émile Zola")]
public void Auteur_retire_dates_et_role_puis_inverse(string brut, string attendu)
=> Assert.Equal(attendu, NettoyageIsbd.Auteur(brut));
[Theory]
[InlineData("Émile Zola", "Émile Zola")]
[InlineData("Antoine de Saint-Exupéry", "Antoine de Saint-Exupéry")]
[InlineData("Molière", "Molière")]
public void Auteur_laisse_passer_ce_qui_est_deja_propre(string brut, string attendu)
=> Assert.Equal(attendu, NettoyageIsbd.Auteur(brut));
[Theory]
// Contre-exemples : le nom se termine légitimement par une initiale, il n'y a pas de rôle
// à retirer — couper au point amputerait le prénom.
[InlineData("Cormen, Thomas H.", "Thomas H. Cormen")]
[InlineData("Tolkien, J. R. R.", "J. R. R. Tolkien")]
// Cas réel : le rôle suit une initiale. Protéger le point de l'initiale ne doit pas
// protéger le rôle — sinon on obtient « Thomas H. Auteur du texte Cormen ».
[InlineData("Cormen, Thomas H. Auteur du texte", "Thomas H. Cormen")]
[InlineData("Tolkien, J. R. R. (1892-1973). Auteur du texte", "J. R. R. Tolkien")]
public void Auteur_distingue_une_initiale_d_un_role(string brut, string attendu)
=> Assert.Equal(attendu, NettoyageIsbd.Auteur(brut));
[Theory]
[InlineData("le Livre de poche (Paris)", "le Livre de poche")]
[InlineData("Librairie générale française (Paris)", "Librairie générale française")]
[InlineData("Gallimard (Paris)", "Gallimard")]
public void Editeur_retire_la_ville_finale(string brut, string attendu)
=> Assert.Equal(attendu, NettoyageIsbd.Editeur(brut));
[Theory]
[InlineData("Gallimard", "Gallimard")]
[InlineData("The MIT Press", "The MIT Press")]
// Parenthèses en milieu de chaîne : ce n'est pas la ville, on n'y touche pas.
[InlineData("Presses (universitaires) de France", "Presses (universitaires) de France")]
public void Editeur_laisse_passer_ce_qui_est_deja_propre(string brut, string attendu)
=> Assert.Equal(attendu, NettoyageIsbd.Editeur(brut));
// ── Le nombre de pages, lu dans dc:format ───────────────────────────────
//
// ⚠️ Ce champ n'est PAS un nombre : c'est une phrase décrivant le support. Les règles sont
// donc volontairement étroites, et l'erreur n'est pas symétrique — un champ vide se remplit
// à la main en trois secondes, un chiffre faux s'enregistre sans que personne ne le voie.
[Theory]
// Formes réellement observées dans les notices enregistrées sous Fixtures/.
[InlineData("1 vol. (113 p.) : ill., couv. ill. en coul. ; 18 cm", 113)]
[InlineData("1 vol. (254 p.) ; 18 cm", 254)]
[InlineData("503 p. : couv. ill. ; 17 cm", 503)]
// Autres formes plausibles du même catalogue.
[InlineData("349 p.", 349)]
[InlineData("1 vol. (XII-349 p.)", 349)]
[InlineData("208 pages", 208)]
[InlineData("1 vol. (1248 p.)", 1248)]
public void NombreDePages_lit_une_pagination(string brut, int attendu)
=> Assert.Equal(attendu, NettoyageIsbd.NombreDePages(brut));
[Theory]
// ⚠️ « 1 vol. » ne vaut pas 1 page, et « 30 cm » ne vaut pas 30 pages : ce sont les deux
// façons les plus faciles de fabriquer un chiffre faux.
[InlineData("1 vol.")]
[InlineData("30 cm")]
[InlineData("2 disques compacts")]
[InlineData("1 disque compact (1 h 05 min)")]
// Une pagination de CONTRIBUTION : les chiffres suivent « p. », ils bornent un extrait
// dans un volume et ne disent rien de son épaisseur.
[InlineData("1 vol. (p. 45-90)")]
// Non paginé entre crochets : on ne sait pas le lire, donc on ne prétend pas.
[InlineData("1 vol. (non paginé [128] p.)")]
// Un nombre à rallonge n'est pas une pagination, et 0 page n'est pas une donnée.
[InlineData("1234567 p.")]
[InlineData("0 p.")]
[InlineData("")]
[InlineData(null)]
public void NombreDePages_rend_null_sur_ce_quil_ne_comprend_pas(string? brut)
=> Assert.Null(NettoyageIsbd.NombreDePages(brut));
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void Champs_vides_donnent_null(string? brut)
{
Assert.Null(NettoyageIsbd.Titre(brut));
Assert.Null(NettoyageIsbd.Auteur(brut));
Assert.Null(NettoyageIsbd.Editeur(brut));
Assert.Null(NettoyageIsbd.NombreDePages(brut));
}
}