This commit is contained in:
278
internal/validation/validator_test.go
Normal file
278
internal/validation/validator_test.go
Normal file
@@ -0,0 +1,278 @@
|
||||
package validation
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestValidateZFSName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid pool name", "tank", false},
|
||||
{"valid dataset name", "tank/data", false},
|
||||
{"valid nested dataset", "tank/data/subdata", false},
|
||||
{"valid with underscore", "tank_data", false},
|
||||
{"valid with dash", "tank-data", false},
|
||||
{"valid with colon", "tank:data", false},
|
||||
{"empty name", "", true},
|
||||
{"starts with dash", "-tank", true},
|
||||
{"starts with dot", ".tank", true},
|
||||
{"invalid character @", "tank@data", true},
|
||||
{"too long", string(make([]byte, 257)), true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidateZFSName(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateZFSName(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateUsername(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid username", "admin", false},
|
||||
{"valid with underscore", "admin_user", false},
|
||||
{"valid with dash", "admin-user", false},
|
||||
{"valid with dot", "admin.user", false},
|
||||
{"too short", "ab", true},
|
||||
{"too long", string(make([]byte, 33)), true},
|
||||
{"empty", "", true},
|
||||
{"invalid character", "admin@user", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidateUsername(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateUsername(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePassword(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid password", "SecurePass123", false},
|
||||
{"valid with special chars", "Secure!Pass123", false},
|
||||
{"too short", "Short1", true},
|
||||
{"no letter", "12345678", true},
|
||||
{"no number", "SecurePass", true},
|
||||
{"empty", "", true},
|
||||
{"too long", string(make([]byte, 129)), true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidatePassword(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidatePassword(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateEmail(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid email", "user@example.com", false},
|
||||
{"valid with subdomain", "user@mail.example.com", false},
|
||||
{"empty (optional)", "", false},
|
||||
{"invalid format", "notanemail", true},
|
||||
{"missing @", "user.example.com", true},
|
||||
{"missing domain", "user@", true},
|
||||
{"too long", string(make([]byte, 255)), true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidateEmail(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateEmail(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateShareName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid share name", "data-share", false},
|
||||
{"valid with underscore", "data_share", false},
|
||||
{"reserved name CON", "CON", true},
|
||||
{"reserved name COM1", "COM1", true},
|
||||
{"too long", string(make([]byte, 81)), true},
|
||||
{"empty", "", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidateShareName(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateShareName(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateIQN(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid IQN", "iqn.2024-12.com.atlas:target1", false},
|
||||
{"invalid format", "iqn.2024-12", true},
|
||||
{"missing iqn prefix", "2024-12.com.atlas:target1", true},
|
||||
{"invalid date format", "iqn.2024-1.com.atlas:target1", true},
|
||||
{"empty", "", true},
|
||||
{"too long", string(make([]byte, 224)), true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidateIQN(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateIQN(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSize(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid size bytes", "1024", false},
|
||||
{"valid size KB", "10K", false},
|
||||
{"valid size MB", "100M", false},
|
||||
{"valid size GB", "1G", false},
|
||||
{"valid size TB", "2T", false},
|
||||
{"lowercase unit", "1g", false},
|
||||
{"invalid unit", "10X", true},
|
||||
{"empty", "", true},
|
||||
{"no number", "G", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidateSize(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateSize(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatePath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid absolute path", "/tank/data", false},
|
||||
{"valid root path", "/", false},
|
||||
{"empty (optional)", "", false},
|
||||
{"relative path", "tank/data", true},
|
||||
{"path traversal", "/tank/../data", true},
|
||||
{"double slash", "/tank//data", true},
|
||||
{"too long", "/" + string(make([]byte, 4096)), true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidatePath(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidatePath(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCIDR(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantErr bool
|
||||
}{
|
||||
{"valid CIDR", "192.168.1.0/24", false},
|
||||
{"valid IP", "192.168.1.1", false},
|
||||
{"wildcard", "*", false},
|
||||
{"valid hostname", "server.example.com", false},
|
||||
{"invalid format", "not@a@valid@format", true},
|
||||
{"empty", "", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := ValidateCIDR(tt.input)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ValidateCIDR(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizeString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"normal string", "hello world", "hello world"},
|
||||
{"with null byte", "hello\x00world", "helloworld"},
|
||||
{"with control chars", "hello\x01\x02world", "helloworld"},
|
||||
{"with whitespace", " hello world ", "hello world"},
|
||||
{"empty", "", ""},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := SanitizeString(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("SanitizeString(%q) = %q, want %q", tt.input, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizePath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"normal path", "/tank/data", "/tank/data"},
|
||||
{"with backslash", "/tank\\data", "/tank/data"},
|
||||
{"with double slash", "/tank//data", "/tank/data"},
|
||||
{"with whitespace", " /tank/data ", "/tank/data"},
|
||||
{"multiple slashes", "/tank///data", "/tank/data"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := SanitizePath(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("SanitizePath(%q) = %q, want %q", tt.input, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user