package runs import ( "errors" "reflect" "strings" "testing" ) // TestCommandGranted is Review Focus 4's pin among others: a prefix matches // word for word and exactly, never as a substring, never case-folded, and a // zero-word prefix matches nothing. func TestCommandGranted(t *testing.T) { ic := [][]string{{"import", "classic"}} for _, tc := range []struct { name string argv []string prefixes [][]string want bool }{ {"prefix then more words", []string{"import", "classic", "--slug", "x"}, ic, true}, {"exactly the prefix", []string{"import", "classic"}, ic, true}, {"shorter than the prefix", []string{"import"}, ic, false}, {"a word that only starts with the prefix word", []string{"importer", "classic"}, ic, false}, {"a word the prefix word only starts", []string{"imp", "classic"}, ic, false}, {"case differs", []string{"Import", "classic"}, ic, false}, {"empty argv", []string{}, ic, false}, {"nil argv", nil, ic, false}, {"empty argv under a zero-word prefix", []string{}, [][]string{{}}, false}, {"second of two prefixes", []string{"import", "sync", "--all"}, [][]string{{"import", "classic"}, {"import", "sync"}}, true}, {"neither of two prefixes", []string{"export", "sync"}, [][]string{{"import", "classic"}, {"import", "sync"}}, false}, {"zero-word prefix", []string{"anything"}, [][]string{{}}, false}, {"nil prefix", []string{"anything"}, [][]string{nil}, false}, {"no prefixes", []string{"anything"}, nil, false}, {"zero-word prefix beside a real one does not widen it", []string{"rm", "-rf"}, [][]string{nil, {"import"}}, false}, } { if got := CommandGranted(tc.argv, tc.prefixes); got != tc.want { t.Errorf("%s: CommandGranted(%q, %q) = %v, want %v", tc.name, tc.argv, tc.prefixes, got, tc.want) } } } func TestCheckCommandPrefixes(t *testing.T) { if err := CheckCommandPrefixes(nil); !errors.Is(err, ErrNoCommands) { t.Errorf("nil: err = %v, want ErrNoCommands", err) } if err := CheckCommandPrefixes([][]string{}); !errors.Is(err, ErrNoCommands) { t.Errorf("empty: err = %v, want ErrNoCommands", err) } word128 := strings.Repeat("a", MaxCommandWordBytes) many := func(n int) [][]string { out := make([][]string, n) for i := range out { out[i] = []string{word128} } return out } for name, bad := range map[string][][]string{ "zero-word prefix": {{"import"}, {}}, "nil prefix": {nil}, "empty word": {{"import", ""}}, "129-byte word": {{"import", word128 + "a"}}, "33 prefixes": many(MaxCommandPrefixes + 1), "zero-word prefix only": {{}}, "a word with a space": {{"import classic"}}, "a word with a comma": {{"import,classic"}}, "a word with a tab": {{"import\tclassic"}}, "a word with ESC": {{"import", "\x1b[8mclassic"}}, "a word with NUL": {{"import", "a\x00"}}, "invalid UTF-8": {{"import", "\xff"}}, "U+FFFD": {{"import", "\ufffd"}}, "a no-break space": {{"import\u00a0classic"}}, "a zero-width space": {{"import\u200bclassic"}}, "a newline": {{"import\n"}}, } { if err := CheckCommandPrefixes(bad); err == nil { t.Errorf("%s: accepted; want refused", name) } } if err := CheckCommandPrefixes(many(MaxCommandPrefixes)); err != nil { t.Errorf("32 prefixes of 128-byte words: %v; want accepted", err) } if err := CheckCommandPrefixes([][]string{{"import", "classic"}, {"import", "sync"}}); err != nil { t.Errorf("two prefixes: %v", err) } if err := CheckCommandPrefixes([][]string{{"import", "--slug=café", "über/ü", "a:b;c"}}); err != nil { t.Errorf("printable non-ASCII and punctuation: %v; want accepted", err) } if err := CheckCommandPrefixes([][]string{{"import", "\x1b"}}); !errors.Is(err, ErrCommandWordChars) { t.Errorf("ESC: err = %v, want ErrCommandWordChars", err) } } // TestParseCommandList is the one text form both the CLI flag and the // console form take: prefixes split on commas, words on spaces, empty // entries dropped. func TestParseCommandList(t *testing.T) { for _, tc := range []struct { in string want [][]string }{ {"", nil}, {" , ,", nil}, {"import classic", [][]string{{"import", "classic"}}}, {"import classic,import sync", [][]string{{"import", "classic"}, {"import", "sync"}}}, {" import classic , import sync ,", [][]string{{"import", "classic"}, {"import", "sync"}}}, } { if got := ParseCommandList(tc.in); !reflect.DeepEqual(got, tc.want) { t.Errorf("ParseCommandList(%q) = %q, want %q", tc.in, got, tc.want) } } if got := FormatCommandList([][]string{{"import", "classic"}, {"import", "sync"}}); got != "import classic, import sync" { t.Errorf("FormatCommandList = %q", got) } } // TestCommandListRoundTrips: every accepted list survives being written out // as text and read back, so a listing copied into a new mint grants exactly // what it showed. func TestCommandListRoundTrips(t *testing.T) { word128 := strings.Repeat("ü", MaxCommandWordBytes/2) max := make([][]string, MaxCommandPrefixes) for i := range max { max[i] = []string{word128, "x"} } for _, p := range [][][]string{ {{"import"}}, {{"import", "classic"}, {"import", "sync", "--all"}}, {{"--slug=café"}, {"a:b;c", "[x]", "\"q\""}}, max, } { if err := CheckCommandPrefixes(p); err != nil { t.Fatalf("fixture %q is not accepted: %v", p, err) } if got := ParseCommandList(FormatCommandList(p)); !reflect.DeepEqual(got, p) { t.Errorf("round trip of %q gave %q", p, got) } } } // FuzzCommandListRoundTrip: whatever text is typed, if the list it parses // to is accepted, formatting and parsing it again gives the same list. func FuzzCommandListRoundTrip(f *testing.F) { for _, s := range []string{"import classic,import sync", " a ,, b c ", "a\u00a0b", "x\x1b", "\xff", "café, über"} { f.Add(s) } f.Fuzz(func(t *testing.T, s string) { p := ParseCommandList(s) if CheckCommandPrefixes(p) != nil { return } if got := ParseCommandList(FormatCommandList(p)); !reflect.DeepEqual(got, p) { t.Fatalf("round trip of %q (from %q) gave %q", p, s, got) } }) }