Repository: urfave/cli
Pull request #1251 (2021-03-07 03:45:42)

Add Destination field to TimestampFlag
## What type of PR is this?

- [ ] bug
- [ ] cleanup  
- [ ] documentation
- [x] feature

## What this PR does / why we need it:

Adds a `Destination` field for the `TimestampFlag` type that allows you to specify a pointer to
a `Timestamp` rather than having to grab the `Timestamp` from the `cli.Context` using the flag
name.

Also updates the `expect` test helper to not use `runtime.Caller` etc directly. Instead, it calls `t.Helper` beforehand, which does the same thing. This is optional, but I think removes some unnecessary code. Happy to omit if preferred.

## Testing

Added a unit test `TestTimestampFlagApply_WithDestination`

## Release Notes

```release-note
Adds Destination field to TimestampFlag
```



Patch:
diff --git a/flag_timestamp.go b/flag_timestamp.go
index 0382a6b..da95512 100644
--- a/flag_timestamp.go
+++ b/flag_timestamp.go
@@ -71,6 +71,7 @@ type TimestampFlag struct {
 	Value       *Timestamp
 	DefaultText string
 	HasBeenSet  bool
+	Destination *Timestamp
 }
 
 // IsSet returns whether or not the flag has been set through env or file
@@ -123,6 +124,10 @@ func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
 	}
 	f.Value.SetLayout(f.Layout)
 
+	if f.Destination != nil {
+		f.Destination.SetLayout(f.Layout)
+	}
+
 	if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
 		if err := f.Value.Set(val); err != nil {
 			return fmt.Errorf("could not parse %q as timestamp value for flag %s: %s", val, f.Name, err)
@@ -131,6 +136,11 @@ func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
 	}
 
 	for _, name := range f.Names() {
+		if f.Destination != nil {
+			set.Var(f.Destination, name, f.Usage)
+			continue
+		}
+
 		set.Var(f.Value, name, f.Usage)
 	}
 	return nil


Test patch:
diff --git a/flag_test.go b/flag_test.go
index b3b0d7c..1cefe82 100644
--- a/flag_test.go
+++ b/flag_test.go
@@ -1973,3 +1973,15 @@ func TestTimestampFlagApply_Fail_Parse_Wrong_Time(t *testing.T) {
 	err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"})
 	expect(t, err, fmt.Errorf("invalid value \"2006-01-02T15:04:05Z\" for flag -time: parsing time \"2006-01-02T15:04:05Z\" as \"Jan 2, 2006 at 3:04pm (MST)\": cannot parse \"2006-01-02T15:04:05Z\" as \"Jan\""))
 }
+
+func TestTimestampFlagApply_WithDestination(t *testing.T) {
+	var destination Timestamp
+	expectedResult, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
+	fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: time.RFC3339, Destination: &destination}
+	set := flag.NewFlagSet("test", 0)
+	_ = fl.Apply(set)
+
+	err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"})
+	expect(t, err, nil)
+	expect(t, *fl.Destination.timestamp, expectedResult)
+}
diff --git a/helpers_test.go b/helpers_test.go
index 9217e89..9ecd8e1 100644
--- a/helpers_test.go
+++ b/helpers_test.go
@@ -3,24 +3,17 @@ package cli
 import (
 	"os"
 	"reflect"
-	"runtime"
-	"strings"
 	"testing"
 )
 
-var (
-	wd, _ = os.Getwd()
-)
-
 func init() {
 	_ = os.Setenv("CLI_TEMPLATE_REPANIC", "1")
 }
 
 func expect(t *testing.T, a interface{}, b interface{}) {
-	_, fn, line, _ := runtime.Caller(1)
-	fn = strings.Replace(fn, wd+"/", "", -1)
+	t.Helper()
 
 	if !reflect.DeepEqual(a, b) {
-		t.Errorf("(%s:%d) Expected %v (type %v) - Got %v (type %v)", fn, line, b, reflect.TypeOf(b), a, reflect.TypeOf(a))
+		t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
 	}
 }