4a8b4a2bc4
- Add test/crypto/ (19 tests): AES-256-GCM encrypt/decrypt, PBKDF2, IsEncrypted, HashPassword - Add test/knownhosts/ (14 tests): TOFU verify, MITM detection, CRUD, persistence - Add test/storage/ (20 tests): KeyPair/Snippet CRUD, encryption, MergeStrategy - Add test/config/ (9 tests): config lifecycle, path getters - Add test/tui/ (10 tests): WrapFooter, ClampWidth, TruncateStr - Fix knownhosts deadlock: Add/Remove use saveInternal() - Export responsive.go functions for testing - Add docs/TEST_PLAN.md with full scenario documentation Coverage: crypto 0%→100%, knownhosts 0%→100%, storage 40%→90%, config 22%→80%, tui 40%→70%
189 lines
4.4 KiB
Go
189 lines
4.4 KiB
Go
package config_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"git.tukangketik.id/swanadiva/hostkeeper/pkg/config"
|
|
)
|
|
|
|
func tempDir(t *testing.T) string {
|
|
t.Helper()
|
|
dir, err := os.MkdirTemp("", "config-test-*")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp dir: %v", err)
|
|
}
|
|
t.Cleanup(func() { os.RemoveAll(dir) })
|
|
return dir
|
|
}
|
|
|
|
// 4.1 New first run — creates default config
|
|
func TestNewFirstRun(t *testing.T) {
|
|
dir := tempDir(t)
|
|
|
|
// Override HOME to use temp dir
|
|
origHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", dir)
|
|
defer os.Setenv("HOME", origHome)
|
|
|
|
cfg, err := config.New()
|
|
if err != nil {
|
|
t.Fatalf("New failed: %v", err)
|
|
}
|
|
if cfg == nil {
|
|
t.Fatal("New should return non-nil Config")
|
|
}
|
|
|
|
appCfg := cfg.GetAppConfig()
|
|
if appCfg == nil {
|
|
t.Fatal("GetAppConfig should return non-nil")
|
|
}
|
|
if appCfg.Version != "1.0.0" {
|
|
t.Errorf("Version = %q, want %q", appCfg.Version, "1.0.0")
|
|
}
|
|
if appCfg.Theme != "dark" {
|
|
t.Errorf("Theme = %q, want %q", appCfg.Theme, "dark")
|
|
}
|
|
}
|
|
|
|
// 4.3 Save
|
|
func TestSave(t *testing.T) {
|
|
dir := tempDir(t)
|
|
origHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", dir)
|
|
defer os.Setenv("HOME", origHome)
|
|
|
|
cfg, _ := config.New()
|
|
appCfg := cfg.GetAppConfig()
|
|
appCfg.Theme = "light"
|
|
|
|
err := cfg.Save()
|
|
if err != nil {
|
|
t.Fatalf("Save failed: %v", err)
|
|
}
|
|
|
|
// Reload and verify
|
|
cfg2, _ := config.New()
|
|
if cfg2.GetAppConfig().Theme != "light" {
|
|
t.Errorf("After Save, Theme = %q, want %q", cfg2.GetAppConfig().Theme, "light")
|
|
}
|
|
}
|
|
|
|
// 4.4 UpdateAppConfig
|
|
func TestUpdateAppConfig(t *testing.T) {
|
|
dir := tempDir(t)
|
|
origHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", dir)
|
|
defer os.Setenv("HOME", origHome)
|
|
|
|
cfg, _ := config.New()
|
|
appCfg := cfg.GetAppConfig()
|
|
appCfg.Theme = "dracula"
|
|
appCfg.DefaultPort = 2222
|
|
|
|
err := cfg.UpdateAppConfig(appCfg)
|
|
if err != nil {
|
|
t.Fatalf("UpdateAppConfig failed: %v", err)
|
|
}
|
|
|
|
// Reload and verify
|
|
cfg2, _ := config.New()
|
|
if cfg2.GetAppConfig().Theme != "dracula" {
|
|
t.Errorf("After UpdateAppConfig, Theme = %q, want %q", cfg2.GetAppConfig().Theme, "dracula")
|
|
}
|
|
if cfg2.GetAppConfig().DefaultPort != 2222 {
|
|
t.Errorf("After UpdateAppConfig, DefaultPort = %d, want 2222", cfg2.GetAppConfig().DefaultPort)
|
|
}
|
|
}
|
|
|
|
// 4.5 GetConfigDir
|
|
func TestGetConfigDir(t *testing.T) {
|
|
dir := tempDir(t)
|
|
origHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", dir)
|
|
defer os.Setenv("HOME", origHome)
|
|
|
|
cfg, _ := config.New()
|
|
configDir := cfg.GetConfigDir()
|
|
if configDir == "" {
|
|
t.Error("GetConfigDir should return non-empty path")
|
|
}
|
|
if !filepath.IsAbs(configDir) {
|
|
t.Errorf("GetConfigDir should return absolute path, got %q", configDir)
|
|
}
|
|
}
|
|
|
|
// 4.6 GetDataDir
|
|
func TestGetDataDir(t *testing.T) {
|
|
dir := tempDir(t)
|
|
origHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", dir)
|
|
defer os.Setenv("HOME", origHome)
|
|
|
|
cfg, _ := config.New()
|
|
dataDir := cfg.GetDataDir()
|
|
if dataDir == "" {
|
|
t.Error("GetDataDir should return non-empty path")
|
|
}
|
|
if !filepath.IsAbs(dataDir) {
|
|
t.Errorf("GetDataDir should return absolute path, got %q", dataDir)
|
|
}
|
|
}
|
|
|
|
// 4.7 GetConfigFilePath
|
|
func TestGetConfigFilePath(t *testing.T) {
|
|
dir := tempDir(t)
|
|
origHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", dir)
|
|
defer os.Setenv("HOME", origHome)
|
|
|
|
cfg, _ := config.New()
|
|
path := cfg.GetConfigFilePath()
|
|
if filepath.Base(path) != "config.json" {
|
|
t.Errorf("GetConfigFilePath should end with config.json, got %q", path)
|
|
}
|
|
}
|
|
|
|
// 4.8 GetHostsFilePath
|
|
func TestGetHostsFilePath(t *testing.T) {
|
|
dir := tempDir(t)
|
|
origHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", dir)
|
|
defer os.Setenv("HOME", origHome)
|
|
|
|
cfg, _ := config.New()
|
|
path := cfg.GetHostsFilePath()
|
|
if filepath.Base(path) != "hosts.json" {
|
|
t.Errorf("GetHostsFilePath should end with hosts.json, got %q", path)
|
|
}
|
|
}
|
|
|
|
// 4.9 GetKeysFilePath
|
|
func TestGetKeysFilePath(t *testing.T) {
|
|
dir := tempDir(t)
|
|
origHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", dir)
|
|
defer os.Setenv("HOME", origHome)
|
|
|
|
cfg, _ := config.New()
|
|
path := cfg.GetKeysFilePath()
|
|
if filepath.Base(path) != "keys.json" {
|
|
t.Errorf("GetKeysFilePath should end with keys.json, got %q", path)
|
|
}
|
|
}
|
|
|
|
// 4.10 GetSnippetsFilePath
|
|
func TestGetSnippetsFilePath(t *testing.T) {
|
|
dir := tempDir(t)
|
|
origHome := os.Getenv("HOME")
|
|
os.Setenv("HOME", dir)
|
|
defer os.Setenv("HOME", origHome)
|
|
|
|
cfg, _ := config.New()
|
|
path := cfg.GetSnippetsFilePath()
|
|
if filepath.Base(path) != "snippets.json" {
|
|
t.Errorf("GetSnippetsFilePath should end with snippets.json, got %q", path)
|
|
}
|
|
}
|