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));
}
}