Files
rogee cec95ff4e8 test: add comprehensive unit tests — coverage 20.2% → 91.8%
Add 12 test files covering all internal packages:

- internal/util/util_test.go (97.2%)
- internal/model/model_test.go (100.0%)
- internal/config/config_test.go (88.1%)
- internal/template/builtin_test.go (98.8%)
- internal/middleware/middleware_test.go (98.7%)
- internal/database/repo_extra_test.go (85.5%)
- internal/rules/converter_test.go (99.1%)
- internal/service/subscription_test.go (75.7%)
- internal/handler/handler_test.go (90.6%)
- internal/filter/filter_extra_test.go (91.9%)
- internal/proxy/client_parser_test.go (96.1%)
- internal/render/render_extra_test.go (99.2%)

Overall: 91.8% (4033/4400 statements) — exceeds 85% acceptance threshold.
All tests pass, go vet clean, go build clean.
2026-07-27 16:12:28 +08:00

826 lines
22 KiB
Go

package util
import (
"encoding/base64"
"strings"
"testing"
)
// ---------- token.go ----------
func TestSHA256Hex(t *testing.T) {
// Known SHA-256 of empty string
got := SHA256Hex("")
want := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
if got != want {
t.Errorf("SHA256Hex(\"\") = %q, want %q", got, want)
}
// Known SHA-256 of "hello"
got = SHA256Hex("hello")
want = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
if got != want {
t.Errorf("SHA256Hex(\"hello\") = %q, want %q", got, want)
}
// Different inputs produce different hashes
if SHA256Hex("a") == SHA256Hex("b") {
t.Error("different inputs should produce different hashes")
}
}
func TestIsTokenValid(t *testing.T) {
tests := []struct {
name string
input string
secret string
want bool
}{
{"correct", "mytoken", "mytoken", true},
{"wrong", "wrong", "mytoken", false},
{"empty input", "", "mytoken", false},
{"empty secret", "mytoken", "", false},
{"both empty", "", "", false},
{"case sensitive", "MyToken", "mytoken", false},
{"long token", strings.Repeat("a", 1000), strings.Repeat("a", 1000), true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsTokenValid(tt.input, tt.secret); got != tt.want {
t.Errorf("IsTokenValid(%q, %q) = %v, want %v", tt.input, tt.secret, got, tt.want)
}
})
}
}
func TestIsGrantTokenValid(t *testing.T) {
// Use the stored hash of a token
secret := "mygranttoken"
storedHash := SHA256Hex(secret)
tests := []struct {
name string
input string
storedHash string
want bool
}{
{"correct", secret, storedHash, true},
{"wrong", "wrong", storedHash, false},
{"empty input", "", storedHash, false},
{"empty storedHash", secret, "", false},
{"both empty", "", "", false},
{"garbage hash", secret, "garbage", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsGrantTokenValid(tt.input, tt.storedHash); got != tt.want {
t.Errorf("IsGrantTokenValid(%q, %q) = %v, want %v", tt.input, tt.storedHash, got, tt.want)
}
})
}
}
func TestRandomToken(t *testing.T) {
tok, err := RandomToken()
if err != nil {
t.Fatalf("RandomToken() error: %v", err)
}
if tok == "" {
t.Error("RandomToken() returned empty string")
}
// Should be base64 RawURL (no padding), 32 chars for 24 bytes
if len(tok) != 32 {
t.Errorf("RandomToken() length = %d, want 32", len(tok))
}
if strings.Contains(tok, "=") {
t.Error("RandomToken() should not contain padding")
}
// Two calls should produce different tokens (probabilistically)
tok2, _ := RandomToken()
if tok == tok2 {
t.Error("two RandomToken() calls produced same value")
}
// Should decode back to 24 bytes
b, err := base64.RawURLEncoding.DecodeString(tok)
if err != nil {
t.Fatalf("RandomToken() not valid base64 raw url: %v", err)
}
if len(b) != 24 {
t.Errorf("decoded token length = %d, want 24", len(b))
}
}
func TestEncodeDecodeBase64(t *testing.T) {
input := "Hello, 世界!"
// Std
encoded := EncodeBase64Std(input)
decoded, err := DecodeBase64Std(encoded)
if err != nil {
t.Fatalf("DecodeBase64Std error: %v", err)
}
if decoded != input {
t.Errorf("Std round-trip failed: got %q, want %q", decoded, input)
}
// URL (with padding)
encoded = EncodeBase64URL(input)
decoded, err = DecodeBase64URL(encoded)
if err != nil {
t.Fatalf("DecodeBase64URL error: %v", err)
}
if decoded != input {
t.Errorf("URL round-trip failed: got %q, want %q", decoded, input)
}
// RawURL (no padding)
encoded = EncodeBase64RawURL(input)
decoded, err = DecodeBase64RawURL(encoded)
if err != nil {
t.Fatalf("DecodeBase64RawURL error: %v", err)
}
if decoded != input {
t.Errorf("RawURL round-trip failed: got %q, want %q", decoded, input)
}
if strings.Contains(encoded, "=") {
t.Error("EncodeBase64RawURL should not produce padding")
}
}
func TestDecodeBase64StdInvalid(t *testing.T) {
if _, err := DecodeBase64Std("!!!invalid"); err == nil {
t.Error("expected error for invalid base64 std")
}
}
func TestDecodeBase64URLInvalid(t *testing.T) {
if _, err := DecodeBase64URL("!!!invalid"); err == nil {
t.Error("expected error for invalid base64 url")
}
}
func TestDecodeBase64RawURLInvalid(t *testing.T) {
if _, err := DecodeBase64RawURL("!!!invalid"); err == nil {
t.Error("expected error for invalid base64 raw url")
}
}
func TestDecodeBase64Auto(t *testing.T) {
input := "Hello World"
// std encoding
std := base64.StdEncoding.EncodeToString([]byte(input))
got, err := DecodeBase64Auto(std)
if err != nil {
t.Fatalf("DecodeBase64Auto(std) error: %v", err)
}
if got != input {
t.Errorf("DecodeBase64Auto(std) = %q, want %q", got, input)
}
// raw url encoding
rawURL := base64.RawURLEncoding.EncodeToString([]byte(input))
got, err = DecodeBase64Auto(rawURL)
if err != nil {
t.Fatalf("DecodeBase64Auto(rawURL) error: %v", err)
}
if got != input {
t.Errorf("DecodeBase64Auto(rawURL) = %q, want %q", got, input)
}
// url encoding with padding
urlEnc := base64.URLEncoding.EncodeToString([]byte(input))
got, err = DecodeBase64Auto(urlEnc)
if err != nil {
t.Fatalf("DecodeBase64Auto(url) error: %v", err)
}
if got != input {
t.Errorf("DecodeBase64Auto(url) = %q, want %q", got, input)
}
// whitespace trimming
got, err = DecodeBase64Auto(" " + std + " ")
if err != nil {
t.Fatalf("DecodeBase64Auto(trimmed) error: %v", err)
}
if got != input {
t.Errorf("DecodeBase64Auto(trimmed) = %q, want %q", got, input)
}
// invalid
if _, err := DecodeBase64Auto("!!!not base64 at all"); err == nil {
t.Error("expected error for invalid base64 in Auto")
}
}
func TestBase64Utf8(t *testing.T) {
input := "Hello, 世界!"
got := Base64Utf8(input)
want := base64.StdEncoding.EncodeToString([]byte(input))
if got != want {
t.Errorf("Base64Utf8(%q) = %q, want %q", input, got, want)
}
// round trip
decoded, err := base64.StdEncoding.DecodeString(got)
if err != nil {
t.Fatalf("decode error: %v", err)
}
if string(decoded) != input {
t.Errorf("round-trip failed: got %q, want %q", string(decoded), input)
}
}
// ---------- path.go ----------
func TestGetByPath(t *testing.T) {
nested := map[string]any{
"ws-opts": map[string]any{
"headers": map[string]any{
"Host": "example.com",
},
"path": "/ws",
},
"server": "1.2.3.4",
"port": 443,
}
tests := []struct {
name string
path string
want any
}{
{"top-level string", "server", "1.2.3.4"},
{"top-level int", "port", 443},
{"nested 2 levels", "ws-opts.headers.Host", "example.com"},
{"nested 1 level", "ws-opts.path", "/ws"},
{"missing key", "nonexistent", nil},
{"missing nested", "ws-opts.nonexistent", nil},
{"missing deep", "a.b.c", nil},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := GetByPath(nested, tt.path)
if got != tt.want {
t.Errorf("GetByPath(%q) = %v, want %v", tt.path, got, tt.want)
}
})
}
// non-map intermediate value
m := map[string]any{"server": "1.2.3.4"}
if got := GetByPath(m, "server.sub"); got != nil {
t.Errorf("GetByPath on non-map intermediate = %v, want nil", got)
}
}
func TestSetByPath(t *testing.T) {
t.Run("top-level new", func(t *testing.T) {
m := map[string]any{}
result := SetByPath(m, "key", "value")
if result["key"] != "value" {
t.Errorf("SetByPath failed: got %v", result["key"])
}
})
t.Run("nested new creates intermediate maps", func(t *testing.T) {
m := map[string]any{}
result := SetByPath(m, "a.b.c", "deep")
// navigate
a := result["a"].(map[string]any)
b := a["b"].(map[string]any)
if b["c"] != "deep" {
t.Errorf("nested set failed: got %v", b["c"])
}
})
t.Run("overwrite existing", func(t *testing.T) {
m := map[string]any{"key": "old"}
result := SetByPath(m, "key", "new")
if result["key"] != "new" {
t.Errorf("overwrite failed: got %v", result["key"])
}
})
t.Run("overwrite nested existing", func(t *testing.T) {
m := map[string]any{
"ws-opts": map[string]any{"path": "/old"},
}
result := SetByPath(m, "ws-opts.path", "/new")
ws := result["ws-opts"].(map[string]any)
if ws["path"] != "/new" {
t.Errorf("nested overwrite failed: got %v", ws["path"])
}
})
t.Run("preserve existing sibling keys", func(t *testing.T) {
m := map[string]any{
"ws-opts": map[string]any{"path": "/ws", "headers": map[string]any{"Host": "h"}},
}
result := SetByPath(m, "ws-opts.newkey", "newval")
ws := result["ws-opts"].(map[string]any)
if ws["path"] != "/ws" {
t.Errorf("sibling 'path' lost: got %v", ws["path"])
}
if ws["newkey"] != "newval" {
t.Errorf("new key not set: got %v", ws["newkey"])
}
})
t.Run("replace non-map intermediate with map", func(t *testing.T) {
m := map[string]any{"a": "stringvalue"}
result := SetByPath(m, "a.b", "val")
a := result["a"].(map[string]any)
if a["b"] != "val" {
t.Errorf("replace non-map intermediate failed: got %v", a["b"])
}
})
}
func TestGetString(t *testing.T) {
m := map[string]any{
"name": "test",
"port": 443,
}
if got := GetString(m, "name"); got != "test" {
t.Errorf("GetString(name) = %q, want %q", got, "test")
}
if got := GetString(m, "port"); got != "" {
t.Errorf("GetString(port) = %q, want empty (non-string)", got)
}
if got := GetString(m, "missing"); got != "" {
t.Errorf("GetString(missing) = %q, want empty", got)
}
}
func TestGetInt(t *testing.T) {
tests := []struct {
name string
m map[string]any
path string
want int
}{
{"int", map[string]any{"port": 443}, "port", 443},
{"int64", map[string]any{"port": int64(443)}, "port", 443},
{"float64", map[string]any{"port": float64(443)}, "port", 443},
{"string numeric", map[string]any{"port": "443"}, "port", 443},
{"string non-numeric", map[string]any{"port": "abc"}, "port", 0},
{"missing", map[string]any{}, "port", 0},
{"non-numeric type", map[string]any{"port": true}, "port", 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetInt(tt.m, tt.path); got != tt.want {
t.Errorf("GetInt(%s) = %d, want %d", tt.path, got, tt.want)
}
})
}
}
func TestGetBool(t *testing.T) {
m := map[string]any{
"enabled": true,
"port": 443,
}
if got := GetBool(m, "enabled"); !got {
t.Error("GetBool(enabled) = false, want true")
}
if got := GetBool(m, "port"); got {
t.Error("GetBool(port) = true, want false (non-bool)")
}
if got := GetBool(m, "missing"); got {
t.Error("GetBool(missing) = true, want false")
}
}
func TestDeepCopy(t *testing.T) {
original := map[string]any{
"name": "test",
"port": 443,
"nested": map[string]any{"key": "val"},
}
cp := DeepCopy(original)
// Values match (note: JSON round-trip converts int → float64)
if cp["name"] != "test" {
t.Errorf("DeepCopy name mismatch: %v", cp["name"])
}
if port, ok := cp["port"].(float64); !ok || port != 443 {
t.Errorf("DeepCopy port mismatch: %v", cp["port"])
}
// Nested map is a different instance (deep)
nestedOrig := original["nested"].(map[string]any)
nestedCopy := cp["nested"].(map[string]any)
nestedCopy["key"] = "changed"
if nestedOrig["key"] == "changed" {
t.Error("DeepCopy did not deep-copy nested map")
}
// Empty input
if got := DeepCopy(map[string]any{}); len(got) != 0 {
t.Errorf("DeepCopy(empty) = %v, want empty map", got)
}
}
func TestStripUndefined(t *testing.T) {
m := map[string]any{
"name": "test",
"empty": "",
"nilval": nil,
"port": 443,
"zero": 0,
"false": false,
"nonempty": "value",
}
result := StripUndefined(m)
if _, ok := result["empty"]; ok {
t.Error("StripUndefined should remove empty strings")
}
if _, ok := result["nilval"]; ok {
t.Error("StripUndefined should remove nil values")
}
if _, ok := result["name"]; !ok {
t.Error("StripUndefined should keep non-empty strings")
}
if _, ok := result["port"]; !ok {
t.Error("StripUndefined should keep ints")
}
if _, ok := result["zero"]; !ok {
t.Error("StripUndefined should keep zero (not nil/empty)")
}
if _, ok := result["false"]; !ok {
t.Error("StripUndefined should keep false (not nil/empty)")
}
}
func TestMergeDeep(t *testing.T) {
base := map[string]any{
"name": "base",
"port": 8080,
"nested": map[string]any{
"a": "base-a",
"b": "base-b",
},
}
next := map[string]any{
"port": 9090,
"nested": map[string]any{
"b": "next-b",
"c": "next-c",
},
"newkey": "next-val",
}
result := MergeDeep(base, next)
if result["name"] != "base" {
t.Errorf("MergeDeep name = %v, want base", result["name"])
}
if result["port"] != 9090 {
t.Errorf("MergeDeep port = %v, want 9090 (overridden)", result["port"])
}
if result["newkey"] != "next-val" {
t.Errorf("MergeDeep newkey = %v, want next-val", result["newkey"])
}
nested := result["nested"].(map[string]any)
if nested["a"] != "base-a" {
t.Errorf("MergeDeep nested.a = %v, want base-a (preserved)", nested["a"])
}
if nested["b"] != "next-b" {
t.Errorf("MergeDeep nested.b = %v, want next-b (overridden)", nested["b"])
}
if nested["c"] != "next-c" {
t.Errorf("MergeDeep nested.c = %v, want next-c (added)", nested["c"])
}
// nil values in next should be skipped
result2 := MergeDeep(map[string]any{"a": "1"}, map[string]any{"a": nil, "b": "2"})
if result2["a"] != "1" {
t.Errorf("MergeDeep nil in next should not override: a = %v", result2["a"])
}
if result2["b"] != "2" {
t.Errorf("MergeDeep b = %v, want 2", result2["b"])
}
// base not mutated
if base["port"] != 8080 {
t.Error("MergeDeep should not mutate base map")
}
}
func TestToId(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{"simple", "My Node", "my-node"},
{"uppercase", "HelloWorld", "helloworld"},
{"special chars", "Node!@#Name", "node-name"},
{"underscores preserved", "my_node", "my_node"},
{"leading/trailing dashes", " --name-- ", "name"},
{"consecutive special", "a b", "a-b"},
{"numbers", "node123", "node123"},
{"mixed", "HK-香港 01", "hk-01"},
{"empty", "", "item"},
{"only special", "!!!", "item"},
{"dashes collapsed", "a--b", "a-b"},
{"long truncation", strings.Repeat("a", 100), strings.Repeat("a", 64)},
{"chinese chars", "香港节点", "item"},
{"underscore and dash", "my_node-name", "my_node-name"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ToId(tt.input)
if got != tt.want {
t.Errorf("ToId(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}
// ---------- flag.go ----------
func TestDetectFlag(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{"Hong Kong CN", "香港 01", "🇭🇰"},
{"Hong Kong EN", "Hong Kong 01", "🇭🇰"},
{"HK abbreviation", "HK 01", "🇭🇰"},
{"Taiwan CN", "台湾 01", "🇹🇼"},
{"Taiwan TW", "台灣 01", "🇹🇼"},
{"Taiwan EN", "Taiwan 01", "🇹🇼"},
{"TW abbreviation", "TW 01", "🇹🇼"},
{"Singapore CN", "新加坡 01", "🇸🇬"},
{"Singapore EN", "Singapore 01", "🇸🇬"},
{"SG abbreviation", "SG 01", "🇸🇬"},
{"Japan CN", "日本 01", "🇯🇵"},
{"Tokyo", "东京 01", "🇯🇵"},
{"Osaka JP", "大阪 01", "🇯🇵"},
{"Japan EN", "Japan 01", "🇯🇵"},
{"JP abbreviation", "JP 01", "🇯🇵"},
{"USA CN", "美国 01", "🇺🇸"},
{"USA EN", "United States 01", "🇺🇸"},
{"Los Angeles", "洛杉矶 01", "🇺🇸"},
{"US abbreviation", "US 01", "🇺🇸"},
{"UK CN", "英国 01", "🇬🇧"},
{"London", "伦敦 01", "🇬🇧"},
{"UK abbreviation", "UK 01", "🇬🇧"},
{"Germany CN", "德国 01", "🇩🇪"},
{"Frankfurt", "法兰克福 01", "🇩🇪"},
{"DE abbreviation", "DE 01", "🇩🇪"},
{"Korea CN", "韩国 01", "🇰🇷"},
{"Seoul", "首尔 01", "🇰🇷"},
{"KR abbreviation", "KR 01", "🇰🇷"},
{"no match", "Unknown Location", "🏳️"},
{"empty", "", "🏳️"},
{"lowercase abbreviation", "hk node", "🇭🇰"},
{"uppercase abbreviation", "HK node", "🇭🇰"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := DetectFlag(tt.input)
if got != tt.want {
t.Errorf("DetectFlag(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}
func TestRemoveFlag(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{"with HK flag", "🇭🇰 香港 01", "香港 01"},
{"with TW flag", "🇹🇼 台湾 01", "台湾 01"},
{"with white flag", "🏳️ Test Node", "Test Node"},
{"no flag", "Test Node", "Test Node"},
{"empty", "", ""},
{"only flag", "🇭🇰", ""},
{"multiple spaces with flag", "🇭🇰 Node", "Node"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := RemoveFlag(tt.input)
if got != tt.want {
t.Errorf("RemoveFlag(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}
func TestNormalizeTaiwanFlag(t *testing.T) {
tests := []struct {
name string
flag string
mode string
want string
}{
{"tw flag ws mode", "🇹🇼", "ws", "🇼🇸"},
{"tw flag tw mode", "🇹🇼", "tw", "🇹🇼"},
{"tw flag default mode", "🇹🇼", "", "🇨🇳"},
{"tw flag other mode", "🇹🇼", "other", "🇨🇳"},
{"non-tw flag ws mode", "🇭🇰", "ws", "🇭🇰"},
{"non-tw flag tw mode", "🇭🇰", "tw", "🇭🇰"},
{"non-tw flag default", "🇺🇸", "", "🇺🇸"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := NormalizeTaiwanFlag(tt.flag, tt.mode)
if got != tt.want {
t.Errorf("NormalizeTaiwanFlag(%q, %q) = %q, want %q", tt.flag, tt.mode, got, tt.want)
}
})
}
}
func TestIsASCII(t *testing.T) {
tests := []struct {
name string
s string
want bool
}{
{"ascii", "Hello World", true},
{"ascii with numbers", "123 abc", true},
{"ascii symbols", "!@#$%^&*()", true},
{"empty", "", true},
{"non-ascii (chinese)", "你好", false},
{"non-ascii (emoji)", "🇭🇰", false},
{"mixed", "Hello 世界", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsASCII(tt.s); got != tt.want {
t.Errorf("IsASCII(%q) = %v, want %v", tt.s, got, tt.want)
}
})
}
}
// ---------- ip.go ----------
func TestIsIPv4(t *testing.T) {
tests := []struct {
name string
input string
want bool
}{
{"valid", "192.168.1.1", true},
{"valid zeros", "0.0.0.0", true},
{"valid max", "255.255.255.255", true},
{"valid single", "1.1.1.1", true},
{"too many parts", "1.2.3.4.5", false},
{"too few parts", "1.2.3", false},
{"part too large", "256.1.1.1", false},
{"non-numeric", "a.b.c.d", false},
{"empty part", "1..1.1", false},
{"empty", "", false},
{"part too long", "1234.1.1.1", false},
{"with letters", "192.168.1.1a", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsIPv4(tt.input); got != tt.want {
t.Errorf("IsIPv4(%q) = %v, want %v", tt.input, got, tt.want)
}
})
}
}
func TestIsIPv6(t *testing.T) {
tests := []struct {
name string
input string
want bool
}{
{"valid full", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", true},
{"valid compressed", "::1", true},
{"valid loopback", "::1", true},
{"valid with zero", "fe80::1", true},
{"missing colon", "192.168.1.1", false},
{"invalid chars", "2001:0db8:85a3::GGGG", false},
{"empty", "", false},
{"simple", "2001::1", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsIPv6(tt.input); got != tt.want {
t.Errorf("IsIPv6(%q) = %v, want %v", tt.input, got, tt.want)
}
})
}
}
func TestIsIPAddress(t *testing.T) {
tests := []struct {
name string
input string
want bool
}{
{"ipv4", "192.168.1.1", true},
{"ipv6", "::1", true},
{"hostname", "example.com", false},
{"empty", "", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsIPAddress(tt.input); got != tt.want {
t.Errorf("IsIPAddress(%q) = %v, want %v", tt.input, got, tt.want)
}
})
}
}
func TestShouldResolveServer(t *testing.T) {
tests := []struct {
name string
server string
want bool
}{
{"hostname", "example.com", true},
{"subdomain", "sub.example.com", true},
{"ipv4", "192.168.1.1", false},
{"ipv6", "::1", false},
{"empty", "", false},
{"whitespace only", " ", false},
{"hostname with spaces", " example.com ", true},
{"no dot", "localhost", false},
{"invalid chars", "exa mple.com", false},
{"with underscore (invalid)", "my_host.com", false},
{"with port-like", "example.com:443", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ShouldResolveServer(tt.server); got != tt.want {
t.Errorf("ShouldResolveServer(%q) = %v, want %v", tt.server, got, tt.want)
}
})
}
}
// ---------- limits.go ----------
func TestLimitsConstants(t *testing.T) {
// Verify the limit constants are set to expected values.
if MaxAPIBodyBytes != 4*1024*1024 {
t.Errorf("MaxAPIBodyBytes = %d, want %d", MaxAPIBodyBytes, 4*1024*1024)
}
if MaxRemoteSourceUrls != 8 {
t.Errorf("MaxRemoteSourceUrls = %d, want 8", MaxRemoteSourceUrls)
}
if MaxRemoteSourceRespBytes != 2*1024*1024 {
t.Errorf("MaxRemoteSourceRespBytes = %d, want %d", MaxRemoteSourceRespBytes, 2*1024*1024)
}
if MaxRemoteSourceTotalBytes != 12*1024*1024 {
t.Errorf("MaxRemoteSourceTotalBytes = %d, want %d", MaxRemoteSourceTotalBytes, 12*1024*1024)
}
if MaxFlowRespBytes != 64*1024 {
t.Errorf("MaxFlowRespBytes = %d, want %d", MaxFlowRespBytes, 64*1024)
}
if MaxDoHRespBytes != 64*1024 {
t.Errorf("MaxDoHRespBytes = %d, want %d", MaxDoHRespBytes, 64*1024)
}
if MaxRecycleEntries != 50 {
t.Errorf("MaxRecycleEntries = %d, want 50", MaxRecycleEntries)
}
if MaxCustomRules != 32 {
t.Errorf("MaxCustomRules = %d, want 32", MaxCustomRules)
}
}
// ---------- random.go ----------
func TestReadRandom(t *testing.T) {
buf := make([]byte, 16)
n, err := readRandom(buf)
if err != nil {
t.Fatalf("readRandom error: %v", err)
}
if n != 16 {
t.Errorf("readRandom returned n=%d, want 16", n)
}
// very unlikely to be all zeros
allZero := true
for _, b := range buf {
if b != 0 {
allZero = false
break
}
}
if allZero {
t.Error("readRandom returned all zeros (suspicious)")
}
// two reads should differ
buf2 := make([]byte, 16)
readRandom(buf2)
same := true
for i := range buf {
if buf[i] != buf2[i] {
same = false
break
}
}
if same {
t.Error("two readRandom calls returned same bytes (suspicious)")
}
}