package sources import ( "reflect" "sort" "testing" "time" ) func TestExtractSubdomains(t *testing.T) { target := "example.com" tests := []struct { name string text string want []string }{ { name: "empty text", text: "", want: nil, }, { name: "no matches", text: "some text with no domains", want: nil, }, { name: "apex only", text: "found example.com here", want: []string{"example.com"}, }, { name: "single subdomain", text: "api.example.com was found", want: []string{"api.example.com"}, }, { name: "multiple subdomains", text: "api.example.com and admin.example.com and dev.example.com", want: []string{"admin.example.com", "api.example.com", "dev.example.com"}, }, { name: "deduplication", text: "api.example.com api.example.com api.example.com", want: []string{"api.example.com"}, }, { name: "uppercase normalized", text: "API.EXAMPLE.COM and Api.Example.com", want: []string{"api.example.com"}, }, { name: "wildcard prefix stripped", text: "*.example.com is a wildcard", want: []string{"example.com"}, }, { name: "different domain filtered", text: "api.example.com and other.different.org and sub.example.com", want: []string{"api.example.com", "sub.example.com"}, }, { name: "partial match not allowed", text: "evilexample.com should not match", want: nil, }, { name: "json-wrapped", text: `{"name":"api.example.com","type":"A"}`, want: []string{"api.example.com"}, }, { name: "mixed with urls", text: `Visit https://api.example.com and https://docs.example.com/path`, want: []string{"api.example.com", "docs.example.com"}, }, { // Regex is greedy: only the longest leftmost match is returned, // not every suffix. This is the v1 baseline behavior. name: "deep subdomain longest match only", text: "a.b.c.example.com", want: []string{"a.b.c.example.com"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := ExtractSubdomains(tt.text, target) sort.Strings(got) sort.Strings(tt.want) if !reflect.DeepEqual(got, tt.want) { t.Errorf("ExtractSubdomains(%q)\n got: %v\n want: %v", tt.text, got, tt.want) } }) } } func TestGetClientForTimeout(t *testing.T) { tests := []struct { timeout time.Duration want string // identify by Timeout field }{ {5 * time.Second, "fast"}, {10 * time.Second, "fast"}, {15 * time.Second, "standard"}, {30 * time.Second, "standard"}, {60 * time.Second, "slow"}, {120 * time.Second, "slow"}, } for _, tt := range tests { c := GetClientForTimeout(tt.timeout) if c == nil { t.Fatalf("GetClientForTimeout(%v) returned nil", tt.timeout) } var gotClient string switch c { case FastClient: gotClient = "fast" case StandardClient: gotClient = "standard" case SlowClient: gotClient = "slow" default: gotClient = "unknown" } if gotClient != tt.want { t.Errorf("GetClientForTimeout(%v) = %s, want %s", tt.timeout, gotClient, tt.want) } } } func TestClientsInitialized(t *testing.T) { if FastClient == nil { t.Error("FastClient is nil") } if StandardClient == nil { t.Error("StandardClient is nil") } if SlowClient == nil { t.Error("SlowClient is nil") } if FastClient.Timeout != 10*time.Second { t.Errorf("FastClient.Timeout = %v, want 10s", FastClient.Timeout) } if StandardClient.Timeout != 15*time.Second { t.Errorf("StandardClient.Timeout = %v, want 15s", StandardClient.Timeout) } if SlowClient.Timeout != 120*time.Second { t.Errorf("SlowClient.Timeout = %v, want 120s", SlowClient.Timeout) } } func TestRegexCompiled(t *testing.T) { if SubdomainRegex == nil { t.Error("SubdomainRegex not compiled") } if EmailDomainRegex == nil { t.Error("EmailDomainRegex not compiled") } if URLDomainRegex == nil { t.Error("URLDomainRegex not compiled") } if JSONSubdomainRegex == nil { t.Error("JSONSubdomainRegex not compiled") } if WildcardPrefixRegex == nil { t.Error("WildcardPrefixRegex not compiled") } }