...

Source file src/github.com/urfave/cli/v2/context_test.go

Documentation: github.com/urfave/cli/v2

     1  package cli
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"os"
     7  	"sort"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  func TestNewContext(t *testing.T) {
    14  	set := flag.NewFlagSet("test", 0)
    15  	set.Int("myflag", 12, "doc")
    16  	set.Int64("myflagInt64", int64(12), "doc")
    17  	set.Uint("myflagUint", uint(93), "doc")
    18  	set.Uint64("myflagUint64", uint64(93), "doc")
    19  	set.Float64("myflag64", float64(17), "doc")
    20  	globalSet := flag.NewFlagSet("test", 0)
    21  	globalSet.Int("myflag", 42, "doc")
    22  	globalSet.Int64("myflagInt64", int64(42), "doc")
    23  	globalSet.Uint("myflagUint", uint(33), "doc")
    24  	globalSet.Uint64("myflagUint64", uint64(33), "doc")
    25  	globalSet.Float64("myflag64", float64(47), "doc")
    26  	globalCtx := NewContext(nil, globalSet, nil)
    27  	command := &Command{Name: "mycommand"}
    28  	c := NewContext(nil, set, globalCtx)
    29  	c.Command = command
    30  	expect(t, c.Int("myflag"), 12)
    31  	expect(t, c.Int64("myflagInt64"), int64(12))
    32  	expect(t, c.Uint("myflagUint"), uint(93))
    33  	expect(t, c.Uint64("myflagUint64"), uint64(93))
    34  	expect(t, c.Float64("myflag64"), float64(17))
    35  	expect(t, c.Command.Name, "mycommand")
    36  }
    37  
    38  func TestContext_Int(t *testing.T) {
    39  	set := flag.NewFlagSet("test", 0)
    40  	set.Int("myflag", 12, "doc")
    41  	parentSet := flag.NewFlagSet("test", 0)
    42  	parentSet.Int("top-flag", 13, "doc")
    43  	parentCtx := NewContext(nil, parentSet, nil)
    44  	c := NewContext(nil, set, parentCtx)
    45  	expect(t, c.Int("myflag"), 12)
    46  	expect(t, c.Int("top-flag"), 13)
    47  }
    48  
    49  func TestContext_Int64(t *testing.T) {
    50  	set := flag.NewFlagSet("test", 0)
    51  	set.Int64("myflagInt64", 12, "doc")
    52  	parentSet := flag.NewFlagSet("test", 0)
    53  	parentSet.Int64("top-flag", 13, "doc")
    54  	parentCtx := NewContext(nil, parentSet, nil)
    55  	c := NewContext(nil, set, parentCtx)
    56  	expect(t, c.Int64("myflagInt64"), int64(12))
    57  	expect(t, c.Int64("top-flag"), int64(13))
    58  }
    59  
    60  func TestContext_Uint(t *testing.T) {
    61  	set := flag.NewFlagSet("test", 0)
    62  	set.Uint("myflagUint", uint(13), "doc")
    63  	parentSet := flag.NewFlagSet("test", 0)
    64  	parentSet.Uint("top-flag", uint(14), "doc")
    65  	parentCtx := NewContext(nil, parentSet, nil)
    66  	c := NewContext(nil, set, parentCtx)
    67  	expect(t, c.Uint("myflagUint"), uint(13))
    68  	expect(t, c.Uint("top-flag"), uint(14))
    69  }
    70  
    71  func TestContext_Uint64(t *testing.T) {
    72  	set := flag.NewFlagSet("test", 0)
    73  	set.Uint64("myflagUint64", uint64(9), "doc")
    74  	parentSet := flag.NewFlagSet("test", 0)
    75  	parentSet.Uint64("top-flag", uint64(10), "doc")
    76  	parentCtx := NewContext(nil, parentSet, nil)
    77  	c := NewContext(nil, set, parentCtx)
    78  	expect(t, c.Uint64("myflagUint64"), uint64(9))
    79  	expect(t, c.Uint64("top-flag"), uint64(10))
    80  }
    81  
    82  func TestContext_Float64(t *testing.T) {
    83  	set := flag.NewFlagSet("test", 0)
    84  	set.Float64("myflag", float64(17), "doc")
    85  	parentSet := flag.NewFlagSet("test", 0)
    86  	parentSet.Float64("top-flag", float64(18), "doc")
    87  	parentCtx := NewContext(nil, parentSet, nil)
    88  	c := NewContext(nil, set, parentCtx)
    89  	expect(t, c.Float64("myflag"), float64(17))
    90  	expect(t, c.Float64("top-flag"), float64(18))
    91  }
    92  
    93  func TestContext_Duration(t *testing.T) {
    94  	set := flag.NewFlagSet("test", 0)
    95  	set.Duration("myflag", 12*time.Second, "doc")
    96  
    97  	parentSet := flag.NewFlagSet("test", 0)
    98  	parentSet.Duration("top-flag", 13*time.Second, "doc")
    99  	parentCtx := NewContext(nil, parentSet, nil)
   100  
   101  	c := NewContext(nil, set, parentCtx)
   102  	expect(t, c.Duration("myflag"), 12*time.Second)
   103  	expect(t, c.Duration("top-flag"), 13*time.Second)
   104  }
   105  
   106  func TestContext_String(t *testing.T) {
   107  	set := flag.NewFlagSet("test", 0)
   108  	set.String("myflag", "hello world", "doc")
   109  	parentSet := flag.NewFlagSet("test", 0)
   110  	parentSet.String("top-flag", "hai veld", "doc")
   111  	parentCtx := NewContext(nil, parentSet, nil)
   112  	c := NewContext(nil, set, parentCtx)
   113  	expect(t, c.String("myflag"), "hello world")
   114  	expect(t, c.String("top-flag"), "hai veld")
   115  	c = NewContext(nil, nil, parentCtx)
   116  	expect(t, c.String("top-flag"), "hai veld")
   117  }
   118  
   119  func TestContext_Path(t *testing.T) {
   120  	set := flag.NewFlagSet("test", 0)
   121  	set.String("path", "path/to/file", "path to file")
   122  	parentSet := flag.NewFlagSet("test", 0)
   123  	parentSet.String("top-path", "path/to/top/file", "doc")
   124  	parentCtx := NewContext(nil, parentSet, nil)
   125  	c := NewContext(nil, set, parentCtx)
   126  	expect(t, c.Path("path"), "path/to/file")
   127  	expect(t, c.Path("top-path"), "path/to/top/file")
   128  }
   129  
   130  func TestContext_Bool(t *testing.T) {
   131  	set := flag.NewFlagSet("test", 0)
   132  	set.Bool("myflag", false, "doc")
   133  	parentSet := flag.NewFlagSet("test", 0)
   134  	parentSet.Bool("top-flag", true, "doc")
   135  	parentCtx := NewContext(nil, parentSet, nil)
   136  	c := NewContext(nil, set, parentCtx)
   137  	expect(t, c.Bool("myflag"), false)
   138  	expect(t, c.Bool("top-flag"), true)
   139  }
   140  
   141  func TestContext_Value(t *testing.T) {
   142  	set := flag.NewFlagSet("test", 0)
   143  	set.Int("myflag", 12, "doc")
   144  	parentSet := flag.NewFlagSet("test", 0)
   145  	parentSet.Int("top-flag", 13, "doc")
   146  	parentCtx := NewContext(nil, parentSet, nil)
   147  	c := NewContext(nil, set, parentCtx)
   148  	expect(t, c.Value("myflag"), 12)
   149  	expect(t, c.Value("top-flag"), 13)
   150  	expect(t, c.Value("unknown-flag"), nil)
   151  }
   152  
   153  func TestContext_Value_InvalidFlagAccessHandler(t *testing.T) {
   154  	var flagName string
   155  	app := &App{
   156  		InvalidFlagAccessHandler: func(_ *Context, name string) {
   157  			flagName = name
   158  		},
   159  		Commands: []*Command{
   160  			{
   161  				Name: "command",
   162  				Subcommands: []*Command{
   163  					{
   164  						Name: "subcommand",
   165  						Action: func(ctx *Context) error {
   166  							ctx.Value("missing")
   167  							return nil
   168  						},
   169  					},
   170  				},
   171  			},
   172  		},
   173  	}
   174  	expect(t, app.Run([]string{"run", "command", "subcommand"}), nil)
   175  	expect(t, flagName, "missing")
   176  }
   177  
   178  func TestContext_Args(t *testing.T) {
   179  	set := flag.NewFlagSet("test", 0)
   180  	set.Bool("myflag", false, "doc")
   181  	c := NewContext(nil, set, nil)
   182  	_ = set.Parse([]string{"--myflag", "bat", "baz"})
   183  	expect(t, c.Args().Len(), 2)
   184  	expect(t, c.Bool("myflag"), true)
   185  }
   186  
   187  func TestContext_NArg(t *testing.T) {
   188  	set := flag.NewFlagSet("test", 0)
   189  	set.Bool("myflag", false, "doc")
   190  	c := NewContext(nil, set, nil)
   191  	_ = set.Parse([]string{"--myflag", "bat", "baz"})
   192  	expect(t, c.NArg(), 2)
   193  }
   194  
   195  func TestContext_IsSet(t *testing.T) {
   196  	set := flag.NewFlagSet("test", 0)
   197  	set.Bool("one-flag", false, "doc")
   198  	set.Bool("two-flag", false, "doc")
   199  	set.String("three-flag", "hello world", "doc")
   200  	parentSet := flag.NewFlagSet("test", 0)
   201  	parentSet.Bool("top-flag", true, "doc")
   202  	parentCtx := NewContext(nil, parentSet, nil)
   203  	ctx := NewContext(nil, set, parentCtx)
   204  
   205  	_ = set.Parse([]string{"--one-flag", "--two-flag", "--three-flag", "frob"})
   206  	_ = parentSet.Parse([]string{"--top-flag"})
   207  
   208  	expect(t, ctx.IsSet("one-flag"), true)
   209  	expect(t, ctx.IsSet("two-flag"), true)
   210  	expect(t, ctx.IsSet("three-flag"), true)
   211  	expect(t, ctx.IsSet("top-flag"), true)
   212  	expect(t, ctx.IsSet("bogus"), false)
   213  }
   214  
   215  func TestContext_IsSet_Aliases(t *testing.T) {
   216  
   217  	var fooSet, fSet, tSet, iglooSet bool
   218  
   219  	a := App{
   220  		Flags: []Flag{
   221  			&Int64Flag{
   222  				Name:    "foo",
   223  				Aliases: []string{"f", "t", "igloo"},
   224  			},
   225  		},
   226  		Action: func(ctx *Context) error {
   227  			fooSet = ctx.IsSet("foo")
   228  			fSet = ctx.IsSet("f")
   229  			tSet = ctx.IsSet("t")
   230  			iglooSet = ctx.IsSet("igloo")
   231  			return nil
   232  		},
   233  	}
   234  
   235  	_ = a.Run([]string{"run"})
   236  	expect(t, fooSet, false)
   237  	expect(t, fSet, false)
   238  	expect(t, tSet, false)
   239  	expect(t, iglooSet, false)
   240  
   241  	_ = a.Run([]string{"run", "--t", "10"})
   242  	expect(t, fooSet, true)
   243  	expect(t, fSet, true)
   244  	expect(t, tSet, true)
   245  	expect(t, iglooSet, true)
   246  }
   247  
   248  // XXX Corresponds to hack in context.IsSet for flags with EnvVar field
   249  // Should be moved to `flag_test` in v2
   250  func TestContext_IsSet_fromEnv(t *testing.T) {
   251  	var (
   252  		timeoutIsSet, tIsSet    bool
   253  		noEnvVarIsSet, nIsSet   bool
   254  		passwordIsSet, pIsSet   bool
   255  		unparsableIsSet, uIsSet bool
   256  	)
   257  
   258  	defer resetEnv(os.Environ())
   259  	os.Clearenv()
   260  	_ = os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
   261  	_ = os.Setenv("APP_PASSWORD", "")
   262  	a := App{
   263  		Flags: []Flag{
   264  			&Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}},
   265  			&StringFlag{Name: "password", Aliases: []string{"p"}, EnvVars: []string{"APP_PASSWORD"}},
   266  			&Float64Flag{Name: "unparsable", Aliases: []string{"u"}, EnvVars: []string{"APP_UNPARSABLE"}},
   267  			&Float64Flag{Name: "no-env-var", Aliases: []string{"n"}},
   268  		},
   269  		Action: func(ctx *Context) error {
   270  			timeoutIsSet = ctx.IsSet("timeout")
   271  			tIsSet = ctx.IsSet("t")
   272  			passwordIsSet = ctx.IsSet("password")
   273  			pIsSet = ctx.IsSet("p")
   274  			unparsableIsSet = ctx.IsSet("unparsable")
   275  			uIsSet = ctx.IsSet("u")
   276  			noEnvVarIsSet = ctx.IsSet("no-env-var")
   277  			nIsSet = ctx.IsSet("n")
   278  			return nil
   279  		},
   280  	}
   281  	_ = a.Run([]string{"run"})
   282  	expect(t, timeoutIsSet, true)
   283  	expect(t, tIsSet, true)
   284  	expect(t, passwordIsSet, true)
   285  	expect(t, pIsSet, true)
   286  	expect(t, noEnvVarIsSet, false)
   287  	expect(t, nIsSet, false)
   288  
   289  	_ = os.Setenv("APP_UNPARSABLE", "foobar")
   290  	_ = a.Run([]string{"run"})
   291  	expect(t, unparsableIsSet, false)
   292  	expect(t, uIsSet, false)
   293  }
   294  
   295  func TestContext_NumFlags(t *testing.T) {
   296  	set := flag.NewFlagSet("test", 0)
   297  	set.Bool("myflag", false, "doc")
   298  	set.String("otherflag", "hello world", "doc")
   299  	globalSet := flag.NewFlagSet("test", 0)
   300  	globalSet.Bool("myflagGlobal", true, "doc")
   301  	globalCtx := NewContext(nil, globalSet, nil)
   302  	c := NewContext(nil, set, globalCtx)
   303  	_ = set.Parse([]string{"--myflag", "--otherflag=foo"})
   304  	_ = globalSet.Parse([]string{"--myflagGlobal"})
   305  	expect(t, c.NumFlags(), 2)
   306  }
   307  
   308  func TestContext_Set(t *testing.T) {
   309  	set := flag.NewFlagSet("test", 0)
   310  	set.Int("int", 5, "an int")
   311  	c := NewContext(nil, set, nil)
   312  
   313  	expect(t, c.IsSet("int"), false)
   314  	_ = c.Set("int", "1")
   315  	expect(t, c.Int("int"), 1)
   316  	expect(t, c.IsSet("int"), true)
   317  }
   318  
   319  func TestContext_Set_InvalidFlagAccessHandler(t *testing.T) {
   320  	set := flag.NewFlagSet("test", 0)
   321  	var flagName string
   322  	app := &App{
   323  		InvalidFlagAccessHandler: func(_ *Context, name string) {
   324  			flagName = name
   325  		},
   326  	}
   327  	c := NewContext(app, set, nil)
   328  	expect(t, c.Set("missing", "") != nil, true)
   329  	expect(t, flagName, "missing")
   330  }
   331  
   332  func TestContext_LocalFlagNames(t *testing.T) {
   333  	set := flag.NewFlagSet("test", 0)
   334  	set.Bool("one-flag", false, "doc")
   335  	set.String("two-flag", "hello world", "doc")
   336  	parentSet := flag.NewFlagSet("test", 0)
   337  	parentSet.Bool("top-flag", true, "doc")
   338  	parentCtx := NewContext(nil, parentSet, nil)
   339  	ctx := NewContext(nil, set, parentCtx)
   340  	_ = set.Parse([]string{"--one-flag", "--two-flag=foo"})
   341  	_ = parentSet.Parse([]string{"--top-flag"})
   342  
   343  	actualFlags := ctx.LocalFlagNames()
   344  	sort.Strings(actualFlags)
   345  
   346  	expect(t, actualFlags, []string{"one-flag", "two-flag"})
   347  }
   348  
   349  func TestContext_FlagNames(t *testing.T) {
   350  	set := flag.NewFlagSet("test", 0)
   351  	set.Bool("one-flag", false, "doc")
   352  	set.String("two-flag", "hello world", "doc")
   353  	parentSet := flag.NewFlagSet("test", 0)
   354  	parentSet.Bool("top-flag", true, "doc")
   355  	parentCtx := NewContext(nil, parentSet, nil)
   356  	ctx := NewContext(nil, set, parentCtx)
   357  	_ = set.Parse([]string{"--one-flag", "--two-flag=foo"})
   358  	_ = parentSet.Parse([]string{"--top-flag"})
   359  
   360  	actualFlags := ctx.FlagNames()
   361  	sort.Strings(actualFlags)
   362  
   363  	expect(t, actualFlags, []string{"one-flag", "top-flag", "two-flag"})
   364  }
   365  
   366  func TestContext_Lineage(t *testing.T) {
   367  	set := flag.NewFlagSet("test", 0)
   368  	set.Bool("local-flag", false, "doc")
   369  	parentSet := flag.NewFlagSet("test", 0)
   370  	parentSet.Bool("top-flag", true, "doc")
   371  	parentCtx := NewContext(nil, parentSet, nil)
   372  	ctx := NewContext(nil, set, parentCtx)
   373  	_ = set.Parse([]string{"--local-flag"})
   374  	_ = parentSet.Parse([]string{"--top-flag"})
   375  
   376  	lineage := ctx.Lineage()
   377  	expect(t, len(lineage), 2)
   378  	expect(t, lineage[0], ctx)
   379  	expect(t, lineage[1], parentCtx)
   380  }
   381  
   382  func TestContext_lookupFlagSet(t *testing.T) {
   383  	set := flag.NewFlagSet("test", 0)
   384  	set.Bool("local-flag", false, "doc")
   385  	parentSet := flag.NewFlagSet("test", 0)
   386  	parentSet.Bool("top-flag", true, "doc")
   387  	parentCtx := NewContext(nil, parentSet, nil)
   388  	ctx := NewContext(nil, set, parentCtx)
   389  	_ = set.Parse([]string{"--local-flag"})
   390  	_ = parentSet.Parse([]string{"--top-flag"})
   391  
   392  	fs := ctx.lookupFlagSet("top-flag")
   393  	expect(t, fs, parentCtx.flagSet)
   394  
   395  	fs = ctx.lookupFlagSet("local-flag")
   396  	expect(t, fs, ctx.flagSet)
   397  
   398  	if fs := ctx.lookupFlagSet("frob"); fs != nil {
   399  		t.Fail()
   400  	}
   401  }
   402  
   403  func TestNonNilContext(t *testing.T) {
   404  	ctx := NewContext(nil, nil, nil)
   405  	if ctx.Context == nil {
   406  		t.Fatal("expected a non nil context when no parent is present")
   407  	}
   408  }
   409  
   410  // TestContextPropagation tests that
   411  // *cli.Context always has a valid
   412  // context.Context
   413  func TestContextPropagation(t *testing.T) {
   414  	type testKey struct{}
   415  
   416  	parent := NewContext(nil, nil, nil)
   417  	parent.Context = context.WithValue(context.Background(), testKey{}, "val")
   418  	ctx := NewContext(nil, nil, parent)
   419  	val := ctx.Context.Value(testKey{})
   420  	if val == nil {
   421  		t.Fatal("expected a parent context to be inherited but got nil")
   422  	}
   423  	valstr, _ := val.(string)
   424  	if valstr != "val" {
   425  		t.Fatalf("expected the context value to be %q but got %q", "val", valstr)
   426  	}
   427  	parent = NewContext(nil, nil, nil)
   428  	parent.Context = nil
   429  	ctx = NewContext(nil, nil, parent)
   430  	if ctx.Context == nil {
   431  		t.Fatal("expected context to not be nil even if the parent's context is nil")
   432  	}
   433  }
   434  
   435  func TestContextAttributeAccessing(t *testing.T) {
   436  	tdata := []struct {
   437  		testCase        string
   438  		setBoolInput    string
   439  		ctxBoolInput    string
   440  		newContextInput *Context
   441  	}{
   442  		{
   443  			testCase:        "empty",
   444  			setBoolInput:    "",
   445  			ctxBoolInput:    "",
   446  			newContextInput: nil,
   447  		},
   448  		{
   449  			testCase:        "empty_with_background_context",
   450  			setBoolInput:    "",
   451  			ctxBoolInput:    "",
   452  			newContextInput: &Context{Context: context.Background()},
   453  		},
   454  		{
   455  			testCase:        "empty_set_bool_and_present_ctx_bool",
   456  			setBoolInput:    "",
   457  			ctxBoolInput:    "ctx-bool",
   458  			newContextInput: nil,
   459  		},
   460  		{
   461  			testCase:        "present_set_bool_and_present_ctx_bool_with_background_context",
   462  			setBoolInput:    "",
   463  			ctxBoolInput:    "ctx-bool",
   464  			newContextInput: &Context{Context: context.Background()},
   465  		},
   466  		{
   467  			testCase:        "present_set_bool_and_present_ctx_bool",
   468  			setBoolInput:    "ctx-bool",
   469  			ctxBoolInput:    "ctx-bool",
   470  			newContextInput: nil,
   471  		},
   472  		{
   473  			testCase:        "present_set_bool_and_present_ctx_bool_with_background_context",
   474  			setBoolInput:    "ctx-bool",
   475  			ctxBoolInput:    "ctx-bool",
   476  			newContextInput: &Context{Context: context.Background()},
   477  		},
   478  		{
   479  			testCase:        "present_set_bool_and_different_ctx_bool",
   480  			setBoolInput:    "ctx-bool",
   481  			ctxBoolInput:    "not-ctx-bool",
   482  			newContextInput: nil,
   483  		},
   484  		{
   485  			testCase:        "present_set_bool_and_different_ctx_bool_with_background_context",
   486  			setBoolInput:    "ctx-bool",
   487  			ctxBoolInput:    "not-ctx-bool",
   488  			newContextInput: &Context{Context: context.Background()},
   489  		},
   490  	}
   491  
   492  	for _, test := range tdata {
   493  		t.Run(test.testCase, func(t *testing.T) {
   494  			// setup
   495  			set := flag.NewFlagSet("some-flag-set-name", 0)
   496  			set.Bool(test.setBoolInput, false, "usage documentation")
   497  			ctx := NewContext(nil, set, test.newContextInput)
   498  
   499  			// logic under test
   500  			value := ctx.Bool(test.ctxBoolInput)
   501  
   502  			// assertions
   503  			if value != false {
   504  				t.Errorf("expected \"value\" to be false, but it was not")
   505  			}
   506  		})
   507  	}
   508  }
   509  
   510  func TestCheckRequiredFlags(t *testing.T) {
   511  	tdata := []struct {
   512  		testCase              string
   513  		parseInput            []string
   514  		envVarInput           [2]string
   515  		flags                 []Flag
   516  		expectedAnError       bool
   517  		expectedErrorContents []string
   518  	}{
   519  		{
   520  			testCase: "empty",
   521  		},
   522  		{
   523  			testCase: "optional",
   524  			flags: []Flag{
   525  				&StringFlag{Name: "optionalFlag"},
   526  			},
   527  		},
   528  		{
   529  			testCase: "required",
   530  			flags: []Flag{
   531  				&StringFlag{Name: "requiredFlag", Required: true},
   532  			},
   533  			expectedAnError:       true,
   534  			expectedErrorContents: []string{"requiredFlag"},
   535  		},
   536  		{
   537  			testCase: "required_and_present",
   538  			flags: []Flag{
   539  				&StringFlag{Name: "requiredFlag", Required: true},
   540  			},
   541  			parseInput: []string{"--requiredFlag", "myinput"},
   542  		},
   543  		{
   544  			testCase: "required_and_present_via_env_var",
   545  			flags: []Flag{
   546  				&StringFlag{Name: "requiredFlag", Required: true, EnvVars: []string{"REQUIRED_FLAG"}},
   547  			},
   548  			envVarInput: [2]string{"REQUIRED_FLAG", "true"},
   549  		},
   550  		{
   551  			testCase: "required_and_optional",
   552  			flags: []Flag{
   553  				&StringFlag{Name: "requiredFlag", Required: true},
   554  				&StringFlag{Name: "optionalFlag"},
   555  			},
   556  			expectedAnError: true,
   557  		},
   558  		{
   559  			testCase: "required_and_optional_and_optional_present",
   560  			flags: []Flag{
   561  				&StringFlag{Name: "requiredFlag", Required: true},
   562  				&StringFlag{Name: "optionalFlag"},
   563  			},
   564  			parseInput:      []string{"--optionalFlag", "myinput"},
   565  			expectedAnError: true,
   566  		},
   567  		{
   568  			testCase: "required_and_optional_and_optional_present_via_env_var",
   569  			flags: []Flag{
   570  				&StringFlag{Name: "requiredFlag", Required: true},
   571  				&StringFlag{Name: "optionalFlag", EnvVars: []string{"OPTIONAL_FLAG"}},
   572  			},
   573  			envVarInput:     [2]string{"OPTIONAL_FLAG", "true"},
   574  			expectedAnError: true,
   575  		},
   576  		{
   577  			testCase: "required_and_optional_and_required_present",
   578  			flags: []Flag{
   579  				&StringFlag{Name: "requiredFlag", Required: true},
   580  				&StringFlag{Name: "optionalFlag"},
   581  			},
   582  			parseInput: []string{"--requiredFlag", "myinput"},
   583  		},
   584  		{
   585  			testCase: "two_required",
   586  			flags: []Flag{
   587  				&StringFlag{Name: "requiredFlagOne", Required: true},
   588  				&StringFlag{Name: "requiredFlagTwo", Required: true},
   589  			},
   590  			expectedAnError:       true,
   591  			expectedErrorContents: []string{"requiredFlagOne", "requiredFlagTwo"},
   592  		},
   593  		{
   594  			testCase: "two_required_and_one_present",
   595  			flags: []Flag{
   596  				&StringFlag{Name: "requiredFlag", Required: true},
   597  				&StringFlag{Name: "requiredFlagTwo", Required: true},
   598  			},
   599  			parseInput:      []string{"--requiredFlag", "myinput"},
   600  			expectedAnError: true,
   601  		},
   602  		{
   603  			testCase: "two_required_and_both_present",
   604  			flags: []Flag{
   605  				&StringFlag{Name: "requiredFlag", Required: true},
   606  				&StringFlag{Name: "requiredFlagTwo", Required: true},
   607  			},
   608  			parseInput: []string{"--requiredFlag", "myinput", "--requiredFlagTwo", "myinput"},
   609  		},
   610  		{
   611  			testCase: "required_flag_with_short_name",
   612  			flags: []Flag{
   613  				&StringSliceFlag{Name: "names", Aliases: []string{"N"}, Required: true},
   614  			},
   615  			parseInput: []string{"-N", "asd", "-N", "qwe"},
   616  		},
   617  		{
   618  			testCase: "required_flag_with_multiple_short_names",
   619  			flags: []Flag{
   620  				&StringSliceFlag{Name: "names", Aliases: []string{"N", "n"}, Required: true},
   621  			},
   622  			parseInput: []string{"-n", "asd", "-n", "qwe"},
   623  		},
   624  		{
   625  			testCase:              "required_flag_with_short_alias_not_printed_on_error",
   626  			expectedAnError:       true,
   627  			expectedErrorContents: []string{"Required flag \"names\" not set"},
   628  			flags: []Flag{
   629  				&StringSliceFlag{Name: "names, n", Required: true},
   630  			},
   631  		},
   632  		{
   633  			testCase:              "required_flag_with_one_character",
   634  			expectedAnError:       true,
   635  			expectedErrorContents: []string{"Required flag \"n\" not set"},
   636  			flags: []Flag{
   637  				&StringFlag{Name: "n", Required: true},
   638  			},
   639  		},
   640  		{
   641  			testCase:              "required_flag_with_alias_errors_with_actual_name",
   642  			expectedAnError:       true,
   643  			expectedErrorContents: []string{"Required flag \"collection\" not set"},
   644  			flags: []Flag{
   645  				&StringFlag{Name: "collection", Required: true, Aliases: []string{"c"}},
   646  			},
   647  		},
   648  		{
   649  			testCase:        "required_flag_without_name_or_aliases_doesnt_error",
   650  			expectedAnError: false,
   651  			flags: []Flag{
   652  				&StringFlag{Required: true},
   653  			},
   654  		},
   655  	}
   656  
   657  	for _, test := range tdata {
   658  		t.Run(test.testCase, func(t *testing.T) {
   659  			// setup
   660  			if test.envVarInput[0] != "" {
   661  				defer resetEnv(os.Environ())
   662  				os.Clearenv()
   663  				_ = os.Setenv(test.envVarInput[0], test.envVarInput[1])
   664  			}
   665  
   666  			set := flag.NewFlagSet("test", 0)
   667  			for _, flags := range test.flags {
   668  				_ = flags.Apply(set)
   669  			}
   670  			_ = set.Parse(test.parseInput)
   671  
   672  			c := &Context{}
   673  			ctx := NewContext(c.App, set, c)
   674  			ctx.Command.Flags = test.flags
   675  
   676  			// logic under test
   677  			err := ctx.checkRequiredFlags(test.flags)
   678  
   679  			// assertions
   680  			if test.expectedAnError && err == nil {
   681  				t.Errorf("expected an error, but there was none")
   682  			}
   683  			if !test.expectedAnError && err != nil {
   684  				t.Errorf("did not expected an error, but there was one: %s", err)
   685  			}
   686  			for _, errString := range test.expectedErrorContents {
   687  				if err != nil {
   688  					if !strings.Contains(err.Error(), errString) {
   689  						t.Errorf("expected error %q to contain %q, but it didn't!", err.Error(), errString)
   690  					}
   691  				}
   692  			}
   693  		})
   694  	}
   695  }
   696  
   697  func TestContext_ParentContext_Set(t *testing.T) {
   698  	parentSet := flag.NewFlagSet("parent", flag.ContinueOnError)
   699  	parentSet.String("Name", "", "")
   700  
   701  	context := NewContext(
   702  		nil,
   703  		flag.NewFlagSet("child", flag.ContinueOnError),
   704  		NewContext(nil, parentSet, nil),
   705  	)
   706  
   707  	err := context.Set("Name", "aaa")
   708  	if err != nil {
   709  		t.Errorf("expect nil. set parent context flag return err: %s", err)
   710  	}
   711  }
   712  

View as plain text