krz/domain-dig
an ios app for DNS & SSL analysis
clone: git clone https://gitbay.org/krz/domain-dig.git
main: DomainDigTests/DomainReportExporterTests.swift · raw
1import XCTest
2@testable import DomainDig
3
4/// Characterization tests for the export surface. These pin the format dispatch,
5/// the JSON round-trip (the canonical machine contract), and the structural
6/// invariants of the human-readable formats.
7final class DomainReportExporterTests: XCTestCase {
8
9 private let decoder: JSONDecoder = {
10 let decoder = JSONDecoder()
11 decoder.dateDecodingStrategy = .iso8601
12 return decoder
13 }()
14
15 func testEveryFormatProducesNonEmptyData() throws {
16 let report = SnapshotFixture.report(availability: .registered)
17 for format in DomainExportFormat.allCases {
18 let data = try DomainReportExporter.data(for: report, format: format)
19 XCTAssertFalse(data.isEmpty, "\(format.rawValue) export was empty")
20 }
21 }
22
23 func testJSONExportRoundTripsToReport() throws {
24 let report = SnapshotFixture.report(domain: "roundtrip.example", availability: .registered)
25
26 let data = try DomainReportExporter.data(for: report, format: .json)
27 let decoded = try decoder.decode(DomainReport.self, from: data)
28
29 XCTAssertEqual(decoded.domain, "roundtrip.example")
30 XCTAssertEqual(decoded.availability, .registered)
31 XCTAssertEqual(decoded.timestamp, report.timestamp)
32 }
33
34 func testBatchJSONExportRoundTripsToReportArray() throws {
35 let reports = [
36 SnapshotFixture.report(domain: "one.example"),
37 SnapshotFixture.report(domain: "two.example")
38 ]
39
40 let data = try DomainReportExporter.data(for: reports, format: .json, title: "Batch")
41 let decoded = try decoder.decode([DomainReport].self, from: data)
42
43 XCTAssertEqual(decoded.map(\.domain), ["one.example", "two.example"])
44 }
45
46 func testCSVHasHeaderAndOneRowPerReport() {
47 let reports = [
48 SnapshotFixture.report(domain: "alpha.example"),
49 SnapshotFixture.report(domain: "beta.example")
50 ]
51
52 let csv = DomainReportExporter.csv(for: reports)
53 let lines = csv.split(separator: "\n", omittingEmptySubsequences: false)
54
55 XCTAssertEqual(lines.count, 3, "one header line plus one row per report")
56 XCTAssertTrue(lines[0].contains("\"domain\""))
57 XCTAssertTrue(csv.contains("\"alpha.example\""))
58 XCTAssertTrue(csv.contains("\"beta.example\""))
59 }
60
61 func testMarkdownIsHeadedAndNamesTheDomain() {
62 let markdown = DomainReportExporter.markdown(for: SnapshotFixture.report(domain: "md.example"))
63
64 XCTAssertTrue(markdown.hasPrefix("# "), "markdown export should open with an H1")
65 XCTAssertTrue(markdown.contains("md.example"))
66 }
67
68 func testTextExportNamesTheDomain() {
69 let text = DomainReportExporter.text(for: SnapshotFixture.report(domain: "txt.example"))
70 XCTAssertTrue(text.contains("txt.example"))
71 }
72
73 func testBatchExportsCarryTitleAndEveryDomain() {
74 let reports = [
75 SnapshotFixture.report(domain: "first.example"),
76 SnapshotFixture.report(domain: "second.example")
77 ]
78
79 let markdown = DomainReportExporter.batchMarkdown(for: reports, title: "Portfolio Sweep")
80 XCTAssertTrue(markdown.contains("Portfolio Sweep"))
81 XCTAssertTrue(markdown.contains("first.example"))
82 XCTAssertTrue(markdown.contains("second.example"))
83
84 let text = DomainReportExporter.batchText(for: reports, title: "Portfolio Sweep")
85 XCTAssertTrue(text.contains("Portfolio Sweep"))
86 XCTAssertTrue(text.contains("first.example"))
87 XCTAssertTrue(text.contains("second.example"))
88 }
89
90 func testPDFExportHasPDFSignature() throws {
91 let data = try DomainReportExporter.data(for: SnapshotFixture.report(), format: .pdf)
92 XCTAssertTrue(data.starts(with: Array("%PDF".utf8)), "PDF export should begin with the %PDF signature")
93 }
94
95 func testTimelineTextNamesTheDomain() {
96 let reports = [
97 SnapshotFixture.report(domain: "timeline.example", timestamp: SnapshotFixture.referenceDate),
98 SnapshotFixture.report(
99 domain: "timeline.example",
100 timestamp: SnapshotFixture.referenceDate.addingTimeInterval(86_400)
101 )
102 ]
103
104 let text = DomainReportExporter.timelineText(for: reports, domain: "timeline.example", includeDiffSummary: false)
105 XCTAssertTrue(text.contains("timeline.example"))
106 }
107}