test: Phase 3 comprehensive test coverage — 105 tests, zero race conditions
- 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%
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user