diff --git a/README.md b/README.md index 0933ea7f0f745ef750912062cfe04ef261f2fc38..5abdada2e5668b95640df4acb9a4510e61804cdb 100644 --- a/README.md +++ b/README.md @@ -146,14 +146,16 @@ The function `Execute()` executes the command. See the section setting.Execute() ``` -### Shadow +### Proxy -The shadow structure is used to copy the values of the flags to the -shadow structure. The shadow structure is set using the `SetShadow()` -and configured using the tag `shadow`. +The proxy structure is used to copy the values of the flags to the +proxy structure. The proxy structure is used to access the values of the +flags. + +The proxy structure must implement the `Proxy` interface. ```go -type Shadow struct { +type MyObj struct { Verbose bool Serve struct { Host string @@ -161,12 +163,14 @@ type Shadow struct { } } +func (m *MyObj) Copy(_ map[string]any) { +} + func main() { setting := New(os.Args[0], Definition{}) - setting.SetShadow(Shadow{}) + setting.SetProxy(&MyObj{}) setting.Parse(os.Args[1:]) setting.Execute() - fmt.Printf("Shadow: %+v", setting.GetShadow()) } ``` diff --git a/api.go b/api.go index b8fe8f482c00fb64b831f388f81316c90182a707..b6fc6ac925b875205ff606d2dc3669e94aacfaef 100644 --- a/api.go +++ b/api.go @@ -12,18 +12,22 @@ import ( "reflect" ) -// ExecuteWithShadow executes the command line arguments and calls the functions. -func ExecuteWithShadow[C any, D Copyable[D]](cmd C, cnf D) *Settings[C] { - return execute(cmd, cnf, os.Args[0], os.Args[1:]) -} - -type noShadow struct{} +type dummyCopyArg struct{} -func (n noShadow) Copy(a noShadow) {} +func (n dummyCopyArg) Copy(_ map[string]any) {} // Execute executes the command line arguments and calls the functions. -func Execute[C any](cmd C) *Settings[C] { - return execute(cmd, noShadow{}, os.Args[0], os.Args[1:]) +func Execute[C any](cmd C, cpy ...Proxy) *Settings[C] { + + if cpy == nil { + return execute(cmd, dummyCopyArg{}, os.Args[0], os.Args[1:]) + } + + if len(cpy) > 1 { + panic("too many arguments") + } + + return execute(cmd, cpy[0], os.Args[0], os.Args[1:]) } // PrintFlagOutput prints the flag output to the standard output. @@ -36,15 +40,15 @@ func (s *Settings[C]) GetFlagOutput() { fmt.Println(s.command.flagSet.Output()) } -// execute is the internal implementation of ExecuteWithShadow. -func execute[C any, D Copyable[D]](cmd C, cnf D, name string, args []string) *Settings[C] { +// execute is the internal implementation of Execute. +func execute[C any, D Proxy](cmd C, proxy D, name string, args []string) *Settings[C] { instance := New(name, cmd) if instance.HasErrors() { return instance } - if (reflect.ValueOf(&cnf).Elem().Type() != reflect.TypeOf(noShadow{})) { - instance.SetShadow(cnf) + if (reflect.ValueOf(&proxy).Elem().Type() != reflect.TypeOf(dummyCopyArg{})) { + instance.SetProxy(proxy) if instance.HasErrors() { return instance } @@ -59,10 +63,6 @@ func execute[C any, D Copyable[D]](cmd C, cnf D, name string, args []string) *Se return instance } - if instance.shadow != nil { - cnf.Copy(instance.shadow.(D)) - } - instance.Execute() if instance.HasErrors() { return instance @@ -87,6 +87,8 @@ func New[C any](name string, definitions C) *Settings[C] { return s } + s.mapping = make(map[string]any) + buf := bytes.NewBufferString("") s.flagOutput = io.Writer(buf) s.definitions = definitions diff --git a/api_test.go b/api_test.go index 079c51a89e537c2caa064af22dfabbd6bf9b4656..fa7e9259423a46245b333cb887a155f5f59ee49d 100644 --- a/api_test.go +++ b/api_test.go @@ -25,7 +25,7 @@ func TestUsage(t *testing.T) { type TestDataStruct struct { } -func (s *TestDataStruct) Copy(x *TestDataStruct) { +func (s *TestDataStruct) Copy(_ map[string]any) { } @@ -44,8 +44,7 @@ func TestExecuteTypeStringIsNotSupported(t *testing.T) { func TestExecuteHelp(t *testing.T) { instance := execute(CmdTest1{}, &TestDataStruct{}, "test", []string{"-h"}) - assert.False(t, instance.HasErrors()) - + assert.True(t, instance.HelpRequested()) } func TestNewIntWithError(t *testing.T) { diff --git a/command.go b/command.go index ff7f5540aba2813c1e67e51653d566f763fbb0bb..9ac4106e55fbf8aab5eee74147c32834b48a8b99 100644 --- a/command.go +++ b/command.go @@ -9,14 +9,13 @@ import ( ) type cmd[C any] struct { - name string - flagSet *flag.FlagSet - tagMapping map[string]string - shadowMapping map[string]string - commands []*cmd[C] - settings *Settings[C] - valuePath []string - functionName string + name string + flagSet *flag.FlagSet + tagMapping map[string]string + commands []*cmd[C] + settings *Settings[C] + valuePath []string + functionName string } func (c *cmd[C]) parse(args []string) { @@ -56,14 +55,13 @@ func (c *cmd[C]) parse(args []string) { func buildCommandStruct[C any](s *Settings[C], name, fkt string, errorHandling flag.ErrorHandling, path []string) *cmd[C] { cc := &cmd[C]{ - name: name, - flagSet: flag.NewFlagSet(name, errorHandling), - commands: []*cmd[C]{}, - settings: s, - tagMapping: map[string]string{}, - shadowMapping: map[string]string{}, - valuePath: path, - functionName: fkt, + name: name, + flagSet: flag.NewFlagSet(name, errorHandling), + commands: []*cmd[C]{}, + settings: s, + tagMapping: map[string]string{}, + valuePath: path, + functionName: fkt, } cc.flagSet.SetOutput(s.flagOutput) @@ -157,15 +155,8 @@ func (c *cmd[C]) parseStruct(dta any) { if m[tagLong] != "" { c.tagMapping[m[tagLong]] = v.Type().Field(i).Name } - - if m[tagShadow] != "" { - c.shadowMapping[v.Type().Field(i).Name] = m[tagShadow] - } - c.initFlags(x, m) } else if m[tagCommand] != "" { - - //c.valuePath = append(c.valuePath, ) c.tagMapping[m[tagCommand]] = v.Type().Field(i).Name c.initCommands(x, m, v.Type().Field(i).Name) diff --git a/error.go b/error.go index 0f14e2e8f2c95436f81408c288e4883e18d2fa4f..91966f4b334e9831a101960e7f4828716e296138 100644 --- a/error.go +++ b/error.go @@ -126,3 +126,9 @@ type MissingFunctionError error func newMissingFunctionError(missing string) MissingFunctionError { return MissingFunctionError(errors.New("missing function " + missing)) } + +type InvalidTypeForPathError error + +func newInvalidTypeForPathError(path string, pt string, nt string) InvalidTypeForPathError { + return InvalidTypeForPathError(errors.New("invalid type for path " + path + ": expected " + pt + ", got " + nt)) +} diff --git a/error_test.go b/error_test.go index 46fc294bd5a1e44730d13deffdcca06aff1428df..cb99613ffb8e1d1e6963a0a6eb3659fdfe4f8208 100644 --- a/error_test.go +++ b/error_test.go @@ -96,3 +96,9 @@ func TestMissingFunctionError(t *testing.T) { _, ok := err.(MissingFunctionError) assert.True(t, ok) } + +func TestInvalidTypeForPathError(t *testing.T) { + err := newInvalidTypeForPathError("test", "test", "test") + _, ok := err.(InvalidTypeForPathError) + assert.True(t, ok) +} diff --git a/execute.go b/execute.go index e2fcd76f8b17991c705bb091e214ca7ba524b6e3..994e1eb19de126b784bd12de9dd2b7440df2846f 100644 --- a/execute.go +++ b/execute.go @@ -6,8 +6,10 @@ package xflags import ( "flag" "fmt" + "github.com/stretchr/testify/assert" "reflect" "strings" + "testing" ) func (s *Settings[C]) Execute() *Settings[C] { @@ -31,7 +33,6 @@ func (s *Settings[C]) Execute() *Settings[C] { func callCmdFunctions[C any](settings *Settings[C], commands []*cmd[C]) bool { - //result := false wasExecuted := false shouldExecute := false @@ -117,3 +118,33 @@ func (s *Settings[C]) MissingCommand() bool { func (s *Settings[C]) WasExecuted() bool { return s.wasExecuted } + +func TestWrongDefinitionType(t *testing.T) { + c := New("root", 2) + c.Parse([]string{"test"}) + c.Execute() + assert.True(t, c.HasErrors()) +} + +type testExecuteCommandStruct struct { + Command1 struct { + } `command:"command1" description:"Command 1" callback:"command1Callback" ` + Command2 struct { + Command3 struct { + } `command:"command3" description:"Command 3" callback:"command3Callback" call:"DoCmd3"` + } `command:"command2" description:"Command 2" callback:"command2Callback" ` +} + +func (c *testExecuteCommandStruct) DoCmd3(s *Settings[testExecuteCommandStruct]) { +} + +func (c *testExecuteCommandStruct) command1Callback(args []string) { + fmt.Println("command1Callback", args) +} + +func TestExecute1(t *testing.T) { + c := New("root", testExecuteCommandStruct{}) + c.Parse([]string{"command2", "command3", "commandX"}) + c.Execute() + assert.False(t, c.HasErrors()) +} diff --git a/flag.go b/flag.go deleted file mode 100644 index 8107e9834aae067b27dc196920cc5a5e5d15bb69..0000000000000000000000000000000000000000 --- a/flag.go +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2022 schukai GmbH -// SPDX-License-Identifier: AGPL-3.0 - -package xflags diff --git a/flag_test.go b/flag_test.go deleted file mode 100644 index 602245980aac39d4c2492e8c5f12689b3dec20b8..0000000000000000000000000000000000000000 --- a/flag_test.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 schukai GmbH -// SPDX-License-Identifier: AGPL-3.0 - -package xflags - -import ( - "fmt" - "github.com/stretchr/testify/assert" - "testing" -) - -func TestWrongDefinitionType(t *testing.T) { - c := New("root", 2) - c.Parse([]string{"test"}) - c.Execute() - assert.True(t, c.HasErrors()) -} - -type testExecuteCommandStruct struct { - Command1 struct { - } `command:"command1" description:"Command 1" callback:"command1Callback" ` - Command2 struct { - Command3 struct { - } `command:"command3" description:"Command 3" callback:"command3Callback" call:"DoCmd3"` - } `command:"command2" description:"Command 2" callback:"command2Callback" ` -} - -func (c *testExecuteCommandStruct) DoCmd3(s *Settings[testExecuteCommandStruct]) { -} - -func (c *testExecuteCommandStruct) command1Callback(args []string) { - fmt.Println("command1Callback", args) -} - -func TestExecute1(t *testing.T) { - c := New("root", testExecuteCommandStruct{}) - c.Parse([]string{"command2", "command3", "commandX"}) - c.Execute() - assert.False(t, c.HasErrors()) -} diff --git a/issue-1_test.go b/issue-1_test.go index aeaac728547d33a70660c953649cc25cd2ae9c7d..7f4f3ad935ebb00af4c78c3e30f9162add719bbb 100644 --- a/issue-1_test.go +++ b/issue-1_test.go @@ -60,7 +60,7 @@ func TestIssue1TestCallCMD4(tp *testing.T) { for i, tt := range testData { tp.Run(strconv.Itoa(i)+":"+strings.Join(tt.args, ","), func(t *testing.T) { - s := execute(testCmdStructIssue1{}, noShadow{}, "test", tt.args) + s := execute(testCmdStructIssue1{}, dummyCopyArg{}, "test", tt.args) assert.Equal(t, tt.hasErrors, s.HasErrors()) assert.Equal(t, tt.hasHint, s.HasHint()) @@ -75,27 +75,27 @@ func TestIssue1TestCallCMD4(tp *testing.T) { } func TestIssue1TestNoCallback(t *testing.T) { - s := execute(testCmdStructIssue1{}, noShadow{}, "test", []string{"cmd1", "cmd6", "cmd7"}) + s := execute(testCmdStructIssue1{}, dummyCopyArg{}, "test", []string{"cmd1", "cmd6", "cmd7"}) assert.Equal(t, 3, len(s.Errors())) assert.False(t, s.WasExecuted()) } func TestIssue1TestToMuchCommands(t *testing.T) { - s := execute(testCmdStructIssue1{}, noShadow{}, "test", []string{"cmd1", "cmd9"}) + s := execute(testCmdStructIssue1{}, dummyCopyArg{}, "test", []string{"cmd1", "cmd9"}) assert.True(t, s.MissingCommand()) assert.False(t, s.WasExecuted()) } // here it is tested whether the last and defined callback is called func TestIssue1TestCallCMD3(t *testing.T) { - s := execute(testCmdStructIssue1{}, noShadow{}, "test", []string{"cmd1", "cmd2", "cmd3"}) + s := execute(testCmdStructIssue1{}, dummyCopyArg{}, "test", []string{"cmd1", "cmd2", "cmd3"}) assert.Equal(t, 0, len(s.Errors())) assert.True(t, s.WasExecuted()) } // NoShadow is an internal Struct for testing func TestIssue1MessageWithNoShadow(t *testing.T) { - s := execute(testCmdStructIssue1{}, noShadow{}, "test", []string{"cmd1", "cmd2", "cmd3", "-v3"}) + s := execute(testCmdStructIssue1{}, dummyCopyArg{}, "test", []string{"cmd1", "cmd2", "cmd3", "-v3"}) assert.Equal(t, 0, len(s.Errors())) } @@ -139,7 +139,7 @@ func TestIssue1Summary(tp *testing.T) { for _, tt := range data { tp.Run(tt.args[0], func(t *testing.T) { - s := execute(testCmdStructIssue1{}, noShadow{}, "test", tt.args) + s := execute(testCmdStructIssue1{}, dummyCopyArg{}, "test", tt.args) assert.Equal(t, tt.helpRequested, s.HelpRequested()) assert.Equal(t, tt.wasExecuted, s.WasExecuted()) assert.Equal(t, tt.missingCommand, s.MissingCommand()) diff --git a/shadow.go b/mapping.go similarity index 50% rename from shadow.go rename to mapping.go index 0f7bd5a68566c6ddd51fa0ba7aec46915890c31b..18fbe371fce01c8a2ea967b6b44ca40ab31ea5f8 100644 --- a/shadow.go +++ b/mapping.go @@ -9,25 +9,26 @@ import ( "strings" ) -// SetShadow sets the shadow struct for the flag configuration. -func (s *Settings[C]) SetShadow(shadow any) *Settings[C] { +// SetProxy sets the shadow struct for the flag configuration. +func (s *Settings[C]) SetProxy(proxy Proxy) *Settings[C] { - if reflect.TypeOf(shadow).Kind() != reflect.Ptr { + if reflect.TypeOf(proxy).Kind() != reflect.Ptr { s.errors = append(s.errors, ShadowMustBePointerError) return s } - if reflect.TypeOf(shadow).Elem().Kind() != reflect.Struct { + if reflect.TypeOf(proxy).Elem().Kind() != reflect.Struct { s.errors = append(s.errors, ShadowMustBePointerError) return s } - s.shadow = shadow + s.proxy = proxy return s } -type Copyable[C any] interface { - Copy(data C) +// Proxy is the interface for the proxy struct. +type Proxy interface { + Copy(map[string]any) } func (s *Settings[C]) assignValues(c cmd[C]) { @@ -46,33 +47,15 @@ func (s *Settings[C]) assignValues(c cmd[C]) { pa := append(c.valuePath, k) p := strings.Join(pa, ".") - err := setValueUsingPath(&s.definitions, p, value) + err := SetValueUsingPath(&s.definitions, p, value) if err != nil { s.errors = append(s.errors, err) } - err = c.setShadowValue(s.shadow, k, value) - if err != nil { - s.errors = append(s.errors, err) - } + s.mapping[p] = value return }) } - -func (c cmd[C]) setShadowValue(obj any, k string, value string) error { - - if obj == nil { - return nil - } - - // set shadow - n, ok := c.shadowMapping[k] - if !ok { - return nil - } - - return setValueUsingPath(obj, n, value) -} diff --git a/shadow_test.go b/mapping_test.go similarity index 79% rename from shadow_test.go rename to mapping_test.go index 71014abfc8d4f9190c82b29fed7b4dbcbe84caf7..723d955f85a9135ce2226639f1d51d08101524bc 100644 --- a/shadow_test.go +++ b/mapping_test.go @@ -20,13 +20,6 @@ type ConfigStruct6 struct { ValSub ConfigStruct6Sub1 } -func TestFlagSetShadowError(t *testing.T) { - settings := New("test", testExecutionStruct{}) - settings.SetShadow(3) - assert.True(t, settings.HasErrors()) - -} - func TestFlagCopyToShadow(t *testing.T) { c := ConfigStruct6{} @@ -35,7 +28,7 @@ func TestFlagCopyToShadow(t *testing.T) { settings := New("test", testExecutionStruct{}) assert.NotNil(t, settings) - settings.SetShadow(&c) + settings.SetProxy(&c) assert.False(t, settings.HasErrors()) settings.Parse([]string{"-a", "command1", "-d"}) @@ -45,8 +38,9 @@ func TestFlagCopyToShadow(t *testing.T) { } -func (s *ConfigStruct6) Copy(p *ConfigStruct6) { - +func (s *ConfigStruct6) Copy(m map[string]any) { + SetValueUsingPath(s, "ValGlobal1", (m["Global1"])) + SetValueUsingPath(s, "ValCommand1Flag2", (m["Command1.Command1Flag2"])) } func TestCopyable(t *testing.T) { diff --git a/parse.go b/parse.go index b659968c81f158fd0f875564f98215023149649c..c0e9865608311d6141d2958e39a6f10d93a7878f 100644 --- a/parse.go +++ b/parse.go @@ -38,5 +38,9 @@ func (s *Settings[C]) Parse(args []string) *Settings[C] { s.command.parse(r) + if s.mapping != nil && s.proxy != nil { + s.proxy.Copy(s.mapping) + } + return s } diff --git a/pathfind.go b/pathfind.go index 8024f57d170beb9c7402c67b6196c64fc930fae8..951bf8fe5d951502bcbcdb3c1e1ab5fc169ece84 100644 --- a/pathfind.go +++ b/pathfind.go @@ -4,13 +4,14 @@ package xflags import ( + "fmt" "reflect" "strconv" "strings" ) // This function returns the value of a field in a struct, given a path to the field. -func getValueFrom[D any](obj D, keyWithDots string) (interface{}, error) { +func GetValueFrom[D any](obj D, keyWithDots string) (any, error) { keySlice := strings.Split(keyWithDots, ".") v := reflect.ValueOf(obj) @@ -49,7 +50,7 @@ func getValueFrom[D any](obj D, keyWithDots string) (interface{}, error) { } // This function sets the value of a field in a struct, given a path to the field. -func setValueUsingPath[D any](obj D, keyWithDots string, newValue string) error { +func SetValueUsingPath[D any](obj D, keyWithDots string, newValue any) error { keySlice := strings.Split(keyWithDots, ".") v := reflect.ValueOf(obj) @@ -94,29 +95,83 @@ func setValueUsingPath[D any](obj D, keyWithDots string, newValue string) error return newCannotSetError(keyWithDots) } + switch v.Kind() { + case reflect.Ptr: + if newValue == nil { + v.Set(reflect.Zero(v.Type())) + } else { + v.Set(reflect.ValueOf(&newValue)) + } + return nil + } + + newValueType := reflect.TypeOf(newValue) + if newValueType == nil { + return newUnsupportedTypePathError(keyWithDots, v.Type()) + } + + newValueKind := reflect.TypeOf(newValue).Kind() + switch v.Kind() { case reflect.String: - v.SetString(newValue) - case reflect.Int: + if newValueKind == reflect.String { + v.SetString(newValue.(string)) + } else { + v.SetString(fmt.Sprintf("%v", newValue)) + } + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - s, err := strconv.Atoi(newValue) - if err != nil { - return err + if newValueKind == reflect.Int { + v.SetInt(int64(newValue.(int))) + } else { + s, err := strconv.ParseInt(newValue.(string), 10, 64) + if err != nil { + return err + } + v.SetInt(s) + } + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + + if newValueKind == reflect.Int { + v.SetUint(uint64(newValue.(int))) + } else { + s, err := strconv.ParseInt(newValue.(string), 10, 64) + if err != nil { + return err + } + v.SetUint(uint64(s)) } - v.SetInt(int64(s)) case reflect.Bool: - v.SetBool(newValue == "true") - case reflect.Float64: - s, err := strconv.ParseFloat(newValue, 64) - if err != nil { - return err + if newValueKind == reflect.Bool { + v.SetBool(newValue.(bool)) + } else { + b, err := strconv.ParseBool(newValue.(string)) + if err != nil { + return err + } + + v.SetBool(b) + } + + case reflect.Float64, reflect.Float32: + + if newValueKind == reflect.Float64 { + v.SetFloat(newValue.(float64)) + } else { + s, err := strconv.ParseFloat(newValue.(string), 64) + if err != nil { + return err + } + + v.SetFloat(s) } - v.SetFloat(s) default: - return newUnsupportedTypeAtTopOfPathError(keyWithDots, v.Type()) + return newInvalidTypeForPathError(keyWithDots, v.Type().String(), newValueKind.String()) } return nil diff --git a/pathfind_test.go b/pathfind_test.go index 6a4e7cd897388adacbed808a8a1deca73a744f49..e3145206698f2fcb45af84fbf2afb277b99e274e 100644 --- a/pathfind_test.go +++ b/pathfind_test.go @@ -32,7 +32,7 @@ func TestPathFindError(t *testing.T) { s := PathfindTestStruct1{} - _, err := getValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.XX") + _, err := GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.XX") if err == nil { t.Error("err == nil") } @@ -58,7 +58,7 @@ func TestPathFindSetValueString(t *testing.T) { for k, v := range testData { s := &PathfindTestStruct1{} - err := setValueUsingPath[*PathfindTestStruct1](s, k, v) + err := SetValueUsingPath[*PathfindTestStruct1](s, k, v) if err != nil { t.Error(err) } @@ -74,7 +74,7 @@ func TestPathFindGetValueFrom(t *testing.T) { s.Sub1.Bs = "3" s.Sub1.Bf = 4.0 - v, err := getValueFrom[PathfindTestStruct1](s, "Sub1.B") + v, err := GetValueFrom[PathfindTestStruct1](s, "Sub1.B") if err != nil { t.Error(err) } @@ -83,7 +83,7 @@ func TestPathFindGetValueFrom(t *testing.T) { t.Error("v != true") } - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Bi") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Bi") if err != nil { t.Error(err) } @@ -92,7 +92,7 @@ func TestPathFindGetValueFrom(t *testing.T) { t.Error("v != 2") } - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Bs") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Bs") if err != nil { t.Error(err) } @@ -101,7 +101,7 @@ func TestPathFindGetValueFrom(t *testing.T) { t.Error("v != 3") } - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Bf") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Bf") if err != nil { t.Error(err) } @@ -115,7 +115,7 @@ func TestPathFindGetValueFrom(t *testing.T) { s.Sub1.Sub2.Cs = "3" s.Sub1.Sub2.Cf = 4.0 - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.C") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.C") if err != nil { t.Error(err) } @@ -124,7 +124,7 @@ func TestPathFindGetValueFrom(t *testing.T) { t.Error("v != true") } - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Ci") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Ci") if err != nil { t.Error(err) } @@ -133,7 +133,7 @@ func TestPathFindGetValueFrom(t *testing.T) { t.Error("v != 2") } - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Cs") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Cs") if err != nil { t.Error(err) } @@ -142,7 +142,7 @@ func TestPathFindGetValueFrom(t *testing.T) { t.Error("v != 3") } - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Cf") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Cf") if err != nil { t.Error(err) } @@ -156,7 +156,7 @@ func TestPathFindGetValueFrom(t *testing.T) { s.Sub1.Sub2.Sub3.Ds = "3" s.Sub1.Sub2.Sub3.Df = 4.0 - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.D") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.D") if err != nil { t.Error(err) @@ -166,7 +166,7 @@ func TestPathFindGetValueFrom(t *testing.T) { t.Error("v != true") } - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Di") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Di") if err != nil { t.Error(err) } @@ -175,7 +175,7 @@ func TestPathFindGetValueFrom(t *testing.T) { t.Error("v != 2") } - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Ds") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Ds") if err != nil { t.Error(err) } @@ -184,7 +184,7 @@ func TestPathFindGetValueFrom(t *testing.T) { t.Error("v != 3") } - v, err = getValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Df") + v, err = GetValueFrom[PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Df") if err != nil { t.Error(err) } @@ -198,10 +198,10 @@ func TestPathFindGetValueFrom(t *testing.T) { func TestPathFindSetValueFrom(t *testing.T) { s := &PathfindTestStruct1{} - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.B", "true") - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Bi", "2") - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Bs", "3") - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Bf", "4.0") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.B", "true") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Bi", "2") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Bs", "3") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Bf", "4.0") if s.Sub1.B != true { t.Error("s.Sub1.B != true") @@ -220,10 +220,10 @@ func TestPathFindSetValueFrom(t *testing.T) { t.Error("s.Sub1.Bf != 4.0") } - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.C", "true") - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Ci", "2") - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Cs", "3") - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Cf", "4.0") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.C", "true") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Ci", "2") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Cs", "3") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Cf", "4.0") if s.Sub1.Sub2.C != true { t.Error("s.Sub1.Sub2.C != true") @@ -250,10 +250,10 @@ func TestPathFindSetValueFrom(t *testing.T) { } - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.D", "true") - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Di", "2") - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Ds", "3") - setValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Df", "4.0") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.D", "true") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Di", "2") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Ds", "3") + SetValueUsingPath[*PathfindTestStruct1](s, "Sub1.Sub2.Sub3.Df", "4.0") if s.Sub1.Sub2.Sub3.D != true { t.Error("s.Sub1.Sub2.Sub3.D != true") diff --git a/readme_test.go b/readme_test.go index 8f9a2fba6fa3e78dc3285488658b605f889e0dd1..38124245130e690556b15ecb28f019e6e4f4ee82 100644 --- a/readme_test.go +++ b/readme_test.go @@ -25,6 +25,13 @@ func TestReadMeInit(t *testing.T) { setting.Parse([]string{"-v", "serve", "-h", "localhost", "-p", "8080"}) setting.Execute() assert.True(t, setting.definitions.Verbose) + + if setting.HasErrors() { + for _, err := range setting.Errors() { + t.Log(err) + } + } + assert.False(t, setting.HasErrors()) } diff --git a/setting.go b/setting.go index 3aed34a42f1bd4fa6275162459a9ecd39a168879..f4456a34f6c1c51ae074afc846e1880eafdb8cda 100644 --- a/setting.go +++ b/setting.go @@ -17,6 +17,7 @@ type config struct { errorHandling flag.ErrorHandling } +// Settings[C] is the main struct for the xflags package. type Settings[C any] struct { definitions C @@ -29,7 +30,8 @@ type Settings[C any] struct { config config - shadow any + mapping map[string]any + proxy Proxy wasExecuted bool hint string diff --git a/tags.go b/tags.go index bf400a08f7750f3b8781caefcda3fdda78f50632..1e0dad71e698c0d01b332c6bcc23811765005c20 100644 --- a/tags.go +++ b/tags.go @@ -15,7 +15,6 @@ const ( tagShort = "short" tagLong = "long" tagDescription = "description" - tagShadow = "shadow" ) func getTagMap(field reflect.StructField) (value map[string]string) {