orama/pkg/config/validate/validators_test.go
2026-02-13 16:18:22 +02:00

344 lines
7.6 KiB
Go

package validate
import (
"strings"
"testing"
)
func TestValidateHostPort(t *testing.T) {
tests := []struct {
name string
hostPort string
wantErr bool
errSubstr string
}{
{"valid localhost:8080", "localhost:8080", false, ""},
{"valid 0.0.0.0:443", "0.0.0.0:443", false, ""},
{"valid 192.168.1.1:9090", "192.168.1.1:9090", false, ""},
{"valid max port", "host:65535", false, ""},
{"valid port 1", "host:1", false, ""},
{"missing port", "localhost", true, "expected format host:port"},
{"missing host", ":8080", true, "host must not be empty"},
{"non-numeric port", "host:abc", true, "port must be a number"},
{"port too large", "host:99999", true, "port must be a number"},
{"port zero", "host:0", true, "port must be a number"},
{"empty string", "", true, "expected format host:port"},
{"negative port", "host:-1", true, "port must be a number"},
{"multiple colons", "host:80:90", true, "expected format host:port"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateHostPort(tt.hostPort)
if tt.wantErr {
if err == nil {
t.Errorf("ValidateHostPort(%q) = nil, want error containing %q", tt.hostPort, tt.errSubstr)
} else if tt.errSubstr != "" && !strings.Contains(err.Error(), tt.errSubstr) {
t.Errorf("ValidateHostPort(%q) error = %q, want error containing %q", tt.hostPort, err.Error(), tt.errSubstr)
}
} else {
if err != nil {
t.Errorf("ValidateHostPort(%q) = %v, want nil", tt.hostPort, err)
}
}
})
}
}
func TestValidatePort(t *testing.T) {
tests := []struct {
name string
port int
wantErr bool
}{
{"valid port 1", 1, false},
{"valid port 80", 80, false},
{"valid port 443", 443, false},
{"valid port 8080", 8080, false},
{"valid port 65535", 65535, false},
{"invalid port 0", 0, true},
{"invalid port -1", -1, true},
{"invalid port 65536", 65536, true},
{"invalid large port", 100000, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidatePort(tt.port)
if tt.wantErr {
if err == nil {
t.Errorf("ValidatePort(%d) = nil, want error", tt.port)
}
} else {
if err != nil {
t.Errorf("ValidatePort(%d) = %v, want nil", tt.port, err)
}
}
})
}
}
func TestValidateHostOrHostPort(t *testing.T) {
tests := []struct {
name string
addr string
wantErr bool
errSubstr string
}{
{"valid host only", "localhost", false, ""},
{"valid hostname", "myserver.example.com", false, ""},
{"valid IP", "192.168.1.1", false, ""},
{"valid host:port", "localhost:8080", false, ""},
{"valid IP:port", "0.0.0.0:443", false, ""},
{"empty string", "", true, "address must not be empty"},
{"invalid port in host:port", "host:abc", true, "port must be a number"},
{"missing host in host:port", ":8080", true, "host must not be empty"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateHostOrHostPort(tt.addr)
if tt.wantErr {
if err == nil {
t.Errorf("ValidateHostOrHostPort(%q) = nil, want error containing %q", tt.addr, tt.errSubstr)
} else if tt.errSubstr != "" && !strings.Contains(err.Error(), tt.errSubstr) {
t.Errorf("ValidateHostOrHostPort(%q) error = %q, want error containing %q", tt.addr, err.Error(), tt.errSubstr)
}
} else {
if err != nil {
t.Errorf("ValidateHostOrHostPort(%q) = %v, want nil", tt.addr, err)
}
}
})
}
}
func TestExtractSwarmKeyHex(t *testing.T) {
validHex := "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
tests := []struct {
name string
input string
want string
}{
{
"full swarm key format",
"/key/swarm/psk/1.0.0/\n/base16/\n" + validHex + "\n",
validHex,
},
{
"full swarm key format no trailing newline",
"/key/swarm/psk/1.0.0/\n/base16/\n" + validHex,
validHex,
},
{
"raw hex string",
validHex,
validHex,
},
{
"with leading and trailing whitespace",
" " + validHex + " ",
validHex,
},
{
"empty string",
"",
"",
},
{
"only header lines no hex",
"/key/swarm/psk/1.0.0/\n/base16/\n",
"/key/swarm/psk/1.0.0/\n/base16/",
},
{
"base16 marker only",
"/base16/\n" + validHex,
validHex,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ExtractSwarmKeyHex(tt.input)
if got != tt.want {
t.Errorf("ExtractSwarmKeyHex(%q) = %q, want %q", tt.input, got, tt.want)
}
})
}
}
func TestValidateSwarmKey(t *testing.T) {
validHex := "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
tests := []struct {
name string
key string
wantErr bool
errSubstr string
}{
{
"valid 64-char hex",
validHex,
false,
"",
},
{
"valid full swarm key format",
"/key/swarm/psk/1.0.0/\n/base16/\n" + validHex,
false,
"",
},
{
"too short",
"a1b2c3d4",
true,
"must be 64 hex characters",
},
{
"too long",
validHex + "ffff",
true,
"must be 64 hex characters",
},
{
"non-hex characters",
"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
true,
"must be valid hexadecimal",
},
{
"empty string",
"",
true,
"must be 64 hex characters",
},
{
"63 chars (one short)",
validHex[:63],
true,
"must be 64 hex characters",
},
{
"65 chars (one over)",
validHex + "a",
true,
"must be 64 hex characters",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateSwarmKey(tt.key)
if tt.wantErr {
if err == nil {
t.Errorf("ValidateSwarmKey(%q) = nil, want error containing %q", tt.key, tt.errSubstr)
} else if tt.errSubstr != "" && !strings.Contains(err.Error(), tt.errSubstr) {
t.Errorf("ValidateSwarmKey(%q) error = %q, want error containing %q", tt.key, err.Error(), tt.errSubstr)
}
} else {
if err != nil {
t.Errorf("ValidateSwarmKey(%q) = %v, want nil", tt.key, err)
}
}
})
}
}
func TestExtractTCPPort(t *testing.T) {
tests := []struct {
name string
multiaddr string
want string
}{
{
"valid multiaddr with tcp port",
"/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWExample",
"4001",
},
{
"valid multiaddr no p2p",
"/ip4/0.0.0.0/tcp/8080",
"8080",
},
{
"ipv6 with tcp port",
"/ip6/::/tcp/9090/p2p/12D3KooWExample",
"9090",
},
{
"no tcp component",
"/ip4/127.0.0.1/udp/4001",
"",
},
{
"empty string",
"",
"",
},
{
"tcp at end without port value",
"/ip4/127.0.0.1/tcp",
"",
},
{
"only tcp with port",
"/tcp/443",
"443",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ExtractTCPPort(tt.multiaddr)
if got != tt.want {
t.Errorf("ExtractTCPPort(%q) = %q, want %q", tt.multiaddr, got, tt.want)
}
})
}
}
func TestValidationError_Error(t *testing.T) {
tests := []struct {
name string
err ValidationError
want string
}{
{
"with hint",
ValidationError{
Path: "discovery.bootstrap_peers[0]",
Message: "invalid multiaddr",
Hint: "expected /ip{4,6}/.../tcp/<port>/p2p/<peerID>",
},
"discovery.bootstrap_peers[0]: invalid multiaddr; expected /ip{4,6}/.../tcp/<port>/p2p/<peerID>",
},
{
"without hint",
ValidationError{
Path: "node.listen_addr",
Message: "must not be empty",
},
"node.listen_addr: must not be empty",
},
{
"empty hint",
ValidationError{
Path: "config.port",
Message: "invalid",
Hint: "",
},
"config.port: invalid",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.err.Error()
if got != tt.want {
t.Errorf("ValidationError.Error() = %q, want %q", got, tt.want)
}
})
}
}