using MaBibli.Api.Data; using MaBibli.Api.Services.Revues; using MaBibli.Shared.Dtos; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; namespace MaBibli.Tests; /// /// Revues et numéros, sur une base SQLite en mémoire : l'unicité d'un ISSN passe par un /// index partiel, qui n'existe qu'en base. /// /// /// L'invariant central : une fiche par revue, les numéros à l'intérieur. C'est ce qui /// évite douze fiches identiques pour douze numéros d'un même magazine. /// public class ServiceRevuesTests : IDisposable { private readonly SqliteConnection _connexion; private readonly MaBibliDbContext _db; private readonly ServiceRevues _revues; private const string Mathieu = "mathieu"; public ServiceRevuesTests() { _connexion = new SqliteConnection("Data Source=:memory:"); _connexion.Open(); var options = new DbContextOptionsBuilder() .UseSqlite(_connexion) .Options; _db = new MaBibliDbContext(options); _db.Database.EnsureCreated(); _revues = new ServiceRevues(_db); } private async Task RevueAsync(string titre = "Médor", string? issn = "2466-6718") { var resultat = await _revues.CreerOuRetrouverAsync( new EnregistrementRevue { Titre = titre, Issn = issn }, Mathieu); Assert.Null(resultat.Erreur); return resultat.Revue!; } [Fact] public async Task Rescanner_la_meme_revue_ne_cree_pas_une_seconde_fiche() { var premiere = await RevueAsync(); // Le second numéro du même magazine porte le même ISSN : c'est le cas NORMAL du flux // « 977 », et il ne doit surtout pas produire une fiche de plus. var seconde = await RevueAsync("Médor (Bruxelles)"); Assert.Equal(premiere.Id, seconde.Id); Assert.Single(await _revues.ListerAsync()); } [Fact] public async Task Une_revue_saisie_a_la_main_apprend_son_issn_au_premier_scan() { var aLaMain = await RevueAsync("Médor", issn: null); var scannee = await RevueAsync("Médor"); Assert.Equal(aLaMain.Id, scannee.Id); Assert.Equal("2466-6718", scannee.Issn); } [Fact] public async Task Les_numeros_vivent_dans_la_revue_et_ne_font_pas_de_fiches() { var revue = await RevueAsync(); await _revues.AjouterNumeroAsync(revue.Id, new AjoutNumeroRevue { Numero = "43", DateParution = new DateTime(2024, 6, 1, 0, 0, 0, DateTimeKind.Utc), }); var apres = (await _revues.AjouterNumeroAsync(revue.Id, new AjoutNumeroRevue { Numero = "44", DateParution = new DateTime(2024, 9, 1, 0, 0, 0, DateTimeKind.Utc), })).Revue!; Assert.Single(await _revues.ListerAsync()); // Du plus récent au plus ancien : sur un magazine, c'est le dernier reçu qu'on cherche. Assert.Equal(["44", "43"], apres.Numeros.Select(n => n.Numero)); } [Fact] public async Task Un_numero_sans_numero_est_refuse() { var revue = await RevueAsync(); var resultat = await _revues.AjouterNumeroAsync(revue.Id, new AjoutNumeroRevue { Numero = " " }); Assert.NotNull(resultat.Erreur); } [Fact] public async Task Le_meme_numero_ne_sajoute_pas_deux_fois() { var revue = await RevueAsync(); await _revues.AjouterNumeroAsync(revue.Id, new AjoutNumeroRevue { Numero = "43" }); var doublon = await _revues.AjouterNumeroAsync(revue.Id, new AjoutNumeroRevue { Numero = "43" }); Assert.NotNull(doublon.Erreur); } [Fact] public async Task Un_numero_a_paraitre_est_refuse() { var revue = await RevueAsync(); var resultat = await _revues.AjouterNumeroAsync(revue.Id, new AjoutNumeroRevue { Numero = "99", DateParution = DateTime.UtcNow.AddMonths(2), }); Assert.NotNull(resultat.Erreur); } [Fact] public async Task Les_numeros_sans_date_ferment_la_liste() { var revue = await RevueAsync(); await _revues.AjouterNumeroAsync(revue.Id, new AjoutNumeroRevue { Numero = "hors-série 1" }); var apres = (await _revues.AjouterNumeroAsync(revue.Id, new AjoutNumeroRevue { Numero = "43", DateParution = new DateTime(2024, 6, 1, 0, 0, 0, DateTimeKind.Utc), })).Revue!; // Une date inconnue ne doit pas faire passer un numéro pour le plus ancien. Assert.Equal(["43", "hors-série 1"], apres.Numeros.Select(n => n.Numero)); } [Fact] public async Task Supprimer_la_revue_emporte_ses_numeros() { var revue = await RevueAsync(); await _revues.AjouterNumeroAsync(revue.Id, new AjoutNumeroRevue { Numero = "43" }); Assert.True(await _revues.SupprimerAsync(revue.Id)); // Contrairement aux livres d'une série, un numéro n'existe que par sa revue. Assert.Empty(await _db.NumerosRevue.ToListAsync()); } [Fact] public async Task Deux_revues_ne_partagent_ni_titre_ni_issn() { await RevueAsync(); var autre = await RevueAsync("Socialter", issn: "2270-4426"); var titrePris = await _revues.ModifierAsync( autre.Id, new EnregistrementRevue { Titre = "médor" }); var issnPris = await _revues.ModifierAsync( autre.Id, new EnregistrementRevue { Titre = "Socialter", Issn = "2466-6718" }); Assert.NotNull(titrePris.Erreur); Assert.NotNull(issnPris.Erreur); } public void Dispose() { _db.Dispose(); _connexion.Dispose(); GC.SuppressFinalize(this); } }