using Remiss.Core; using Remiss.Core.Abstractions; using Remiss.Core.Audit; using Remiss.Core.Models; using Remiss.Core.Pdf; using Remiss.Core.Security; using Xunit; namespace Remiss.Core.Tests; public sealed class WorkflowTests : IDisposable { private readonly string _dir = Path.Combine(Path.GetTempPath(), "remiss-wf-" + Guid.NewGuid().ToString("N")); public WorkflowTests() => Directory.CreateDirectory(_dir); public void Dispose() { try { Directory.Delete(_dir, recursive: true); } catch { /* ignore */ } } private sealed class FakePrinter : IPrinter { public string? PrintedFile { get; private set; } public string? Printer { get; private set; } public void Print(string pdfPath, string? printerName) { Assert.True(File.Exists(pdfPath)); // mergad fil finns när utskrift anropas PrintedFile = pdfPath; Printer = printerName; } } [Fact] public void Run_generatesMergesPrintsAndWritesDebugCopy() { var source = Path.Combine(_dir, "remiss.pdf"); CoverPageGenerator.Generate(source, new CoverInfo("Body", "hsa-body", DateTime.Now)); var debugDir = Path.Combine(_dir, "debug"); var cfg = new AppConfig { TargetPrinter = "TestPrinter", DebugOutputDir = debugDir }; var audit = new AuditLogger(Path.Combine(_dir, "audit.jsonl"), Path.Combine(_dir, "error.log")); var printer = new FakePrinter(); using (var temp = new SecureTempStore(Path.Combine(_dir, "tmp"))) { new RemissWorkflow(cfg, printer, audit).Run(source, new Mottagning("Hud SU", "hsa-1"), temp); } Assert.Equal("TestPrinter", printer.Printer); var debugCopies = Directory.GetFiles(debugDir, "remiss-debug-*.pdf"); Assert.Single(debugCopies); using var merged = PdfSharp.Pdf.IO.PdfReader.Open(debugCopies[0], PdfSharp.Pdf.IO.PdfDocumentOpenMode.Import); Assert.Equal(2, merged.PageCount); // försättsblad + "remiss" var auditText = File.ReadAllText(Path.Combine(_dir, "audit.jsonl")); Assert.Contains("remiss.sent", auditText); } [Fact] public void Run_withBlankTargetPrinter_passesBlankThroughAndAuditsAPrinter() { var source = Path.Combine(_dir, "remiss.pdf"); CoverPageGenerator.Generate(source, new CoverInfo("Body", "hsa-body", DateTime.Now)); var cfg = new AppConfig { TargetPrinter = "" }; var audit = new AuditLogger(Path.Combine(_dir, "audit.jsonl"), Path.Combine(_dir, "error.log")); var printer = new FakePrinter(); using (var temp = new SecureTempStore(Path.Combine(_dir, "tmp"))) { new RemissWorkflow(cfg, printer, audit).Run(source, new Mottagning("Hud SU", "hsa-1"), temp); } Assert.True(string.IsNullOrEmpty(printer.Printer)); // SumatraPDF väljer -print-to-default Assert.Contains("printer=", File.ReadAllText(Path.Combine(_dir, "audit.jsonl"))); } [Fact] public void Run_propagatesPrinterFailureAndAuditsTheStage() { var source = Path.Combine(_dir, "remiss.pdf"); CoverPageGenerator.Generate(source, new CoverInfo("Body", "hsa-body", DateTime.Now)); var cfg = new AppConfig { TargetPrinter = "X" }; var audit = new AuditLogger(Path.Combine(_dir, "audit.jsonl"), Path.Combine(_dir, "error.log")); var boom = new ThrowingPrinter(); using var temp = new SecureTempStore(Path.Combine(_dir, "tmp")); Assert.Throws(() => new RemissWorkflow(cfg, boom, audit).Run(source, new Mottagning("Hud SU", "hsa-1"), temp)); var auditText = File.ReadAllText(Path.Combine(_dir, "audit.jsonl")); Assert.Contains("remiss.failed", auditText); Assert.Contains("\"stage\":\"print\"", auditText); } private sealed class ThrowingPrinter : IPrinter { public void Print(string pdfPath, string? printerName) => throw new InvalidOperationException("no printer"); } }