package tui import ( "testing" tea "github.com/charmbracelet/bubbletea" "git.dcglab.co.uk/steve/emcli/internal/store" ) func validFields() Fields { return Fields{ Name: "work", Mode: "RW", IMAPHost: "imap.x.com", IMAPPort: "993", IMAPSecurity: "tls", SMTPHost: "smtp.x.com", SMTPPort: "465", SMTPSecurity: "tls", Username: "u@x.com", Password: "pw", } } func TestFieldsValidateRequired(t *testing.T) { f := validFields() f.Name = "" if err := f.Validate(); err == nil { t.Fatal("missing name must fail validation") } f = validFields() f.Username = "" if err := f.Validate(); err == nil { t.Fatal("missing username must fail validation") } f = validFields() f.IMAPHost = "" if err := f.Validate(); err == nil { t.Fatal("missing imap host must fail validation") } } func TestFieldsValidateEnums(t *testing.T) { f := validFields() f.Mode = "XX" if err := f.Validate(); err == nil { t.Fatal("mode must be RO or RW") } f = validFields() f.IMAPSecurity = "ssl" if err := f.Validate(); err == nil { t.Fatal("security must be tls or starttls") } f = validFields() f.IMAPPort = "notnum" if err := f.Validate(); err == nil { t.Fatal("port must be numeric") } } func TestFieldsValidateRWNeedsSMTP(t *testing.T) { f := validFields() f.SMTPHost = "" if err := f.Validate(); err == nil { t.Fatal("RW account requires an SMTP host") } // RO without SMTP is fine. f = validFields() f.Mode = "RO" f.SMTPHost, f.SMTPPort, f.SMTPSecurity = "", "", "" if err := f.Validate(); err != nil { t.Fatalf("RO without SMTP should validate: %v", err) } } func TestFieldsToAccount(t *testing.T) { f := validFields() f.WhitelistIn = true f.SubjectRegex = "^urgent" acc, pwSet := f.ToAccount() if !pwSet { t.Fatal("password was provided, PasswordSet should be true") } if acc.Name != "work" || acc.Mode != "RW" || acc.IMAPPort != 993 || acc.SMTPPort != 465 { t.Fatalf("account not assembled: %+v", acc) } if acc.AuthType != "password" || !acc.WhitelistInEnabled || acc.SubjectRegex != "^urgent" { t.Fatalf("account flags wrong: %+v", acc) } if acc.Password != "pw" { t.Fatalf("password not carried: %q", acc.Password) } } func TestFieldsToAccountBlankPassword(t *testing.T) { f := validFields() f.Password = "" _, pwSet := f.ToAccount() if pwSet { t.Fatal("blank password should report PasswordSet=false (edit keeps existing)") } } func TestFieldsFromAccountRoundTrip(t *testing.T) { a := store.Account{ Name: "g", Mode: "RW", IMAPHost: "i", IMAPPort: 993, IMAPSecurity: "tls", SMTPHost: "s", SMTPPort: 587, SMTPSecurity: "starttls", Username: "u@x.com", WhitelistOutEnabled: true, SubjectRegex: "re:", } f := FieldsFromAccount(a) if f.Name != "g" || f.IMAPPort != "993" || f.SMTPPort != "587" || !f.WhitelistOut || f.SubjectRegex != "re:" { t.Fatalf("FieldsFromAccount wrong: %+v", f) } // Password is never read back from an account. if f.Password != "" { t.Fatalf("password must not be prefilled: %q", f.Password) } } func TestAccountFormSubmitValid(t *testing.T) { m := NewAccountForm(validFields(), false) // Enter submits; with valid fields the form completes. nm, _ := m.Update(tea.KeyMsg{Type: tea.KeyEnter}) m = nm.(AccountForm) if !m.Done() || m.Cancelled() { t.Fatalf("valid submit should be Done, not cancelled (err=%v)", m.Err()) } if m.Account().Name != "work" { t.Fatalf("submitted account wrong: %+v", m.Account()) } } func TestAccountFormSubmitInvalidStays(t *testing.T) { f := validFields() f.Name = "" m := NewAccountForm(f, false) nm, _ := m.Update(tea.KeyMsg{Type: tea.KeyEnter}) m = nm.(AccountForm) if m.Done() { t.Fatal("invalid submit must not complete the form") } if m.Err() == nil { t.Fatal("invalid submit should set an error to show the user") } } func TestAccountFormCancel(t *testing.T) { m := NewAccountForm(validFields(), false) nm, _ := m.Update(tea.KeyMsg{Type: tea.KeyEsc}) m = nm.(AccountForm) if !m.Cancelled() { t.Fatal("esc should cancel the form") } }