diff --git a/basic_test.go b/basic_test.go index 93041db..c106581 100644 --- a/basic_test.go +++ b/basic_test.go @@ -15,6 +15,8 @@ import ( ) func TestBool(t *testing.T) { + var ptr *bool + testCases := []testCase{ {0, false, false}, {int(0), false, false}, @@ -36,6 +38,7 @@ func TestBool(t *testing.T) { {json.Number("0"), false, false}, {nil, false, false}, + {ptr, false, false}, {"false", false, false}, {"FALSE", false, false}, {"False", false, false}, @@ -103,6 +106,8 @@ func TestString(t *testing.T) { } key := &Key{"foo"} + var ptr *string + testCases := []testCase{ {int(8), "8", false}, {int8(8), "8", false}, @@ -120,6 +125,7 @@ func TestString(t *testing.T) { {true, "true", false}, {false, "false", false}, {nil, "", false}, + {ptr, "", false}, {[]byte("one time"), "one time", false}, {"one more time", "one more time", false}, {template.HTML("one time"), "one time", false}, diff --git a/indirect.go b/indirect.go index 1c10d86..093345f 100644 --- a/indirect.go +++ b/indirect.go @@ -24,7 +24,12 @@ func indirect(i any) (any, bool) { } v := reflect.ValueOf(i) - for v.Kind() == reflect.Ptr && !v.IsNil() { + + for v.Kind() == reflect.Ptr || (v.Kind() == reflect.Interface && v.Elem().Kind() == reflect.Ptr) { + if v.IsNil() { + return nil, true + } + v = v.Elem() } diff --git a/indirect_test.go b/indirect_test.go index 95f28f3..d1d290a 100644 --- a/indirect_test.go +++ b/indirect_test.go @@ -11,13 +11,56 @@ import ( qt "github.com/frankban/quicktest" ) -func TestIndirectPointers(t *testing.T) { +func TestIndirect(t *testing.T) { c := qt.New(t) x := 13 y := &x z := &y - c.Assert(ToInt(y), qt.Equals, 13) - c.Assert(ToInt(z), qt.Equals, 13) + var ptr *string + var ptrptr **string + + var i any + + var n = int(13) + var i2 any = n + + var i3 any = &n + + var b *bool + var i4 any = b + + testCases := []struct { + input any + expected any + expectedOk bool + }{ + {x, 13, false}, + {y, 13, true}, + {z, 13, true}, + {ptr, nil, true}, + {ptrptr, nil, true}, + {i, nil, false}, + {&i, nil, true}, + {i2, 13, false}, + {&i2, 13, true}, + {i3, 13, true}, + {&i3, 13, true}, + {i4, nil, true}, + {&i4, nil, true}, + {nil, nil, false}, + } + + for _, testCase := range testCases { + // TODO: remove after minimum Go version is >=1.22 + testCase := testCase + + t.Run("", func(t *testing.T) { + v, ok := indirect(testCase.input) + + c.Assert(v, qt.Equals, testCase.expected) + c.Assert(ok, qt.Equals, testCase.expectedOk) + }) + } } diff --git a/time.go b/time.go index d16ba45..744cd5a 100644 --- a/time.go +++ b/time.go @@ -53,6 +53,8 @@ func ToTimeInDefaultLocationE(i any, location *time.Location) (tim time.Time, er return time.Unix(int64(v), 0), nil case uint64: return time.Unix(int64(v), 0), nil + case nil: + return time.Time{}, nil default: return time.Time{}, fmt.Errorf(errorMsg, i, i, time.Time{}) } @@ -87,6 +89,8 @@ func ToDurationE(i any) (time.Duration, error) { } return time.ParseDuration(s) + case nil: + return time.Duration(0), nil default: if i, ok := resolveAlias(i); ok { return ToDurationE(i) diff --git a/time_test.go b/time_test.go index 4b00b1d..a22ea98 100644 --- a/time_test.go +++ b/time_test.go @@ -19,6 +19,8 @@ import ( ) func TestTime(t *testing.T) { + var ptr *time.Time + testCases := []testCase{ {"2009-11-10 23:00:00 +0000 UTC", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false}, // Time.String() {"Tue Nov 10 23:00:00 2009", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false}, // ANSIC @@ -56,6 +58,8 @@ func TestTime(t *testing.T) { {json.Number("1234567890"), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false}, {time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false}, + {ptr, time.Time{}, false}, + // Failure cases {"2006", time.Time{}, true}, {json.Number("123.4567890"), time.Time{}, true}, @@ -68,6 +72,8 @@ func TestTime(t *testing.T) { func TestDuration(t *testing.T) { type MyDuration time.Duration + var ptr *time.Duration + var expected time.Duration = 5 testCases := []testCase{ @@ -94,6 +100,9 @@ func TestDuration(t *testing.T) { {string("5m"), time.Minute * expected, false}, {string("5h"), time.Hour * expected, false}, + {0, time.Duration(0), false}, + {ptr, time.Duration(0), false}, + // Aliases {MyInt(5), expected, false}, {MyString("5"), expected, false},