diff options
Diffstat (limited to 'internal/scope/scope_test.go')
| -rw-r--r-- | internal/scope/scope_test.go | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/internal/scope/scope_test.go b/internal/scope/scope_test.go new file mode 100644 index 0000000..fee5d44 --- /dev/null +++ b/internal/scope/scope_test.go @@ -0,0 +1,96 @@ +package scope + +import "testing" + +func TestInScopeEmptyRulesMeansEverything(t *testing.T) { + if !InScope(nil, "example.com") { + t.Error("empty rule set should mean everything is in scope") + } + if !InScope([]Rule{}, "anything.at.all") { + t.Error("empty rule set should mean everything is in scope") + } +} + +func TestInScopeAllDisabledMeansEverything(t *testing.T) { + rules := []Rule{{Enabled: false, Pattern: "example.com"}} + if !InScope(rules, "unrelated.org") { + t.Error("no enabled rules should mean everything is in scope") + } +} + +func TestInScopeSubstringMatch(t *testing.T) { + rules := []Rule{{Enabled: true, Pattern: "example.com"}} + tests := []struct { + host string + want bool + }{ + {"example.com", true}, + {"www.example.com", true}, + {"api.example.com", true}, + {"example.com.evil.org", true}, // substring containment, deliberately simple + {"other.org", false}, + } + for _, tt := range tests { + if got := InScope(rules, tt.host); got != tt.want { + t.Errorf("InScope(%q) = %v, want %v", tt.host, got, tt.want) + } + } +} + +func TestInScopeCaseInsensitive(t *testing.T) { + rules := []Rule{{Enabled: true, Pattern: "Example.COM"}} + if !InScope(rules, "www.EXAMPLE.com") { + t.Error("substring match should be case-insensitive") + } +} + +func TestInScopeRegex(t *testing.T) { + rules := []Rule{{Enabled: true, Pattern: `(^|\.)example\.com$`, IsRegex: true}} + tests := []struct { + host string + want bool + }{ + {"example.com", true}, + {"api.example.com", true}, + {"notexample.com", false}, + {"example.com.evil.org", false}, + } + for _, tt := range tests { + if got := InScope(rules, tt.host); got != tt.want { + t.Errorf("InScope(%q) = %v, want %v", tt.host, got, tt.want) + } + } +} + +func TestInScopeInvalidRegexNeverMatches(t *testing.T) { + rules := []Rule{{Enabled: true, Pattern: "(unclosed", IsRegex: true}} + if InScope(rules, "example.com") { + t.Error("an invalid regex rule should never match, not panic or false-positive") + } +} + +func TestInScopeMultipleRulesAnyMatch(t *testing.T) { + rules := []Rule{ + {Enabled: true, Pattern: "example.com"}, + {Enabled: true, Pattern: "other.org"}, + } + if !InScope(rules, "other.org") { + t.Error("should match the second rule") + } + if InScope(rules, "unrelated.net") { + t.Error("should not match either rule") + } +} + +func TestInScopeDisabledRuleIgnored(t *testing.T) { + rules := []Rule{ + {Enabled: false, Pattern: "example.com"}, + {Enabled: true, Pattern: "other.org"}, + } + if InScope(rules, "example.com") { + t.Error("a disabled rule should not match") + } + if !InScope(rules, "other.org") { + t.Error("the enabled rule should still match") + } +} |