using Omika.App.Local.Abstractions; using Omika.App.Local.Models; using Omika.App.Local.Services; using Omika.Core.Contracts.Common; using Omika.Core.Contracts.Configuration; using Omika.Core.Contracts.Mobile.License; namespace Omika.Tests.Mobile.Local; /// /// Tests du service local de référentiel ParametreMetier (TypeTemps). /// Vérifie que /// retourne uniquement les types de temps depuis le bootstrap local, sans /// aucun appel API, avec la clé métier canonique et le libellé métier. /// public sealed class ParametreMetierLocalServiceTests { [Fact] public async Task GetTypeTempsAsync_RetourneUniquementLesTypeTemps_Batik() { // Arrange : référentiel Batik (groupe TypeTemps porté par PA_Code = "18"). var bootstrap = new LocalBootstrapState { ParametresMetier = [ new ParametreMetierDto { Id = "TRAVAIL", Code = "18", Libelle = "Travail", Ordre = 1 }, new ParametreMetierDto { Id = "TRAJET", Code = "18", Libelle = "Trajet", Ordre = 2 }, new ParametreMetierDto { Id = "PAUSE", Code = "18", Libelle = "Pause", Ordre = 3 }, new ParametreMetierDto { Id = "AUTRE", Code = "99", Libelle = "Autre catégorie", Ordre = 4 } ] }; var service = CreateService(bootstrap); // Act IReadOnlyList result = await service.GetTypeTempsAsync(); // Assert Assert.Equal(3, result.Count); Assert.All(result, r => Assert.Equal("18", r.Code)); Assert.Equal("TRAVAIL", result[0].Key); Assert.Equal("Travail", result[0].Label); Assert.Equal("TRAJET", result[1].Key); Assert.Equal("Trajet", result[1].Label); Assert.Equal("PAUSE", result[2].Key); Assert.Equal("Pause", result[2].Label); } [Fact] public async Task GetTypeTempsAsync_RetourneUniquementLesTypeTemps_Omika() { // Arrange : référentiel Omika (groupe TypeTemps porté par PA_Categorie = "18"). var bootstrap = new LocalBootstrapState { ParametresMetier = [ new ParametreMetierDto { Id = "TT-01", Categorie = "18", Libelle = "Travail", Ordre = 1 }, new ParametreMetierDto { Id = "TT-02", Categorie = "18", Libelle = "Trajet", Ordre = 2 }, new ParametreMetierDto { Id = "AUTRE", Categorie = "99", Libelle = "Autre catégorie", Ordre = 3 } ] }; var service = CreateService(bootstrap); // Act IReadOnlyList result = await service.GetTypeTempsAsync(); // Assert Assert.Equal(2, result.Count); Assert.Equal("TT-01", result[0].Key); Assert.Equal("Travail", result[0].Label); Assert.Equal("TT-02", result[1].Key); Assert.Equal("Trajet", result[1].Label); } [Fact] public async Task GetTypeTempsAsync_KeyEstLaCleMetierCanonique() { // Arrange : la clé exposée doit être la clé métier (Id), jamais un PK HFSQL. var bootstrap = new LocalBootstrapState { ParametresMetier = [ new ParametreMetierDto { Id = "CLE_METIER_TT", Code = "18", Libelle = "Travail", Ordre = 1 } ] }; var service = CreateService(bootstrap); // Act IReadOnlyList result = await service.GetTypeTempsAsync(); // Assert ReferenceValueDto option = Assert.Single(result); Assert.Equal("CLE_METIER_TT", option.Key); Assert.Equal("CLE_METIER_TT", option.Key); } [Fact] public async Task GetTypeTempsAsync_LabelVientDuLibelleMetier() { // Arrange : le libellé exposé doit être le libellé métier, pas le code technique. var bootstrap = new LocalBootstrapState { ParametresMetier = [ new ParametreMetierDto { Id = "TT-01", Code = "18", Libelle = "Déplacement client", Ordre = 1 } ] }; var service = CreateService(bootstrap); // Act IReadOnlyList result = await service.GetTypeTempsAsync(); // Assert ReferenceValueDto option = Assert.Single(result); Assert.Equal("Déplacement client", option.Label); Assert.NotEqual("TT-01", option.Label); } [Fact] public async Task GetTypeTempsAsync_SansBootstrap_RetourneListeVide() { // Arrange : aucune session / bootstrap local. var service = new ParametreMetierLocalService(new FakeSessionService(null)); // Act IReadOnlyList result = await service.GetTypeTempsAsync(); // Assert Assert.Empty(result); } [Fact] public async Task GetTypeTempsAsync_ConserveLOrdreMetier() { // Arrange : l'ordre du bootstrap (PA_Ordre) est conservé, pas de tri par libellé. var bootstrap = new LocalBootstrapState { ParametresMetier = [ new ParametreMetierDto { Id = "Z", Code = "18", Libelle = "Zulu", Ordre = 1 }, new ParametreMetierDto { Id = "A", Code = "18", Libelle = "Alpha", Ordre = 2 } ] }; var service = CreateService(bootstrap); // Act IReadOnlyList result = await service.GetTypeTempsAsync(); // Assert : l'ordre métier (Z avant A) est conservé, pas de tri alphabétique. Assert.Equal("Z", result[0].Key); Assert.Equal("A", result[1].Key); } private static ParametreMetierLocalService CreateService(LocalBootstrapState bootstrap) => new(new FakeSessionService(bootstrap)); private sealed class FakeSessionService : IMobileSessionService { private readonly LocalBootstrapState? _bootstrap; public FakeSessionService(LocalBootstrapState? bootstrap) => _bootstrap = bootstrap; public Task HasValidSessionAsync(CancellationToken cancellationToken = default) => Task.FromResult(true); public Task HasExpiredSessionAsync(CancellationToken cancellationToken = default) => Task.FromResult(false); public Task ActivateAsync(string codeClient, string numeroLicence, CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task ValidateAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); public Task GetBootstrapAsync(CancellationToken cancellationToken = default) => Task.FromResult(_bootstrap); public Task GetAccessTokenAsync(CancellationToken cancellationToken = default) => Task.FromResult(null); public Task ClearSessionAsync(CancellationToken cancellationToken = default) => Task.CompletedTask; public Task EnsureDevelopmentSessionAsync(CancellationToken cancellationToken = default) => Task.CompletedTask; } }