package main import ( "bufio" "bytes" "errors" "slices" "strings" "testing" ) func TestCleanInput(t *testing.T) { t.Parallel() cases := []struct { name string input string expected []string }{ { name: "it should split words at whitepspace", input: "stevan reece freeborn", expected: []string{"stevan", "reece", "freeborn"}, }, { name: "it should trim leading and or training whitespace", input: " hello world ", expected: []string{"hello", "world"}, }, { name: "it should normalize words to lowercase", input: "got to catch them ALL", expected: []string{"got", "to", "catch", "them", "all"}, }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { t.Parallel() result := cleanInput(c.input) if slices.Equal(result, c.expected) { return } t.Errorf("received %v but expected %v", result, c.expected) }) } } type erroringInputScanner struct { timesCalled int } func (m *erroringInputScanner) Err() error { if m.timesCalled == 0 { m.timesCalled += 1 return errors.New("oh no!") } return nil } func (m *erroringInputScanner) Text() string { return "" } func (m *erroringInputScanner) Scan() bool { return true } func TestRunRepl(t *testing.T) { t.Parallel() cases := []struct { name string input string expected string getScanner func(*strings.Reader) inputScanner sanitizer func(string) []string }{ { name: "it should print custom prompt", input: "", expected: "Pokedex > ", getScanner: func(r *strings.Reader) inputScanner { return bufio.NewScanner(r) }, sanitizer: cleanInput, }, { name: "it should print appropriate error message when scan fails", input: "", expected: "Pokedex > Sorry I didn't get that.", getScanner: func(r *strings.Reader) inputScanner { return &erroringInputScanner{} }, sanitizer: cleanInput, }, { name: "it should print appropriate error message when sanitizer returns no words", input: "Hi! my command is hello\n", expected: "Pokedex > Sorry I couldn't understand that.", getScanner: func(r *strings.Reader) inputScanner { return bufio.NewScanner(r) }, sanitizer: func(s string) []string { return []string{} }, }, { name: "it should print expected message for unknown command", input: "STFU please\n", expected: "Unknown command", getScanner: func(r *strings.Reader) inputScanner { return bufio.NewScanner(r) }, sanitizer: cleanInput, }, // TODO: Need to refactor after considering os.exit call // { // name: "it should execute command if found", // input: "EXIT\n", // expected: "Closing the Pokedex... Goodbye!\n", // getScanner: func(r *strings.Reader) inputScanner { // return bufio.NewScanner(r) // }, // sanitizer: cleanInput, // }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { t.Parallel() in := strings.NewReader(c.input) out := new(bytes.Buffer) runREPL(c.getScanner(in), out, c.sanitizer) result := out.String() if strings.Contains(result, c.expected) { return } t.Errorf("expected %q to contain %q", result, c.expected) }) } }