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:
@@ -72,9 +72,14 @@ func (kh *KnownHosts) load() error {
|
||||
|
||||
// Save writes the known_hosts file
|
||||
func (kh *KnownHosts) Save() error {
|
||||
kh.mu.RLock()
|
||||
defer kh.mu.RUnlock()
|
||||
kh.mu.Lock()
|
||||
defer kh.mu.Unlock()
|
||||
|
||||
return kh.saveInternal()
|
||||
}
|
||||
|
||||
// saveInternal writes the known_hosts file without locking (caller must hold lock)
|
||||
func (kh *KnownHosts) saveInternal() error {
|
||||
var hosts []*HostKey
|
||||
for _, h := range kh.hosts {
|
||||
hosts = append(hosts, h)
|
||||
@@ -124,7 +129,7 @@ func (kh *KnownHosts) Add(hostname string, port int, remoteKey cryptossh.PublicK
|
||||
AddedAt: time.Now(),
|
||||
}
|
||||
|
||||
return kh.Save()
|
||||
return kh.saveInternal()
|
||||
}
|
||||
|
||||
// Remove removes a host key
|
||||
@@ -135,7 +140,7 @@ func (kh *KnownHosts) Remove(hostname string, port int) error {
|
||||
key := fmt.Sprintf("%s:%d", hostname, port)
|
||||
delete(kh.hosts, key)
|
||||
|
||||
return kh.Save()
|
||||
return kh.saveInternal()
|
||||
}
|
||||
|
||||
// Get returns the stored host key for a given host
|
||||
|
||||
@@ -106,3 +106,20 @@ func truncateStr(s string, maxLen int) string {
|
||||
}
|
||||
return string(result) + "…"
|
||||
}
|
||||
|
||||
// Exported wrappers for testing
|
||||
|
||||
// WrapFooter wraps a footer string into multiple lines that fit availW
|
||||
func WrapFooter(text string, availW int) string {
|
||||
return wrapFooter(text, availW)
|
||||
}
|
||||
|
||||
// ClampWidth clamps a target box width to fit within the terminal
|
||||
func ClampWidth(target, termWidth int) int {
|
||||
return clampWidth(target, termWidth)
|
||||
}
|
||||
|
||||
// TruncateStr truncates a string to maxLen with an ellipsis character
|
||||
func TruncateStr(s string, maxLen int) string {
|
||||
return truncateStr(s, maxLen)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user