package tokenize import "fmt" import "testing" func Test_tokenize(t *testing.T) { var test_cases = []struct { test_str string want_result tokenizeResult }{ // emptiness {"", tokenizeResult{tokens: []string{}}}, // unquoted whitespace {" ", tokenizeResult{tokens: []string{}}}, {"\t", tokenizeResult{tokens: []string{}}}, {"\n", tokenizeResult{tokens: []string{}}}, {" \t\n", tokenizeResult{tokens: []string{}}}, {" \tfoo", tokenizeResult{tokens: []string{"foo"}}}, {"foo ", tokenizeResult{tokens: []string{"foo"}}}, {"foo bar", tokenizeResult{tokens: []string{"foo", "bar"}}}, {"foo\nbar", tokenizeResult{tokens: []string{"foo", "bar"}}}, {"foo\tbar", tokenizeResult{tokens: []string{"foo", "bar"}}}, // single quotes {"'", tokenizeResult{tokens: []string{}, code: tokenizeResultCodeMissingEndSingleQuote}}, {"''", tokenizeResult{tokens: []string{""}}}, {"fo''o", tokenizeResult{tokens: []string{"foo"}}}, {"foo '' bar", tokenizeResult{tokens: []string{"foo", "", "bar"}}}, {"foo 'and' bar", tokenizeResult{tokens: []string{"foo", "and", "bar"}}}, {"foo '\\\t\n' bar", tokenizeResult{tokens: []string{"foo", "\\\t\n", "bar"}}}, {"foo ' space bar '", tokenizeResult{tokens: []string{"foo", " space bar "}}}, {"foo 'John \"Spaceman\" Doe'", tokenizeResult{tokens: []string{"foo", "John \"Spaceman\" Doe"}}}, // double quotes {"\"", tokenizeResult{tokens: []string{}, code: tokenizeResultCodeMissingEndDoubleQuote}}, {"\"\"", tokenizeResult{tokens: []string{""}}}, {"fo\"\"o", tokenizeResult{tokens: []string{"foo"}}}, {"foo \"\" bar", tokenizeResult{tokens: []string{"foo", "", "bar"}}}, {"foo \"and\" bar", tokenizeResult{tokens: []string{"foo", "and", "bar"}}}, {"foo \"\\\t\n\" bar", tokenizeResult{tokens: []string{"foo", "\\\t\n", "bar"}}}, {"foo \" space bar \"", tokenizeResult{tokens: []string{"foo", " space bar "}}}, {"foo \"Joe's lunch\"", tokenizeResult{tokens: []string{"foo", "Joe's lunch"}}}, // lone backslash {"\\", tokenizeResult{tokens: []string{}, code: tokenizeResultCodeMissingEscapedCharacter}}, {"\\\\", tokenizeResult{tokens: []string{"\\"}}}, {"\\a", tokenizeResult{tokens: []string{"a"}}}, {"\\?", tokenizeResult{tokens: []string{"?"}}}, {"\\$", tokenizeResult{tokens: []string{"$"}}}, {"\\ ", tokenizeResult{tokens: []string{" "}}}, {"\\\t", tokenizeResult{tokens: []string{"\t"}}}, {"\\\n", tokenizeResult{tokens: []string{"\n"}}}, {"fo\\o", tokenizeResult{tokens: []string{"foo"}}}, {"fo\\\\o", tokenizeResult{tokens: []string{"fo\\o"}}}, {"foo \\ bar", tokenizeResult{tokens: []string{"foo", " bar"}}}, {"foo \\\\ bar", tokenizeResult{tokens: []string{"foo", "\\", "bar"}}}, {"foo \\'bar\\' baz", tokenizeResult{tokens: []string{"foo", "'bar'", "baz"}}}, // } for _, tc := range test_cases { t.Run(fmt.Sprintf("%q", tc.test_str), func(t *testing.T) { have_result := tokenize(tc.test_str) if have_result.code != tc.want_result.code { t.Errorf("unexpected result .code: got %s, want %s in %v", have_result.code, tc.want_result.code, have_result) return } if have_result.err_loc != tc.want_result.err_loc { t.Errorf("unexpected result .err_loc: got %d, want %d in %v", have_result.err_loc, tc.want_result.err_loc, have_result) return } if len(have_result.tokens) != len(tc.want_result.tokens) { t.Errorf("unexpected number of result .tokens: got %d, want %d in %v", len(have_result.tokens), len(tc.want_result.tokens), have_result) return } for i := range have_result.tokens { if have_result.tokens[i] == tc.want_result.tokens[i] { continue } t.Errorf("unexpected token in result .tokens[%d]: got %q, want %q in %v", i, have_result.tokens[i], tc.want_result.tokens[i], have_result) return } }) } } func Test_reader_tossUntilNeitherOf(t *testing.T) { var test_cases = []struct { test_startpos uint test_data string test_needles string want_endpos uint want_ok bool }{ {0, "", "", 0, false}, {0, "", "x", 0, false}, {0, "", "xy", 0, false}, {0, "x", "", 0, false}, {0, "x", "x", 1, true}, {0, "x", "xy", 1, true}, {0, "x", "yx", 1, true}, {0, "xa", "x", 1, true}, {0, "xa", "xy", 1, true}, {0, "xa", "yx", 1, true}, {0, "xya", "x", 1, true}, {0, "xya", "xy", 2, true}, {0, "xya", "yx", 2, true}, {1, "xxya", "x", 2, true}, {1, "xxya", "xy", 3, true}, {1, "xxya", "yx", 3, true}, } for _, tc := range test_cases { t.Run(fmt.Sprintf("%q[%d:]-%q", tc.test_data, tc.test_startpos, tc.test_needles), func(t *testing.T) { test_reader := reader{data: tc.test_data} test_reader.pos = tc.test_startpos have_ok := test_reader.tossUntilNeitherOf(tc.test_needles) if test_reader.pos != tc.want_endpos { t.Errorf("unexpected position after toss: got %d, want %d", test_reader.pos, tc.want_endpos) return } if have_ok != tc.want_ok { t.Errorf("unexpected ok: got %v, want %v", have_ok, tc.want_ok) return } }) } }