Add comprehensive test suite

This commit is contained in:
2026-02-01 17:53:03 -05:00
parent c5279243c0
commit 63c3c10f2b
8 changed files with 1696 additions and 15 deletions

View File

@@ -0,0 +1,243 @@
package handlers
import (
"testing"
)
func TestCustomFilter_IsBlocked(t *testing.T) {
cf := NewCustomFilter()
tests := []struct {
name string
subdomain string
want bool
}{
{
name: "exact match - dws",
subdomain: "dws",
want: true,
},
{
name: "exact match - dubey",
subdomain: "dubey",
want: true,
},
{
name: "exact match - tanishq",
subdomain: "tanishq",
want: true,
},
{
name: "exact match - tdubey",
subdomain: "tdubey",
want: true,
},
{
name: "with hyphens - dubey-web",
subdomain: "dubey-web",
want: true,
},
{
name: "with hyphens - tanishq-dubey",
subdomain: "tanishq-dubey",
want: true,
},
{
name: "leet speak - dub3y",
subdomain: "dub3y",
want: true,
},
{
name: "leet speak - t4nishq",
subdomain: "t4nishq",
want: true,
},
{
name: "leet speak - dw5",
subdomain: "dw5",
want: true,
},
{
name: "combined term - dubeydns",
subdomain: "dubeydns",
want: true,
},
{
name: "combined term - dws-ddns",
subdomain: "dws-ddns",
want: true,
},
{
name: "safe subdomain - myhome",
subdomain: "myhome",
want: false,
},
{
name: "safe subdomain - office",
subdomain: "office",
want: false,
},
{
name: "safe subdomain - server01",
subdomain: "server01",
want: false,
},
{
name: "case insensitive - DWS",
subdomain: "DWS",
want: true,
},
{
name: "case insensitive - Tanishq",
subdomain: "Tanishq",
want: true,
},
{
name: "mixed case - DuBeY",
subdomain: "DuBeY",
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := cf.IsBlocked(tt.subdomain)
if got != tt.want {
t.Errorf("IsBlocked(%q) = %v, want %v", tt.subdomain, got, tt.want)
}
})
}
}
func TestCustomFilter_normalize(t *testing.T) {
cf := NewCustomFilter()
tests := []struct {
name string
text string
want string
}{
{
name: "lowercase conversion",
text: "DuBeY",
want: "dubey",
},
{
name: "remove hyphens",
text: "dubey-web",
want: "dubeyweb",
},
{
name: "remove underscores",
text: "dubey_web",
want: "dubeyweb",
},
{
name: "remove dots",
text: "dubey.web",
want: "dubeyweb",
},
{
name: "remove spaces",
text: "dubey web",
want: "dubeyweb",
},
{
name: "leet speak conversion",
text: "dub3y",
want: "dubey",
},
{
name: "leet speak conversion - t4nishq",
text: "t4nishq",
want: "tanishq",
},
{
name: "leet speak conversion - dw5",
text: "dw5",
want: "dws",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := cf.normalize(tt.text)
if got != tt.want {
t.Errorf("normalize(%q) = %q, want %q", tt.text, got, tt.want)
}
})
}
}
func TestIsValidSubdomain(t *testing.T) {
tests := []struct {
name string
subdomain string
want bool
}{
{
name: "valid - simple",
subdomain: "myhome",
want: true,
},
{
name: "valid - with hyphen",
subdomain: "my-home",
want: true,
},
{
name: "valid - with numbers",
subdomain: "home123",
want: true,
},
{
name: "valid - minimum length",
subdomain: "abc",
want: true,
},
{
name: "invalid - too short",
subdomain: "ab",
want: false,
},
{
name: "invalid - too long",
subdomain: "thisisaverylongsubdomainthatexceedsthesixtythreecharacterlimitforsubdomains",
want: false,
},
{
name: "invalid - starts with hyphen",
subdomain: "-myhome",
want: false,
},
{
name: "invalid - ends with hyphen",
subdomain: "myhome-",
want: false,
},
{
name: "invalid - contains special chars",
subdomain: "my_home",
want: false,
},
{
name: "invalid - contains dot",
subdomain: "my.home",
want: false,
},
{
name: "invalid - empty",
subdomain: "",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := isValidSubdomain(tt.subdomain)
if got != tt.want {
t.Errorf("isValidSubdomain(%q) = %v, want %v", tt.subdomain, got, tt.want)
}
})
}
}

View File

@@ -0,0 +1,45 @@
package handlers
import (
"regexp"
"strings"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
func init() {
// Register custom validators
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("alphanumdash", alphanumdashValidator)
}
}
// alphanumdashValidator validates that a string contains only alphanumeric characters and hyphens
var alphanumdashValidator validator.Func = func(fl validator.FieldLevel) bool {
value := fl.Field().String()
// Allow alphanumeric and hyphens only
match := regexp.MustCompile(`^[a-zA-Z0-9-]+$`).MatchString(value)
return match
}
// IsValidSubdomainFormat checks if a subdomain string is valid (exported for use in validation)
func IsValidSubdomainFormat(subdomain string) bool {
// Must be at least 3 characters
if len(subdomain) < 3 {
return false
}
// Must not exceed 63 characters
if len(subdomain) > 63 {
return false
}
// Must not start or end with hyphen
if strings.HasPrefix(subdomain, "-") || strings.HasSuffix(subdomain, "-") {
return false
}
// Must contain only alphanumeric and hyphens
return regexp.MustCompile(`^[a-zA-Z0-9-]+$`).MatchString(subdomain)
}