diff --git a/pkg/diff/diff.go b/pkg/diff/diff.go index 3d28a43c6f..6f1d1b52b1 100644 --- a/pkg/diff/diff.go +++ b/pkg/diff/diff.go @@ -144,6 +144,10 @@ func DiffStructureds(x, y any, opts ...Option) (*Result, error) { } func (d *differ) diff(path []PathStep, vx, vy reflect.Value) error { + if !vx.IsValid() && !vy.IsValid() { + return nil + } + if !vx.IsValid() { if d.equateEmpty && isEmptyInterface(vy) { return nil @@ -403,6 +407,8 @@ func floatNumber(v reflect.Value) float64 { switch v.Kind() { case reflect.Float32, reflect.Float64: return v.Float() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return float64(v.Uint()) default: return float64(v.Int()) } @@ -410,7 +416,9 @@ func floatNumber(v reflect.Value) float64 { func isNumberValue(v reflect.Value) bool { switch v.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: return true default: return false @@ -419,7 +427,9 @@ func isNumberValue(v reflect.Value) bool { func convertToNumber(v reflect.Value) (reflect.Value, bool) { switch v.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Float32, reflect.Float64: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: return v, true case reflect.String: if n, err := strconv.ParseFloat(v.String(), 64); err == nil { diff --git a/pkg/diff/diff_test.go b/pkg/diff/diff_test.go index de8504687b..630d9af24f 100644 --- a/pkg/diff/diff_test.go +++ b/pkg/diff/diff_test.go @@ -558,6 +558,87 @@ func TestDiff_Array(t *testing.T) { } } +func TestDiff_Uint(t *testing.T) { + testcases := []struct { + name string + old unstructured.Unstructured + new unstructured.Unstructured + options []Option + diffNum int + }{ + { + name: "identical uint values have no diff", + old: unstructured.Unstructured{ + Object: map[string]any{ + "spec": map[string]any{ + "port": uint(8080), + }, + }, + }, + new: unstructured.Unstructured{ + Object: map[string]any{ + "spec": map[string]any{ + "port": uint(8080), + }, + }, + }, + diffNum: 0, + }, + { + name: "differing uint values report diff", + old: unstructured.Unstructured{ + Object: map[string]any{ + "spec": map[string]any{ + "port": uint(8080), + }, + }, + }, + new: unstructured.Unstructured{ + Object: map[string]any{ + "spec": map[string]any{ + "port": uint(9090), + }, + }, + }, + diffNum: 1, + }, + { + name: "uint and numeric string equated with WithCompareNumberAndNumericString", + old: unstructured.Unstructured{ + Object: map[string]any{ + "spec": map[string]any{ + "port": uint64(8080), + }, + }, + }, + new: unstructured.Unstructured{ + Object: map[string]any{ + "spec": map[string]any{ + "port": "8080", + }, + }, + }, + options: []Option{WithCompareNumberAndNumericString()}, + diffNum: 0, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + result, err := DiffUnstructureds(tc.old, tc.new, "", tc.options...) + require.NoError(t, err) + assert.Equal(t, tc.diffNum, result.NumNodes()) + }) + } +} + +func TestDiff_BothInvalid(t *testing.T) { + d := &differ{result: &Result{}} + err := d.diff(nil, reflect.Value{}, reflect.Value{}) + require.NoError(t, err) + assert.Equal(t, 0, d.result.NumNodes()) +} + func TestIsEmptyInterface(t *testing.T) { testcases := []struct { name string diff --git a/pkg/diff/renderer.go b/pkg/diff/renderer.go index 274ca4ecab..24c43cad3d 100644 --- a/pkg/diff/renderer.go +++ b/pkg/diff/renderer.go @@ -196,10 +196,12 @@ func renderNodeValue(v reflect.Value, prefix string) (string, bool) { case reflect.String: return v.String(), false - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return strconv.FormatInt(v.Int(), 10), false + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(v.Uint(), 10), false + case reflect.Float32, reflect.Float64: return strconv.FormatFloat(v.Float(), 'f', -1, 64), false @@ -216,10 +218,12 @@ func RenderPrimitiveValue(v reflect.Value) string { case reflect.String: return v.String() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return strconv.FormatInt(v.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(v.Uint(), 10) + case reflect.Float32, reflect.Float64: return strconv.FormatFloat(v.Float(), 'f', -1, 64) diff --git a/pkg/diff/renderer_test.go b/pkg/diff/renderer_test.go index 606bacaae4..8732785be4 100644 --- a/pkg/diff/renderer_test.go +++ b/pkg/diff/renderer_test.go @@ -202,6 +202,16 @@ func TestRenderPrimitiveValue(t *testing.T) { value: 1, expected: "1", }, + { + name: "uint", + value: uint(42), + expected: "42", + }, + { + name: "uint64", + value: uint64(100), + expected: "100", + }, { name: "float", value: 1.25,