using System.IO; using System.Linq; using Omika.App.Local.Services; namespace Omika.Tests.Mobile.Local; /// /// Tests de l'export des journaux de diagnostic locaux vers un fichier .txt /// destiné à la pièce jointe d'un email de support. /// public class SupportLogExporterTests : IDisposable { private readonly string _directory; public SupportLogExporterTests() { _directory = Path.Combine( Path.GetTempPath(), "omika-support-logs-test-" + System.Guid.NewGuid().ToString("N")); Directory.CreateDirectory(_directory); } public void Dispose() { try { Directory.Delete(_directory, recursive: true); } catch { // Best-effort. } } [Fact] public void Export_AucunJournal_ProduitUnePieceJointeAvecNote() { var exporter = new SupportLogExporter(_directory); string? path = exporter.ExportLatestLogs(); // Assert : l'email de support ne part jamais sans pièce jointe ; à défaut // de journaux, le .txt contient une note explicite. Assert.NotNull(path); Assert.True(File.Exists(path)); string content = File.ReadAllText(path!); Assert.Contains("Aucun journal de diagnostic", content); } [Fact] public void Export_DossierInexistant_CreeLeDossierEtProduitUnePieceJointe() { var exporter = new SupportLogExporter(Path.Combine(_directory, "inexistant")); string? path = exporter.ExportLatestLogs(); // Assert : le dossier est créé à la volée et une pièce jointe est produite. Assert.NotNull(path); Assert.True(File.Exists(path)); } [Fact] public void Export_JournauxPresent_EcritFichierTxtAvecContenu() { // Arrange : deux fichiers JSONL (ordre chronologique par nom). File.WriteAllText( Path.Combine(_directory, "omika-diagnostic-20260101-001.jsonl"), "{\"eventCode\":\"A\"}\n{\"eventCode\":\"B\"}\n"); File.WriteAllText( Path.Combine(_directory, "omika-diagnostic-20260101-002.jsonl"), "{\"eventCode\":\"C\"}\n"); var exporter = new SupportLogExporter(_directory); // Act string? path = exporter.ExportLatestLogs(); // Assert : fichier .txt produit dans le même répertoire, avec le contenu // des deux journaux et leurs en-têtes. Assert.NotNull(path); Assert.True(File.Exists(path)); string content = File.ReadAllText(path!); Assert.Contains("omika-diagnostic-20260101-001.jsonl", content); Assert.Contains("{\"eventCode\":\"A\"}", content); Assert.Contains("omika-diagnostic-20260101-002.jsonl", content); Assert.Contains("{\"eventCode\":\"C\"}", content); } [Fact] public void Export_CrashLogsPresent_SontJointes() { // Arrange : un journal de crash (écrit par ExceptionTelemetry) + un JSONL. File.WriteAllText( Path.Combine(_directory, "omika-diagnostic-20260101-001.jsonl"), "{\"eventCode\":\"A\"}\n"); File.WriteAllText( Path.Combine(_directory, "omika-crash-20260101.log"), "[2026-01-01 10:00:00.000] System.IO.IOException: disque plein\n"); var exporter = new SupportLogExporter(_directory); // Act string? path = exporter.ExportLatestLogs(); // Assert : le contenu du journal de crash est joint au .txt de support. Assert.NotNull(path); string content = File.ReadAllText(path!); Assert.Contains("omika-crash-20260101.log", content); Assert.Contains("System.IO.IOException: disque plein", content); } [Fact] public void Export_SecondExport_NeRelitPasLeFichierDeSortie() { // Arrange File.WriteAllText( Path.Combine(_directory, "omika-diagnostic-20260101-001.jsonl"), "{\"eventCode\":\"A\"}\n"); var exporter = new SupportLogExporter(_directory); // Act : deux exports successifs. string? path = exporter.ExportLatestLogs(); Assert.NotNull(path); // Assert : le .txt de sortie (omika-support-logs.txt) ne correspond pas au // motif *.jsonl, donc il n'est pas relu ni dupliqué dans le contenu. string content = File.ReadAllText(path!); Assert.DoesNotContain("omika-support-logs.txt", content); Assert.Equal(1, content.Split("--- omika-diagnostic-").Length - 1); } }