github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/shell/autocomplete/flags_test.go (about)

     1  package autocomplete_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  	"testing"
     9  
    10  	_ "github.com/lmorg/murex/builtins"
    11  	"github.com/lmorg/murex/config/defaults"
    12  	"github.com/lmorg/murex/lang"
    13  	"github.com/lmorg/murex/lang/ref"
    14  	"github.com/lmorg/murex/shell/autocomplete"
    15  	"github.com/lmorg/murex/test/count"
    16  	"github.com/lmorg/murex/utils/json"
    17  	"github.com/lmorg/murex/utils/parser"
    18  	"github.com/lmorg/murex/utils/readline"
    19  )
    20  
    21  type testAutocompleteFlagsT struct {
    22  	CmdLine  string
    23  	ExpItems []string
    24  	ExpDefs  map[string]string
    25  }
    26  
    27  func initAutocompleteFlagsTest(exe string, acJson string) {
    28  	lang.InitEnv()
    29  	defaults.Config(lang.ShellProcess.Config, false)
    30  	//debug.Enabled = true
    31  
    32  	err := lang.ShellProcess.Config.Set("shell", "autocomplete-soft-timeout", 3000, nil)
    33  	if err != nil {
    34  		panic(err.Error())
    35  	}
    36  
    37  	err = lang.ShellProcess.Config.Set("shell", "autocomplete-hard-timeout", 10000, nil)
    38  	if err != nil {
    39  		panic(err.Error())
    40  	}
    41  
    42  	var flags []autocomplete.Flags
    43  
    44  	err = json.UnmarshalMurex([]byte(acJson), &flags)
    45  	if err != nil {
    46  		panic(err.Error())
    47  	}
    48  
    49  	for i := range flags {
    50  		// So we don't have nil values in JSON
    51  		if len(flags[i].Flags) == 0 {
    52  			flags[i].Flags = make([]string, 0)
    53  		}
    54  
    55  		sort.Strings(flags[i].Flags)
    56  	}
    57  
    58  	autocomplete.ExesFlags[exe] = flags
    59  	autocomplete.ExesFlagsFileRef[exe] = &ref.File{Source: &ref.Source{Module: "test/test"}}
    60  }
    61  
    62  func testAutocompleteFlags(t *testing.T, tests []testAutocompleteFlagsT) {
    63  	t.Helper()
    64  	count.Tests(t, len(tests))
    65  
    66  	for i, test := range tests {
    67  		var err error
    68  		errCallback := func(e error) { err = e }
    69  
    70  		pt, _ := parser.Parse([]rune(test.CmdLine), 0)
    71  
    72  		dtc := readline.DelayedTabContext{}
    73  		dtc.Context, _ = context.WithCancel(context.Background())
    74  
    75  		act := autocomplete.AutoCompleteT{
    76  			Definitions:       make(map[string]string),
    77  			ErrCallback:       errCallback,
    78  			DelayedTabContext: dtc,
    79  			ParsedTokens:      pt,
    80  		}
    81  
    82  		autocomplete.MatchFlags(&act)
    83  
    84  		//fmt.Println(jsonOutput(pt.Parameters))
    85  
    86  		if err != nil {
    87  			t.Errorf("Error in test %d: %s", i, err.Error())
    88  			continue
    89  		}
    90  
    91  		sort.Strings(test.ExpItems)
    92  		sort.Strings(act.Items)
    93  
    94  		expectedItems := jsonOutput(test.ExpItems)
    95  		actualItems := jsonOutput(act.Items)
    96  		expectedDefs := jsonOutput(test.ExpDefs)
    97  		actualDefs := jsonOutput(act.Definitions)
    98  
    99  		if len(test.ExpItems) != len(act.Items) || len(test.ExpDefs) != len(act.Definitions) {
   100  			t.Errorf("Item count != expected item count")
   101  			t.Logf("  Test number:      %d", i)
   102  			t.Logf("  Command line:     %s", test.CmdLine)
   103  			t.Logf("  Expected n Items: %d", len(test.ExpItems))
   104  			t.Logf("  Actual n Items:   %d", len(act.Items))
   105  			t.Logf("  Expected n Defs:  %d", len(test.ExpDefs))
   106  			t.Logf("  Actual n Defs:    %d", len(act.Definitions))
   107  			t.Logf("  exp json items:   %s", expectedItems)
   108  			t.Logf("  act json items:   %s", actualItems)
   109  			t.Logf("  exp json defs:    %s", expectedDefs)
   110  			t.Logf("  act json defs:    %s", actualDefs)
   111  			goto nextTest
   112  		}
   113  
   114  		for item := range test.ExpItems {
   115  			if test.ExpItems[item] != act.Items[item] {
   116  				t.Errorf("test.ExpItems[item] != act.Items[item]")
   117  				t.Logf("  Test number:      %d", i)
   118  				t.Logf("  Command line:     %s", test.CmdLine)
   119  				t.Logf("  Item index:       %d", item)
   120  				t.Logf("  Expected Item:    %s", test.ExpItems[item])
   121  				t.Logf("  Actual Item:      %s", act.Items[item])
   122  				t.Logf("  exp json items:   %s", expectedItems)
   123  				t.Logf("  act json items:   %s", actualItems)
   124  				t.Logf("  exp json defs:    %s", expectedDefs)
   125  				t.Logf("  act json defs:    %s", actualDefs)
   126  				goto nextTest
   127  			}
   128  		}
   129  
   130  		for k := range test.ExpDefs {
   131  			if test.ExpDefs[k] != act.Definitions[k] {
   132  				t.Errorf("test.ExpDefs[k] != act.Definitions[k]")
   133  				t.Logf("  Test number:      %d", i)
   134  				t.Logf("  Command line:     %s", test.CmdLine)
   135  				t.Logf("  Definition key:   %s", k)
   136  				t.Logf("  Expected def:     %s", test.ExpDefs[k])
   137  				t.Logf("  Actual def:       %s", act.Definitions[k])
   138  				t.Logf("  exp json items:   %s", expectedItems)
   139  				t.Logf("  act json items:   %s", actualItems)
   140  				t.Logf("  exp json defs:    %s", expectedDefs)
   141  				t.Logf("  act json defs:    %s", actualDefs)
   142  				goto nextTest
   143  			}
   144  		}
   145  	nextTest:
   146  	}
   147  }
   148  
   149  func jsonOutput(v interface{}) string {
   150  	b, err := json.Marshal(v, false)
   151  	if err != nil && !strings.Contains(err.Error(), "o data returned") {
   152  		panic(err.Error())
   153  	}
   154  	return string(b)
   155  }
   156  
   157  func TestAutocompleteDocgen(t *testing.T) {
   158  	json := `
   159  		[
   160  			{
   161  				"AllowMultiple": true,
   162  				"Optional": true,
   163  				"FlagsDesc": {
   164  					"-panic": "panic",
   165  					"-readonly": "ro",
   166  					"-verbose": "v",
   167  					"-version": "ver",
   168  					"-warning": "warn"
   169  				}
   170  			},
   171  			{
   172  				"FlagsDesc": {
   173  					"-config": "conf"
   174  				},
   175  				"FlagValues": {
   176  					"-config": [{
   177  						"IncFiles": true
   178  					}]
   179  				}
   180  			}
   181  		]`
   182  
   183  	initAutocompleteFlagsTest(t.Name(), json)
   184  
   185  	tests := []testAutocompleteFlagsT{
   186  		{
   187  			CmdLine: fmt.Sprintf(`%s -`, t.Name()),
   188  			ExpItems: []string{
   189  				`panic`,
   190  				"readonly",
   191  				"verbose",
   192  				"version",
   193  				"warning",
   194  				"config",
   195  			},
   196  			ExpDefs: map[string]string{
   197  				"config":   "conf",
   198  				"panic":    "panic",
   199  				"readonly": "ro",
   200  				"verbose":  "v",
   201  				"version":  "ver",
   202  				"warning":  "warn",
   203  			},
   204  		},
   205  		{
   206  			CmdLine: fmt.Sprintf(`%s -p`, t.Name()),
   207  			ExpItems: []string{
   208  				`anic`,
   209  			},
   210  			ExpDefs: map[string]string{
   211  				`anic`: `panic`,
   212  			},
   213  		},
   214  		{
   215  			CmdLine: fmt.Sprintf(`%s -panic -w`, t.Name()),
   216  			ExpItems: []string{
   217  				`arning`,
   218  			},
   219  			ExpDefs: map[string]string{
   220  				`arning`: `warn`,
   221  			},
   222  		},
   223  		{
   224  			CmdLine: fmt.Sprintf(`%s -panic -c`, t.Name()),
   225  			ExpItems: []string{
   226  				`onfig`,
   227  			},
   228  			ExpDefs: map[string]string{
   229  				`onfig`: `conf`,
   230  			},
   231  		},
   232  		{
   233  			CmdLine: fmt.Sprintf(`%s -panic -config R`, t.Name()),
   234  			ExpItems: []string{
   235  				`EADME.md`,
   236  			},
   237  			ExpDefs: map[string]string{},
   238  		},
   239  	}
   240  
   241  	testAutocompleteFlags(t, tests)
   242  }
   243  
   244  func TestAutocompleteDocgenBug(t *testing.T) {
   245  	json := `
   246  		[
   247  			{
   248  				"AllowMultiple": true,
   249  				"Optional": true,
   250  				"FlagsDesc": {
   251  					"-panic": "panic",
   252  					"-readonly": "ro",
   253  					"-verbose": "v",
   254  					"-version": "ver",
   255  					"-warning": "warn",
   256  					"-config": "conf"
   257  				},
   258  				"FlagValues": {
   259  					"-config": [{
   260  						"IncFiles": true
   261  					}]
   262  				}
   263  			}
   264  		]`
   265  
   266  	initAutocompleteFlagsTest(t.Name(), json)
   267  
   268  	tests := []testAutocompleteFlagsT{
   269  		{
   270  			CmdLine: fmt.Sprintf(`%s -`, t.Name()),
   271  			ExpItems: []string{
   272  				`panic`,
   273  				"readonly",
   274  				"verbose",
   275  				"version",
   276  				"warning",
   277  				"config",
   278  			},
   279  			ExpDefs: map[string]string{
   280  				"config":   "conf",
   281  				"panic":    "panic",
   282  				"readonly": "ro",
   283  				"verbose":  "v",
   284  				"version":  "ver",
   285  				"warning":  "warn",
   286  			},
   287  		},
   288  		{
   289  			CmdLine: fmt.Sprintf(`%s -p`, t.Name()),
   290  			ExpItems: []string{
   291  				`anic`,
   292  			},
   293  			ExpDefs: map[string]string{
   294  				`anic`: `panic`,
   295  			},
   296  		},
   297  		{
   298  			CmdLine: fmt.Sprintf(`%s -panic -w`, t.Name()),
   299  			ExpItems: []string{
   300  				`arning`,
   301  			},
   302  			ExpDefs: map[string]string{
   303  				`arning`: `warn`,
   304  			},
   305  		},
   306  		{
   307  			CmdLine: fmt.Sprintf(`%s -panic -c`, t.Name()),
   308  			ExpItems: []string{
   309  				`onfig`,
   310  			},
   311  			ExpDefs: map[string]string{
   312  				`onfig`: `conf`,
   313  			},
   314  		},
   315  		{
   316  			CmdLine: fmt.Sprintf(`%s -panic -config R`, t.Name()),
   317  			ExpItems: []string{
   318  				`EADME.md`,
   319  			},
   320  			ExpDefs: map[string]string{},
   321  		},
   322  	}
   323  
   324  	testAutocompleteFlags(t, tests)
   325  }
   326  
   327  func TestAutocompleteDynamic(t *testing.T) {
   328  	json := `
   329  		[
   330  			{
   331  				"AllowMultiple": true,
   332  				"Dynamic": ({
   333  					a: [Monday..Friday]
   334  				})
   335  			}
   336  		]`
   337  
   338  	initAutocompleteFlagsTest(t.Name(), json)
   339  
   340  	tests := []testAutocompleteFlagsT{
   341  		{
   342  			CmdLine: fmt.Sprintf(`%s `, t.Name()),
   343  			ExpItems: []string{
   344  				`Monday`,
   345  				`Tuesday`,
   346  				`Wednesday`,
   347  				`Thursday`,
   348  				`Friday`,
   349  			},
   350  			ExpDefs: map[string]string{},
   351  		},
   352  		{
   353  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
   354  			ExpItems: []string{
   355  				`uesday`,
   356  				`hursday`,
   357  			},
   358  			ExpDefs: map[string]string{},
   359  		},
   360  		{
   361  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
   362  			ExpItems: []string{
   363  				`Monday`,
   364  				`Tuesday`,
   365  				`Wednesday`,
   366  				`Thursday`,
   367  				`Friday`,
   368  			},
   369  			ExpDefs: map[string]string{},
   370  		},
   371  		{
   372  			CmdLine: fmt.Sprintf(`%s Tuesday T`, t.Name()),
   373  			ExpItems: []string{
   374  				`uesday`,
   375  				`hursday`,
   376  			},
   377  			ExpDefs: map[string]string{},
   378  		},
   379  	}
   380  
   381  	testAutocompleteFlags(t, tests)
   382  }
   383  
   384  func TestAutocompleteDynamicDesc(t *testing.T) {
   385  	json := `
   386  		[
   387  			{
   388  				"AllowMultiple": true,
   389  				"DynamicDesc": ({
   390  					map { a: [Monday..Friday] } { a: [1..5] }
   391  				})
   392  			}
   393  		]`
   394  
   395  	initAutocompleteFlagsTest(t.Name(), json)
   396  
   397  	tests := []testAutocompleteFlagsT{
   398  		{
   399  			CmdLine: t.Name(),
   400  			ExpItems: []string{
   401  				`Monday`,
   402  				`Tuesday`,
   403  				`Wednesday`,
   404  				`Thursday`,
   405  				`Friday`,
   406  			},
   407  			ExpDefs: map[string]string{
   408  				`Monday`:    `1`,
   409  				`Tuesday`:   `2`,
   410  				`Wednesday`: `3`,
   411  				`Thursday`:  `4`,
   412  				`Friday`:    `5`,
   413  			},
   414  		},
   415  		{
   416  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
   417  			ExpItems: []string{
   418  				`uesday`,
   419  				`hursday`,
   420  			},
   421  			ExpDefs: map[string]string{
   422  				`uesday`:  `2`,
   423  				`hursday`: `4`,
   424  			},
   425  		},
   426  		{
   427  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
   428  			ExpItems: []string{
   429  				`Monday`,
   430  				`Tuesday`,
   431  				`Wednesday`,
   432  				`Thursday`,
   433  				`Friday`,
   434  			},
   435  			ExpDefs: map[string]string{
   436  				`Monday`:    `1`,
   437  				`Tuesday`:   `2`,
   438  				`Wednesday`: `3`,
   439  				`Thursday`:  `4`,
   440  				`Friday`:    `5`,
   441  			},
   442  		},
   443  		{
   444  			CmdLine: fmt.Sprintf(`%s Tuesday T`, t.Name()),
   445  			ExpItems: []string{
   446  				`uesday`,
   447  				`hursday`,
   448  			},
   449  			ExpDefs: map[string]string{
   450  				`uesday`:  `2`,
   451  				`hursday`: `4`,
   452  			},
   453  		},
   454  	}
   455  
   456  	testAutocompleteFlags(t, tests)
   457  }
   458  
   459  /////
   460  
   461  func TestAutocompleteDynamicArrayChain(t *testing.T) {
   462  	json := `
   463  		[
   464  			{
   465  				"Dynamic": ({
   466  					a: [Monday..Friday]
   467  				})
   468  			},
   469  			{
   470  				"Dynamic": ({
   471  					a: [Jan..Mar]
   472  				})
   473  			}
   474  		]`
   475  
   476  	initAutocompleteFlagsTest(t.Name(), json)
   477  
   478  	tests := []testAutocompleteFlagsT{
   479  		{
   480  			CmdLine: t.Name(),
   481  			ExpItems: []string{
   482  				`Monday`,
   483  				`Tuesday`,
   484  				`Wednesday`,
   485  				`Thursday`,
   486  				`Friday`,
   487  			},
   488  			ExpDefs: map[string]string{},
   489  		},
   490  		{
   491  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
   492  			ExpItems: []string{
   493  				`uesday`,
   494  				`hursday`,
   495  			},
   496  			ExpDefs: map[string]string{},
   497  		},
   498  		{
   499  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
   500  			ExpItems: []string{
   501  				`Jan`,
   502  				`Feb`,
   503  				`Mar`,
   504  			},
   505  			ExpDefs: map[string]string{},
   506  		},
   507  	}
   508  
   509  	testAutocompleteFlags(t, tests)
   510  }
   511  
   512  func TestAutocompleteDynamicArrayChainOptional(t *testing.T) {
   513  	json := `
   514  		[
   515  			{
   516  				"Optional": true,
   517  				"Dynamic": ({
   518  					a: [Monday..Friday]
   519  				})
   520  			},
   521  			{
   522  				"Dynamic": ({
   523  					a: [Jan..Mar]
   524  				})
   525  			}
   526  		]`
   527  
   528  	initAutocompleteFlagsTest(t.Name(), json)
   529  
   530  	tests := []testAutocompleteFlagsT{
   531  		{
   532  			CmdLine: t.Name(),
   533  			ExpItems: []string{
   534  				`Monday`,
   535  				`Tuesday`,
   536  				`Wednesday`,
   537  				`Thursday`,
   538  				`Friday`,
   539  				`Jan`,
   540  				`Feb`,
   541  				`Mar`,
   542  			},
   543  			ExpDefs: map[string]string{},
   544  		},
   545  		{
   546  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
   547  			ExpItems: []string{
   548  				`uesday`,
   549  				`hursday`,
   550  			},
   551  			ExpDefs: map[string]string{},
   552  		},
   553  		{
   554  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
   555  			ExpItems: []string{
   556  				`Jan`,
   557  				`Feb`,
   558  				`Mar`,
   559  			},
   560  			ExpDefs: map[string]string{},
   561  		},
   562  		{
   563  			CmdLine: fmt.Sprintf(`%s F`, t.Name()),
   564  			ExpItems: []string{
   565  				`riday`,
   566  				`eb`,
   567  			},
   568  			ExpDefs: map[string]string{},
   569  		},
   570  		{
   571  			CmdLine: fmt.Sprintf(`%s J`, t.Name()),
   572  			ExpItems: []string{
   573  				`an`,
   574  			},
   575  			ExpDefs: map[string]string{},
   576  		},
   577  	}
   578  
   579  	testAutocompleteFlags(t, tests)
   580  }
   581  
   582  func TestAutocompleteDynamicArrayChainOptionalMultiple(t *testing.T) {
   583  	json := `
   584  		[
   585  			{
   586  				"Optional": true,
   587  				"AllowMultiple": true,
   588  				"Dynamic": ({
   589  					a: [Monday..Friday]
   590  				})
   591  			},
   592  			{
   593  				"Dynamic": ({
   594  					a: [Jan..Mar]
   595  				})
   596  			}
   597  		]`
   598  
   599  	initAutocompleteFlagsTest(t.Name(), json)
   600  
   601  	tests := []testAutocompleteFlagsT{
   602  		{
   603  			CmdLine: t.Name(),
   604  			ExpItems: []string{
   605  				`Monday`,
   606  				`Tuesday`,
   607  				`Wednesday`,
   608  				`Thursday`,
   609  				`Friday`,
   610  				`Jan`,
   611  				`Feb`,
   612  				`Mar`,
   613  			},
   614  			ExpDefs: map[string]string{},
   615  		},
   616  		{
   617  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
   618  			ExpItems: []string{
   619  				`uesday`,
   620  				`hursday`,
   621  			},
   622  			ExpDefs: map[string]string{},
   623  		},
   624  		{
   625  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
   626  			ExpItems: []string{
   627  				`Monday`,
   628  				`Tuesday`,
   629  				`Wednesday`,
   630  				`Thursday`,
   631  				`Friday`,
   632  				`Jan`,
   633  				`Feb`,
   634  				`Mar`,
   635  			},
   636  			ExpDefs: map[string]string{},
   637  		},
   638  		{
   639  			CmdLine: fmt.Sprintf(`%s F`, t.Name()),
   640  			ExpItems: []string{
   641  				`riday`,
   642  				`eb`,
   643  			},
   644  			ExpDefs: map[string]string{},
   645  		},
   646  		{
   647  			CmdLine: fmt.Sprintf(`%s J`, t.Name()),
   648  			ExpItems: []string{
   649  				`an`,
   650  			},
   651  			ExpDefs: map[string]string{},
   652  		},
   653  	}
   654  
   655  	testAutocompleteFlags(t, tests)
   656  }
   657  
   658  /////
   659  
   660  func TestAutocompleteDynamicDescArrayChain(t *testing.T) {
   661  	json := `
   662  		[
   663  			{
   664  				"DynamicDesc": ({
   665  					map { a: [Monday..Friday] } { a: [Monday..Friday] }
   666  				})
   667  			},
   668  			{
   669  				"DynamicDesc": ({
   670  					map { a: [Jan..Mar] } { a: [Jan..Mar] }
   671  				})
   672  			}
   673  		]`
   674  
   675  	initAutocompleteFlagsTest(t.Name(), json)
   676  
   677  	tests := []testAutocompleteFlagsT{
   678  		{
   679  			CmdLine: t.Name(),
   680  			ExpItems: []string{
   681  				`Monday`,
   682  				`Tuesday`,
   683  				`Wednesday`,
   684  				`Thursday`,
   685  				`Friday`,
   686  			},
   687  			ExpDefs: map[string]string{
   688  				`Monday`:    `Monday`,
   689  				`Tuesday`:   `Tuesday`,
   690  				`Wednesday`: `Wednesday`,
   691  				`Thursday`:  `Thursday`,
   692  				`Friday`:    `Friday`,
   693  			},
   694  		},
   695  		{
   696  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
   697  			ExpItems: []string{
   698  				`uesday`,
   699  				`hursday`,
   700  			},
   701  			ExpDefs: map[string]string{
   702  				`uesday`:  `Tuesday`,
   703  				`hursday`: `Thursday`,
   704  			},
   705  		},
   706  		{
   707  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
   708  			ExpItems: []string{
   709  				`Jan`,
   710  				`Feb`,
   711  				`Mar`,
   712  			},
   713  			ExpDefs: map[string]string{
   714  				`Jan`: `Jan`,
   715  				`Feb`: `Feb`,
   716  				`Mar`: `Mar`,
   717  			},
   718  		},
   719  	}
   720  
   721  	testAutocompleteFlags(t, tests)
   722  }
   723  
   724  func TestAutocompleteDynamicDescArrayChainOptional(t *testing.T) {
   725  	json := `
   726  		[
   727  			{
   728  				"Optional": true,
   729  				"DynamicDesc": ({
   730  					map { a: [Monday..Friday] } { a: [Monday..Friday] }
   731  				})
   732  			},
   733  			{
   734  				"DynamicDesc": ({
   735  					map { a: [Jan..Mar] } { a: [Jan..Mar] }
   736  				})
   737  			}
   738  		]`
   739  
   740  	initAutocompleteFlagsTest(t.Name(), json)
   741  
   742  	tests := []testAutocompleteFlagsT{
   743  		{
   744  			CmdLine: t.Name(),
   745  			ExpItems: []string{
   746  				`Monday`,
   747  				`Tuesday`,
   748  				`Wednesday`,
   749  				`Thursday`,
   750  				`Friday`,
   751  				`Jan`,
   752  				`Feb`,
   753  				`Mar`,
   754  			},
   755  			ExpDefs: map[string]string{
   756  				`Monday`:    `Monday`,
   757  				`Tuesday`:   `Tuesday`,
   758  				`Wednesday`: `Wednesday`,
   759  				`Thursday`:  `Thursday`,
   760  				`Friday`:    `Friday`,
   761  				`Jan`:       `Jan`,
   762  				`Feb`:       `Feb`,
   763  				`Mar`:       `Mar`,
   764  			},
   765  		},
   766  		{
   767  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
   768  			ExpItems: []string{
   769  				`uesday`,
   770  				`hursday`,
   771  			},
   772  			ExpDefs: map[string]string{
   773  				`uesday`:  `Tuesday`,
   774  				`hursday`: `Thursday`,
   775  			},
   776  		},
   777  		{
   778  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
   779  			ExpItems: []string{
   780  				`Jan`,
   781  				`Feb`,
   782  				`Mar`,
   783  			},
   784  			ExpDefs: map[string]string{
   785  				`Jan`: `Jan`,
   786  				`Feb`: `Feb`,
   787  				`Mar`: `Mar`,
   788  			},
   789  		},
   790  		{
   791  			CmdLine: fmt.Sprintf(`%s F`, t.Name()),
   792  			ExpItems: []string{
   793  				`riday`,
   794  				`eb`,
   795  			},
   796  			ExpDefs: map[string]string{
   797  				`riday`: `Friday`,
   798  				`eb`:    `Feb`,
   799  			},
   800  		},
   801  		{
   802  			CmdLine: fmt.Sprintf(`%s J`, t.Name()),
   803  			ExpItems: []string{
   804  				`an`,
   805  			},
   806  			ExpDefs: map[string]string{
   807  				`an`: `Jan`,
   808  			},
   809  		},
   810  	}
   811  
   812  	testAutocompleteFlags(t, tests)
   813  }
   814  
   815  func TestAutocompleteDynamicDescArrayChainOptionalMultiple(t *testing.T) {
   816  	json := `
   817  		[
   818  			{
   819  				"Optional": true,
   820  				"AllowMultiple": true,
   821  				"DynamicDesc": ({
   822  					map { a: [Monday..Friday] } { a: [Monday..Friday] }
   823  				})
   824  			},
   825  			{
   826  				"DynamicDesc": ({
   827  					map { a: [Jan..Mar] } { a: [Jan..Mar] }
   828  				})
   829  			}
   830  		]`
   831  
   832  	initAutocompleteFlagsTest(t.Name(), json)
   833  
   834  	tests := []testAutocompleteFlagsT{
   835  		{
   836  			CmdLine: t.Name(),
   837  			ExpItems: []string{
   838  				`Monday`,
   839  				`Tuesday`,
   840  				`Wednesday`,
   841  				`Thursday`,
   842  				`Friday`,
   843  				`Jan`,
   844  				`Feb`,
   845  				`Mar`,
   846  			},
   847  			ExpDefs: map[string]string{
   848  				`Monday`:    `Monday`,
   849  				`Tuesday`:   `Tuesday`,
   850  				`Wednesday`: `Wednesday`,
   851  				`Thursday`:  `Thursday`,
   852  				`Friday`:    `Friday`,
   853  				`Jan`:       `Jan`,
   854  				`Feb`:       `Feb`,
   855  				`Mar`:       `Mar`,
   856  			},
   857  		},
   858  		{
   859  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
   860  			ExpItems: []string{
   861  				`uesday`,
   862  				`hursday`,
   863  			},
   864  			ExpDefs: map[string]string{
   865  				`uesday`:  `Tuesday`,
   866  				`hursday`: `Thursday`,
   867  			},
   868  		},
   869  		{
   870  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
   871  			ExpItems: []string{
   872  				`Monday`,
   873  				`Tuesday`,
   874  				`Wednesday`,
   875  				`Thursday`,
   876  				`Friday`,
   877  				`Jan`,
   878  				`Feb`,
   879  				`Mar`,
   880  			},
   881  			ExpDefs: map[string]string{
   882  				`Monday`:    `Monday`,
   883  				`Tuesday`:   `Tuesday`,
   884  				`Wednesday`: `Wednesday`,
   885  				`Thursday`:  `Thursday`,
   886  				`Friday`:    `Friday`,
   887  				`Jan`:       `Jan`,
   888  				`Feb`:       `Feb`,
   889  				`Mar`:       `Mar`,
   890  			},
   891  		},
   892  		{
   893  			CmdLine: fmt.Sprintf(`%s F`, t.Name()),
   894  			ExpItems: []string{
   895  				`riday`,
   896  				`eb`,
   897  			},
   898  			ExpDefs: map[string]string{
   899  				`riday`: `Friday`,
   900  				`eb`:    `Feb`,
   901  			},
   902  		},
   903  		{
   904  			CmdLine: fmt.Sprintf(`%s J`, t.Name()),
   905  			ExpItems: []string{
   906  				`an`,
   907  			},
   908  			ExpDefs: map[string]string{
   909  				`an`: `Jan`,
   910  			},
   911  		},
   912  	}
   913  
   914  	testAutocompleteFlags(t, tests)
   915  }
   916  
   917  /////
   918  
   919  func TestAutocompleteNested(t *testing.T) {
   920  	json := `
   921  		[
   922  			{
   923  				"Flags": [ "Sunday", "Monday", "Happy Days" ],
   924  				"FlagValues": {
   925  					"Sunday": [{
   926  						"Dynamic": ({ a: [1..3] })
   927  					}],
   928  					"Monday": [{
   929  						"Flags": [ "a", "b", "c" ]
   930  					}]
   931  				}
   932  			}
   933  		]`
   934  
   935  	initAutocompleteFlagsTest(t.Name(), json)
   936  
   937  	tests := []testAutocompleteFlagsT{
   938  		{
   939  			CmdLine: t.Name(),
   940  			ExpItems: []string{
   941  				`Sunday`,
   942  				`Monday`,
   943  				`Happy Days`,
   944  			},
   945  			ExpDefs: map[string]string{},
   946  		},
   947  		{
   948  			CmdLine: fmt.Sprintf(`%s S`, t.Name()),
   949  			ExpItems: []string{
   950  				`unday`,
   951  			},
   952  			ExpDefs: map[string]string{},
   953  		},
   954  		{
   955  			CmdLine: fmt.Sprintf(`%s Sunday `, t.Name()),
   956  			ExpItems: []string{
   957  				`1`,
   958  				`2`,
   959  				`3`,
   960  			},
   961  			ExpDefs: map[string]string{},
   962  		},
   963  		{
   964  			CmdLine: fmt.Sprintf(`%s Monday `, t.Name()),
   965  			ExpItems: []string{
   966  				`a`,
   967  				`b`,
   968  				`c`,
   969  			},
   970  			ExpDefs: map[string]string{},
   971  		},
   972  	}
   973  
   974  	testAutocompleteFlags(t, tests)
   975  }
   976  
   977  /////
   978  
   979  func TestAutocompleteComplexNestedDynamic(t *testing.T) {
   980  	json := `
   981  		[
   982  			{
   983  				"Optional": true,
   984  				"Dynamic": ({
   985  					out: optional
   986  				})
   987  			},
   988  			{
   989  				"Dynamic": ({
   990  					a: [Sunday..Friday]
   991  				}),
   992  				"FlagValues": {
   993  					"Sunday": [{
   994  						"Dynamic": ({ a: [1..3] })
   995  					}],
   996  					"Monday": [{
   997  						"Flags": [ "a", "b", "c" ]
   998  					}]
   999  				}
  1000  			},
  1001  			{
  1002  				"Dynamic": ({
  1003  					a: [Jan..Mar]
  1004  				})
  1005  			}
  1006  		]`
  1007  
  1008  	initAutocompleteFlagsTest(t.Name(), json)
  1009  
  1010  	tests := []testAutocompleteFlagsT{
  1011  		{
  1012  			CmdLine: t.Name(),
  1013  			ExpItems: []string{
  1014  				`optional`,
  1015  				`Sunday`,
  1016  				`Monday`,
  1017  				`Tuesday`,
  1018  				`Wednesday`,
  1019  				`Thursday`,
  1020  				`Friday`,
  1021  			},
  1022  			ExpDefs: map[string]string{},
  1023  		},
  1024  		{
  1025  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
  1026  			ExpItems: []string{
  1027  				`uesday`,
  1028  				`hursday`,
  1029  			},
  1030  			ExpDefs: map[string]string{},
  1031  		},
  1032  		{
  1033  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
  1034  			ExpItems: []string{
  1035  				`Jan`,
  1036  				`Feb`,
  1037  				`Mar`,
  1038  			},
  1039  			ExpDefs: map[string]string{},
  1040  		},
  1041  		{
  1042  			CmdLine: fmt.Sprintf(`%s Sunday `, t.Name()),
  1043  			ExpItems: []string{
  1044  				`1`,
  1045  				`2`,
  1046  				`3`,
  1047  			},
  1048  			ExpDefs: map[string]string{},
  1049  		},
  1050  		{
  1051  			CmdLine: fmt.Sprintf(`%s Monday `, t.Name()),
  1052  			ExpItems: []string{
  1053  				`a`,
  1054  				`b`,
  1055  				`c`,
  1056  			},
  1057  			ExpDefs: map[string]string{},
  1058  		},
  1059  		{
  1060  			CmdLine:  fmt.Sprintf(`%s z`, t.Name()),
  1061  			ExpItems: []string{},
  1062  			ExpDefs:  map[string]string{},
  1063  		},
  1064  		{
  1065  			CmdLine:  fmt.Sprintf(`%s z `, t.Name()),
  1066  			ExpItems: []string{},
  1067  			ExpDefs:  map[string]string{},
  1068  		},
  1069  		{
  1070  			CmdLine:  fmt.Sprintf(`%s Sunday z`, t.Name()),
  1071  			ExpItems: []string{},
  1072  			ExpDefs:  map[string]string{},
  1073  		},
  1074  		{
  1075  			CmdLine:  fmt.Sprintf(`%s Sunday z `, t.Name()),
  1076  			ExpItems: []string{},
  1077  			ExpDefs:  map[string]string{},
  1078  		},
  1079  	}
  1080  
  1081  	testAutocompleteFlags(t, tests)
  1082  }
  1083  
  1084  func TestAutocompleteComplexNestedDynamicDesc(t *testing.T) {
  1085  	json := `
  1086  		[
  1087  			{
  1088  				"Optional": true,
  1089  				"DynamicDesc": ({
  1090  					map { out "Optional" } { out "optional" }
  1091  				})
  1092  			},
  1093  			{
  1094  				"DynamicDesc": ({
  1095  					map { a: [Sunday..Friday] } { a: [sunday..friday] }
  1096  				}),
  1097  				"FlagValues": {
  1098  					"Sunday": [{
  1099  						"DynamicDesc": ({
  1100  							map { a: [1..3] } { a: [1..3] }
  1101  						})
  1102  					}],
  1103  					"Monday": [{
  1104  						"DynamicDesc": ({
  1105  							map { a: [a..c] } { a: [a..c] }
  1106  						})
  1107  					}]
  1108  				}
  1109  			},
  1110  			{
  1111  				"DynamicDesc": ({
  1112  					map { a: [Jan..Mar] } { a: [jan..mar] }
  1113  				})
  1114  			}
  1115  		]`
  1116  
  1117  	initAutocompleteFlagsTest(t.Name(), json)
  1118  
  1119  	tests := []testAutocompleteFlagsT{
  1120  		{
  1121  			CmdLine: t.Name(),
  1122  			ExpItems: []string{
  1123  				`Optional`,
  1124  				`Sunday`,
  1125  				`Monday`,
  1126  				`Tuesday`,
  1127  				`Wednesday`,
  1128  				`Thursday`,
  1129  				`Friday`,
  1130  			},
  1131  			ExpDefs: map[string]string{
  1132  				`Optional`:  `optional`,
  1133  				`Sunday`:    `sunday`,
  1134  				`Monday`:    `monday`,
  1135  				`Tuesday`:   `tuesday`,
  1136  				`Wednesday`: `wednesday`,
  1137  				`Thursday`:  `thursday`,
  1138  				`Friday`:    `friday`,
  1139  			},
  1140  		},
  1141  		{
  1142  			CmdLine: fmt.Sprintf(`%s T`, t.Name()),
  1143  			ExpItems: []string{
  1144  				`uesday`,
  1145  				`hursday`,
  1146  			},
  1147  			ExpDefs: map[string]string{
  1148  				`uesday`:  `tuesday`,
  1149  				`hursday`: `thursday`,
  1150  			},
  1151  		},
  1152  		{
  1153  			CmdLine: fmt.Sprintf(`%s Tuesday `, t.Name()),
  1154  			ExpItems: []string{
  1155  				`Jan`,
  1156  				`Feb`,
  1157  				`Mar`,
  1158  			},
  1159  			ExpDefs: map[string]string{
  1160  				`Jan`: `jan`,
  1161  				`Feb`: `feb`,
  1162  				`Mar`: `mar`,
  1163  			},
  1164  		},
  1165  		{
  1166  			CmdLine: fmt.Sprintf(`%s Sunday `, t.Name()),
  1167  			ExpItems: []string{
  1168  				`1`,
  1169  				`2`,
  1170  				`3`,
  1171  			},
  1172  			ExpDefs: map[string]string{
  1173  				`1`: `1`,
  1174  				`2`: `2`,
  1175  				`3`: `3`,
  1176  			},
  1177  		},
  1178  		{
  1179  			CmdLine: fmt.Sprintf(`%s Monday `, t.Name()),
  1180  			ExpItems: []string{
  1181  				`a`,
  1182  				`b`,
  1183  				`c`,
  1184  			},
  1185  			ExpDefs: map[string]string{
  1186  				`a`: `a`,
  1187  				`b`: `b`,
  1188  				`c`: `c`,
  1189  			},
  1190  		},
  1191  		{
  1192  			CmdLine:  fmt.Sprintf(`%s z `, t.Name()),
  1193  			ExpItems: []string{},
  1194  			ExpDefs:  map[string]string{},
  1195  		},
  1196  		{
  1197  			CmdLine:  fmt.Sprintf(`%s z`, t.Name()),
  1198  			ExpItems: []string{},
  1199  			ExpDefs:  map[string]string{},
  1200  		},
  1201  		{
  1202  			CmdLine:  fmt.Sprintf(`%s z `, t.Name()),
  1203  			ExpItems: []string{},
  1204  			ExpDefs:  map[string]string{},
  1205  		},
  1206  		{
  1207  			CmdLine:  fmt.Sprintf(`%s Sunday z`, t.Name()),
  1208  			ExpItems: []string{},
  1209  			ExpDefs:  map[string]string{},
  1210  		},
  1211  		{
  1212  			CmdLine:  fmt.Sprintf(`%s Sunday z `, t.Name()),
  1213  			ExpItems: []string{},
  1214  			ExpDefs:  map[string]string{},
  1215  		},
  1216  	}
  1217  
  1218  	testAutocompleteFlags(t, tests)
  1219  }