krz/domain-dig
an ios app for DNS & SSL analysis
clone: git clone https://gitbay.org/krz/domain-dig.git
v5.0.3: DomainDigTests/Fixtures/SnapshotFixture.swift · raw
1import Foundation
2@testable import DomainDig
3
4/// Deterministic builders for the deep `LookupSnapshot` / `DomainReport` models
5/// so the core unit tests can construct inputs without wiring up every one of the
6/// ~75 snapshot fields at each call site.
7///
8/// `snapshot(...)` exposes only the fields the tests actually vary; everything
9/// else defaults to an empty/absent value. `report(...)` runs a snapshot through
10/// the real `DomainReportBuilder`, which is both the natural constructor for the
11/// otherwise-unconstructable `DomainReport` and, for the builder tests, the unit
12/// under test.
13enum SnapshotFixture {
14 /// Fixed instant so timestamp-derived output (diff ranges, export headers) is
15 /// stable across runs.
16 static let referenceDate = Date(timeIntervalSince1970: 1_700_000_000)
17
18 static let defaultResolverURL = "https://resolver.example/dns-query"
19
20 static func snapshot(
21 domain: String = "example.com",
22 timestamp: Date = referenceDate,
23 resolverURLString: String = defaultResolverURL,
24 resultSource: LookupResultSource = .live,
25 availability: DomainAvailabilityStatus? = nil,
26 ownership: DomainOwnership? = nil,
27 dnsSections: [DNSSection] = [],
28 ptrRecord: String? = nil,
29 sslInfo: SSLCertificateInfo? = nil,
30 httpHeaders: [HTTPHeader] = [],
31 httpStatusCode: Int? = nil,
32 httpSecurityGrade: String? = nil,
33 subdomains: [DiscoveredSubdomain] = [],
34 extendedSubdomains: [DiscoveredSubdomain] = [],
35 isPartialSnapshot: Bool = false,
36 validationIssues: [String] = [],
37 changeSummary: DomainChangeSummary? = nil
38 ) -> LookupSnapshot {
39 LookupSnapshot(
40 historyEntryID: nil,
41 domain: domain,
42 timestamp: timestamp,
43 trackedDomainID: nil,
44 note: nil,
45 appVersion: "test",
46 resolverDisplayName: "Test Resolver",
47 resolverURLString: resolverURLString,
48 dataSources: [],
49 provenanceBySection: [:],
50 availabilityConfidence: nil,
51 ownershipConfidence: nil,
52 subdomainConfidence: nil,
53 emailSecurityConfidence: nil,
54 geolocationConfidence: nil,
55 errorDetails: [:],
56 isPartialSnapshot: isPartialSnapshot,
57 validationIssues: validationIssues,
58 totalLookupDurationMs: nil,
59 snapshotIndex: nil,
60 previousSnapshotID: nil,
61 changeCount: 0,
62 severitySummary: nil,
63 dnsSections: dnsSections,
64 dnsError: nil,
65 availabilityResult: availability.map { DomainAvailabilityResult(domain: domain, status: $0) },
66 suggestions: [],
67 sslInfo: sslInfo,
68 sslError: nil,
69 hstsPreloaded: nil,
70 httpHeaders: httpHeaders,
71 httpSecurityGrade: httpSecurityGrade,
72 httpStatusCode: httpStatusCode,
73 httpResponseTimeMs: nil,
74 httpProtocol: nil,
75 http3Advertised: false,
76 httpHeadersError: nil,
77 reachabilityResults: [],
78 reachabilityError: nil,
79 ipGeolocation: nil,
80 ipGeolocationError: nil,
81 emailSecurity: nil,
82 emailSecurityError: nil,
83 ownership: ownership,
84 ownershipError: nil,
85 ownershipHistory: [],
86 ownershipHistoryError: nil,
87 inferredProvider: nil,
88 priorProviders: [],
89 domainClassification: nil,
90 ownershipTransitions: [],
91 hostingTransitions: [],
92 subdomainHistory: [],
93 riskSignals: [],
94 intelligenceTimeline: [],
95 ptrRecord: ptrRecord,
96 ptrError: nil,
97 redirectChain: [],
98 redirectChainError: nil,
99 subdomains: subdomains,
100 subdomainsError: nil,
101 extendedSubdomains: extendedSubdomains,
102 extendedSubdomainsError: nil,
103 dnsHistory: [],
104 dnsHistoryError: nil,
105 domainPricing: nil,
106 domainPricingError: nil,
107 reputation: nil,
108 reputationError: nil,
109 portScanResults: [],
110 portScanError: nil,
111 changeSummary: changeSummary,
112 resultSource: resultSource,
113 cachedSections: [],
114 statusMessage: nil
115 )
116 }
117
118 static func report(
119 domain: String = "example.com",
120 timestamp: Date = referenceDate,
121 resolverURLString: String = defaultResolverURL,
122 resultSource: LookupResultSource = .live,
123 availability: DomainAvailabilityStatus? = nil,
124 ownership: DomainOwnership? = nil,
125 dnsSections: [DNSSection] = [],
126 ptrRecord: String? = nil,
127 sslInfo: SSLCertificateInfo? = nil,
128 httpHeaders: [HTTPHeader] = [],
129 httpStatusCode: Int? = nil,
130 httpSecurityGrade: String? = nil,
131 subdomains: [DiscoveredSubdomain] = [],
132 extendedSubdomains: [DiscoveredSubdomain] = [],
133 isPartialSnapshot: Bool = false,
134 validationIssues: [String] = []
135 ) -> DomainReport {
136 DomainReportBuilder().build(
137 from: snapshot(
138 domain: domain,
139 timestamp: timestamp,
140 resolverURLString: resolverURLString,
141 resultSource: resultSource,
142 availability: availability,
143 ownership: ownership,
144 dnsSections: dnsSections,
145 ptrRecord: ptrRecord,
146 sslInfo: sslInfo,
147 httpHeaders: httpHeaders,
148 httpStatusCode: httpStatusCode,
149 httpSecurityGrade: httpSecurityGrade,
150 subdomains: subdomains,
151 extendedSubdomains: extendedSubdomains,
152 isPartialSnapshot: isPartialSnapshot,
153 validationIssues: validationIssues
154 ),
155 deriveChangeSummary: false
156 )
157 }
158
159 // MARK: - Nested model conveniences
160
161 static func dnsSection(
162 type: DNSRecordType,
163 values: [String],
164 ttl: Int = 300,
165 dnssecSigned: Bool? = nil,
166 wildcards: [String] = []
167 ) -> DNSSection {
168 DNSSection(
169 recordType: type,
170 records: values.map { DNSRecord(value: $0, ttl: ttl) },
171 wildcardRecords: wildcards.map { DNSRecord(value: $0, ttl: ttl) },
172 dnssecSigned: dnssecSigned
173 )
174 }
175
176 static func certificate(
177 commonName: String = "example.com",
178 issuer: String = "Test CA",
179 daysUntilExpiry: Int = 90
180 ) -> SSLCertificateInfo {
181 SSLCertificateInfo(
182 commonName: commonName,
183 subjectAltNames: [commonName],
184 issuer: issuer,
185 validFrom: referenceDate,
186 validUntil: referenceDate.addingTimeInterval(Double(daysUntilExpiry) * 86_400),
187 daysUntilExpiry: daysUntilExpiry,
188 chainDepth: 1
189 )
190 }
191}