using MaBibli.Api.Services.Isbn; using MaBibli.Shared.Dtos; namespace MaBibli.Tests; /// /// Parsing de réponses SRU réelles de la BnF (schéma dublincore). /// public class BnfSruParserTests { [Theory] // Le piège bloquant, mesuré : ces trois ISBN-13 donnent 0 notice, leur ISBN-10 en donne. [InlineData("bnf-9782070612758.xml", 1)] // Le Petit Prince (2007) : trouvé en ISBN-13 [InlineData("bnf-9782253004226.xml", 0)] // Germinal en ISBN-13 : rien [InlineData("bnf-2253004227.xml", 3)] // Germinal en ISBN-10 : 3 rééditions [InlineData("bnf-9782080704092.xml", 0)] // Le Horla en ISBN-13 : rien [InlineData("bnf-2080704095.xml", 1)] // Le Horla en ISBN-10 : 1 notice [InlineData("bnf-9780262033848.xml", 0)] // Livre étranger : absent du dépôt légal français [InlineData("bnf-0262033844.xml", 0)] // …sous les deux formes d'ISBN public void NombreDeNotices_correspond_aux_mesures(string fixture, int attendu) => Assert.Equal(attendu, BnfSruParser.LireNombreDeNotices(Fixture.Lire(fixture))); [Fact] public void Petit_Prince_est_parse_et_nettoye() { var candidats = BnfSruParser.Parser( Fixture.Lire("bnf-9782070612758.xml"), "9782070612758", "https://couverture"); var c = Assert.Single(candidats); Assert.Equal("Le petit prince", c.Titre); Assert.Equal("Antoine de Saint-Exupéry", c.Auteur); Assert.Equal("Gallimard", c.Editeur); Assert.Equal("2007", c.Annee); Assert.Equal("fre", c.Langue); Assert.Equal(SourceMetadonnees.Bnf, c.Source); Assert.Equal("9782070612758", c.IsbnInterroge); Assert.Equal("https://couverture", c.CoverUrl); Assert.StartsWith("ark:/12148/", c.IdentifiantSource); Assert.Equal($"https://catalogue.bnf.fr/{c.IdentifiantSource}", c.UrlNotice); } /// /// Le nombre de pages est lu dans dc:format, qui décrit le support en toutes lettres. /// /// /// ⚠️ Il est proposé, jamais imposé : la valeur traverse le candidat jusqu'à un champ /// modifiable. Les deux formes du catalogue sont représentées ici — « 1 vol. (113 p.) … » /// et « 503 p. … » —, et les dimensions qui les suivent (« ; 18 cm ») ne doivent surtout pas /// être prises pour une pagination. /// [Fact] public void Le_nombre_de_pages_est_lu_dans_la_description_materielle() { var petitPrince = BnfSruParser.Parser( Fixture.Lire("bnf-9782070612758.xml"), "9782070612758", null); Assert.Equal(113, Assert.Single(petitPrince).NombrePages); var germinal = BnfSruParser.Parser( Fixture.Lire("bnf-2253004227.xml"), "2253004227", null); Assert.Equal([503, 605, 538], germinal.Select(c => c.NombrePages)); } [Fact] public void Germinal_renvoie_les_trois_reeditions_distinctes() { // Décision actée : on ne choisit pas à la place de l'utilisateur, on remonte tout. var candidats = BnfSruParser.Parser( Fixture.Lire("bnf-2253004227.xml"), "2253004227", null); Assert.Equal(3, candidats.Count); Assert.All(candidats, c => Assert.Equal("Germinal", c.Titre)); Assert.All(candidats, c => Assert.Equal("Émile Zola", c.Auteur)); Assert.Equal( ["le Livre de poche", "Librairie générale française", "Librairie générale française"], candidats.Select(c => c.Editeur)); Assert.Equal(["1979", "2000", "1983"], candidats.Select(c => c.Annee)); // Les notices doivent rester discernables : sans ark distinct l'utilisateur ne peut pas trancher. Assert.Equal(3, candidats.Select(c => c.IdentifiantSource).Distinct().Count()); } [Fact] public void Le_Horla_est_parse_depuis_lisbn10() { var candidats = BnfSruParser.Parser( Fixture.Lire("bnf-2080704095.xml"), "2080704095", null); var c = Assert.Single(candidats); // La BnF écrit « Le horla » : le nettoyage ne doit pas « corriger » la casse de la source. Assert.Equal("Le horla", c.Titre); Assert.Equal("Guy de Maupassant", c.Auteur); Assert.Equal("2080704095", c.IsbnInterroge); Assert.DoesNotContain("(", c.Editeur ?? string.Empty); } /// /// Notice minimale bâtie à la main, au format de celles de la BnF. /// /// /// Les cas ci-dessous n'ont pas de réponse réelle enregistrée : ils portent sur la manière /// dont le parseur combine ses règles, pas sur la lecture du XML — que les fixtures /// réelles couvrent déjà. /// private static string Notice(string titre, params string[] auteurs) => $""" 1 {titre} {string.Concat(auteurs.Select(a => $"{a}"))} """; /// /// Cas réel de l'ISBN 9782749942636 : la BnF recolle le nom de l'auteur en fin de /// titre sans le séparateur ISBD. Il faut donc les auteurs nettoyés avant de pouvoir /// finir le titre — c'est l'ordre des opérations qui est vérifié ici. /// [Fact] public void Le_nom_de_lauteur_colle_en_fin_de_titre_est_retire() { var candidats = BnfSruParser.Parser( Notice( "Le plus grand défi de l'histoire de l'humanité : face à la catastrophe " + "écologique et sociale (Nouvelle éd. augmentée) Aurélien Barrau", "Barrau, Aurélien (1973-....). Auteur du texte"), "9782749942636", null); var c = Assert.Single(candidats); Assert.Equal( "Le plus grand défi de l'histoire de l'humanité : face à la catastrophe écologique " + "et sociale (Nouvelle éd. augmentée)", c.Titre); Assert.Equal(["Aurélien Barrau"], c.Auteurs); } /// Contre-exemple : un nom de personne ailleurs que tout à la fin reste en place. [Fact] public void Un_nom_de_personne_dans_le_titre_nest_pas_mutile() { var candidats = BnfSruParser.Parser( Notice("Lettre à Émile Zola et autres textes", "Maupassant, Guy de (1850-1893)"), "0000000000", null); Assert.Equal("Lettre à Émile Zola et autres textes", Assert.Single(candidats).Titre); } [Fact] public void Plusieurs_dc_creator_donnent_plusieurs_auteurs() { var candidats = BnfSruParser.Parser( Notice( "Le Horla et autres nouvelles", "Maupassant, Guy de (1850-1893). Auteur du texte", "Zola, Émile (1840-1902). Préfacier"), "0000000000", null); var c = Assert.Single(candidats); Assert.Equal(["Guy de Maupassant", "Émile Zola"], c.Auteurs); // La forme « une ligne » reste disponible pour un champ de saisie unique. Assert.Equal("Guy de Maupassant; Émile Zola", c.Auteur); } [Fact] public void Reponse_sans_notice_donne_une_liste_vide_et_pas_une_exception() { var candidats = BnfSruParser.Parser( Fixture.Lire("bnf-9780262033848.xml"), "9780262033848", null); Assert.Empty(candidats); } }