using System.Text.Json; using App.Core.Interfaces.Licensing; using App.Core.Services.Licensing; namespace App.Core.Tests.Licensing; /// /// Couvre uniquement le flux "essai" de LicenseService (pas de licence installée) : c'est la /// partie testable sans dépendre de la vraie clé publique Ed25519, qui n'est pas encore générée /// (voir Ed25519PublicKeyProvider). Le flux "licence installée" (ActivateLicense / licence déjà /// présente) sera couvert une fois LicenseGenerator exécuté pour de vrai et la clé embarquée. /// public class LicenseServiceTests { private sealed class FakeHardwareIdProvider(HardwareId hardwareId) : IHardwareIdProvider { public HardwareId GetCurrent() => hardwareId; } private sealed class FakeTrialStateStore : ITrialStateStore { public TrialState? Stored { get; private set; } public TrialState? Load() => Stored; public void Save(TrialState state) => Stored = state; } private sealed class FakeLicenseFileRepository : ILicenseFileRepository { public LicenseFile? Installed { get; set; } public LicenseFile? LoadInstalled() => Installed; public void Install(LicenseFile license) => Installed = license; } private sealed class CorruptedLicenseFileRepository : ILicenseFileRepository { public LicenseFile? LoadInstalled() => throw new JsonException("fichier .lic corrompu (test)"); public void Install(LicenseFile license) => throw new NotSupportedException(); } private static readonly HardwareId TestHardware = new("MB-TEST", "DISK-TEST"); private static LicenseService CreateService(FakeTrialStateStore trialStore, ILicenseFileRepository? licenseRepo = null) => new(new FakeHardwareIdProvider(TestHardware), trialStore, licenseRepo ?? new FakeLicenseFileRepository()); [Fact] public void CheckLicenseStatus_FirstLaunch_CreatesTrialAndReturnsFullDuration() { var trialStore = new FakeTrialStateStore(); var service = CreateService(trialStore); var now = new DateTime(2026, 1, 1, 9, 0, 0, DateTimeKind.Utc); var result = service.CheckLicenseStatus(now); Assert.Equal(LicenseStatus.TrialActive, result.Status); Assert.Equal(TrialState.TrialDurationDays, result.TrialDaysRemaining); Assert.NotNull(trialStore.Stored); Assert.Equal(now, trialStore.Stored!.InstallDateUtc); Assert.Equal(TestHardware.ComputeHash(), trialStore.Stored.HardwareIdHash); } [Fact] public void CheckLicenseStatus_SubsequentLaunch_ReturnsRemainingDaysAndUpdatesLastRun() { var trialStore = new FakeTrialStateStore(); var service = CreateService(trialStore); var installDate = new DateTime(2026, 1, 1, 9, 0, 0, DateTimeKind.Utc); service.CheckLicenseStatus(installDate); var result = service.CheckLicenseStatus(installDate.AddDays(10)); Assert.Equal(LicenseStatus.TrialActive, result.Status); Assert.Equal(20, result.TrialDaysRemaining); Assert.Equal(installDate.AddDays(10), trialStore.Stored!.LastRunTimestampUtc); Assert.Equal(installDate, trialStore.Stored.InstallDateUtc); // date d'installation jamais modifiée } [Fact] public void CheckLicenseStatus_After30Days_ReturnsTrialExpired() { var trialStore = new FakeTrialStateStore(); var service = CreateService(trialStore); var installDate = new DateTime(2026, 1, 1, 9, 0, 0, DateTimeKind.Utc); service.CheckLicenseStatus(installDate); var result = service.CheckLicenseStatus(installDate.AddDays(31)); Assert.Equal(LicenseStatus.TrialExpired, result.Status); Assert.Equal(0, result.TrialDaysRemaining); } [Fact] public void CheckLicenseStatus_ClockRolledBack_ReturnsClockTamperDetected() { var trialStore = new FakeTrialStateStore(); var service = CreateService(trialStore); var installDate = new DateTime(2026, 1, 15, 9, 0, 0, DateTimeKind.Utc); service.CheckLicenseStatus(installDate); // L'utilisateur recule l'horloge système de 5 jours pour tenter de prolonger l'essai. var result = service.CheckLicenseStatus(installDate.AddDays(-5)); Assert.Equal(LicenseStatus.ClockTamperDetected, result.Status); } [Fact] public void GetCurrentHardwareId_DelegatesToHardwareIdProvider() { var service = CreateService(new FakeTrialStateStore()); Assert.Equal(TestHardware, service.GetCurrentHardwareId()); } [Fact] public void CheckLicenseStatus_CorruptedLicenseFile_ReturnsInvalidRatherThanFallingBackToTrial() { var trialStore = new FakeTrialStateStore(); var service = CreateService(trialStore, new CorruptedLicenseFileRepository()); var result = service.CheckLicenseStatus(DateTime.UtcNow); Assert.Equal(LicenseStatus.InvalidSignature, result.Status); // Ne doit surtout pas avoir créé un nouvel essai : corrompre le fichier ne doit jamais // redonner 30 jours gratuits. Assert.Null(trialStore.Stored); } }