using MaBibli.Api.Data; using MaBibli.Api.Services.Catalogue; using MaBibli.Shared.Catalogue; using MaBibli.Shared.Dtos; using MaBibli.Shared.Entites; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; namespace MaBibli.Tests; /// /// CRUD du catalogue, sur une base SQLite en mémoire : même moteur qu'en production, /// aucun fichier, aucun réseau. /// public class ServiceCatalogueTests : IDisposable { private readonly SqliteConnection _connexion; private readonly MaBibliDbContext _db; private readonly ServiceCatalogue _service; public ServiceCatalogueTests() { // La connexion doit rester ouverte : SQLite détruit une base « :memory: » à sa fermeture. _connexion = new SqliteConnection("Data Source=:memory:"); _connexion.Open(); var options = new DbContextOptionsBuilder() .UseSqlite(_connexion) .Options; _db = new MaBibliDbContext(options); _db.Database.EnsureCreated(); _service = new ServiceCatalogue(_db); } private static EnregistrementLivre Saisie( string titre, string? auteur = null, string? isbn = null, Format format = Format.Physique, Statut statut = Statut.ALire) => new() { Titre = titre, Auteur = auteur, Isbn = isbn, Format = format, Statut = statut, }; [Fact] public async Task Creer_enregistre_le_livre_et_trace_lauteur_de_la_saisie() { var resultat = await _service.CreerAsync(Saisie("Germinal", "Émile Zola"), "mathieu"); Assert.Null(resultat.Erreur); var livre = resultat.Livre!; Assert.True(livre.Id > 0); Assert.Equal("Germinal", livre.Titre); Assert.Equal("mathieu", livre.AjoutePar); Assert.NotEqual(default, livre.DateAjout); } [Fact] public async Task Creer_normalise_lisbn() { var resultat = await _service.CreerAsync(Saisie("Germinal", isbn: "978-2-253-00422-6"), "mathieu"); Assert.Equal("9782253004226", resultat.Livre!.Isbn); } [Fact] public async Task Creer_refuse_un_titre_vide() { var resultat = await _service.CreerAsync(Saisie(" "), "mathieu"); Assert.Null(resultat.Livre); Assert.NotNull(resultat.Erreur); } [Fact] public async Task Creer_refuse_un_isbn_invalide_mais_accepte_labsence_disbn() { var invalide = await _service.CreerAsync(Saisie("Sans titre", isbn: "1234567890123"), "mathieu"); Assert.Null(invalide.Livre); Assert.NotNull(invalide.Erreur); // Certains livres n'ont pas d'ISBN : l'absence doit rester parfaitement légitime. var sansIsbn = await _service.CreerAsync(Saisie("Carnet de famille"), "mathieu"); Assert.Null(sansIsbn.Erreur); Assert.Null(sansIsbn.Livre!.Isbn); } [Fact] public async Task Le_catalogue_est_unique_physiques_et_numeriques_cohabitent() { await _service.CreerAsync(Saisie("Papier", format: Format.Physique), "mathieu"); await _service.CreerAsync(Saisie("Epub", format: Format.Numerique), "mathieu"); var tout = await _service.ListerAsync(new CritereLivres()); Assert.Equal(2, tout.Count); var numeriques = await _service.ListerAsync(new CritereLivres { Format = Format.Numerique }); Assert.Equal(["Epub"], numeriques.Select(l => l.Titre)); } [Fact] public async Task La_recherche_traverse_bien_SQLite() { await _service.CreerAsync(Saisie("Germinal", "Émile Zola"), "mathieu"); await _service.CreerAsync(Saisie("Le Horla", "Guy de Maupassant"), "mathieu"); var parAuteur = await _service.ListerAsync(new CritereLivres { Recherche = "maupassant" }); Assert.Equal(["Le Horla"], parAuteur.Select(l => l.Titre)); var parTitre = await _service.ListerAsync(new CritereLivres { Recherche = "GERMI" }); Assert.Equal(["Germinal"], parTitre.Select(l => l.Titre)); } /// /// Invariant central : la bibliothèque est commune. Des livres saisis par des comptes /// différents doivent tous ressortir, quelle que soit la personne qui consulte. /// [Fact] public async Task La_liste_renvoie_les_livres_de_tous_les_utilisateurs() { await _service.CreerAsync(Saisie("Livre de Mathieu"), "mathieu"); await _service.CreerAsync(Saisie("Livre de Camille"), "camille"); await _service.CreerAsync(Saisie("Livre anonyme"), null); var tout = await _service.ListerAsync(new CritereLivres()); Assert.Equal(3, tout.Count); Assert.Contains(tout, l => l.AjoutePar == "mathieu"); Assert.Contains(tout, l => l.AjoutePar == "camille"); Assert.Contains(tout, l => l.AjoutePar is null); } [Fact] public async Task Modifier_ne_reecrit_ni_AjoutePar_ni_DateAjout() { var cree = (await _service.CreerAsync(Saisie("Titre initial", "Auteur"), "camille")).Livre!; var modifie = await _service.ModifierAsync(cree.Id, new EnregistrementLivre { Titre = "Titre corrigé", Auteur = "Auteur corrigé", Format = Format.Numerique, Statut = Statut.Lu, }); Assert.Null(modifie.Erreur); Assert.Equal("Titre corrigé", modifie.Livre!.Titre); Assert.Equal(Format.Numerique, modifie.Livre.Format); // La trace de la saisie d'origine survit à l'édition, y compris par quelqu'un d'autre. Assert.Equal("camille", modifie.Livre.AjoutePar); Assert.Equal(cree.DateAjout, modifie.Livre.DateAjout); } [Fact] public async Task Modifier_un_livre_inexistant_est_signale_comme_introuvable() { var resultat = await _service.ModifierAsync(4242, Saisie("Fantôme")); Assert.True(resultat.EstIntrouvable); } [Fact] public async Task Changer_le_statut_ne_touche_que_le_statut() { var cree = (await _service.CreerAsync(Saisie("Germinal", "Émile Zola"), "mathieu")).Livre!; var apres = await _service.ChangerStatutAsync(cree.Id, Statut.EnCours); Assert.NotNull(apres); Assert.Equal(Statut.EnCours, apres!.Statut); Assert.Equal(cree.Titre, apres.Titre); Assert.Equal(cree.Auteur, apres.Auteur); Assert.Equal(cree.AjoutePar, apres.AjoutePar); } [Fact] public async Task Changer_le_statut_dun_livre_inexistant_renvoie_null() => Assert.Null(await _service.ChangerStatutAsync(4242, Statut.Lu)); [Fact] public async Task Supprimer_retire_le_livre_du_catalogue() { var cree = (await _service.CreerAsync(Saisie("À jeter"), "mathieu")).Livre!; Assert.True(await _service.SupprimerAsync(cree.Id)); Assert.Null(await _service.ObtenirAsync(cree.Id)); Assert.Empty(await _service.ListerAsync(new CritereLivres())); // Seconde suppression : plus rien à supprimer. Assert.False(await _service.SupprimerAsync(cree.Id)); } [Fact] public async Task Obtenir_renvoie_la_fiche_complete() { var cree = (await _service.CreerAsync( Saisie("Le Horla", "Guy de Maupassant", "9782080704092"), "mathieu")).Livre!; var relu = await _service.ObtenirAsync(cree.Id); Assert.NotNull(relu); Assert.Equal("Le Horla", relu!.Titre); Assert.Equal("9782080704092", relu.Isbn); } public void Dispose() { _db.Dispose(); _connexion.Dispose(); GC.SuppressFinalize(this); } }