package checker import ( "encoding/json" "net" "testing" sdk "git.happydns.org/checker-sdk-go/checker" ) func TestLooksGeneric(t *testing.T) { v4 := net.ParseIP("203.0.113.42") v6 := net.ParseIP("2001:db8::1") cases := []struct { name string host string ip net.IP want bool }{ {"dotted ip embedded", "host-203.0.113.42.example.net", v4, true}, {"hyphenated ip embedded", "203-0-113-42.isp.example.net", v4, true}, {"dhcp pattern", "dhcp-10-20-30.isp.example.net", v4, true}, {"pool pattern", "pool.10.20.30.isp.example.net", v4, true}, {"dyn pattern", "dyn-203-0-113.isp.example.net", v4, true}, {"clean hostname", "mail.example.com", v4, false}, {"hostname with single digit suffix (not generic)", "host1.example.com", v4, false}, {"static-www should not match", "static-www.example.com", v4, false}, {"v6 short prefix only", "ipv6-2001-db8.example.net", v6, false}, {"v6 dash-grouped embedded", "host-2001-0db8-0000-0000-0000-0000-0000-0001.isp.example.net", v6, true}, {"v6 flat hex embedded", "h20010db8000000000000000000000001.isp.example.net", v6, true}, {"v6 dotted nibble embedded", "host.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.example.net", v6, true}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { if got := looksGeneric(tc.host, tc.ip); got != tc.want { t.Errorf("looksGeneric(%q, %s) = %v, want %v", tc.host, tc.ip, got, tc.want) } }) } } func TestIPEqual(t *testing.T) { v4 := net.ParseIP("1.2.3.4") if !ipEqual("1.2.3.4", v4) { t.Error("expected 1.2.3.4 to equal itself") } if !ipEqual("::ffff:1.2.3.4", v4) { t.Error("expected v4-mapped v6 to equal v4") } if ipEqual("1.2.3.5", v4) { t.Error("different addresses should not be equal") } if ipEqual("not-an-ip", v4) { t.Error("invalid input must not be equal") } } func TestResolvePTRInputs_FromDomainSubdomain(t *testing.T) { opts := sdk.CheckerOptions{ "domain_name": "3.2.1.in-addr.arpa", "subdomain": "4", } owner, target, ttl, err := resolvePTRInputs(opts) if err != nil { t.Fatalf("unexpected error: %v", err) } if owner != "4.3.2.1.in-addr.arpa." { t.Errorf("owner = %q, want 4.3.2.1.in-addr.arpa.", owner) } if target != "" { t.Errorf("target = %q, want empty", target) } if ttl != 0 { t.Errorf("ttl = %d, want 0", ttl) } } func TestResolvePTRInputs_ApexSubdomain(t *testing.T) { opts := sdk.CheckerOptions{ "domain_name": "4.3.2.1.in-addr.arpa.", "subdomain": "@", } owner, _, _, err := resolvePTRInputs(opts) if err != nil { t.Fatalf("unexpected error: %v", err) } if owner != "4.3.2.1.in-addr.arpa." { t.Errorf("owner = %q, want 4.3.2.1.in-addr.arpa.", owner) } } func TestResolvePTRInputs_ExpectedTarget(t *testing.T) { opts := sdk.CheckerOptions{ "domain_name": "3.2.1.in-addr.arpa", "subdomain": "4", "expected_target": "Mail.Example.COM", } _, target, _, err := resolvePTRInputs(opts) if err != nil { t.Fatalf("unexpected error: %v", err) } if target != "mail.example.com." { t.Errorf("target = %q, want mail.example.com.", target) } } func TestResolvePTRInputs_MissingDomain(t *testing.T) { if _, _, _, err := resolvePTRInputs(sdk.CheckerOptions{}); err == nil { t.Fatal("expected error for missing domain_name") } } func TestResolvePTRInputs_FromService(t *testing.T) { rec := map[string]any{ "Hdr": map[string]any{ "Name": "4", "Rrtype": 12, "Class": 1, "Ttl": 3600, }, "Ptr": "Mail.Example.COM.", } svc, _ := json.Marshal(map[string]any{"Record": rec}) envelope, _ := json.Marshal(map[string]any{ "_svctype": "svcs.PTR", "_domain": "3.2.1.in-addr.arpa", "Service": json.RawMessage(svc), }) opts := sdk.CheckerOptions{"service": json.RawMessage(envelope)} owner, target, ttl, err := resolvePTRInputs(opts) if err != nil { t.Fatalf("unexpected error: %v", err) } if owner != "4.3.2.1.in-addr.arpa." { t.Errorf("owner = %q, want 4.3.2.1.in-addr.arpa.", owner) } if target != "mail.example.com." { t.Errorf("target = %q, want mail.example.com.", target) } if ttl != 3600 { t.Errorf("ttl = %d, want 3600", ttl) } } func TestResolvePTRInputs_WrongServiceType(t *testing.T) { envelope, _ := json.Marshal(map[string]any{ "_svctype": "svcs.A", "_domain": "example.com", "Service": json.RawMessage(`{"Record":null}`), }) opts := sdk.CheckerOptions{"service": json.RawMessage(envelope)} if _, _, _, err := resolvePTRInputs(opts); err == nil { t.Fatal("expected error for non-PTR service type") } }