From 8ff971fc783bdaa9210b51302e094f200b57ee43 Mon Sep 17 00:00:00 2001 From: Danilo Pantani Date: Fri, 19 Jul 2024 15:56:26 +0200 Subject: [PATCH] feat: add custom flag parser for extensions (#4269) * add custom flag parser * add changelog --- changelog.md | 1 + ignite/cmd/plugin_test.go | 16 +- ignite/services/plugin/flag.go | 162 +++++ ignite/services/plugin/flag_test.go | 580 ++++++++++++++++++ .../plugin/testdata/example-plugin/main.go | 2 +- 5 files changed, 752 insertions(+), 9 deletions(-) create mode 100644 ignite/services/plugin/flag.go create mode 100644 ignite/services/plugin/flag_test.go diff --git a/changelog.md b/changelog.md index 3894828ae3..6f643fa2d1 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ - [#4111](https://github.com/ignite/cli/pull/4111) Remove vuex generation - [#4113](https://github.com/ignite/cli/pull/4113) Generate chain config documentation automatically - [#4131](https://github.com/ignite/cli/pull/4131) Support `bytes` as data type in the `scaffold` commands +- [#4269](https://github.com/ignite/cli/pull/4269) Add custom flag parser for extensions ### Changes diff --git a/ignite/cmd/plugin_test.go b/ignite/cmd/plugin_test.go index cb9bfd846f..32f78ac16f 100644 --- a/ignite/cmd/plugin_test.go +++ b/ignite/cmd/plugin_test.go @@ -44,7 +44,7 @@ func buildRootCmd(ctx context.Context) *cobra.Command { return rootCmd } -func assertFlags(t *testing.T, expectedFlags []*plugin.Flag, execCmd *plugin.ExecutedCommand) { +func assertFlags(t *testing.T, expectedFlags plugin.Flags, execCmd *plugin.ExecutedCommand) { t.Helper() var ( have []string @@ -79,7 +79,7 @@ func TestLinkPluginCmds(t *testing.T) { // define a plugin with command flags pluginWithFlags = &plugin.Command{ Use: "flaggy", - Flags: []*plugin.Flag{ + Flags: plugin.Flags{ {Name: "flag1", Type: plugin.FlagTypeString}, {Name: "flag2", Type: plugin.FlagTypeInt, DefaultValue: "0", Value: "0"}, }, @@ -424,7 +424,7 @@ func TestLinkPluginHooks(t *testing.T) { // helper to assert pluginInterface.ExecuteHook*() calls in expected order // (pre, then post, then cleanup) - expectExecuteHook = func(t *testing.T, p *mocks.PluginInterface, expectedFlags []*plugin.Flag, hooks ...*plugin.Hook) { + expectExecuteHook = func(t *testing.T, p *mocks.PluginInterface, expectedFlags plugin.Flags, hooks ...*plugin.Hook) { t.Helper() matcher := func(hook *plugin.Hook) any { return mock.MatchedBy(func(execHook *plugin.ExecutedHook) bool { @@ -522,7 +522,7 @@ func TestLinkPluginHooks(t *testing.T) { p.EXPECT(). Manifest(ctx). Return(&plugin.Manifest{Hooks: []*plugin.Hook{hook}}, nil) - expectExecuteHook(t, p, []*plugin.Flag{{Name: "path"}}, hook) + expectExecuteHook(t, p, plugin.Flags{{Name: "path"}}, hook) }, }, { @@ -540,7 +540,7 @@ func TestLinkPluginHooks(t *testing.T) { p.EXPECT(). Manifest(ctx). Return(&plugin.Manifest{Hooks: []*plugin.Hook{hook1, hook2}}, nil) - expectExecuteHook(t, p, []*plugin.Flag{{Name: "path"}}, hook1, hook2) + expectExecuteHook(t, p, plugin.Flags{{Name: "path"}}, hook1, hook2) }, }, { @@ -562,7 +562,7 @@ func TestLinkPluginHooks(t *testing.T) { p.EXPECT(). Manifest(ctx). Return(&plugin.Manifest{Hooks: []*plugin.Hook{hookChain1, hookChain2, hookModule}}, nil) - expectExecuteHook(t, p, []*plugin.Flag{{Name: "path"}}, hookChain1, hookChain2) + expectExecuteHook(t, p, plugin.Flags{{Name: "path"}}, hookChain1, hookChain2) expectExecuteHook(t, p, nil, hookModule) }, }, @@ -583,7 +583,7 @@ func TestLinkPluginHooks(t *testing.T) { p.EXPECT(). Manifest(ctx). Return(&plugin.Manifest{Hooks: hooks}, nil) - expectExecuteHook(t, p, []*plugin.Flag{{Name: "path"}}, hooks...) + expectExecuteHook(t, p, plugin.Flags{{Name: "path"}}, hooks...) }, }, { @@ -601,7 +601,7 @@ func TestLinkPluginHooks(t *testing.T) { p.EXPECT(). Manifest(ctx). Return(&plugin.Manifest{Hooks: []*plugin.Hook{hookChain, hookModule}}, nil) - expectExecuteHook(t, p, []*plugin.Flag{{Name: "path"}}, hookChain) + expectExecuteHook(t, p, plugin.Flags{{Name: "path"}}, hookChain) expectExecuteHook(t, p, nil, hookModule) }, }, diff --git a/ignite/services/plugin/flag.go b/ignite/services/plugin/flag.go new file mode 100644 index 0000000000..dc51f37f68 --- /dev/null +++ b/ignite/services/plugin/flag.go @@ -0,0 +1,162 @@ +package plugin + +import ( + "strconv" + "strings" + + "github.com/ignite/cli/v29/ignite/pkg/errors" +) + +var ( + // ErrFlagNotFound error key flag not found. + ErrFlagNotFound = errors.New("flag not found") + // ErrInvalidFlagType error invalid flag type. + ErrInvalidFlagType = errors.New("invalid flag type") + // ErrFlagAssertion error flag type assertion failed. + ErrFlagAssertion = errors.New("flag type assertion failed") +) + +// Flags represents a slice of Flag pointers. +type Flags []*Flag + +// getValue returns the value of the flag with the specified key and type. +// It uses the provided conversion function to convert the string value to the desired type. +func (f Flags) getValue(key string, flagType FlagType, convFunc func(v string) (interface{}, error)) (interface{}, error) { + for _, flag := range f { + if flag.Name == key { + if flag.Type != flagType { + return nil, errors.Wrapf(ErrInvalidFlagType, "invalid flag type %v for key %s", flag.Type, key) + } + return convFunc(flagValue(flag)) + } + } + return nil, errors.Wrap(ErrFlagNotFound, key) +} + +// GetString retrieves the string value of the flag with the specified key. +func (f Flags) GetString(key string) (string, error) { + v, err := f.getValue(key, FlagTypeString, func(v string) (interface{}, error) { + return strings.TrimSpace(v), nil + }) + if err != nil { + return "", err + } + result, ok := v.(string) + if !ok { + return "", errors.Wrapf(ErrFlagAssertion, "invalid assertion type %T for key %s", v, key) + } + return result, nil +} + +// GetStringSlice retrieves the string slice value of the flag with the specified key. +func (f Flags) GetStringSlice(key string) ([]string, error) { + v, err := f.getValue(key, FlagTypeStringSlice, func(v string) (interface{}, error) { + v = strings.Trim(v, "[]") + s := strings.Split(v, ",") + if len(s) == 0 || (len(s) == 1 && s[0] == "") { + return []string{}, nil + } + return s, nil + }) + if err != nil { + return []string{}, err + } + result, ok := v.([]string) + if !ok { + return []string{}, errors.Wrapf(ErrFlagAssertion, "invalid string slice assertion type %T for key %s", v, key) + } + return result, nil +} + +// GetBool retrieves the boolean value of the flag with the specified key. +func (f Flags) GetBool(key string) (bool, error) { + v, err := f.getValue(key, FlagTypeBool, func(v string) (interface{}, error) { + return strconv.ParseBool(v) + }) + if err != nil { + return false, err + } + result, ok := v.(bool) + if !ok { + return false, errors.Wrapf(ErrFlagAssertion, "invalid bool assertion type %T for key %s", v, key) + } + return result, nil +} + +// GetInt retrieves the integer value of the flag with the specified key. +func (f Flags) GetInt(key string) (int, error) { + v, err := f.getValue(key, FlagTypeInt, func(v string) (interface{}, error) { + return strconv.Atoi(v) + }) + if err != nil { + return 0, err + } + result, ok := v.(int) + if !ok { + return 0, errors.Wrapf(ErrFlagAssertion, "invalid int assertion type %T for key %s", v, key) + } + return result, nil +} + +// GetInt64 retrieves the int64 value of the flag with the specified key. +func (f Flags) GetInt64(key string) (int64, error) { + v, err := f.getValue(key, FlagTypeInt64, func(v string) (interface{}, error) { + return strconv.ParseInt(v, 10, 64) + }) + if err != nil { + return int64(0), err + } + result, ok := v.(int64) + if !ok { + return int64(0), errors.Wrapf(ErrFlagAssertion, "invalid int64 assertion type %T for key %s", v, key) + } + return result, nil +} + +// GetUint retrieves the uint value of the flag with the specified key. +func (f Flags) GetUint(key string) (uint, error) { + v, err := f.getValue(key, FlagTypeUint, func(v string) (interface{}, error) { + return strconv.ParseUint(v, 10, 64) + }) + if err != nil { + return uint(0), err + } + result, ok := v.(uint64) + if !ok { + return uint(0), errors.Wrapf(ErrFlagAssertion, "invalid uint assertion type %T for key %s", v, key) + } + return uint(result), nil +} + +// GetUint64 retrieves the uint64 value of the flag with the specified key. +func (f Flags) GetUint64(key string) (uint64, error) { + v, err := f.getValue(key, FlagTypeUint64, func(v string) (interface{}, error) { + return strconv.ParseUint(v, 10, 64) + }) + if err != nil { + return uint64(0), err + } + result, ok := v.(uint64) + if !ok { + return uint64(0), errors.Wrapf(ErrFlagAssertion, "invalid uint64 assertion type %T for key %s", v, key) + } + return result, nil +} + +// flagValue returns the value of the flag if set, otherwise returns the default value. +func flagValue(flag *Flag) string { + if flag.Value != "" { + return flag.Value + } + if flag.DefaultValue != "" { + return flag.DefaultValue + } + if flag.Type == FlagTypeBool || + flag.Type == FlagTypeInt || + flag.Type == FlagTypeInt64 || + flag.Type == FlagTypeUint || + flag.Type == FlagTypeUint64 { + return "0" + } + return "" +} diff --git a/ignite/services/plugin/flag_test.go b/ignite/services/plugin/flag_test.go new file mode 100644 index 0000000000..a318fbabd3 --- /dev/null +++ b/ignite/services/plugin/flag_test.go @@ -0,0 +1,580 @@ +package plugin + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ignite/cli/v29/ignite/pkg/errors" +) + +const ( + flagString1 = "string_flag_1" + flagString2 = "string_flag_2" + flagString3 = "string_flag_3" + flagStringSlice1 = "string_slice_flag_1" + flagStringSlice2 = "string_slice_flag_2" + flagStringSlice3 = "string_slice_flag_3" + flagBool1 = "bool_flag_1" + flagBool2 = "bool_flag_2" + flagBool3 = "bool_flag_3" + flagInt1 = "int_flag_1" + flagInt2 = "int_flag_2" + flagInt3 = "int_flag_3" + flagUint1 = "uint_flag_1" + flagUint2 = "uint_flag_2" + flagUint3 = "uint_flag_3" + flagInt641 = "int64_flag_1" + flagInt642 = "int64_flag_2" + flagInt643 = "int64_flag_3" + flagUint641 = "uint64_flag_1" + flagUint642 = "uint64_flag_2" + flagUint643 = "uint64_flag_3" + flagWrongType1 = "wrong_type_1" + flagWrongType2 = "wrong_type_2" + flagWrongType3 = "wrong_type_3" +) + +var testFlags = Flags{ + {Name: flagString1, Value: "text_1", DefaultValue: "def_text_1", Type: FlagTypeString}, + {Name: flagString2, DefaultValue: "def_text_2", Type: FlagTypeString}, + {Name: flagString3, Type: FlagTypeString}, + + {Name: flagStringSlice1, Value: "slice_1,slice_2", DefaultValue: "slice_1,slice_2,slice_3", Type: FlagTypeStringSlice}, + {Name: flagStringSlice2, DefaultValue: "slice_1,slice_2,slice_3", Type: FlagTypeStringSlice}, + {Name: flagStringSlice3, Type: FlagTypeStringSlice}, + + {Name: flagInt1, Value: "-100", DefaultValue: "300", Type: FlagTypeInt}, + {Name: flagInt2, DefaultValue: "200", Type: FlagTypeInt}, + {Name: flagInt3, Type: FlagTypeInt}, + + {Name: flagUint1, Value: "22", DefaultValue: "34", Type: FlagTypeUint}, + {Name: flagUint2, DefaultValue: "40", Type: FlagTypeUint}, + {Name: flagUint3, Type: FlagTypeUint}, + + {Name: flagInt641, Value: "123", DefaultValue: "641", Type: FlagTypeInt64}, + {Name: flagInt642, DefaultValue: "344", Type: FlagTypeInt64}, + {Name: flagInt643, Type: FlagTypeInt64}, + + {Name: flagUint641, Value: "123", DefaultValue: "433333", Type: FlagTypeUint64}, + {Name: flagUint642, DefaultValue: "100000", Type: FlagTypeUint64}, + {Name: flagUint643, Type: FlagTypeUint64}, + + {Name: flagBool1, Value: "true", DefaultValue: "false", Type: FlagTypeBool}, + {Name: flagBool2, DefaultValue: "true", Type: FlagTypeBool}, + {Name: flagBool3, Type: FlagTypeBool}, + + {Name: flagWrongType1, Value: "text_wrong", DefaultValue: "def_text", Type: FlagTypeUint64}, + {Name: flagWrongType2, DefaultValue: "text_wrong", Type: FlagTypeBool}, + {Name: flagWrongType3, Type: FlagTypeInt}, +} + +func TestFlags_GetBool(t *testing.T) { + tests := []struct { + name string + key string + f Flags + want bool + err error + }{ + { + name: "flag with value", + key: flagBool1, + f: testFlags, + want: true, + }, + { + name: "flag with default value", + key: flagBool2, + f: testFlags, + want: true, + }, + { + name: "flag without value and default value", + key: flagBool3, + f: testFlags, + want: false, + }, + { + name: "invalid flag type", + key: flagString1, + f: testFlags, + err: errors.Wrapf(ErrInvalidFlagType, "invalid flag type %v for key %s", FlagTypeString, flagString1), + }, + { + name: "invalid flag", + key: "invalid_key", + f: testFlags, + err: errors.Wrap(ErrFlagNotFound, "invalid_key"), + }, + { + name: "wrong flag type", + key: flagWrongType1, + f: testFlags, + err: errors.Wrap(ErrInvalidFlagType, "invalid flag type TYPE_FLAG_UINT64 for key wrong_type_1"), + }, + { + name: "wrong flag value", + key: flagWrongType2, + f: testFlags, + err: errors.New("strconv.ParseBool: parsing \"text_wrong\": invalid syntax"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.f.GetBool(tt.key) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestFlags_GetInt(t *testing.T) { + tests := []struct { + name string + f Flags + key string + want int + err error + }{ + { + name: "flag with value", + key: flagInt1, + f: testFlags, + want: -100, + }, + { + name: "flag with default value", + key: flagInt2, + f: testFlags, + want: 200, + }, + { + name: "flag without value and default value", + key: flagInt3, + f: testFlags, + want: 0, + }, + { + name: "invalid flag type", + key: flagString1, + f: testFlags, + err: errors.Wrapf(ErrInvalidFlagType, "invalid flag type %v for key %s", FlagTypeString, flagString1), + }, + { + name: "invalid flag", + key: "invalid_key", + f: testFlags, + err: errors.Wrap(ErrFlagNotFound, "invalid_key"), + }, + { + name: "wrong flag type", + key: flagWrongType2, + f: testFlags, + err: errors.Wrap(ErrInvalidFlagType, "invalid flag type TYPE_FLAG_BOOL for key wrong_type_2"), + }, + { + name: "wrong flag value without default or value", + key: flagWrongType3, + f: testFlags, + want: 0, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.f.GetInt(tt.key) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestFlags_GetInt64(t *testing.T) { + tests := []struct { + name string + f Flags + key string + want int64 + err error + }{ + { + name: "flag with value", + key: flagInt641, + f: testFlags, + want: 123, + }, + { + name: "flag with default value", + key: flagInt642, + f: testFlags, + want: 344, + }, + { + name: "flag without value and default value", + key: flagInt643, + f: testFlags, + want: 0, + }, + { + name: "invalid flag type", + key: flagString1, + f: testFlags, + err: errors.Wrapf(ErrInvalidFlagType, "invalid flag type %v for key %s", FlagTypeString, flagString1), + }, + { + name: "invalid flag", + key: "invalid_key", + f: testFlags, + err: errors.Wrap(ErrFlagNotFound, "invalid_key"), + }, + { + name: "wrong flag type", + key: flagWrongType3, + f: testFlags, + err: errors.Wrap(ErrInvalidFlagType, "invalid flag type TYPE_FLAG_INT for key wrong_type_3"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.f.GetInt64(tt.key) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestFlags_GetString(t *testing.T) { + tests := []struct { + name string + f Flags + key string + want string + err error + }{ + { + name: "flag with value", + key: flagString1, + f: testFlags, + want: "text_1", + }, + { + name: "flag with default value", + key: flagString2, + f: testFlags, + want: "def_text_2", + }, + { + name: "flag without value and default value", + key: flagString3, + f: testFlags, + want: "", + }, + { + name: "invalid flag type", + key: flagInt1, + f: testFlags, + err: errors.Wrapf(ErrInvalidFlagType, "invalid flag type %v for key %s", FlagTypeInt, flagInt1), + }, + { + name: "invalid flag", + key: "invalid_key", + f: testFlags, + err: errors.Wrap(ErrFlagNotFound, "invalid_key"), + }, + { + name: "wrong flag type", + key: flagWrongType2, + f: testFlags, + err: errors.Wrap(ErrInvalidFlagType, "invalid flag type TYPE_FLAG_BOOL for key wrong_type_2"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.f.GetString(tt.key) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestFlags_GetStringSlice(t *testing.T) { + tests := []struct { + name string + f Flags + key string + want []string + err error + }{ + { + name: "flag with default value", + key: flagStringSlice1, + f: testFlags, + want: []string{"slice_1", "slice_2"}, + }, + { + name: "flag with default value", + key: flagStringSlice2, + f: testFlags, + want: []string{"slice_1", "slice_2", "slice_3"}, + }, + { + name: "flag without value and default value", + key: flagStringSlice3, + f: testFlags, + want: []string{}, + }, + { + name: "invalid flag type", + key: flagString1, + f: testFlags, + err: errors.Wrapf(ErrInvalidFlagType, "invalid flag type %v for key %s", FlagTypeString, flagString1), + }, + { + name: "invalid flag", + key: "invalid_key", + f: testFlags, + err: errors.Wrap(ErrFlagNotFound, "invalid_key"), + }, + { + name: "wrong flag type", + key: flagWrongType1, + f: testFlags, + err: errors.Wrap(ErrInvalidFlagType, "invalid flag type TYPE_FLAG_UINT64 for key wrong_type_1"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.f.GetStringSlice(tt.key) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestFlags_GetUint(t *testing.T) { + tests := []struct { + name string + f Flags + key string + want uint + err error + }{ + { + name: "flag with value", + key: flagUint1, + f: testFlags, + want: 22, + }, + { + name: "flag with default value", + key: flagUint2, + f: testFlags, + want: 40, + }, + { + name: "flag without value and default value", + key: flagUint3, + f: testFlags, + want: 0, + }, + { + name: "invalid flag type", + key: flagString1, + f: testFlags, + err: errors.Wrapf(ErrInvalidFlagType, "invalid flag type %v for key %s", FlagTypeString, flagString1), + }, + { + name: "invalid flag", + key: "invalid_key", + f: testFlags, + err: errors.Wrap(ErrFlagNotFound, "invalid_key"), + }, + { + name: "wrong flag type", + key: flagWrongType1, + f: testFlags, + err: errors.Wrap(ErrInvalidFlagType, "invalid flag type TYPE_FLAG_UINT64 for key wrong_type_1"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.f.GetUint(tt.key) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestFlags_GetUint64(t *testing.T) { + tests := []struct { + name string + f Flags + key string + want uint64 + err error + }{ + { + name: "flag with value", + key: flagUint641, + f: testFlags, + want: 123, + }, + { + name: "flag with default value", + key: flagUint642, + f: testFlags, + want: 100000, + }, + { + name: "flag without value and default value", + key: flagUint643, + f: testFlags, + want: 0, + }, + { + name: "invalid flag type", + key: flagString1, + f: testFlags, + err: errors.Wrapf(ErrInvalidFlagType, "invalid flag type %v for key %s", FlagTypeString, flagString1), + }, + { + name: "invalid flag", + key: "invalid_key", + f: testFlags, + err: errors.Wrap(ErrFlagNotFound, "invalid_key"), + }, + { + name: "wrong flag type", + key: flagWrongType1, + f: testFlags, + err: errors.New("strconv.ParseUint: parsing \"text_wrong\": invalid syntax"), + }, + { + name: "wrong flag type", + key: flagWrongType3, + f: testFlags, + err: errors.Wrap(ErrInvalidFlagType, "invalid flag type TYPE_FLAG_INT for key wrong_type_3"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.f.GetUint64(tt.key) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func TestFlags_getValue(t *testing.T) { + tests := []struct { + name string + f Flags + key string + flagType FlagType + convFunc func(v string) (interface{}, error) + want interface{} + err error + }{ + { + name: "Valid string conversion", + f: testFlags, + key: flagString1, + flagType: FlagTypeString, + convFunc: func(v string) (interface{}, error) { return v, nil }, + want: "text_1", + }, + { + name: "Invalid flag type", + f: testFlags, + key: flagString1, + flagType: FlagTypeInt, + convFunc: func(v string) (interface{}, error) { return v, nil }, + err: errors.Wrapf(ErrInvalidFlagType, "invalid flag type %v for key %s", FlagTypeString, flagString1), + }, + { + name: "Flag not found", + f: testFlags, + key: "non_existing_flag", + flagType: FlagTypeString, + convFunc: func(v string) (interface{}, error) { return v, nil }, + err: errors.Wrap(ErrFlagNotFound, "non_existing_flag"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.f.getValue(tt.key, tt.flagType, tt.convFunc) + if tt.err != nil { + require.Error(t, err) + require.Equal(t, tt.err.Error(), err.Error()) + return + } + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} + +func Test_flagValue(t *testing.T) { + tests := []struct { + name string + flag *Flag + want string + }{ + { + name: "Flag with value", + flag: &Flag{Name: flagString1, Value: "actual_value", DefaultValue: "default_value"}, + want: "actual_value", + }, + { + name: "Flag with default value", + flag: &Flag{Name: flagString1, DefaultValue: "default_value"}, + want: "default_value", + }, + { + name: "Flag without value and default value", + flag: &Flag{Name: flagString1}, + want: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := flagValue(tt.flag) + require.Equal(t, tt.want, got) + }) + } +} diff --git a/integration/plugin/testdata/example-plugin/main.go b/integration/plugin/testdata/example-plugin/main.go index 9d86a99fec..f8ff8d2950 100644 --- a/integration/plugin/testdata/example-plugin/main.go +++ b/integration/plugin/testdata/example-plugin/main.go @@ -19,7 +19,7 @@ func (p) Manifest(context.Context) (*plugin.Manifest, error) { Use: "example-plugin", Short: "Explain what the command is doing...", Long: "Long description goes here...", - Flags: []*plugin.Flag{ + Flags: plugin.Flags{ {Name: "my-flag", Type: plugin.FlagTypeString, Usage: "my flag description"}, }, PlaceCommandUnder: "ignite",