mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-06 18:54:06 +00:00
Merge pull request #127838 from benluddy/unstructured-nested-number-as-float64
Add NestedNumberAsFloat64 unstructured field accessor.
This commit is contained in:
commit
aa09157014
@ -125,6 +125,28 @@ func NestedInt64(obj map[string]interface{}, fields ...string) (int64, bool, err
|
|||||||
return i, true, nil
|
return i, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NestedNumberAsFloat64 returns the float64 value of a nested field. If the field's value is a
|
||||||
|
// float64, it is returned. If the field's value is an int64 that can be losslessly converted to
|
||||||
|
// float64, it will be converted and returned. Returns false if value is not found and an error if
|
||||||
|
// not a float64 or an int64 that can be accurately represented as a float64.
|
||||||
|
func NestedNumberAsFloat64(obj map[string]interface{}, fields ...string) (float64, bool, error) {
|
||||||
|
val, found, err := NestedFieldNoCopy(obj, fields...)
|
||||||
|
if !found || err != nil {
|
||||||
|
return 0, found, err
|
||||||
|
}
|
||||||
|
switch x := val.(type) {
|
||||||
|
case int64:
|
||||||
|
if x != int64(float64(x)) {
|
||||||
|
return 0, false, fmt.Errorf("%v accessor error: int64 value %v cannot be losslessly converted to float64", jsonPath(fields), x)
|
||||||
|
}
|
||||||
|
return float64(x), true, nil
|
||||||
|
case float64:
|
||||||
|
return x, true, nil
|
||||||
|
default:
|
||||||
|
return 0, false, fmt.Errorf("%v accessor error: %v is of the type %T, expected float64 or int64", jsonPath(fields), val, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NestedStringSlice returns a copy of []string value of a nested field.
|
// NestedStringSlice returns a copy of []string value of a nested field.
|
||||||
// Returns false if value is not found and an error if not a []interface{} or contains non-string items in the slice.
|
// Returns false if value is not found and an error if not a []interface{} or contains non-string items in the slice.
|
||||||
func NestedStringSlice(obj map[string]interface{}, fields ...string) ([]string, bool, error) {
|
func NestedStringSlice(obj map[string]interface{}, fields ...string) ([]string, bool, error) {
|
||||||
|
@ -18,6 +18,7 @@ package unstructured
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -225,3 +226,74 @@ func TestSetNestedMap(t *testing.T) {
|
|||||||
assert.Len(t, obj["x"].(map[string]interface{})["z"], 1)
|
assert.Len(t, obj["x"].(map[string]interface{})["z"], 1)
|
||||||
assert.Equal(t, "bar", obj["x"].(map[string]interface{})["z"].(map[string]interface{})["b"])
|
assert.Equal(t, "bar", obj["x"].(map[string]interface{})["z"].(map[string]interface{})["b"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNestedNumberAsFloat64(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
obj map[string]interface{}
|
||||||
|
path []string
|
||||||
|
wantFloat64 float64
|
||||||
|
wantBool bool
|
||||||
|
wantErrMessage string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "not found",
|
||||||
|
obj: nil,
|
||||||
|
path: []string{"missing"},
|
||||||
|
wantFloat64: 0,
|
||||||
|
wantBool: false,
|
||||||
|
wantErrMessage: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "found float64",
|
||||||
|
obj: map[string]interface{}{"value": float64(42)},
|
||||||
|
path: []string{"value"},
|
||||||
|
wantFloat64: 42,
|
||||||
|
wantBool: true,
|
||||||
|
wantErrMessage: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "found unexpected type bool",
|
||||||
|
obj: map[string]interface{}{"value": true},
|
||||||
|
path: []string{"value"},
|
||||||
|
wantFloat64: 0,
|
||||||
|
wantBool: false,
|
||||||
|
wantErrMessage: ".value accessor error: true is of the type bool, expected float64 or int64",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "found int64",
|
||||||
|
obj: map[string]interface{}{"value": int64(42)},
|
||||||
|
path: []string{"value"},
|
||||||
|
wantFloat64: 42,
|
||||||
|
wantBool: true,
|
||||||
|
wantErrMessage: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "found int64 not representable as float64",
|
||||||
|
obj: map[string]interface{}{"value": int64(math.MaxInt64)},
|
||||||
|
path: []string{"value"},
|
||||||
|
wantFloat64: 0,
|
||||||
|
wantBool: false,
|
||||||
|
wantErrMessage: ".value accessor error: int64 value 9223372036854775807 cannot be losslessly converted to float64",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
gotFloat64, gotBool, gotErr := NestedNumberAsFloat64(tc.obj, tc.path...)
|
||||||
|
if gotFloat64 != tc.wantFloat64 {
|
||||||
|
t.Errorf("got %v, wanted %v", gotFloat64, tc.wantFloat64)
|
||||||
|
}
|
||||||
|
if gotBool != tc.wantBool {
|
||||||
|
t.Errorf("got %t, wanted %t", gotBool, tc.wantBool)
|
||||||
|
}
|
||||||
|
if tc.wantErrMessage != "" {
|
||||||
|
if gotErr == nil {
|
||||||
|
t.Errorf("got nil error, wanted %s", tc.wantErrMessage)
|
||||||
|
} else if gotErrMessage := gotErr.Error(); gotErrMessage != tc.wantErrMessage {
|
||||||
|
t.Errorf("wanted error %q, got: %v", gotErrMessage, tc.wantErrMessage)
|
||||||
|
}
|
||||||
|
} else if gotErr != nil {
|
||||||
|
t.Errorf("wanted nil error, got %v", gotErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user