sshm/internal/history/parser_test.go
Gu1llaum-3 167e4c0a09 feat: add SSH connection history with Ctrl+H navigation
Track SSH connections (configured + manual) with searchable history view.
Press Ctrl+H to view history, Ctrl+L to return. Add manual connections
to config with 'a'.

- Parse and store manual SSH connections
- History TUI with search and filtering
- Connection count and timestamps
2025-10-15 21:10:38 +02:00

278 lines
6.2 KiB
Go

package history
import (
"testing"
)
func TestParseSSHArgs(t *testing.T) {
tests := []struct {
name string
args []string
wantConn *ManualConnection
wantOk bool
}{
{
name: "user@host",
args: []string{"user@example.com"},
wantConn: &ManualConnection{
User: "user",
Hostname: "example.com",
Port: "22",
},
wantOk: true,
},
{
name: "user@host with -p port",
args: []string{"-p", "2222", "user@example.com"},
wantConn: &ManualConnection{
User: "user",
Hostname: "example.com",
Port: "2222",
},
wantOk: true,
},
{
name: "user@host with -p2222 (no space)",
args: []string{"-p2222", "user@example.com"},
wantConn: &ManualConnection{
User: "user",
Hostname: "example.com",
Port: "2222",
},
wantOk: true,
},
{
name: "user@host with -i identity",
args: []string{"-i", "~/.ssh/id_rsa", "user@example.com"},
wantConn: &ManualConnection{
User: "user",
Hostname: "example.com",
Port: "22",
Identity: "~/.ssh/id_rsa",
},
wantOk: true,
},
{
name: "complete connection",
args: []string{"-p", "2222", "-i", "~/.ssh/id_rsa", "guillaume@127.0.0.1"},
wantConn: &ManualConnection{
User: "guillaume",
Hostname: "127.0.0.1",
Port: "2222",
Identity: "~/.ssh/id_rsa",
},
wantOk: true,
},
{
name: "just hostname (no user)",
args: []string{"example.com"},
wantConn: &ManualConnection{
Hostname: "example.com",
Port: "22",
// User will be current system user, so we don't check it
},
wantOk: true,
},
{
name: "config file args should return false",
args: []string{"-F", "~/.ssh/config", "host"},
wantConn: nil,
wantOk: false,
},
{
name: "empty args",
args: []string{},
wantConn: nil,
wantOk: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotConn, gotOk := ParseSSHArgs(tt.args)
if gotOk != tt.wantOk {
t.Errorf("ParseSSHArgs() gotOk = %v, want %v", gotOk, tt.wantOk)
return
}
if !tt.wantOk {
if gotConn != nil {
t.Errorf("ParseSSHArgs() gotConn = %v, want nil", gotConn)
}
return
}
if gotConn == nil {
t.Errorf("ParseSSHArgs() gotConn = nil, want non-nil")
return
}
if gotConn.User != tt.wantConn.User {
// Skip user check if wantConn.User is empty (current user)
if tt.wantConn.User != "" {
t.Errorf("ParseSSHArgs() User = %v, want %v", gotConn.User, tt.wantConn.User)
}
}
if gotConn.Hostname != tt.wantConn.Hostname {
t.Errorf("ParseSSHArgs() Hostname = %v, want %v", gotConn.Hostname, tt.wantConn.Hostname)
}
if gotConn.Port != tt.wantConn.Port {
t.Errorf("ParseSSHArgs() Port = %v, want %v", gotConn.Port, tt.wantConn.Port)
}
if gotConn.Identity != tt.wantConn.Identity {
t.Errorf("ParseSSHArgs() Identity = %v, want %v", gotConn.Identity, tt.wantConn.Identity)
}
})
}
}
func TestIsManualSSHCommand(t *testing.T) {
tests := []struct {
name string
args []string
want bool
}{
{
name: "user@host is manual",
args: []string{"user@example.com"},
want: true,
},
{
name: "with -p flag is manual",
args: []string{"-p", "2222", "host"},
want: true,
},
{
name: "with -p2222 is manual",
args: []string{"-p2222", "host"},
want: true,
},
{
name: "just hostname is not manual",
args: []string{"myhost"},
want: false,
},
{
name: "empty is not manual",
args: []string{},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsManualSSHCommand(tt.args); got != tt.want {
t.Errorf("IsManualSSHCommand() = %v, want %v", got, tt.want)
}
})
}
}
func TestManualConnectionID(t *testing.T) {
tests := []struct {
name string
conn ManualConnection
wantHostID string
wantUser string
wantHostname string
wantPort string
}{
{
name: "complete connection",
conn: ManualConnection{
User: "guillaume",
Hostname: "127.0.0.1",
Port: "2222",
Identity: "~/.ssh/id_rsa",
},
wantHostID: "manual:guillaume@127.0.0.1:2222",
wantUser: "guillaume",
wantHostname: "127.0.0.1",
wantPort: "2222",
},
{
name: "default port",
conn: ManualConnection{
User: "user",
Hostname: "example.com",
Port: "",
},
wantHostID: "manual:user@example.com:22",
wantUser: "user",
wantHostname: "example.com",
wantPort: "22",
},
{
name: "no user specified",
conn: ManualConnection{
Hostname: "example.com",
Port: "2222",
},
wantHostID: "manual:default@example.com:2222",
wantUser: "default",
wantHostname: "example.com",
wantPort: "2222",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Test generation
gotHostID := generateManualHostID(tt.conn)
if gotHostID != tt.wantHostID {
t.Errorf("generateManualHostID() = %v, want %v", gotHostID, tt.wantHostID)
}
// Test IsManualConnection
if !IsManualConnection(gotHostID) {
t.Errorf("IsManualConnection(%v) = false, want true", gotHostID)
}
// Test parsing
user, hostname, port, ok := ParseManualConnectionID(gotHostID)
if !ok {
t.Errorf("ParseManualConnectionID() ok = false, want true")
}
if user != tt.wantUser {
t.Errorf("ParseManualConnectionID() user = %v, want %v", user, tt.wantUser)
}
if hostname != tt.wantHostname {
t.Errorf("ParseManualConnectionID() hostname = %v, want %v", hostname, tt.wantHostname)
}
if port != tt.wantPort {
t.Errorf("ParseManualConnectionID() port = %v, want %v", port, tt.wantPort)
}
})
}
}
func TestParseManualConnectionID_Invalid(t *testing.T) {
tests := []struct {
name string
hostID string
}{
{
name: "not a manual connection",
hostID: "myhost",
},
{
name: "missing components",
hostID: "manual:invalid",
},
{
name: "no @ sign",
hostID: "manual:hostname:22",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, _, _, ok := ParseManualConnectionID(tt.hostID)
if ok {
t.Errorf("ParseManualConnectionID() ok = true, want false for invalid input")
}
})
}
}