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