login_test.go

  1package tui
  2
  3import (
  4	"testing"
  5
  6	tea "charm.land/bubbletea/v2"
  7)
  8
  9func TestProtocolComboboxCycles(t *testing.T) {
 10	m := NewLogin(true)
 11
 12	// Starts focused on the protocol combobox with the default selection.
 13	if got := m.protocol(); got != "imap" {
 14		t.Fatalf("initial protocol = %q, want imap", got)
 15	}
 16
 17	right := tea.KeyPressMsg{Code: tea.KeyRight}
 18	want := []string{"jmap", "pop3", "maildir", "imap"} // wraps around
 19	for _, w := range want {
 20		model, _ := m.Update(right)
 21		m = model.(*Login)
 22		if got := m.protocol(); got != w {
 23			t.Fatalf("after right, protocol = %q, want %q", got, w)
 24		}
 25	}
 26
 27	// Left cycles backwards, wrapping from imap to maildir.
 28	model, _ := m.Update(tea.KeyPressMsg{Code: tea.KeyLeft})
 29	m = model.(*Login)
 30	if got := m.protocol(); got != "maildir" {
 31		t.Fatalf("after left, protocol = %q, want maildir", got)
 32	}
 33}
 34
 35func TestProtocolComboboxIgnoresTyping(t *testing.T) {
 36	m := NewLogin(true)
 37	// Focused on the protocol field; typed characters must not edit it.
 38	model, _ := m.Update(tea.KeyPressMsg{Code: 'x', Text: "x"})
 39	m = model.(*Login)
 40	if got := m.protocol(); got != "imap" {
 41		t.Fatalf("after typing, protocol = %q, want imap (unchanged)", got)
 42	}
 43}
 44
 45func TestValidPort(t *testing.T) {
 46	tests := []struct {
 47		name     string
 48		input    string
 49		fallback int
 50		want     int
 51	}{
 52		{"empty string returns fallback", "", 993, 993},
 53		{"valid port 993", "993", 143, 993},
 54		{"valid port 1 (minimum)", "1", 993, 1},
 55		{"valid port 65535 (maximum)", "65535", 993, 65535},
 56		{"valid port 587", "587", 25, 587},
 57		{"valid port 995", "995", 110, 995},
 58		{"port 0 is invalid, returns fallback", "0", 993, 993},
 59		{"negative port is invalid", "-1", 993, 993},
 60		{"port over 65535 is invalid", "70000", 993, 993},
 61		{"non-numeric returns fallback", "abc", 993, 993},
 62		{"port with spaces returns fallback", " 993 ", 993, 993},
 63		{"port 8080", "8080", 993, 8080},
 64		{"large negative number", "-99999", 993, 993},
 65		{"very large number", "9999999", 993, 993},
 66	}
 67
 68	for _, tt := range tests {
 69		t.Run(tt.name, func(t *testing.T) {
 70			got := validPort(tt.input, tt.fallback)
 71			if got != tt.want {
 72				t.Errorf("validPort(%q, %d) = %d, want %d", tt.input, tt.fallback, got, tt.want)
 73			}
 74		})
 75	}
 76}
 77
 78func TestValidPortDifferentFallbacks(t *testing.T) {
 79	if got := validPort("", 143); got != 143 {
 80		t.Errorf("empty with fallback 143 = %d, want 143", got)
 81	}
 82	if got := validPort("", 587); got != 587 {
 83		t.Errorf("empty with fallback 587 = %d, want 587", got)
 84	}
 85	if got := validPort("", 995); got != 995 {
 86		t.Errorf("empty with fallback 995 = %d, want 995", got)
 87	}
 88	if got := validPort("bad", 25); got != 25 {
 89		t.Errorf("invalid with fallback 25 = %d, want 25", got)
 90	}
 91}
 92
 93func TestSubmitFormPortValidation(t *testing.T) {
 94	m := NewLogin(true)
 95
 96	tests := []struct {
 97		name     string
 98		portVal  string
 99		want     int
100		fallback int
101	}{
102		{"valid custom port 143", "143", 143, 993},
103		{"invalid port 0 falls back", "0", 993, 993},
104		{"invalid negative port falls back", "-1", 993, 993},
105		{"invalid overflow port falls back", "70000", 993, 993},
106		{"non-numeric port falls back", "abc", 993, 993},
107		{"empty port uses default", "", 993, 993},
108		{"boundary port 1", "1", 1, 993},
109		{"boundary port 65535", "65535", 65535, 993},
110	}
111
112	for _, tt := range tests {
113		t.Run(tt.name, func(t *testing.T) {
114			m.inputs[inputIMAPPort].SetValue(tt.portVal)
115			fn := m.submitForm()
116			msg := fn().(Credentials)
117			if msg.IMAPPort != tt.want {
118				t.Errorf("IMAPPort for input %q = %d, want %d", tt.portVal, msg.IMAPPort, tt.want)
119			}
120		})
121	}
122}