Skip to content

Commit 32211fc

Browse files
authored
Merge pull request #45101 from hashicorp/td-non-pointer-iszero
Allows passing non-pointer types to `types.IsZero`
2 parents 7fa0950 + 90c5928 commit 32211fc

File tree

2 files changed

+80
-6
lines changed

2 files changed

+80
-6
lines changed

internal/types/zero.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import (
77
"reflect"
88
)
99

10-
// IsZero returns true if `v` is `nil`, is a pointer to `nil`, or points to the zero value of `T`.
11-
func IsZero[T any](v *T) bool {
12-
if v == nil {
13-
return true
10+
// IsZero returns true if `v` is the zero value of `T`, `nil`, is a pointer to `nil`, or points to the zero value of `T`.
11+
func IsZero[T any](v T) bool {
12+
val := reflect.ValueOf(v)
13+
val = reflect.Indirect(val)
14+
15+
if val.Kind() == reflect.Interface {
16+
val = val.Elem()
1417
}
1518

16-
if val := reflect.ValueOf(*v); !val.IsValid() || val.IsZero() {
19+
if !val.IsValid() || val.IsZero() {
1720
return true
1821
}
1922

internal/types/zero_test.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type AIsZero struct {
1212
Value int
1313
}
1414

15-
func TestIsZero(t *testing.T) {
15+
func TestIsZeroPtr(t *testing.T) {
1616
t.Parallel()
1717

1818
zero := Zero[AIsZero]()
@@ -53,6 +53,36 @@ func TestIsZero(t *testing.T) {
5353
}
5454
}
5555

56+
func TestIsZeroStructValue(t *testing.T) {
57+
t.Parallel()
58+
59+
testCases := map[string]struct {
60+
Value AIsZero
61+
Expected bool
62+
}{
63+
"zero value struct": {
64+
Value: AIsZero{},
65+
Expected: true,
66+
},
67+
"non-zero value struct": {
68+
Value: AIsZero{Value: 42},
69+
Expected: false,
70+
},
71+
}
72+
73+
for name, testCase := range testCases {
74+
t.Run(name, func(t *testing.T) {
75+
t.Parallel()
76+
77+
got := IsZero(testCase.Value)
78+
79+
if got != testCase.Expected {
80+
t.Errorf("got %t, expected %t", got, testCase.Expected)
81+
}
82+
})
83+
}
84+
}
85+
5686
func TestIsZeroPointerToAny(t *testing.T) {
5787
t.Parallel()
5888

@@ -98,3 +128,44 @@ func TestIsZeroPointerToAny(t *testing.T) {
98128
})
99129
}
100130
}
131+
132+
func TestIsZeroAnyValue(t *testing.T) {
133+
t.Parallel()
134+
135+
testCases := map[string]struct {
136+
Value any
137+
Expected bool
138+
}{
139+
"nil value": {
140+
Expected: true,
141+
},
142+
"zero int value": {
143+
Value: 0,
144+
Expected: true,
145+
},
146+
"zero string value": {
147+
Value: "",
148+
Expected: true,
149+
},
150+
"non-zero int value": {
151+
Value: 1,
152+
Expected: false,
153+
},
154+
"non-zero string value": {
155+
Value: "string",
156+
Expected: false,
157+
},
158+
}
159+
160+
for name, testCase := range testCases {
161+
t.Run(name, func(t *testing.T) {
162+
t.Parallel()
163+
164+
got := IsZero(testCase.Value)
165+
166+
if got != testCase.Expected {
167+
t.Errorf("got %t, expected %t", got, testCase.Expected)
168+
}
169+
})
170+
}
171+
}

0 commit comments

Comments
 (0)