86 lines
2.7 KiB
Go
86 lines
2.7 KiB
Go
package routing
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
// TestValidateEmptyErrorsSerializeAsArray guards the JSON shape API clients
|
|
// depend on: a valid profile's Validate() must marshal to `[]`, not `null`.
|
|
func TestValidateEmptyErrorsSerializeAsArray(t *testing.T) {
|
|
raw, err := json.Marshal(Default().Validate())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(raw) != "[]" {
|
|
t.Fatalf("want `[]`, got %s", raw)
|
|
}
|
|
}
|
|
|
|
func TestValidate(t *testing.T) {
|
|
ok := Default()
|
|
ok.Rules = []Rule{{Type: "domain_suffix", Value: "example.com", Action: "direct", Enabled: true}}
|
|
e := ok.Validate()
|
|
if len(e) != 0 {
|
|
t.Fatalf("valid profile got errors %v", e)
|
|
}
|
|
if e == nil {
|
|
t.Fatal("Validate must return a non-nil empty slice (serializes to [] not null)")
|
|
}
|
|
|
|
bad := Default()
|
|
bad.Mode = "weird" // 非法 mode
|
|
bad.Final = "reject" // final 只能 proxy|direct
|
|
bad.Rules = []Rule{
|
|
{Type: "ip_cidr", Value: "not-a-cidr", Action: "proxy", Enabled: true}, // CIDR 非法
|
|
{Type: "geosite", Value: "netflix", Action: "direct", Enabled: true}, // 不在白名单(仅 cn)
|
|
{Type: "bogus", Value: "x", Action: "direct", Enabled: true}, // type 非法
|
|
}
|
|
errs := bad.Validate()
|
|
if len(errs) < 5 {
|
|
t.Fatalf("want >=5 field errors, got %d: %v", len(errs), errs)
|
|
}
|
|
}
|
|
|
|
func TestValidateCountLimit(t *testing.T) {
|
|
p := Default()
|
|
for i := 0; i < 201; i++ {
|
|
p.Rules = append(p.Rules, Rule{Type: "domain", Value: "a.com", Action: "proxy", Enabled: true})
|
|
}
|
|
if e := p.Validate(); len(e) == 0 {
|
|
t.Fatal("want count-limit error")
|
|
}
|
|
}
|
|
|
|
func TestNormalizeDedupAndTrim(t *testing.T) {
|
|
p := Default()
|
|
p.Rules = []Rule{
|
|
{Type: "domain", Value: " a.com ", Action: "proxy", Enabled: true},
|
|
{Type: "domain", Value: "a.com", Action: "proxy", Enabled: false},
|
|
{Type: "domain", Value: "b.com", Action: "proxy", Enabled: true},
|
|
}
|
|
p.Normalize()
|
|
if len(p.Rules) != 2 {
|
|
t.Fatalf("want 2 rules after dedup, got %d: %v", len(p.Rules), p.Rules)
|
|
}
|
|
if p.Rules[0].Value != "a.com" || p.Rules[1].Value != "b.com" {
|
|
t.Fatalf("want first-occurrence order preserved, got %v", p.Rules)
|
|
}
|
|
}
|
|
|
|
// TestNormalizeDedupNoSeparatorCollision guards against the historical
|
|
// string-concatenation dedup key ("type|value|action"): two distinct rules
|
|
// whose Value contains "|" could concatenate to the same string even though
|
|
// (type, value, action) differ. The struct-keyed dedup must tell them apart.
|
|
func TestNormalizeDedupNoSeparatorCollision(t *testing.T) {
|
|
p := Default()
|
|
p.Rules = []Rule{
|
|
{Type: "domain", Value: "a|b", Action: "proxy", Enabled: true},
|
|
{Type: "domain", Value: "a", Action: "b|proxy", Enabled: true},
|
|
}
|
|
p.Normalize()
|
|
if len(p.Rules) != 2 {
|
|
t.Fatalf("want 2 distinct rules preserved (no false collision), got %d: %v", len(p.Rules), p.Rules)
|
|
}
|
|
}
|