package ssh import ( "testing" ) func TestParse_BareHostname(t *testing.T) { got := Parse([]string{"myhost"}) assertParsed(t, got, "myhost", "", 0) } func TestParse_UserAtHost(t *testing.T) { got := Parse([]string{"admin@myhost"}) assertParsed(t, got, "myhost", "admin", 0) } func TestParse_PortFlag_Separated(t *testing.T) { got := Parse([]string{"-p", "2222", "myhost"}) assertParsed(t, got, "myhost", "", 2) } func TestParse_PortFlag_Attached(t *testing.T) { got := Parse([]string{"-p2222", "myhost"}) assertParsed(t, got, "myhost", "", 1) } func TestParse_IdentityFlag(t *testing.T) { got := Parse([]string{"-i", "/path/to/key", "user@myhost", "ls"}) assertParsed(t, got, "myhost", "user", 2) } func TestParse_VerboseFlag(t *testing.T) { got := Parse([]string{"-v", "myhost"}) assertParsed(t, got, "myhost", "", 1) } func TestParse_OptionFlag(t *testing.T) { got := Parse([]string{"-o", "StrictHostKeyChecking=no", "myhost"}) assertParsed(t, got, "myhost", "", 2) } func TestParse_JumpHost(t *testing.T) { got := Parse([]string{"-J", "jumphost", "-p", "22", "target"}) assertParsed(t, got, "target", "", 4) } func TestParse_MultipleFlags(t *testing.T) { got := Parse([]string{"-v", "-p", "22", "-i", "key", "root@host", "uptime"}) assertParsed(t, got, "host", "root", 5) } func TestParse_DoubleDash(t *testing.T) { got := Parse([]string{"--", "myhost"}) assertParsed(t, got, "myhost", "", 1) } func TestParse_DoubleDash_WithFlags(t *testing.T) { // flags after -- should be treated as destination got := Parse([]string{"-v", "--", "-not-a-flag"}) assertParsed(t, got, "-not-a-flag", "", 2) } func TestParse_NoDestination(t *testing.T) { got := Parse([]string{"-v", "-p", "2222"}) if got != nil { t.Errorf("expected nil for args without destination, got %+v", got) } } func TestParse_EmptyArgs(t *testing.T) { got := Parse([]string{}) if got != nil { t.Error("empty args should return nil") } } func TestParse_OnlyDoubleDash(t *testing.T) { got := Parse([]string{"--"}) if got != nil { t.Error("only -- with no destination should return nil") } } func TestReplaceHost_PlainHost(t *testing.T) { args := []string{"myhost"} result := ReplaceHost(args, 0, "10.0.0.1") if result[0] != "10.0.0.1" { t.Errorf("got %q, want %q", result[0], "10.0.0.1") } } func TestReplaceHost_PreservesUserPrefix(t *testing.T) { args := []string{"-p", "22", "admin@myhost", "ls"} result := ReplaceHost(args, 2, "10.0.0.1") if result[2] != "admin@10.0.0.1" { t.Errorf("got %q, want %q", result[2], "admin@10.0.0.1") } } func TestReplaceHost_DoesNotMutateOriginal(t *testing.T) { args := []string{"myhost"} _ = ReplaceHost(args, 0, "10.0.0.1") if args[0] != "myhost" { t.Error("ReplaceHost must not mutate the original slice") } } func TestReplaceHost_OtherArgsUnchanged(t *testing.T) { args := []string{"-p", "22", "myhost"} result := ReplaceHost(args, 2, "10.0.0.1") if result[0] != "-p" || result[1] != "22" { t.Errorf("other args should be unchanged: %v", result) } } func TestHasUserFlag_FlagSeparated(t *testing.T) { if !HasUserFlag([]string{"-l", "admin", "host"}) { t.Error("should detect -l ") } } func TestHasUserFlag_FlagAttached(t *testing.T) { if !HasUserFlag([]string{"-ladmin", "host"}) { t.Error("should detect -l (attached form)") } } func TestHasUserFlag_NotPresent(t *testing.T) { if HasUserFlag([]string{"-p", "22", "host"}) { t.Error("should not detect user flag when absent") } } func TestHasUserFlag_EmptyArgs(t *testing.T) { if HasUserFlag([]string{}) { t.Error("empty args should return false") } } func TestHasUserFlag_LFlagAtEnd(t *testing.T) { // -l at the very end with no value — should not panic if HasUserFlag([]string{"-l"}) { t.Error("-l with no value should return false") } } func assertParsed(t *testing.T, got *ParsedArgs, host, user string, destIdx int) { t.Helper() if got == nil { t.Fatal("Parse returned nil") } if got.Host != host { t.Errorf("host: got %q, want %q", got.Host, host) } if got.User != user { t.Errorf("user: got %q, want %q", got.User, user) } if got.DestIdx != destIdx { t.Errorf("destIdx: got %d, want %d", got.DestIdx, destIdx) } }