k8s.io/apimachinery@v0.29.2/pkg/util/diff/diff.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package diff 18 19 import ( 20 "bytes" 21 "fmt" 22 "reflect" 23 "strings" 24 "text/tabwriter" 25 26 "github.com/google/go-cmp/cmp" 27 "k8s.io/apimachinery/pkg/util/dump" 28 ) 29 30 func legacyDiff(a, b interface{}) string { 31 return cmp.Diff(a, b) 32 } 33 34 // StringDiff diffs a and b and returns a human readable diff. 35 // DEPRECATED: use github.com/google/go-cmp/cmp.Diff 36 func StringDiff(a, b string) string { 37 return legacyDiff(a, b) 38 } 39 40 // ObjectDiff prints the diff of two go objects and fails if the objects 41 // contain unhandled unexported fields. 42 // DEPRECATED: use github.com/google/go-cmp/cmp.Diff 43 func ObjectDiff(a, b interface{}) string { 44 return legacyDiff(a, b) 45 } 46 47 // ObjectGoPrintDiff prints the diff of two go objects and fails if the objects 48 // contain unhandled unexported fields. 49 // DEPRECATED: use github.com/google/go-cmp/cmp.Diff 50 func ObjectGoPrintDiff(a, b interface{}) string { 51 return legacyDiff(a, b) 52 } 53 54 // ObjectReflectDiff prints the diff of two go objects and fails if the objects 55 // contain unhandled unexported fields. 56 // DEPRECATED: use github.com/google/go-cmp/cmp.Diff 57 func ObjectReflectDiff(a, b interface{}) string { 58 return legacyDiff(a, b) 59 } 60 61 // ObjectGoPrintSideBySide prints a and b as textual dumps side by side, 62 // enabling easy visual scanning for mismatches. 63 func ObjectGoPrintSideBySide(a, b interface{}) string { 64 sA := dump.Pretty(a) 65 sB := dump.Pretty(b) 66 67 linesA := strings.Split(sA, "\n") 68 linesB := strings.Split(sB, "\n") 69 width := 0 70 for _, s := range linesA { 71 l := len(s) 72 if l > width { 73 width = l 74 } 75 } 76 for _, s := range linesB { 77 l := len(s) 78 if l > width { 79 width = l 80 } 81 } 82 buf := &bytes.Buffer{} 83 w := tabwriter.NewWriter(buf, width, 0, 1, ' ', 0) 84 max := len(linesA) 85 if len(linesB) > max { 86 max = len(linesB) 87 } 88 for i := 0; i < max; i++ { 89 var a, b string 90 if i < len(linesA) { 91 a = linesA[i] 92 } 93 if i < len(linesB) { 94 b = linesB[i] 95 } 96 fmt.Fprintf(w, "%s\t%s\n", a, b) 97 } 98 w.Flush() 99 return buf.String() 100 } 101 102 // IgnoreUnset is an option that ignores fields that are unset on the right 103 // hand side of a comparison. This is useful in testing to assert that an 104 // object is a derivative. 105 func IgnoreUnset() cmp.Option { 106 return cmp.Options{ 107 // ignore unset fields in v2 108 cmp.FilterPath(func(path cmp.Path) bool { 109 _, v2 := path.Last().Values() 110 switch v2.Kind() { 111 case reflect.Slice, reflect.Map: 112 if v2.IsNil() || v2.Len() == 0 { 113 return true 114 } 115 case reflect.String: 116 if v2.Len() == 0 { 117 return true 118 } 119 case reflect.Interface, reflect.Pointer: 120 if v2.IsNil() { 121 return true 122 } 123 } 124 return false 125 }, cmp.Ignore()), 126 // ignore map entries that aren't set in v2 127 cmp.FilterPath(func(path cmp.Path) bool { 128 switch i := path.Last().(type) { 129 case cmp.MapIndex: 130 if _, v2 := i.Values(); !v2.IsValid() { 131 fmt.Println("E") 132 return true 133 } 134 } 135 return false 136 }, cmp.Ignore()), 137 } 138 }