using MaBibli.Shared.Catalogue; using MaBibli.Shared.Entites; namespace MaBibli.Tests; /// /// Filtrage et recherche du catalogue. Purement en mémoire : ni base, ni réseau. /// public class FiltreLivresTests { private static readonly Livre[] Catalogue = [ new() { Id = 1, Titre = "Germinal", Auteur = "Émile Zola", Format = Format.Physique, Statut = Statut.Lu, AjoutePar = "mathieu", }, new() { Id = 2, Titre = "La Bête humaine", Auteur = "Émile Zola", Format = Format.Numerique, Statut = Statut.ALire, AjoutePar = "camille", }, new() { Id = 3, Titre = "Le Horla", Auteur = "Guy de Maupassant", Format = Format.Physique, Statut = Statut.EnCours, AjoutePar = "camille", }, new() { Id = 4, Titre = "Bel-Ami", Auteur = null, Format = Format.Numerique, Statut = Statut.Lu, AjoutePar = null, }, ]; private static List Filtrer(CritereLivres criteres) => FiltreLivres.Appliquer(Catalogue.AsQueryable(), criteres).ToList(); [Fact] public void Sans_critere_tout_le_catalogue_remonte() => Assert.Equal(4, Filtrer(new CritereLivres()).Count); [Fact] public void Le_tri_est_alphabetique_sur_le_titre() => Assert.Equal( ["Bel-Ami", "Germinal", "La Bête humaine", "Le Horla"], Filtrer(new CritereLivres()).Select(l => l.Titre)); [Theory] [InlineData(Format.Physique, 2)] [InlineData(Format.Numerique, 2)] public void Le_filtre_format_ne_garde_que_ce_format(Format format, int attendu) { var resultat = Filtrer(new CritereLivres { Format = format }); Assert.Equal(attendu, resultat.Count); Assert.All(resultat, l => Assert.Equal(format, l.Format)); } [Theory] [InlineData(Statut.ALire, 1)] [InlineData(Statut.EnCours, 1)] [InlineData(Statut.Lu, 2)] public void Le_filtre_statut_ne_garde_que_ce_statut(Statut statut, int attendu) { var resultat = Filtrer(new CritereLivres { Statut = statut }); Assert.Equal(attendu, resultat.Count); Assert.All(resultat, l => Assert.Equal(statut, l.Statut)); } [Fact] public void La_recherche_porte_sur_le_titre() => Assert.Equal(["Germinal"], Filtrer(new CritereLivres { Recherche = "germ" }).Select(l => l.Titre)); [Fact] public void La_recherche_porte_aussi_sur_lauteur() => Assert.Equal( ["Germinal", "La Bête humaine"], Filtrer(new CritereLivres { Recherche = "zola" }).Select(l => l.Titre)); [Theory] [InlineData("HORLA")] [InlineData("horla")] [InlineData(" Horla ")] public void La_recherche_ignore_la_casse_et_les_espaces_autour(string terme) => Assert.Single(Filtrer(new CritereLivres { Recherche = terme })); [Fact] public void Un_livre_sans_auteur_ne_fait_pas_echouer_la_recherche() { // Le livre 4 a Auteur = null : la clause sur l'auteur doit le traverser sans exploser. var resultat = Filtrer(new CritereLivres { Recherche = "bel" }); Assert.Equal(["Bel-Ami"], resultat.Select(l => l.Titre)); } [Fact] public void Les_criteres_se_combinent() { var resultat = Filtrer(new CritereLivres { Recherche = "zola", Format = Format.Physique, Statut = Statut.Lu, }); Assert.Equal(["Germinal"], resultat.Select(l => l.Titre)); } [Fact] public void Une_recherche_vide_equivaut_a_aucune_recherche() { Assert.Equal(4, Filtrer(new CritereLivres { Recherche = " " }).Count); Assert.Equal(4, Filtrer(new CritereLivres { Recherche = "" }).Count); } /// /// Invariant le plus important du projet. La bibliothèque est commune au foyer : /// une lecture ne doit JAMAIS être restreinte à ce qu'a saisi l'utilisateur courant. /// Ce test échouerait au moindre filtre ajouté sur AjoutePar. /// [Fact] public void La_lecture_ne_filtre_jamais_sur_AjoutePar() { var resultat = Filtrer(new CritereLivres()); // Les livres des trois provenances (deux comptes + un sans trace) sont tous là. Assert.Contains(resultat, l => l.AjoutePar == "mathieu"); Assert.Contains(resultat, l => l.AjoutePar == "camille"); Assert.Contains(resultat, l => l.AjoutePar is null); Assert.Equal(Catalogue.Length, resultat.Count); } /// /// Second verrou sur le même invariant, par le type : aucun critère de consultation ne doit /// permettre d'exprimer un cloisonnement par utilisateur. Si quelqu'un ajoute une propriété /// « AjoutePar » à , ce test le lui rappelle. /// [Fact] public void Les_criteres_nexposent_aucun_champ_dutilisateur() { var proprietes = typeof(CritereLivres) .GetProperties() .Select(p => p.Name) .ToArray(); Assert.DoesNotContain(proprietes, nom => nom.Contains("Ajoute", StringComparison.OrdinalIgnoreCase)); Assert.DoesNotContain(proprietes, nom => nom.Contains("Utilisateur", StringComparison.OrdinalIgnoreCase)); } }