github.com/arneball/complete@v1.1.2/complete_test.go (about)

     1  package complete
     2  
     3  import (
     4  	"bytes"
     5  	"os"
     6  	"sort"
     7  	"strings"
     8  	"testing"
     9  )
    10  
    11  func TestCompleter_Complete(t *testing.T) {
    12  	t.Parallel()
    13  	initTests()
    14  
    15  	c := Command{
    16  		Sub: Commands{
    17  			"sub1": {
    18  				Flags: Flags{
    19  					"-flag1": PredictAnything,
    20  					"-flag2": PredictNothing,
    21  				},
    22  			},
    23  			"sub2": {
    24  				Flags: Flags{
    25  					"-flag2": PredictNothing,
    26  					"-flag3": PredictSet("opt1", "opt2", "opt12"),
    27  				},
    28  				Args: PredictFiles("*.md"),
    29  			},
    30  		},
    31  		Flags: Flags{
    32  			"-o": PredictFiles("*.txt"),
    33  		},
    34  		GlobalFlags: Flags{
    35  			"-h":       PredictNothing,
    36  			"-global1": PredictAnything,
    37  		},
    38  	}
    39  	cmp := New("cmd", c)
    40  
    41  	tests := []struct {
    42  		args string
    43  		want []string
    44  	}{
    45  		{
    46  			args: "",
    47  			want: []string{"sub1", "sub2"},
    48  		},
    49  		{
    50  			args: "-",
    51  			want: []string{"-h", "-global1", "-o"},
    52  		},
    53  		{
    54  			args: "-h ",
    55  			want: []string{"sub1", "sub2"},
    56  		},
    57  		{
    58  			args: "-global1 ", // global1 is known follow flag
    59  			want: []string{},
    60  		},
    61  		{
    62  			args: "sub",
    63  			want: []string{"sub1", "sub2"},
    64  		},
    65  		{
    66  			args: "sub1",
    67  			want: []string{"sub1"},
    68  		},
    69  		{
    70  			args: "sub2",
    71  			want: []string{"sub2"},
    72  		},
    73  		{
    74  			args: "sub1 ",
    75  			want: []string{},
    76  		},
    77  		{
    78  			args: "sub1 -",
    79  			want: []string{"-flag1", "-flag2", "-h", "-global1"},
    80  		},
    81  		{
    82  			args: "sub2 ",
    83  			want: []string{"./", "dir/", "outer/", "readme.md"},
    84  		},
    85  		{
    86  			args: "sub2 ./",
    87  			want: []string{"./", "./readme.md", "./dir/", "./outer/"},
    88  		},
    89  		{
    90  			args: "sub2 re",
    91  			want: []string{"readme.md"},
    92  		},
    93  		{
    94  			args: "sub2 ./re",
    95  			want: []string{"./readme.md"},
    96  		},
    97  		{
    98  			args: "sub2 -flag2 ",
    99  			want: []string{"./", "dir/", "outer/", "readme.md"},
   100  		},
   101  		{
   102  			args: "sub1 -fl",
   103  			want: []string{"-flag1", "-flag2"},
   104  		},
   105  		{
   106  			args: "sub1 -flag1",
   107  			want: []string{"-flag1"},
   108  		},
   109  		{
   110  			args: "sub1 -flag1 ",
   111  			want: []string{}, // flag1 is unknown follow flag
   112  		},
   113  		{
   114  			args: "sub1 -flag2 -",
   115  			want: []string{"-flag1", "-flag2", "-h", "-global1"},
   116  		},
   117  		{
   118  			args: "-no-such-flag",
   119  			want: []string{},
   120  		},
   121  		{
   122  			args: "-no-such-flag ",
   123  			want: []string{"sub1", "sub2"},
   124  		},
   125  		{
   126  			args: "-no-such-flag -",
   127  			want: []string{"-h", "-global1", "-o"},
   128  		},
   129  		{
   130  			args: "no-such-command",
   131  			want: []string{},
   132  		},
   133  		{
   134  			args: "no-such-command ",
   135  			want: []string{"sub1", "sub2"},
   136  		},
   137  		{
   138  			args: "-o ",
   139  			want: []string{"a.txt", "b.txt", "c.txt", ".dot.txt", "./", "dir/", "outer/"},
   140  		},
   141  		{
   142  			args: "-o ./no-su",
   143  			want: []string{},
   144  		},
   145  		{
   146  			args: "-o ./",
   147  			want: []string{"./a.txt", "./b.txt", "./c.txt", "./.dot.txt", "./", "./dir/", "./outer/"},
   148  		},
   149  		{
   150  			args: "-o=./",
   151  			want: []string{"./a.txt", "./b.txt", "./c.txt", "./.dot.txt", "./", "./dir/", "./outer/"},
   152  		},
   153  		{
   154  			args: "-o .",
   155  			want: []string{"./a.txt", "./b.txt", "./c.txt", "./.dot.txt", "./", "./dir/", "./outer/"},
   156  		},
   157  		{
   158  			args: "-o ./b",
   159  			want: []string{"./b.txt"},
   160  		},
   161  		{
   162  			args: "-o=./b",
   163  			want: []string{"./b.txt"},
   164  		},
   165  		{
   166  			args: "-o ./read",
   167  			want: []string{},
   168  		},
   169  		{
   170  			args: "-o=./read",
   171  			want: []string{},
   172  		},
   173  		{
   174  			args: "-o ./readme.md",
   175  			want: []string{},
   176  		},
   177  		{
   178  			args: "-o ./readme.md ",
   179  			want: []string{"sub1", "sub2"},
   180  		},
   181  		{
   182  			args: "-o=./readme.md ",
   183  			want: []string{"sub1", "sub2"},
   184  		},
   185  		{
   186  			args: "-o sub2 -flag3 ",
   187  			want: []string{"opt1", "opt2", "opt12"},
   188  		},
   189  		{
   190  			args: "-o sub2 -flag3 opt1",
   191  			want: []string{"opt1", "opt12"},
   192  		},
   193  		{
   194  			args: "-o sub2 -flag3 opt",
   195  			want: []string{"opt1", "opt2", "opt12"},
   196  		},
   197  	}
   198  
   199  	for _, tt := range tests {
   200  		t.Run(tt.args, func(t *testing.T) {
   201  			got := runComplete(cmp, tt.args)
   202  
   203  			sort.Strings(tt.want)
   204  			sort.Strings(got)
   205  
   206  			if !equalSlices(got, tt.want) {
   207  				t.Errorf("failed '%s'\ngot: %s\nwant: %s", t.Name(), got, tt.want)
   208  			}
   209  		})
   210  	}
   211  }
   212  
   213  func TestCompleter_Complete_SharedPrefix(t *testing.T) {
   214  	t.Parallel()
   215  	initTests()
   216  
   217  	c := Command{
   218  		Sub: Commands{
   219  			"status": {
   220  				Flags: Flags{
   221  					"-f3": PredictNothing,
   222  				},
   223  			},
   224  			"job": {
   225  				Sub: Commands{
   226  					"status": {
   227  						Flags: Flags{
   228  							"-f4": PredictNothing,
   229  						},
   230  					},
   231  				},
   232  			},
   233  		},
   234  		Flags: Flags{
   235  			"-o": PredictFiles("*.txt"),
   236  		},
   237  		GlobalFlags: Flags{
   238  			"-h":       PredictNothing,
   239  			"-global1": PredictAnything,
   240  		},
   241  	}
   242  
   243  	cmp := New("cmd", c)
   244  
   245  	tests := []struct {
   246  		args string
   247  		want []string
   248  	}{
   249  		{
   250  			args: "",
   251  			want: []string{"status", "job"},
   252  		},
   253  		{
   254  			args: "-",
   255  			want: []string{"-h", "-global1", "-o"},
   256  		},
   257  		{
   258  			args: "j",
   259  			want: []string{"job"},
   260  		},
   261  		{
   262  			args: "job ",
   263  			want: []string{"status"},
   264  		},
   265  		{
   266  			args: "job -",
   267  			want: []string{"-h", "-global1"},
   268  		},
   269  		{
   270  			args: "job status ",
   271  			want: []string{},
   272  		},
   273  		{
   274  			args: "job status -",
   275  			want: []string{"-f4", "-h", "-global1"},
   276  		},
   277  	}
   278  
   279  	for _, tt := range tests {
   280  		t.Run(tt.args, func(t *testing.T) {
   281  			got := runComplete(cmp, tt.args)
   282  
   283  			sort.Strings(tt.want)
   284  			sort.Strings(got)
   285  
   286  			if !equalSlices(got, tt.want) {
   287  				t.Errorf("failed '%s'\ngot = %s\nwant: %s", t.Name(), got, tt.want)
   288  			}
   289  		})
   290  	}
   291  }
   292  
   293  // runComplete runs the complete login for test purposes
   294  // it gets the complete struct and command line arguments and returns
   295  // the complete options
   296  func runComplete(c *Complete, args string) (completions []string) {
   297  	os.Setenv(envComplete, "cmd "+args)
   298  	b := bytes.NewBuffer(nil)
   299  	c.Out = b
   300  	c.Complete()
   301  	completions = parseOutput(b.String())
   302  	return
   303  }
   304  
   305  func parseOutput(output string) []string {
   306  	lines := strings.Split(output, "\n")
   307  	options := []string{}
   308  	for _, l := range lines {
   309  		if l != "" {
   310  			options = append(options, l)
   311  		}
   312  	}
   313  	return options
   314  }
   315  
   316  func equalSlices(a, b []string) bool {
   317  	if len(a) != len(b) {
   318  		return false
   319  	}
   320  	for i := range a {
   321  		if a[i] != b[i] {
   322  			return false
   323  		}
   324  	}
   325  	return true
   326  }