Add unit tests
This commit is contained in:
293
internal/config/config_test.go
Normal file
293
internal/config/config_test.go
Normal file
@@ -0,0 +1,293 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateDomainPattern(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pattern string
|
||||
wantErr bool
|
||||
}{
|
||||
// Valid patterns
|
||||
{"valid domain", "example.com", false},
|
||||
{"valid subdomain", "api.example.com", false},
|
||||
{"valid wildcard", "*.example.com", false},
|
||||
{"valid wildcard subdomain", "*.api.example.com", false},
|
||||
{"localhost", "localhost", false},
|
||||
|
||||
// Invalid patterns
|
||||
{"protocol included", "https://example.com", true},
|
||||
{"path included", "example.com/path", true},
|
||||
{"port included", "example.com:443", true},
|
||||
{"wildcard too broad", "*.com", true},
|
||||
{"invalid wildcard position", "example.*.com", true},
|
||||
{"trailing wildcard", "example.com.*", true},
|
||||
{"leading dot", ".example.com", true},
|
||||
{"trailing dot", "example.com.", true},
|
||||
{"no TLD", "example", true},
|
||||
{"empty wildcard domain part", "*.", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validateDomainPattern(tt.pattern)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("validateDomainPattern(%q) error = %v, wantErr %v", tt.pattern, err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchesDomain(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
hostname string
|
||||
pattern string
|
||||
want bool
|
||||
}{
|
||||
// Exact matches
|
||||
{"exact match", "example.com", "example.com", true},
|
||||
{"exact match case insensitive", "Example.COM", "example.com", true},
|
||||
{"exact no match", "other.com", "example.com", false},
|
||||
|
||||
// Wildcard matches
|
||||
{"wildcard match subdomain", "api.example.com", "*.example.com", true},
|
||||
{"wildcard match deep subdomain", "deep.api.example.com", "*.example.com", true},
|
||||
{"wildcard no match base domain", "example.com", "*.example.com", false},
|
||||
{"wildcard no match different domain", "api.other.com", "*.example.com", false},
|
||||
{"wildcard case insensitive", "API.Example.COM", "*.example.com", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := MatchesDomain(tt.hostname, tt.pattern)
|
||||
if got != tt.want {
|
||||
t.Errorf("MatchesDomain(%q, %q) = %v, want %v", tt.hostname, tt.pattern, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config Config
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid empty config",
|
||||
config: Config{},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid config with domains",
|
||||
config: Config{
|
||||
Network: NetworkConfig{
|
||||
AllowedDomains: []string{"example.com", "*.github.com"},
|
||||
DeniedDomains: []string{"blocked.com"},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid allowed domain",
|
||||
config: Config{
|
||||
Network: NetworkConfig{
|
||||
AllowedDomains: []string{"https://example.com"},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid denied domain",
|
||||
config: Config{
|
||||
Network: NetworkConfig{
|
||||
DeniedDomains: []string{"*.com"},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty denyRead path",
|
||||
config: Config{
|
||||
Filesystem: FilesystemConfig{
|
||||
DenyRead: []string{""},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty allowWrite path",
|
||||
config: Config{
|
||||
Filesystem: FilesystemConfig{
|
||||
AllowWrite: []string{""},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty denyWrite path",
|
||||
config: Config{
|
||||
Filesystem: FilesystemConfig{
|
||||
DenyWrite: []string{""},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.config.Validate()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Config.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefault(t *testing.T) {
|
||||
cfg := Default()
|
||||
if cfg == nil {
|
||||
t.Fatal("Default() returned nil")
|
||||
}
|
||||
if cfg.Network.AllowedDomains == nil {
|
||||
t.Error("AllowedDomains should not be nil")
|
||||
}
|
||||
if cfg.Network.DeniedDomains == nil {
|
||||
t.Error("DeniedDomains should not be nil")
|
||||
}
|
||||
if cfg.Filesystem.DenyRead == nil {
|
||||
t.Error("DenyRead should not be nil")
|
||||
}
|
||||
if cfg.Filesystem.AllowWrite == nil {
|
||||
t.Error("AllowWrite should not be nil")
|
||||
}
|
||||
if cfg.Filesystem.DenyWrite == nil {
|
||||
t.Error("DenyWrite should not be nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoad(t *testing.T) {
|
||||
// Create temp directory for test files
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
content string
|
||||
setup func(string) string // returns path
|
||||
wantNil bool
|
||||
wantErr bool
|
||||
checkConfig func(*testing.T, *Config)
|
||||
}{
|
||||
{
|
||||
name: "nonexistent file",
|
||||
setup: func(dir string) string { return filepath.Join(dir, "nonexistent.json") },
|
||||
wantNil: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty file",
|
||||
content: "",
|
||||
setup: func(dir string) string {
|
||||
path := filepath.Join(dir, "empty.json")
|
||||
_ = os.WriteFile(path, []byte(""), 0o644)
|
||||
return path
|
||||
},
|
||||
wantNil: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "whitespace only file",
|
||||
content: " \n\t ",
|
||||
setup: func(dir string) string {
|
||||
path := filepath.Join(dir, "whitespace.json")
|
||||
_ = os.WriteFile(path, []byte(" \n\t "), 0o644)
|
||||
return path
|
||||
},
|
||||
wantNil: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid config",
|
||||
setup: func(dir string) string {
|
||||
path := filepath.Join(dir, "valid.json")
|
||||
content := `{"network":{"allowedDomains":["example.com"]}}`
|
||||
_ = os.WriteFile(path, []byte(content), 0o644)
|
||||
return path
|
||||
},
|
||||
wantNil: false,
|
||||
wantErr: false,
|
||||
checkConfig: func(t *testing.T, cfg *Config) {
|
||||
if len(cfg.Network.AllowedDomains) != 1 {
|
||||
t.Errorf("expected 1 allowed domain, got %d", len(cfg.Network.AllowedDomains))
|
||||
}
|
||||
if cfg.Network.AllowedDomains[0] != "example.com" {
|
||||
t.Errorf("expected example.com, got %s", cfg.Network.AllowedDomains[0])
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid JSON",
|
||||
setup: func(dir string) string {
|
||||
path := filepath.Join(dir, "invalid.json")
|
||||
_ = os.WriteFile(path, []byte("{invalid json}"), 0o644)
|
||||
return path
|
||||
},
|
||||
wantNil: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid domain in config",
|
||||
setup: func(dir string) string {
|
||||
path := filepath.Join(dir, "invalid_domain.json")
|
||||
content := `{"network":{"allowedDomains":["*.com"]}}`
|
||||
_ = os.WriteFile(path, []byte(content), 0o644)
|
||||
return path
|
||||
},
|
||||
wantNil: false,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
path := tt.setup(tmpDir)
|
||||
cfg, err := Load(path)
|
||||
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Load() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if tt.wantNil && cfg != nil {
|
||||
t.Error("Load() expected nil config")
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantNil && !tt.wantErr && cfg == nil {
|
||||
t.Error("Load() returned nil config unexpectedly")
|
||||
return
|
||||
}
|
||||
|
||||
if tt.checkConfig != nil && cfg != nil {
|
||||
tt.checkConfig(t, cfg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultConfigPath(t *testing.T) {
|
||||
path := DefaultConfigPath()
|
||||
if path == "" {
|
||||
t.Error("DefaultConfigPath() returned empty string")
|
||||
}
|
||||
// Should end with .fence.json
|
||||
if filepath.Base(path) != ".fence.json" {
|
||||
t.Errorf("DefaultConfigPath() = %q, expected to end with .fence.json", path)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user