krz/domain-dig

an ios app for DNS & SSL analysis

clone: git clone https://gitbay.org/krz/domain-dig.git

v5.0.2: DomainDigTests/DomainReportBuilderTests.swift · raw

  1import XCTest
  2@testable import DomainDig
  3
  4/// Characterization tests for the snapshot  report projection. These lock the
  5/// field-mapping and derivation rules the export/diff contracts depend on.
  6final class DomainReportBuilderTests: XCTestCase {
  7    private let builder = DomainReportBuilder()
  8
  9    func testCoreIdentityFieldsPassThrough() {
 10        let report = builder.build(
 11            from: SnapshotFixture.snapshot(
 12                domain: "mapped.example",
 13                resolverURLString: "https://r.example/dns-query"
 14            ),
 15            deriveChangeSummary: false
 16        )
 17
 18        XCTAssertEqual(report.domain, "mapped.example")
 19        XCTAssertEqual(report.timestamp, SnapshotFixture.referenceDate)
 20        XCTAssertEqual(report.resolverURLString, "https://r.example/dns-query")
 21        XCTAssertFalse(report.metadata.schemaVersion.isEmpty)
 22    }
 23
 24    func testAvailabilityDefaultsToUnknownWhenAbsent() {
 25        let unknown = builder.build(from: SnapshotFixture.snapshot(availability: nil), deriveChangeSummary: false)
 26        XCTAssertEqual(unknown.availability, .unknown)
 27
 28        let registered = builder.build(from: SnapshotFixture.snapshot(availability: .registered), deriveChangeSummary: false)
 29        XCTAssertEqual(registered.availability, .registered)
 30    }
 31
 32    func testPrimaryIPComesFromFirstARecord() {
 33        let report = builder.build(
 34            from: SnapshotFixture.snapshot(
 35                dnsSections: [
 36                    SnapshotFixture.dnsSection(type: .A, values: ["198.51.100.7", "198.51.100.8"]),
 37                    SnapshotFixture.dnsSection(type: .AAAA, values: ["2001:db8::1"])
 38                ]
 39            ),
 40            deriveChangeSummary: false
 41        )
 42
 43        XCTAssertEqual(report.dns.primaryIP, "198.51.100.7")
 44        XCTAssertEqual(report.network.primaryIP, "198.51.100.7")
 45    }
 46
 47    func testPrimaryIPNilWithoutARecord() {
 48        let report = builder.build(
 49            from: SnapshotFixture.snapshot(
 50                dnsSections: [SnapshotFixture.dnsSection(type: .MX, values: ["mail.example.com"])]
 51            ),
 52            deriveChangeSummary: false
 53        )
 54        XCTAssertNil(report.dns.primaryIP)
 55    }
 56
 57    func testDNSSECDerivedFromSections() {
 58        let signed = builder.build(
 59            from: SnapshotFixture.snapshot(
 60                dnsSections: [SnapshotFixture.dnsSection(type: .A, values: ["203.0.113.1"], dnssecSigned: true)]
 61            ),
 62            deriveChangeSummary: false
 63        )
 64        XCTAssertEqual(signed.dns.dnssecSigned, true)
 65
 66        let unknown = builder.build(
 67            from: SnapshotFixture.snapshot(
 68                dnsSections: [SnapshotFixture.dnsSection(type: .A, values: ["203.0.113.1"])]
 69            ),
 70            deriveChangeSummary: false
 71        )
 72        XCTAssertNil(unknown.dns.dnssecSigned)
 73    }
 74
 75    func testTLSStatusReflectsCertificatePresence() {
 76        let valid = builder.build(
 77            from: SnapshotFixture.snapshot(sslInfo: SnapshotFixture.certificate()),
 78            deriveChangeSummary: false
 79        )
 80        XCTAssertEqual(valid.web.tlsStatus, "valid")
 81
 82        let missing = builder.build(from: SnapshotFixture.snapshot(sslInfo: nil), deriveChangeSummary: false)
 83        XCTAssertEqual(missing.web.tlsStatus, "unavailable")
 84    }
 85
 86    func testWebHeaderCountAndFinalURL() {
 87        let report = builder.build(
 88            from: SnapshotFixture.snapshot(
 89                httpHeaders: [
 90                    HTTPHeader(name: "Content-Type", value: "text/html"),
 91                    HTTPHeader(name: "Strict-Transport-Security", value: "max-age=63072000")
 92                ],
 93                httpStatusCode: 200
 94            ),
 95            deriveChangeSummary: false
 96        )
 97
 98        XCTAssertEqual(report.web.headerCount, 2)
 99        XCTAssertEqual(report.web.statusCode, 200)
100        XCTAssertNil(report.web.finalURL, "no redirect chain means no final URL")
101    }
102
103    func testPartialSnapshotAndValidationIssuesPropagate() {
104        let report = builder.build(
105            from: SnapshotFixture.snapshot(
106                isPartialSnapshot: true,
107                validationIssues: ["missing DNS", "stale WHOIS"]
108            ),
109            deriveChangeSummary: false
110        )
111
112        XCTAssertTrue(report.isPartialSnapshot)
113        XCTAssertEqual(report.validationIssues, ["missing DNS", "stale WHOIS"])
114        XCTAssertTrue(report.metadata.isPartialSnapshot)
115        XCTAssertEqual(report.metadata.validationIssues, ["missing DNS", "stale WHOIS"])
116    }
117
118    func testRecordSectionsArePreserved() {
119        let sections = [
120            SnapshotFixture.dnsSection(type: .A, values: ["203.0.113.1"]),
121            SnapshotFixture.dnsSection(type: .MX, values: ["mail.example.com"])
122        ]
123        let report = builder.build(
124            from: SnapshotFixture.snapshot(dnsSections: sections),
125            deriveChangeSummary: false
126        )
127
128        XCTAssertEqual(Set(report.dns.recordSections.map(\.recordType)), [.A, .MX])
129    }
130}