mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-06 02:34:03 +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
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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) {
|
||||
|
@ -18,6 +18,7 @@ package unstructured
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@ -225,3 +226,74 @@ func TestSetNestedMap(t *testing.T) {
|
||||
assert.Len(t, obj["x"].(map[string]interface{})["z"], 1)
|
||||
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