package prompter import ( "fmt" "strings" "testing" "github.com/stretchr/testify/assert" ) // Test helpers func IndexFor(options []string, answer string) (int, error) { for ix, a := range options { if a == answer { return ix, nil } } return -1, NoSuchAnswerErr(answer) } func AssertOptions(t *testing.T, expected, actual []string) { assert.Equal(t, expected, actual) } func NoSuchAnswerErr(answer string) error { return fmt.Errorf("no such answer '%s'", answer) } func NoSuchPromptErr(prompt string) error { return fmt.Errorf("no such prompt '%s'", prompt) } type SelectStub struct { Prompt string ExpectedOpts []string Fn func(string, string, []string) (int, error) } type InputStub struct { Prompt string Fn func(string, string) (string, error) } type ConfirmStub struct { Prompt string Fn func(string, bool) (bool, error) } type MultiSelectStub struct { Prompt string ExpectedOpts []string Fn func(string, []string, []string) ([]int, error) } type InputHostnameStub struct { Fn func() (string, error) } type PasswordStub struct { Prompt string Fn func(string) (string, error) } type AuthTokenStub struct { Fn func() (string, error) } type ConfirmDeletionStub struct { Prompt string Fn func(string) error } type MockPrompter struct { PrompterMock t *testing.T SelectStubs []SelectStub InputStubs []InputStub ConfirmStubs []ConfirmStub MultiSelectStubs []MultiSelectStub InputHostnameStubs []InputHostnameStub PasswordStubs []PasswordStub AuthTokenStubs []AuthTokenStub ConfirmDeletionStubs []ConfirmDeletionStub } func NewMockPrompter(t *testing.T) *MockPrompter { m := &MockPrompter{ t: t, SelectStubs: []SelectStub{}, InputStubs: []InputStub{}, ConfirmStubs: []ConfirmStub{}, MultiSelectStubs: []MultiSelectStub{}, InputHostnameStubs: []InputHostnameStub{}, PasswordStubs: []PasswordStub{}, AuthTokenStubs: []AuthTokenStub{}, ConfirmDeletionStubs: []ConfirmDeletionStub{}, } t.Cleanup(m.Verify) m.SelectFunc = func(p, d string, opts []string) (int, error) { var s SelectStub if len(m.SelectStubs) > 0 { s = m.SelectStubs[0] m.SelectStubs = m.SelectStubs[1:len(m.SelectStubs)] } else { return -1, NoSuchPromptErr(p) } if s.Prompt != p { return -1, NoSuchPromptErr(p) } AssertOptions(m.t, s.ExpectedOpts, opts) return s.Fn(p, d, opts) } m.MultiSelectFunc = func(p string, d, opts []string) ([]int, error) { var s MultiSelectStub if len(m.MultiSelectStubs) > 0 { s = m.MultiSelectStubs[0] m.MultiSelectStubs = m.MultiSelectStubs[1:len(m.MultiSelectStubs)] } else { return []int{}, NoSuchPromptErr(p) } if s.Prompt != p { return []int{}, NoSuchPromptErr(p) } AssertOptions(m.t, s.ExpectedOpts, opts) return s.Fn(p, d, opts) } m.InputFunc = func(p, d string) (string, error) { var s InputStub if len(m.InputStubs) > 0 { s = m.InputStubs[0] m.InputStubs = m.InputStubs[1:len(m.InputStubs)] } else { return "", NoSuchPromptErr(p) } if s.Prompt != p { return "", NoSuchPromptErr(p) } return s.Fn(p, d) } m.ConfirmFunc = func(p string, d bool) (bool, error) { var s ConfirmStub if len(m.ConfirmStubs) > 0 { s = m.ConfirmStubs[0] m.ConfirmStubs = m.ConfirmStubs[1:len(m.ConfirmStubs)] } else { return false, NoSuchPromptErr(p) } if s.Prompt != p { return false, NoSuchPromptErr(p) } return s.Fn(p, d) } m.InputHostnameFunc = func() (string, error) { var s InputHostnameStub if len(m.InputHostnameStubs) > 0 { s = m.InputHostnameStubs[0] m.InputHostnameStubs = m.InputHostnameStubs[1:len(m.InputHostnameStubs)] } else { return "", NoSuchPromptErr("InputHostname") } return s.Fn() } m.PasswordFunc = func(p string) (string, error) { var s PasswordStub if len(m.PasswordStubs) > 0 { s = m.PasswordStubs[0] m.PasswordStubs = m.PasswordStubs[1:len(m.PasswordStubs)] } else { return "", NoSuchPromptErr(p) } if s.Prompt != p { return "", NoSuchPromptErr(p) } return s.Fn(p) } m.AuthTokenFunc = func() (string, error) { var s AuthTokenStub if len(m.AuthTokenStubs) > 0 { s = m.AuthTokenStubs[0] m.AuthTokenStubs = m.AuthTokenStubs[1:len(m.AuthTokenStubs)] } else { return "", NoSuchPromptErr("AuthToken") } return s.Fn() } m.ConfirmDeletionFunc = func(p string) error { var s ConfirmDeletionStub if len(m.ConfirmDeletionStubs) > 0 { s = m.ConfirmDeletionStubs[0] m.ConfirmDeletionStubs = m.ConfirmDeletionStubs[1:len(m.ConfirmDeletionStubs)] } else { return NoSuchPromptErr("ConfirmDeletion") } return s.Fn(p) } // TODO MarkdownEditor(string, string, bool) (string, error) return m } func (m *MockPrompter) RegisterSelect(prompt string, opts []string, stub func(_, _ string, _ []string) (int, error)) { m.SelectStubs = append(m.SelectStubs, SelectStub{ Prompt: prompt, ExpectedOpts: opts, Fn: stub}) } func (m *MockPrompter) RegisterMultiSelect(prompt string, d, opts []string, stub func(_ string, _, _ []string) ([]int, error)) { m.MultiSelectStubs = append(m.MultiSelectStubs, MultiSelectStub{ Prompt: prompt, ExpectedOpts: opts, Fn: stub}) } func (m *MockPrompter) RegisterInput(prompt string, stub func(_, _ string) (string, error)) { m.InputStubs = append(m.InputStubs, InputStub{Prompt: prompt, Fn: stub}) } func (m *MockPrompter) RegisterConfirm(prompt string, stub func(_ string, _ bool) (bool, error)) { m.ConfirmStubs = append(m.ConfirmStubs, ConfirmStub{Prompt: prompt, Fn: stub}) } func (m *MockPrompter) RegisterInputHostname(stub func() (string, error)) { m.InputHostnameStubs = append(m.InputHostnameStubs, InputHostnameStub{Fn: stub}) } func (m *MockPrompter) RegisterPassword(prompt string, stub func(string) (string, error)) { m.PasswordStubs = append(m.PasswordStubs, PasswordStub{Fn: stub}) } func (m *MockPrompter) RegisterConfirmDeletion(prompt string, stub func(string) error) { m.ConfirmDeletionStubs = append(m.ConfirmDeletionStubs, ConfirmDeletionStub{Prompt: prompt, Fn: stub}) } func (m *MockPrompter) Verify() { errs := []string{} if len(m.SelectStubs) > 0 { errs = append(errs, "Select") } if len(m.InputStubs) > 0 { errs = append(errs, "Input") } if len(m.ConfirmStubs) > 0 { errs = append(errs, "Confirm") } // TODO other prompt types if len(errs) > 0 { m.t.Helper() m.t.Errorf("%d unmatched calls to %s", len(errs), strings.Join(errs, ",")) } }