using System; using System.IO; using System.Linq; using iText.Kernel.Pdf; using UtilitatPdf; internal static class Program { private static string root; private static int passed; private static void Main() { root = Path.Combine(Path.GetTempPath(), "utilitatpdf-tests-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { Run("single input is copied unchanged", () => { string input = Pdf("single.pdf", 101); string output = At("single-out.pdf"); Merge(output, input); Equal(File.ReadAllBytes(input), File.ReadAllBytes(output)); }); Run("multiple inputs preserve page order", () => { string a = Pdf("a.pdf", 101, 102); string b = Pdf("b.pdf", 201); string c = Pdf("c.pdf", 301, 302); byte[] original = File.ReadAllBytes(a); Merge(At("merged.pdf"), a, b, c); using (var result = new PdfDocument(new PdfReader(At("merged.pdf")))) { int[] widths = { 101, 102, 201, 301, 302 }; Check(result.GetNumberOfPages() == widths.Length); for (int i = 0; i < widths.Length; i++) Check(result.GetPage(i + 1).GetPageSize().GetWidth() == widths[i]); } Equal(original, File.ReadAllBytes(a)); }); Run("same input and output is rejected", () => { string a = Pdf("same.pdf", 100); byte[] original = File.ReadAllBytes(a); Fails(() => Merge(a, a)); Equal(original, File.ReadAllBytes(a)); }); Run("normalized source path is protected", () => { string a = Pdf("normalized.pdf", 100); byte[] original = File.ReadAllBytes(a); Fails(() => Merge(At("./normalized.pdf"), a, At("b.pdf"))); Equal(original, File.ReadAllBytes(a)); }); Run("existing output survives corrupt later input", () => { string output = Pdf("existing.pdf", 999); byte[] original = File.ReadAllBytes(output); File.WriteAllText(At("broken.pdf"), "not a PDF"); Fails(() => Merge(output, At("a.pdf"), At("broken.pdf"))); Equal(original, File.ReadAllBytes(output)); using (File.Open(At("a.pdf"), FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { } }); Run("failed merge creates no final output", () => { string output = At("failed.pdf"); Fails(() => Merge(output, At("a.pdf"), At("broken.pdf"))); Check(!File.Exists(output)); }); Run("missing source preserves existing output", () => { byte[] original = File.ReadAllBytes(At("existing.pdf")); Fails(() => Merge(At("existing.pdf"), At("missing.pdf"))); Equal(original, File.ReadAllBytes(At("existing.pdf"))); }); Run("successful merge replaces existing output", () => { Merge(At("existing.pdf"), At("a.pdf"), At("b.pdf")); using (var result = new PdfDocument(new PdfReader(At("existing.pdf")))) Check(result.GetNumberOfPages() == 3); }); Run("single input replaces existing output", () => { Merge(At("existing.pdf"), At("a.pdf")); Equal(File.ReadAllBytes(At("a.pdf")), File.ReadAllBytes(At("existing.pdf"))); }); Run("overwrite disabled preserves destination", () => { byte[] original = File.ReadAllBytes(At("existing.pdf")); var merge = new PdfMergeFiles(At("existing.pdf"), false); merge.AddFile(At("b.pdf")); Fails(merge.Generate); Equal(original, File.ReadAllBytes(At("existing.pdf"))); }); Run("empty input list preserves destination", () => { byte[] original = File.ReadAllBytes(At("existing.pdf")); Fails(new PdfMergeFiles(At("existing.pdf")).Generate); Equal(original, File.ReadAllBytes(At("existing.pdf"))); }); Run("publish failure preserves destination directory", () => { string output = At("directory.pdf"); Directory.CreateDirectory(output); File.WriteAllText(Path.Combine(output, "keep.txt"), "keep"); Fails(() => Merge(output, At("a.pdf"))); Check(File.ReadAllText(Path.Combine(output, "keep.txt")) == "keep"); }); Console.WriteLine($"{passed} regression cases passed."); } finally { Directory.Delete(root, true); } } private static string At(string name) => Path.Combine(root, name); private static string Pdf(string name, params int[] widths) { string path = At(name); using (var pdf = new PdfDocument(new PdfWriter(path))) foreach (int width in widths) pdf.AddNewPage(new iText.Kernel.Geom.PageSize(width, 400)); return path; } private static void Merge(string output, params string[] inputs) { var merger = new PdfMergeFiles(output); foreach (string input in inputs) merger.AddFile(input); merger.Generate(); } private static void Check(bool condition) { if (!condition) throw new Exception("Assertion failed."); } private static void Equal(byte[] expected, byte[] actual) => Check(expected.SequenceEqual(actual)); private static void Fails(Action action) { try { action(); } catch (Exception) { return; } throw new Exception("Expected the operation to fail."); } private static void Run(string name, Action action) { action(); Check(Directory.GetFiles(root, ".utilitatpdf-*.tmp").Length == 0); Console.WriteLine("PASS " + name); passed++; } }