using Omika.App.Local.Abstractions; using Omika.App.Local.Models; using Omika.Core.Contracts.Mobile.Languages; namespace Omika.Tests.Mobile.Local; /// /// Double de test de : conserve /// la langue choisie en mémoire, sans SQLite ni identité de bootstrap. /// public sealed class FakeLangueSecondairePreferenceService : ILangueSecondairePreferenceService { private LangueSecondairePreference _preference = LangueSecondairePreference.ParDefaut; /// Langue effectivement enregistrée (dernier appel réussi). public LangueSecondairePreference Enregistree => _preference; /// Nombre d'appels à . public int Effacements { get; private set; } /// Configure la préférence retournée par . public void Set(string code, string libelle = "") => _preference = LangueSecondairePreference.Normaliser(code, libelle); /// public Task GetAsync(CancellationToken cancellationToken = default) => Task.FromResult(_preference); /// public Task SaveAsync(string code, string libelle, CancellationToken cancellationToken = default) { // Même règle que l'implémentation réelle : un code vide n'est jamais // enregistré (c'est EffacerAsync qui retire la langue). if (string.IsNullOrWhiteSpace(code)) { throw new ArgumentException("Le code de langue est requis.", nameof(code)); } _preference = LangueSecondairePreference.Normaliser(code, libelle); return Task.CompletedTask; } /// public Task EffacerAsync(CancellationToken cancellationToken = default) { Effacements++; _preference = LangueSecondairePreference.ParDefaut; return Task.CompletedTask; } } /// /// Double de test de : aucun réseau, aucune /// écriture disque. La liste et le résultat de téléchargement sont pilotés par /// le test. /// public sealed class FakeLanguagePackService : ILanguagePackService { /// Langues retournées par . public List Langues { get; } = []; /// URL de base retournée (paramètre SRV_LANGUES simulé). public string? UrlBase { get; set; } = "https://langues.exemple.test"; /// Erreur à lever par (cas hors ligne). public Exception? EchecListe { get; set; } /// Erreur à lever par . public Exception? EchecTelechargement { get; set; } /// Codes de langue effectivement téléchargés. public List Telecharges { get; } = []; /// Codes de langue effectivement supprimés. public List Supprimes { get; } = []; /// Vrai si le dernier appel de liste demandait le réseau. public bool DernierAppelReseau { get; private set; } /// public Task GetUrlBaseAsync(CancellationToken cancellationToken = default) => Task.FromResult(UrlBase); /// public Task> ListerLanguesAsync( bool forcerReseau = false, CancellationToken cancellationToken = default) { DernierAppelReseau = forcerReseau; if (EchecListe is not null) { throw EchecListe; } return Task.FromResult>(Langues); } /// public Task TelechargerAsync( string code, IProgress? progression = null, CancellationToken cancellationToken = default) { if (EchecTelechargement is not null) { throw EchecTelechargement; } Telecharges.Add(code); var fichier = new FichierModeleInstalle { Sens = LanguageModelDirections.VersFrancais, NomFichier = "encoder.onnx", TailleOctets = 1024, Sha256 = new string('a', 64) }; return Task.FromResult(new PackLangueInstalle { Code = code, Libelle = code, Version = "1.0.0", InstalleLeUtc = DateTimeOffset.UtcNow, Fichiers = [fichier] }); } /// public Task SupprimerAsync(string code, CancellationToken cancellationToken = default) { Supprimes.Add(code); return Task.CompletedTask; } /// Construit une langue disponible pour les tests. public static LangueDisponible Langue( string code, string libelle, bool installee = false, long taille = 120_000_000) => new() { Code = code, Libelle = libelle, Version = "1.0.0", TailleOctets = taille, NombreFichiers = 3, EstInstallee = installee, VersionInstallee = installee ? "1.0.0" : string.Empty }; } /// /// Double de test de : la disponibilité, l'état /// d'installation et la traduction sont pilotés par le test. Aucun modèle ONNX /// n'est nécessaire, et aucun texte n'est réellement traduit. /// public sealed class FakeTranslationService : ITranslationService { /// Vrai si un moteur d'inférence est simulé comme présent. public bool EstDisponible { get; set; } /// Vrai si les modèles sont simulés comme installés. public bool ModelesInstalles { get; set; } /// Texte retourné par la traduction. public string Resultat { get; set; } = "[traduit]"; /// Erreur à lever à la place d'une traduction. public Exception? Echec { get; set; } /// Sens demandés lors des traductions (dans l'ordre). public List SensDemandes { get; } = []; /// public Task EstInstalleeAsync( string codeLangue, SensTraduction sens, CancellationToken cancellationToken = default) => Task.FromResult(ModelesInstalles); /// public Task TraduireAsync( string? texte, string codeLangue, SensTraduction sens, CancellationToken cancellationToken = default) { SensDemandes.Add(sens); return Echec is not null ? Task.FromException(Echec) : Task.FromResult(Resultat); } }