| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- package commands
- import (
- "bytes"
- "flag"
- "testing"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- // TestParseArgsAllowsFlagsAfterOperands pins the one way ParseArgs departs from fl.Parse,
- // that a flag may follow an operand, and that it departs in no other: a negative number
- // is a flag, as Parse reads it, and goes after "--" when it is meant as an operand.
- func TestParseArgsAllowsFlagsAfterOperands(t *testing.T) {
- cases := map[string]struct {
- args []string
- wantOps []string
- wantN string
- wantV bool
- wantJSON bool
- wantErr string
- }{
- "flag after operand": {args: []string{"x", "-json"}, wantOps: []string{"x"}, wantJSON: true},
- "flags around": {args: []string{"-v", "x", "-n", "1", "y"}, wantOps: []string{"x", "y"}, wantV: true, wantN: "1"},
- "value after operand": {args: []string{"x", "-n", "-1"}, wantOps: []string{"x"}, wantN: "-1"},
- "equals value": {args: []string{"-n=-1", "x"}, wantOps: []string{"x"}, wantN: "-1"},
- "terminator after": {args: []string{"x", "--", "-json", "-1"}, wantOps: []string{"x", "-json", "-1"}},
- "terminator": {args: []string{"--", "-json"}, wantOps: []string{"-json"}},
- "defined numeric": {args: []string{"-2", "x"}, wantOps: []string{"x"}, wantV: true},
- "negative number": {args: []string{"-1"}, wantErr: "flag provided but not defined: -1"},
- "bad flag after": {args: []string{"x", "-nope"}, wantErr: "flag provided but not defined: -nope"},
- "undefined flag": {args: []string{"-nope", "x"}, wantErr: "flag provided but not defined: -nope"},
- "missing value": {args: []string{"-n"}, wantErr: "flag needs an argument: -n"},
- }
- for name, tc := range cases {
- t.Run(name, func(t *testing.T) {
- fl := flag.NewFlagSet("t", flag.ContinueOnError)
- fl.SetOutput(&bytes.Buffer{})
- n := fl.String("n", "", "")
- v := fl.Bool("v", false, "")
- two := fl.Bool("2", false, "a flag that happens to be a number")
- asJSON := fl.Bool(FlagJSON, false, "")
- ops, err := ParseArgs(fl, tc.args)
- if tc.wantErr != "" {
- require.ErrorContains(t, err, tc.wantErr)
- return
- }
- require.NoError(t, err)
- assert.Equal(t, tc.wantOps, ops)
- assert.Equal(t, tc.wantN, *n)
- assert.Equal(t, tc.wantV, *v || *two)
- assert.Equal(t, tc.wantJSON, *asJSON)
- })
- }
- }
- // TestDispatchFlagAfterOperand: the same through a registered command with no Flags of
- // its own, which only has the presentation flags to find.
- func TestDispatchFlagAfterOperand(t *testing.T) {
- out := &bytes.Buffer{}
- require.NoError(t, testRegistry().DispatchArgs([]string{"served", "x", "-json"}, MergedOutput(out)))
- assert.Equal(t, "\"read x\"\n", out.String())
- }
- // TestLookupArg pins the reading of an argument's shape that ParseArgs and nebula ctl
- // share.
- func TestLookupArg(t *testing.T) {
- fl := flag.NewFlagSet("t", flag.ContinueOnError)
- fl.String("n", "", "")
- fl.Bool("v", false, "")
- for _, tc := range []struct {
- arg string
- name string
- hasValue bool
- }{
- {"-n", "n", false},
- {"--n", "n", false},
- {"-n=1", "n", true},
- {"--n=", "n", true},
- {"-v", "v", false},
- {"-nope", "", false},
- {"-1", "", false},
- } {
- f, hasValue := LookupArg(fl, tc.arg)
- if tc.name == "" {
- assert.Nil(t, f, tc.arg)
- } else {
- require.NotNil(t, f, tc.arg)
- assert.Equal(t, tc.name, f.Name, tc.arg)
- }
- assert.Equal(t, tc.hasValue, hasValue, tc.arg)
- }
- assert.True(t, IsBoolFlag(fl.Lookup("v")))
- assert.False(t, IsBoolFlag(fl.Lookup("n")))
- }
|