| package config |
|
|
| import ( |
| "os" |
| "path/filepath" |
| "testing" |
| ) |
|
|
| func TestSetConfigValue_ServerFields(t *testing.T) { |
| tests := []struct { |
| path string |
| value string |
| check func(*FileConfig) bool |
| wantErr bool |
| }{ |
| {"server.port", "8080", func(fc *FileConfig) bool { return fc.Server.Port == "8080" }, false}, |
| {"server.bind", "0.0.0.0", func(fc *FileConfig) bool { return fc.Server.Bind == "0.0.0.0" }, false}, |
| {"server.token", "secret", func(fc *FileConfig) bool { return fc.Server.Token == "secret" }, false}, |
| {"server.stateDir", "/tmp/state", func(fc *FileConfig) bool { return fc.Server.StateDir == "/tmp/state" }, false}, |
| {"server.unknown", "value", nil, true}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.path+"="+tt.value, func(t *testing.T) { |
| fc := &FileConfig{} |
| err := SetConfigValue(fc, tt.path, tt.value) |
| if (err != nil) != tt.wantErr { |
| t.Errorf("SetConfigValue() error = %v, wantErr %v", err, tt.wantErr) |
| return |
| } |
| if !tt.wantErr && !tt.check(fc) { |
| t.Errorf("SetConfigValue() did not set value correctly") |
| } |
| }) |
| } |
| } |
|
|
| func TestSetConfigValue_BrowserAndInstanceDefaultsFields(t *testing.T) { |
| tests := []struct { |
| path string |
| value string |
| check func(*FileConfig) bool |
| wantErr bool |
| }{ |
| {"browser.version", "144.0.7559.133", func(fc *FileConfig) bool { return fc.Browser.ChromeVersion == "144.0.7559.133" }, false}, |
| {"browser.binary", "/tmp/chrome", func(fc *FileConfig) bool { return fc.Browser.ChromeBinary == "/tmp/chrome" }, false}, |
| {"instanceDefaults.mode", "headed", func(fc *FileConfig) bool { return fc.InstanceDefaults.Mode == "headed" }, false}, |
| {"instanceDefaults.maxTabs", "50", func(fc *FileConfig) bool { return *fc.InstanceDefaults.MaxTabs == 50 }, false}, |
| {"instanceDefaults.stealthLevel", "full", func(fc *FileConfig) bool { return fc.InstanceDefaults.StealthLevel == "full" }, false}, |
| {"instanceDefaults.tabEvictionPolicy", "close_lru", func(fc *FileConfig) bool { return fc.InstanceDefaults.TabEvictionPolicy == "close_lru" }, false}, |
| {"instanceDefaults.blockAds", "yes", func(fc *FileConfig) bool { return *fc.InstanceDefaults.BlockAds == true }, false}, |
| {"profiles.baseDir", "/tmp/profiles", func(fc *FileConfig) bool { return fc.Profiles.BaseDir == "/tmp/profiles" }, false}, |
| {"instanceDefaults.noRestore", "maybe", nil, true}, |
| {"instanceDefaults.maxTabs", "many", nil, true}, |
| {"instanceDefaults.unknown", "value", nil, true}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.path+"="+tt.value, func(t *testing.T) { |
| fc := &FileConfig{} |
| err := SetConfigValue(fc, tt.path, tt.value) |
| if (err != nil) != tt.wantErr { |
| t.Errorf("SetConfigValue() error = %v, wantErr %v", err, tt.wantErr) |
| return |
| } |
| if !tt.wantErr && !tt.check(fc) { |
| t.Errorf("SetConfigValue() did not set value correctly") |
| } |
| }) |
| } |
| } |
|
|
| func TestSetConfigValue_SecurityFields(t *testing.T) { |
| tests := []struct { |
| path string |
| value string |
| check func(*FileConfig) bool |
| wantErr bool |
| }{ |
| {"security.allowEvaluate", "true", func(fc *FileConfig) bool { return *fc.Security.AllowEvaluate == true }, false}, |
| {"security.allowMacro", "1", func(fc *FileConfig) bool { return *fc.Security.AllowMacro == true }, false}, |
| {"security.allowScreencast", "false", func(fc *FileConfig) bool { return *fc.Security.AllowScreencast == false }, false}, |
| {"security.allowDownload", "on", func(fc *FileConfig) bool { return *fc.Security.AllowDownload == true }, false}, |
| {"security.allowUpload", "off", func(fc *FileConfig) bool { return *fc.Security.AllowUpload == false }, false}, |
| {"security.allowEvaluate", "maybe", nil, true}, |
| {"security.unknown", "true", nil, true}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.path+"="+tt.value, func(t *testing.T) { |
| fc := &FileConfig{} |
| err := SetConfigValue(fc, tt.path, tt.value) |
| if (err != nil) != tt.wantErr { |
| t.Errorf("SetConfigValue() error = %v, wantErr %v", err, tt.wantErr) |
| return |
| } |
| if !tt.wantErr && !tt.check(fc) { |
| t.Errorf("SetConfigValue() did not set value correctly") |
| } |
| }) |
| } |
| } |
|
|
| func TestSetConfigValue_MultiInstanceFields(t *testing.T) { |
| tests := []struct { |
| path string |
| value string |
| check func(*FileConfig) bool |
| wantErr bool |
| }{ |
| {"multiInstance.strategy", "explicit", func(fc *FileConfig) bool { return fc.MultiInstance.Strategy == "explicit" }, false}, |
| {"multiInstance.allocationPolicy", "round_robin", func(fc *FileConfig) bool { return fc.MultiInstance.AllocationPolicy == "round_robin" }, false}, |
| {"multiInstance.instancePortStart", "9900", func(fc *FileConfig) bool { return *fc.MultiInstance.InstancePortStart == 9900 }, false}, |
| {"multiInstance.restart.maxRestarts", "12", func(fc *FileConfig) bool { |
| return fc.MultiInstance.Restart.MaxRestarts != nil && *fc.MultiInstance.Restart.MaxRestarts == 12 |
| }, false}, |
| {"multiInstance.restart.initBackoffSec", "3", func(fc *FileConfig) bool { |
| return fc.MultiInstance.Restart.InitBackoffSec != nil && *fc.MultiInstance.Restart.InitBackoffSec == 3 |
| }, false}, |
| {"multiInstance.unknown", "value", nil, true}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.path+"="+tt.value, func(t *testing.T) { |
| fc := &FileConfig{} |
| err := SetConfigValue(fc, tt.path, tt.value) |
| if (err != nil) != tt.wantErr { |
| t.Errorf("SetConfigValue() error = %v, wantErr %v", err, tt.wantErr) |
| return |
| } |
| if !tt.wantErr && !tt.check(fc) { |
| t.Errorf("SetConfigValue() did not set value correctly") |
| } |
| }) |
| } |
| } |
|
|
| func TestSetConfigValue_AttachFields(t *testing.T) { |
| tests := []struct { |
| path string |
| value string |
| check func(*FileConfig) bool |
| wantErr bool |
| }{ |
| {"security.attach.enabled", "true", func(fc *FileConfig) bool { return fc.Security.Attach.Enabled != nil && *fc.Security.Attach.Enabled }, false}, |
| {"security.attach.allowHosts", "localhost, chrome.internal", func(fc *FileConfig) bool { |
| return len(fc.Security.Attach.AllowHosts) == 2 && fc.Security.Attach.AllowHosts[1] == "chrome.internal" |
| }, false}, |
| {"security.attach.allowSchemes", "ws,wss", func(fc *FileConfig) bool { |
| return len(fc.Security.Attach.AllowSchemes) == 2 && fc.Security.Attach.AllowSchemes[0] == "ws" |
| }, false}, |
| {"security.attach.enabled", "maybe", nil, true}, |
| {"security.attach.unknown", "value", nil, true}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.path+"="+tt.value, func(t *testing.T) { |
| fc := &FileConfig{} |
| err := SetConfigValue(fc, tt.path, tt.value) |
| if (err != nil) != tt.wantErr { |
| t.Errorf("SetConfigValue() error = %v, wantErr %v", err, tt.wantErr) |
| return |
| } |
| if !tt.wantErr && !tt.check(fc) { |
| t.Errorf("SetConfigValue() did not set value correctly") |
| } |
| }) |
| } |
| } |
|
|
| func TestSetConfigValue_IDPIFields(t *testing.T) { |
| tests := []struct { |
| path string |
| value string |
| check func(*FileConfig) bool |
| wantErr bool |
| }{ |
| {"security.idpi.enabled", "true", func(fc *FileConfig) bool { return fc.Security.IDPI.Enabled }, false}, |
| {"security.idpi.allowedDomains", "localhost, example.com", func(fc *FileConfig) bool { |
| return len(fc.Security.IDPI.AllowedDomains) == 2 && fc.Security.IDPI.AllowedDomains[1] == "example.com" |
| }, false}, |
| {"security.idpi.strictMode", "false", func(fc *FileConfig) bool { return !fc.Security.IDPI.StrictMode }, false}, |
| {"security.idpi.scanContent", "true", func(fc *FileConfig) bool { return fc.Security.IDPI.ScanContent }, false}, |
| {"security.idpi.wrapContent", "true", func(fc *FileConfig) bool { return fc.Security.IDPI.WrapContent }, false}, |
| {"security.idpi.customPatterns", "ignore previous instructions, exfiltrate data", func(fc *FileConfig) bool { |
| return len(fc.Security.IDPI.CustomPatterns) == 2 && fc.Security.IDPI.CustomPatterns[0] == "ignore previous instructions" |
| }, false}, |
| {"security.idpi.enabled", "maybe", nil, true}, |
| {"security.idpi.unknown", "value", nil, true}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.path+"="+tt.value, func(t *testing.T) { |
| fc := &FileConfig{} |
| err := SetConfigValue(fc, tt.path, tt.value) |
| if (err != nil) != tt.wantErr { |
| t.Errorf("SetConfigValue() error = %v, wantErr %v", err, tt.wantErr) |
| return |
| } |
| if !tt.wantErr && !tt.check(fc) { |
| t.Errorf("SetConfigValue() did not set value correctly") |
| } |
| }) |
| } |
| } |
|
|
| func TestSetConfigValue_TimeoutsFields(t *testing.T) { |
| tests := []struct { |
| path string |
| value string |
| check func(*FileConfig) bool |
| wantErr bool |
| }{ |
| {"timeouts.actionSec", "60", func(fc *FileConfig) bool { return fc.Timeouts.ActionSec == 60 }, false}, |
| {"timeouts.navigateSec", "120", func(fc *FileConfig) bool { return fc.Timeouts.NavigateSec == 120 }, false}, |
| {"timeouts.shutdownSec", "30", func(fc *FileConfig) bool { return fc.Timeouts.ShutdownSec == 30 }, false}, |
| {"timeouts.waitNavMs", "2000", func(fc *FileConfig) bool { return fc.Timeouts.WaitNavMs == 2000 }, false}, |
| {"timeouts.actionSec", "fast", nil, true}, |
| {"timeouts.unknown", "10", nil, true}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.path+"="+tt.value, func(t *testing.T) { |
| fc := &FileConfig{} |
| err := SetConfigValue(fc, tt.path, tt.value) |
| if (err != nil) != tt.wantErr { |
| t.Errorf("SetConfigValue() error = %v, wantErr %v", err, tt.wantErr) |
| return |
| } |
| if !tt.wantErr && !tt.check(fc) { |
| t.Errorf("SetConfigValue() did not set value correctly") |
| } |
| }) |
| } |
| } |
|
|
| func TestSetConfigValue_InvalidPaths(t *testing.T) { |
| tests := []string{ |
| "port", |
| "", |
| "unknown.field", |
| "server", |
| "a.b.c", |
| } |
|
|
| for _, path := range tests { |
| t.Run(path, func(t *testing.T) { |
| fc := &FileConfig{} |
| err := SetConfigValue(fc, path, "value") |
| if err == nil { |
| t.Errorf("SetConfigValue(%q) should have failed", path) |
| } |
| }) |
| } |
| } |
|
|
| func TestPatchConfigJSON(t *testing.T) { |
| fc := &FileConfig{ |
| Server: ServerConfig{ |
| Port: "9867", |
| Bind: "127.0.0.1", |
| }, |
| InstanceDefaults: InstanceDefaultsConfig{ |
| StealthLevel: "light", |
| }, |
| } |
|
|
| |
| patch := `{"server": {"port": "8080", "token": "secret"}}` |
| if err := PatchConfigJSON(fc, patch); err != nil { |
| t.Fatalf("PatchConfigJSON() error = %v", err) |
| } |
|
|
| if fc.Server.Port != "8080" { |
| t.Errorf("port = %v, want 8080", fc.Server.Port) |
| } |
| if fc.Server.Token != "secret" { |
| t.Errorf("token = %v, want secret", fc.Server.Token) |
| } |
| |
| if fc.Server.Bind != "127.0.0.1" { |
| t.Errorf("bind = %v, want 127.0.0.1 (should be preserved)", fc.Server.Bind) |
| } |
| |
| if fc.InstanceDefaults.StealthLevel != "light" { |
| t.Errorf("stealthLevel = %v, want light (should be preserved)", fc.InstanceDefaults.StealthLevel) |
| } |
| } |
|
|
| func TestPatchConfigJSON_NestedMerge(t *testing.T) { |
| fc := &FileConfig{ |
| InstanceDefaults: InstanceDefaultsConfig{ |
| StealthLevel: "light", |
| TabEvictionPolicy: "reject", |
| }, |
| } |
|
|
| |
| patch := `{"instanceDefaults": {"stealthLevel": "full"}}` |
| if err := PatchConfigJSON(fc, patch); err != nil { |
| t.Fatalf("PatchConfigJSON() error = %v", err) |
| } |
|
|
| if fc.InstanceDefaults.StealthLevel != "full" { |
| t.Errorf("stealthLevel = %v, want full", fc.InstanceDefaults.StealthLevel) |
| } |
| |
| if fc.InstanceDefaults.TabEvictionPolicy != "reject" { |
| t.Errorf("tabEvictionPolicy = %v, want reject (should be preserved)", fc.InstanceDefaults.TabEvictionPolicy) |
| } |
| } |
|
|
| func TestPatchConfigJSON_InvalidJSON(t *testing.T) { |
| fc := &FileConfig{} |
| err := PatchConfigJSON(fc, "not json") |
| if err == nil { |
| t.Error("PatchConfigJSON() should fail on invalid JSON") |
| } |
| } |
|
|
| func TestLoadAndSaveFileConfig(t *testing.T) { |
| tmpDir := t.TempDir() |
| configPath := filepath.Join(tmpDir, "config.json") |
| _ = os.Setenv("PINCHTAB_CONFIG", configPath) |
| defer func() { _ = os.Unsetenv("PINCHTAB_CONFIG") }() |
|
|
| |
| fc, path, err := LoadFileConfig() |
| if err != nil { |
| t.Fatalf("LoadFileConfig() error = %v", err) |
| } |
| if path != configPath { |
| t.Errorf("path = %v, want %v", path, configPath) |
| } |
|
|
| |
| fc.Server.Port = "8080" |
| fc.InstanceDefaults.StealthLevel = "full" |
|
|
| |
| if err := SaveFileConfig(fc, path); err != nil { |
| t.Fatalf("SaveFileConfig() error = %v", err) |
| } |
|
|
| |
| fc2, _, err := LoadFileConfig() |
| if err != nil { |
| t.Fatalf("LoadFileConfig() second time error = %v", err) |
| } |
|
|
| if fc2.Server.Port != "8080" { |
| t.Errorf("loaded port = %v, want 8080", fc2.Server.Port) |
| } |
| if fc2.InstanceDefaults.StealthLevel != "full" { |
| t.Errorf("loaded stealthLevel = %v, want full", fc2.InstanceDefaults.StealthLevel) |
| } |
| } |
|
|
| func TestLoadAndSaveFileConfigPreservesExplicitZeroValues(t *testing.T) { |
| tmpDir := t.TempDir() |
| configPath := filepath.Join(tmpDir, "config.json") |
| _ = os.Setenv("PINCHTAB_CONFIG", configPath) |
| defer func() { _ = os.Unsetenv("PINCHTAB_CONFIG") }() |
|
|
| fc := DefaultFileConfig() |
| fc.Server.Bind = "" |
| fc.Server.Token = "" |
| fc.Browser.ExtensionPaths = []string{} |
| fc.InstanceDefaults.UserAgent = "" |
| fc.Security.IDPI.StrictMode = false |
| fc.Security.IDPI.AllowedDomains = []string{} |
| fc.Security.IDPI.CustomPatterns = []string{} |
|
|
| if err := SaveFileConfig(&fc, configPath); err != nil { |
| t.Fatalf("SaveFileConfig() error = %v", err) |
| } |
|
|
| loaded, _, err := LoadFileConfig() |
| if err != nil { |
| t.Fatalf("LoadFileConfig() error = %v", err) |
| } |
|
|
| if loaded.Server.Bind != "" { |
| t.Errorf("loaded bind = %q, want empty string", loaded.Server.Bind) |
| } |
| if loaded.Security.IDPI.StrictMode { |
| t.Errorf("loaded strictMode = %v, want false", loaded.Security.IDPI.StrictMode) |
| } |
| if len(loaded.Security.IDPI.AllowedDomains) != 0 { |
| t.Errorf("loaded allowedDomains = %v, want empty list", loaded.Security.IDPI.AllowedDomains) |
| } |
| if len(loaded.Browser.ExtensionPaths) != 0 { |
| t.Errorf("loaded extensionPaths = %v, want empty list", loaded.Browser.ExtensionPaths) |
| } |
| } |
|
|
| func TestParseBool(t *testing.T) { |
| tests := []struct { |
| input string |
| want bool |
| wantErr bool |
| }{ |
| {"true", true, false}, |
| {"True", true, false}, |
| {"TRUE", true, false}, |
| {"1", true, false}, |
| {"yes", true, false}, |
| {"on", true, false}, |
| {"false", false, false}, |
| {"False", false, false}, |
| {"0", false, false}, |
| {"no", false, false}, |
| {"off", false, false}, |
| {"maybe", false, true}, |
| {"", false, true}, |
| {"2", false, true}, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.input, func(t *testing.T) { |
| got, err := parseBool(tt.input) |
| if (err != nil) != tt.wantErr { |
| t.Errorf("parseBool(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr) |
| return |
| } |
| if !tt.wantErr && got != tt.want { |
| t.Errorf("parseBool(%q) = %v, want %v", tt.input, got, tt.want) |
| } |
| }) |
| } |
| } |
|
|
| |
|
|
| func TestGetConfigValue_RoundTrip(t *testing.T) { |
| |
| |
| triples := []struct { |
| path string |
| value string |
| want string |
| }{ |
| {"server.port", "8080", "8080"}, |
| {"server.bind", "0.0.0.0", "0.0.0.0"}, |
| {"server.token", "s3cr3t", "s3cr3t"}, |
| {"server.stateDir", "/tmp/state", "/tmp/state"}, |
| {"browser.version", "120.0", "120.0"}, |
| {"browser.binary", "/usr/bin/chrome", "/usr/bin/chrome"}, |
| {"instanceDefaults.mode", "headed", "headed"}, |
| {"instanceDefaults.noRestore", "true", "true"}, |
| {"instanceDefaults.blockImages", "false", "false"}, |
| {"instanceDefaults.blockAds", "1", "true"}, |
| {"instanceDefaults.maxTabs", "50", "50"}, |
| {"instanceDefaults.maxParallelTabs", "8", "8"}, |
| {"instanceDefaults.userAgent", "MyBot/1.0", "MyBot/1.0"}, |
| {"instanceDefaults.stealthLevel", "full", "full"}, |
| {"instanceDefaults.tabEvictionPolicy", "close_lru", "close_lru"}, |
| {"security.allowEvaluate", "true", "true"}, |
| {"security.allowMacro", "false", "false"}, |
| {"security.allowScreencast", "on", "true"}, |
| {"security.allowDownload", "off", "false"}, |
| {"security.allowUpload", "yes", "true"}, |
| {"profiles.baseDir", "/profiles", "/profiles"}, |
| {"profiles.defaultProfile", "agent", "agent"}, |
| {"multiInstance.strategy", "explicit", "explicit"}, |
| {"multiInstance.allocationPolicy", "round_robin", "round_robin"}, |
| {"multiInstance.instancePortStart", "9900", "9900"}, |
| {"multiInstance.instancePortEnd", "9950", "9950"}, |
| {"multiInstance.restart.maxRestarts", "12", "12"}, |
| {"multiInstance.restart.initBackoffSec", "3", "3"}, |
| {"multiInstance.restart.maxBackoffSec", "45", "45"}, |
| {"multiInstance.restart.stableAfterSec", "600", "600"}, |
| {"security.attach.enabled", "true", "true"}, |
| {"security.idpi.enabled", "true", "true"}, |
| {"security.idpi.allowedDomains", "localhost,example.com", "localhost,example.com"}, |
| {"security.idpi.strictMode", "false", "false"}, |
| {"security.idpi.scanContent", "true", "true"}, |
| {"security.idpi.wrapContent", "true", "true"}, |
| {"security.idpi.customPatterns", "ignore previous instructions,exfiltrate", "ignore previous instructions,exfiltrate"}, |
| {"timeouts.actionSec", "60", "60"}, |
| {"timeouts.navigateSec", "90", "90"}, |
| {"timeouts.shutdownSec", "15", "15"}, |
| {"timeouts.waitNavMs", "3000", "3000"}, |
| } |
|
|
| for _, tt := range triples { |
| t.Run(tt.path, func(t *testing.T) { |
| fc := &FileConfig{} |
| if err := SetConfigValue(fc, tt.path, tt.value); err != nil { |
| t.Fatalf("SetConfigValue(%q, %q) error = %v", tt.path, tt.value, err) |
| } |
| got, err := GetConfigValue(fc, tt.path) |
| if err != nil { |
| t.Fatalf("GetConfigValue(%q) error = %v", tt.path, err) |
| } |
| if got != tt.want { |
| t.Errorf("GetConfigValue(%q) = %q, want %q", tt.path, got, tt.want) |
| } |
| }) |
| } |
| } |
|
|
| func TestGetConfigValue_NilPointerReturnsEmpty(t *testing.T) { |
| fc := &FileConfig{} |
| |
| ptrs := []string{ |
| "instanceDefaults.noRestore", |
| "instanceDefaults.blockImages", |
| "instanceDefaults.blockMedia", |
| "instanceDefaults.blockAds", |
| "instanceDefaults.maxTabs", |
| "instanceDefaults.maxParallelTabs", |
| "instanceDefaults.noAnimations", |
| "security.allowEvaluate", |
| "security.allowMacro", |
| "security.allowScreencast", |
| "security.allowDownload", |
| "security.allowUpload", |
| "multiInstance.instancePortStart", |
| "multiInstance.instancePortEnd", |
| "security.attach.enabled", |
| } |
| for _, path := range ptrs { |
| t.Run(path, func(t *testing.T) { |
| got, err := GetConfigValue(fc, path) |
| if err != nil { |
| t.Fatalf("GetConfigValue(%q) unexpected error: %v", path, err) |
| } |
| if got != "" { |
| t.Errorf("GetConfigValue(%q) = %q, want empty string for unset pointer", path, got) |
| } |
| }) |
| } |
| } |
|
|
| func TestGetConfigValue_AttachSlices(t *testing.T) { |
| fc := &FileConfig{} |
| fc.Security.Attach.AllowHosts = []string{"127.0.0.1", "localhost"} |
| fc.Security.Attach.AllowSchemes = []string{"ws", "wss"} |
|
|
| hosts, err := GetConfigValue(fc, "security.attach.allowHosts") |
| if err != nil { |
| t.Fatalf("GetConfigValue(security.attach.allowHosts) error = %v", err) |
| } |
| if hosts != "127.0.0.1,localhost" { |
| t.Errorf("allowHosts = %q, want %q", hosts, "127.0.0.1,localhost") |
| } |
|
|
| schemes, err := GetConfigValue(fc, "security.attach.allowSchemes") |
| if err != nil { |
| t.Fatalf("GetConfigValue(security.attach.allowSchemes) error = %v", err) |
| } |
| if schemes != "ws,wss" { |
| t.Errorf("allowSchemes = %q, want %q", schemes, "ws,wss") |
| } |
| } |
|
|
| func TestGetConfigValue_UnknownPaths(t *testing.T) { |
| fc := &FileConfig{} |
| errorCases := []string{ |
| "port", |
| "", |
| "unknown.field", |
| "server.ghost", |
| "security.attach.badfield", |
| "security.idpi.badfield", |
| } |
| for _, path := range errorCases { |
| t.Run(path, func(t *testing.T) { |
| _, err := GetConfigValue(fc, path) |
| if err == nil { |
| t.Errorf("GetConfigValue(%q) should have returned an error", path) |
| } |
| }) |
| } |
| } |
|
|