Skip to content

Commit 999ccb8

Browse files
benluddyk8s-publishing-bot
authored andcommitted
Test concrete type changes in unstructured float64 JSON roundtrips.
During JSON roundtrips of unstructured objects, float64 values with no fractional component will in certain cases roundtrip to int64. This is potentially surprising existing behavior. Adding dedicated test coverage for this will help codify the behavior and mitigate future regression risk. Kubernetes-commit: 707ee63456c60a4b37275018ad6a044e3700e1c7
1 parent 0db5dbf commit 999ccb8

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

pkg/runtime/serializer/json/json_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -1042,3 +1042,50 @@ func TestEncode(t *testing.T) {
10421042
})
10431043
}
10441044
}
1045+
1046+
// TestRoundtripUnstructuredFloat64 demonstrates that encoding a fractionless float64 value to JSON
1047+
// then decoding into interface{} can produce a value with concrete type int64. This is a
1048+
// consequence of two specific behaviors. First, there is nothing in the JSON encoding of a
1049+
// fractionless float64 value to distinguish it from the JSON encoding of an integer value. Second,
1050+
// if, when unmarshaling into interface{}, the decoder encounters a JSON number with no decimal
1051+
// point in the input, it produces a value with concrete type int64 as long as the number can be
1052+
// precisely represented by an int64.
1053+
func TestRoundtripUnstructuredFractionlessFloat64(t *testing.T) {
1054+
s := json.NewSerializerWithOptions(json.DefaultMetaFactory, runtime.NewScheme(), runtime.NewScheme(), json.SerializerOptions{})
1055+
1056+
initial := &unstructured.Unstructured{Object: map[string]interface{}{
1057+
"apiVersion": "v1",
1058+
"kind": "Test",
1059+
"with-fraction": float64(1.5),
1060+
"without-fraction": float64(1),
1061+
"without-fraction-big-positive": float64(9223372036854776000),
1062+
"without-fraction-big-negative": float64(-9223372036854776000),
1063+
}}
1064+
1065+
var buf bytes.Buffer
1066+
if err := s.Encode(initial, &buf); err != nil {
1067+
t.Fatal(err)
1068+
}
1069+
1070+
final := &unstructured.Unstructured{}
1071+
got, _, err := s.Decode(buf.Bytes(), nil, final)
1072+
if err != nil {
1073+
t.Fatal(err)
1074+
}
1075+
if got != final {
1076+
t.Fatalf("expected Decode to return target Unstructured object but got: %v", got)
1077+
}
1078+
1079+
expected := &unstructured.Unstructured{Object: map[string]interface{}{
1080+
"apiVersion": "v1",
1081+
"kind": "Test",
1082+
"with-fraction": float64(1.5),
1083+
"without-fraction": int64(1), // note the change in concrete type
1084+
"without-fraction-big-positive": float64(9223372036854776000),
1085+
"without-fraction-big-negative": float64(-9223372036854776000),
1086+
}}
1087+
1088+
if diff := cmp.Diff(expected, final); diff != "" {
1089+
t.Fatalf("unexpected diff:\n%s", diff)
1090+
}
1091+
}

0 commit comments

Comments
 (0)