123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- package flags
- import (
- "bytes"
- "io"
- "os"
- "path"
- "path/filepath"
- "reflect"
- "runtime"
- "strings"
- "testing"
- )
- type TestComplete struct {
- }
- func (t *TestComplete) Complete(match string) []Completion {
- options := []string{
- "hello world",
- "hello universe",
- "hello multiverse",
- }
- ret := make([]Completion, 0, len(options))
- for _, o := range options {
- if strings.HasPrefix(o, match) {
- ret = append(ret, Completion{
- Item: o,
- })
- }
- }
- return ret
- }
- var completionTestOptions struct {
- Verbose bool `short:"v" long:"verbose" description:"Verbose messages"`
- Debug bool `short:"d" long:"debug" description:"Enable debug"`
- Info bool `short:"i" description:"Display info"`
- Version bool `long:"version" description:"Show version"`
- Required bool `long:"required" required:"true" description:"This is required"`
- Hidden bool `long:"hidden" hidden:"true" description:"This is hidden"`
- AddCommand struct {
- Positional struct {
- Filename Filename
- } `positional-args:"yes"`
- } `command:"add" description:"add an item"`
- AddMultiCommand struct {
- Positional struct {
- Filename []Filename
- } `positional-args:"yes"`
- Extra []Filename `short:"f"`
- } `command:"add-multi" description:"add multiple items"`
- AddMultiCommandFlag struct {
- Files []Filename `short:"f"`
- } `command:"add-multi-flag" description:"add multiple items via flags"`
- RemoveCommand struct {
- Other bool `short:"o"`
- File Filename `short:"f" long:"filename"`
- } `command:"rm" description:"remove an item"`
- RenameCommand struct {
- Completed TestComplete `short:"c" long:"completed"`
- } `command:"rename" description:"rename an item"`
- }
- type completionTest struct {
- Args []string
- Completed []string
- ShowDescriptions bool
- }
- var completionTests []completionTest
- func init() {
- _, sourcefile, _, _ := runtime.Caller(0)
- completionTestSourcedir := filepath.Join(filepath.SplitList(path.Dir(sourcefile))...)
- completionTestFilename := []string{filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion_test.go")}
- completionTests = []completionTest{
- {
- // Short names
- []string{"-"},
- []string{"--debug", "--required", "--verbose", "--version", "-i"},
- false,
- },
- {
- // Short names full
- []string{"-i"},
- []string{"-i"},
- false,
- },
- {
- // Short names concatenated
- []string{"-dv"},
- []string{"-dv"},
- false,
- },
- {
- // Long names
- []string{"--"},
- []string{"--debug", "--required", "--verbose", "--version"},
- false,
- },
- {
- // Long names with descriptions
- []string{"--"},
- []string{
- "--debug # Enable debug",
- "--required # This is required",
- "--verbose # Verbose messages",
- "--version # Show version",
- },
- true,
- },
- {
- // Long names partial
- []string{"--ver"},
- []string{"--verbose", "--version"},
- false,
- },
- {
- // Commands
- []string{""},
- []string{"add", "add-multi", "add-multi-flag", "rename", "rm"},
- false,
- },
- {
- // Commands with descriptions
- []string{""},
- []string{
- "add # add an item",
- "add-multi # add multiple items",
- "add-multi-flag # add multiple items via flags",
- "rename # rename an item",
- "rm # remove an item",
- },
- true,
- },
- {
- // Commands partial
- []string{"r"},
- []string{"rename", "rm"},
- false,
- },
- {
- // Positional filename
- []string{"add", filepath.Join(completionTestSourcedir, "completion")},
- completionTestFilename,
- false,
- },
- {
- // Multiple positional filename (1 arg)
- []string{"add-multi", filepath.Join(completionTestSourcedir, "completion")},
- completionTestFilename,
- false,
- },
- {
- // Multiple positional filename (2 args)
- []string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")},
- completionTestFilename,
- false,
- },
- {
- // Multiple positional filename (3 args)
- []string{"add-multi", filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion.go"), filepath.Join(completionTestSourcedir, "completion")},
- completionTestFilename,
- false,
- },
- {
- // Flag filename
- []string{"rm", "-f", path.Join(completionTestSourcedir, "completion")},
- completionTestFilename,
- false,
- },
- {
- // Flag short concat last filename
- []string{"rm", "-of", path.Join(completionTestSourcedir, "completion")},
- completionTestFilename,
- false,
- },
- {
- // Flag concat filename
- []string{"rm", "-f" + path.Join(completionTestSourcedir, "completion")},
- []string{"-f" + completionTestFilename[0], "-f" + completionTestFilename[1]},
- false,
- },
- {
- // Flag equal concat filename
- []string{"rm", "-f=" + path.Join(completionTestSourcedir, "completion")},
- []string{"-f=" + completionTestFilename[0], "-f=" + completionTestFilename[1]},
- false,
- },
- {
- // Flag concat long filename
- []string{"rm", "--filename=" + path.Join(completionTestSourcedir, "completion")},
- []string{"--filename=" + completionTestFilename[0], "--filename=" + completionTestFilename[1]},
- false,
- },
- {
- // Flag long filename
- []string{"rm", "--filename", path.Join(completionTestSourcedir, "completion")},
- completionTestFilename,
- false,
- },
- {
- // Custom completed
- []string{"rename", "-c", "hello un"},
- []string{"hello universe"},
- false,
- },
- {
- // Multiple flag filename
- []string{"add-multi-flag", "-f", filepath.Join(completionTestSourcedir, "completion")},
- completionTestFilename,
- false,
- },
- }
- }
- func TestCompletion(t *testing.T) {
- p := NewParser(&completionTestOptions, Default)
- c := &completion{parser: p}
- for _, test := range completionTests {
- if test.ShowDescriptions {
- continue
- }
- ret := c.complete(test.Args)
- items := make([]string, len(ret))
- for i, v := range ret {
- items[i] = v.Item
- }
- if !reflect.DeepEqual(items, test.Completed) {
- t.Errorf("Args: %#v, %#v\n Expected: %#v\n Got: %#v", test.Args, test.ShowDescriptions, test.Completed, items)
- }
- }
- }
- func TestParserCompletion(t *testing.T) {
- for _, test := range completionTests {
- if test.ShowDescriptions {
- os.Setenv("GO_FLAGS_COMPLETION", "verbose")
- } else {
- os.Setenv("GO_FLAGS_COMPLETION", "1")
- }
- tmp := os.Stdout
- r, w, _ := os.Pipe()
- os.Stdout = w
- out := make(chan string)
- go func() {
- var buf bytes.Buffer
- io.Copy(&buf, r)
- out <- buf.String()
- }()
- p := NewParser(&completionTestOptions, None)
- p.CompletionHandler = func(items []Completion) {
- comp := &completion{parser: p}
- comp.print(items, test.ShowDescriptions)
- }
- _, err := p.ParseArgs(test.Args)
- w.Close()
- os.Stdout = tmp
- if err != nil {
- t.Fatalf("Unexpected error: %s", err)
- }
- got := strings.Split(strings.Trim(<-out, "\n"), "\n")
- if !reflect.DeepEqual(got, test.Completed) {
- t.Errorf("Expected: %#v\nGot: %#v", test.Completed, got)
- }
- }
- os.Setenv("GO_FLAGS_COMPLETION", "")
- }
|