|
| 1 | +# SPDX-License-Identifier: PMPL-1.0-or-later |
| 2 | +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk> |
| 3 | +# |
| 4 | +# dns_records_test.exs — Unit, property, and E2E tests for DNS Records module. |
| 5 | + |
| 6 | +defmodule HINFOLOCFluctuator.DNSRecordsTest do |
| 7 | + use ExUnit.Case, async: true |
| 8 | + |
| 9 | + alias HINFOLOCFluctuator.DNSRecords.HINFO |
| 10 | + alias HINFOLOCFluctuator.DNSRecords.LOC |
| 11 | + |
| 12 | + # ================================================================ |
| 13 | + # Unit tests: HINFO record creation |
| 14 | + # ================================================================ |
| 15 | + |
| 16 | + describe "HINFO.new/3" do |
| 17 | + test "creates HINFO record with required fields" do |
| 18 | + record = HINFO.new("example.com", "x86_64", "Linux") |
| 19 | + assert record.domain == "example.com" |
| 20 | + assert record.cpu == "x86_64" |
| 21 | + assert record.os == "Linux" |
| 22 | + end |
| 23 | + |
| 24 | + test "HINFO default TTL is 300" do |
| 25 | + record = HINFO.new("test.com", "arm64", "FreeBSD") |
| 26 | + assert record.ttl == 300 |
| 27 | + end |
| 28 | + |
| 29 | + test "HINFO default class is :IN" do |
| 30 | + record = HINFO.new("test.com", "riscv64", "OpenBSD") |
| 31 | + assert record.class == :IN |
| 32 | + end |
| 33 | + |
| 34 | + test "HINFO custom TTL is respected" do |
| 35 | + record = HINFO.new("test.com", "x86_64", "Linux", ttl: 3600) |
| 36 | + assert record.ttl == 3600 |
| 37 | + end |
| 38 | + |
| 39 | + test "HINFO struct has correct keys" do |
| 40 | + record = HINFO.new("example.com", "x86_64", "Linux") |
| 41 | + assert Map.has_key?(record, :domain) |
| 42 | + assert Map.has_key?(record, :cpu) |
| 43 | + assert Map.has_key?(record, :os) |
| 44 | + assert Map.has_key?(record, :ttl) |
| 45 | + assert Map.has_key?(record, :class) |
| 46 | + end |
| 47 | + end |
| 48 | + |
| 49 | + # ================================================================ |
| 50 | + # Unit tests: LOC record creation |
| 51 | + # ================================================================ |
| 52 | + |
| 53 | + describe "LOC.new/4" do |
| 54 | + test "creates LOC record with coordinates" do |
| 55 | + record = LOC.new("example.com", 51.5, -0.1, 10.0) |
| 56 | + assert record.domain == "example.com" |
| 57 | + assert record.latitude == 51.5 |
| 58 | + assert record.longitude == -0.1 |
| 59 | + assert record.altitude == 10.0 |
| 60 | + end |
| 61 | + |
| 62 | + test "LOC default TTL is 300" do |
| 63 | + record = LOC.new("test.com", 0.0, 0.0, 0.0) |
| 64 | + assert record.ttl == 300 |
| 65 | + end |
| 66 | + |
| 67 | + test "LOC default class is :IN" do |
| 68 | + record = LOC.new("test.com", 0.0, 0.0, 0.0) |
| 69 | + assert record.class == :IN |
| 70 | + end |
| 71 | + |
| 72 | + test "LOC struct has required keys" do |
| 73 | + record = LOC.new("test.com", 1.0, 2.0, 3.0) |
| 74 | + assert Map.has_key?(record, :latitude) |
| 75 | + assert Map.has_key?(record, :longitude) |
| 76 | + assert Map.has_key?(record, :altitude) |
| 77 | + end |
| 78 | + end |
| 79 | + |
| 80 | + # ================================================================ |
| 81 | + # Property tests: Invariants over varied inputs |
| 82 | + # ================================================================ |
| 83 | + |
| 84 | + describe "HINFO property invariants" do |
| 85 | + test "domain is always preserved exactly" do |
| 86 | + domains = ["a.com", "test.example.org", "x.y.z.co.uk", "single", "with-hyphen.net"] |
| 87 | + for domain <- domains do |
| 88 | + record = HINFO.new(domain, "cpu", "os") |
| 89 | + assert record.domain == domain |
| 90 | + end |
| 91 | + end |
| 92 | + |
| 93 | + test "CPU string is always preserved exactly" do |
| 94 | + cpus = ["x86_64", "arm64", "riscv64", "ppc64", "mips", "s390x"] |
| 95 | + for cpu <- cpus do |
| 96 | + record = HINFO.new("test.com", cpu, "Linux") |
| 97 | + assert record.cpu == cpu |
| 98 | + end |
| 99 | + end |
| 100 | + |
| 101 | + test "TTL is always the value provided" do |
| 102 | + ttls = [60, 300, 900, 3600, 86400] |
| 103 | + for ttl <- ttls do |
| 104 | + record = HINFO.new("test.com", "x86", "Linux", ttl: ttl) |
| 105 | + assert record.ttl == ttl |
| 106 | + end |
| 107 | + end |
| 108 | + end |
| 109 | + |
| 110 | + describe "LOC property invariants" do |
| 111 | + test "coordinates are preserved exactly" do |
| 112 | + coords = [{0.0, 0.0, 0.0}, {90.0, 180.0, 100.0}, {-90.0, -180.0, -100.0}] |
| 113 | + for {lat, lon, alt} <- coords do |
| 114 | + record = LOC.new("test.com", lat, lon, alt) |
| 115 | + assert record.latitude == lat |
| 116 | + assert record.longitude == lon |
| 117 | + assert record.altitude == alt |
| 118 | + end |
| 119 | + end |
| 120 | + end |
| 121 | + |
| 122 | + # ================================================================ |
| 123 | + # E2E tests: Full record lifecycle |
| 124 | + # ================================================================ |
| 125 | + |
| 126 | + describe "E2E: HINFO zone file format" do |
| 127 | + test "HINFO serializes to zone file format" do |
| 128 | + record = HINFO.new("example.com", "x86_64", "Linux") |
| 129 | + zone = HINFO.to_zone_format(record) |
| 130 | + assert is_binary(zone) |
| 131 | + assert String.contains?(zone, "HINFO") |
| 132 | + end |
| 133 | + |
| 134 | + test "HINFO zone file contains domain" do |
| 135 | + record = HINFO.new("my.domain.com", "arm64", "FreeBSD") |
| 136 | + zone = HINFO.to_zone_format(record) |
| 137 | + assert String.contains?(zone, "my.domain.com") |
| 138 | + end |
| 139 | + |
| 140 | + test "HINFO zone file contains CPU and OS" do |
| 141 | + record = HINFO.new("test.com", "riscv64", "NixOS") |
| 142 | + zone = HINFO.to_zone_format(record) |
| 143 | + assert String.contains?(zone, "riscv64") |
| 144 | + assert String.contains?(zone, "NixOS") |
| 145 | + end |
| 146 | + end |
| 147 | +end |
0 commit comments