Skip to content

Commit 165bd50

Browse files
authored
dyn: fix zero values conversion / IsZero() method (#3649)
## Changes - Fix IsZero() method for types like int64. This fixes ToConvert for NumWorkers field in ClusterSpec. - Do not panic in dyn.V() if other int types are encountered. - If panic does happen, include type name. ## Why ToConvert() depends on it and is broken. This unblocks #3650 #3646 ## Tests New unit tests.
1 parent efa69f4 commit 165bd50

File tree

4 files changed

+57
-25
lines changed

4 files changed

+57
-25
lines changed

libs/dyn/convert/to_typed_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ func TestToTypedStructZeroFieldsForceSend(t *testing.T) {
130130
type Tmp struct {
131131
Foo string `json:"foo"`
132132
Bar string `json:"bar,omitempty"`
133+
NumWorkers int `json:"num_workers,omitempty"`
133134
ForceSendFields []string `json:"-"`
134135
}
135136

@@ -143,12 +144,13 @@ func TestToTypedStructZeroFieldsForceSend(t *testing.T) {
143144
m := dyn.Mapping{}
144145
m.SetLoc("foo", nil, dyn.V(""))
145146
m.SetLoc("bar", nil, dyn.V(""))
147+
m.SetLoc("num_workers", nil, dyn.V(int64(0)))
146148
v := dyn.V(m)
147149

148150
// The previously set fields should be cleared.
149151
err := ToTyped(&out, v)
150152
require.NoError(t, err)
151-
assert.Equal(t, Tmp{ForceSendFields: []string{"Foo", "Bar"}}, out)
153+
assert.Equal(t, Tmp{ForceSendFields: []string{"Foo", "Bar", "NumWorkers"}}, out)
152154
}
153155

154156
func TestToTypedStructAnonymousByValue(t *testing.T) {

libs/dyn/kind.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ func kindOf(v any) Kind {
2929
return KindString
3030
case bool:
3131
return KindBool
32-
case int, int32, int64:
32+
case int, int8, int16, int32, int64:
33+
return KindInt
34+
case uint, uint8, uint16, uint32, uint64:
3335
return KindInt
3436
case float32, float64:
3537
return KindFloat
@@ -38,7 +40,7 @@ func kindOf(v any) Kind {
3840
case nil:
3941
return KindNil
4042
default:
41-
panic("not handled")
43+
panic(fmt.Sprintf("not handled: %T", v))
4244
}
4345
}
4446

libs/dyn/value.go

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dyn
22

33
import (
44
"fmt"
5+
"reflect"
56
"slices"
67
)
78

@@ -136,30 +137,17 @@ func (v Value) AsAny() any {
136137
}
137138

138139
func (v Value) IsZero() bool {
139-
switch v.k {
140-
case KindInvalid:
140+
if v.v == nil {
141141
return true
142-
case KindMap:
143-
m := v.v.(Mapping)
144-
return m.Len() == 0
145-
case KindSequence:
146-
vv := v.v.([]Value)
147-
return len(vv) == 0
148-
case KindNil:
149-
return true
150-
case KindString:
151-
return v.v == ""
152-
case KindBool:
153-
return v.v == false
154-
case KindInt:
155-
return v.v == 0
156-
case KindFloat:
157-
return v.v == 0.0
158-
case KindTime:
159-
t := v.v.(Time)
160-
return t.IsZero()
142+
}
143+
144+
switch x := v.v.(type) {
145+
case Mapping:
146+
return x.Len() == 0
147+
case []Value:
148+
return len(x) == 0
161149
default:
162-
return false
150+
return reflect.ValueOf(x).IsZero()
163151
}
164152
}
165153

libs/dyn/value_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,43 @@ func TestValueIsValid(t *testing.T) {
4949
intValue := dyn.V(1)
5050
assert.True(t, intValue.IsValid())
5151
}
52+
53+
func TestIsZero(t *testing.T) {
54+
assert.True(t, dyn.V(0).IsZero(), "int")
55+
assert.True(t, dyn.V(int(0)).IsZero(), "int")
56+
assert.False(t, dyn.V(int(1)).IsZero(), "int")
57+
assert.True(t, dyn.V(uint(0)).IsZero(), "uint")
58+
59+
assert.True(t, dyn.V(int8(0)).IsZero(), "int8")
60+
assert.True(t, dyn.V(uint8(0)).IsZero(), "uint8")
61+
62+
assert.True(t, dyn.V(int16(0)).IsZero(), "int16")
63+
assert.True(t, dyn.V(uint16(0)).IsZero(), "uint16")
64+
65+
assert.True(t, dyn.V(int32(0)).IsZero(), "int32")
66+
assert.False(t, dyn.V(int32(1)).IsZero(), "int32")
67+
assert.True(t, dyn.V(uint32(0)).IsZero(), "uint32")
68+
69+
assert.True(t, dyn.V(int64(0)).IsZero(), "int64")
70+
assert.False(t, dyn.V(int64(-1)).IsZero(), "int64")
71+
72+
assert.True(t, dyn.V(uint64(0)).IsZero(), "uint64")
73+
assert.False(t, dyn.V(uint64(2)).IsZero(), "uint64")
74+
75+
assert.True(t, dyn.V("").IsZero(), "string")
76+
assert.False(t, dyn.V("x").IsZero(), "string")
77+
78+
assert.True(t, dyn.V(false).IsZero(), "bool")
79+
assert.False(t, dyn.V(true).IsZero(), "bool")
80+
81+
assert.True(t, dyn.V(float32(0.0)).IsZero(), "float32")
82+
assert.False(t, dyn.V(float32(0.01)).IsZero(), "float32")
83+
84+
assert.True(t, dyn.V(float64(0.0)).IsZero(), "float64")
85+
assert.False(t, dyn.V(float64(0.01)).IsZero(), "float64")
86+
87+
assert.True(t, dyn.V(dyn.Time{}).IsZero(), "time")
88+
assert.True(t, dyn.V(dyn.Mapping{}).IsZero(), "Mapping")
89+
assert.True(t, dyn.V([]dyn.Value{}).IsZero(), "Sequence")
90+
assert.False(t, dyn.V([]dyn.Value{dyn.V(0)}).IsZero(), "Sequence")
91+
}

0 commit comments

Comments
 (0)