github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/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/davecgh/go-spew/spew"
    27  	"github.com/google/go-cmp/cmp"
    28  )
    29  
    30  // StringDiff diffs a and b and returns a human readable diff.
    31  func StringDiff(a, b string) string {
    32  	ba := []byte(a)
    33  	bb := []byte(b)
    34  	out := []byte{}
    35  	i := 0
    36  	for ; i < len(ba) && i < len(bb); i++ {
    37  		if ba[i] != bb[i] {
    38  			break
    39  		}
    40  		out = append(out, ba[i])
    41  	}
    42  	out = append(out, []byte("\n\nA: ")...)
    43  	out = append(out, ba[i:]...)
    44  	out = append(out, []byte("\n\nB: ")...)
    45  	out = append(out, bb[i:]...)
    46  	out = append(out, []byte("\n\n")...)
    47  	return string(out)
    48  }
    49  
    50  func legacyDiff(a, b interface{}) string {
    51  	return cmp.Diff(a, b)
    52  }
    53  
    54  // ObjectDiff 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 ObjectDiff(a, b interface{}) string {
    58  	return legacyDiff(a, b)
    59  }
    60  
    61  // ObjectGoPrintDiff prints the diff of two go objects and fails if the objects
    62  // contain unhandled unexported fields.
    63  // DEPRECATED: use github.com/google/go-cmp/cmp.Diff
    64  func ObjectGoPrintDiff(a, b interface{}) string {
    65  	return legacyDiff(a, b)
    66  }
    67  
    68  // ObjectReflectDiff prints the diff of two go objects and fails if the objects
    69  // contain unhandled unexported fields.
    70  // DEPRECATED: use github.com/google/go-cmp/cmp.Diff
    71  func ObjectReflectDiff(a, b interface{}) string {
    72  	return legacyDiff(a, b)
    73  }
    74  
    75  // ObjectGoPrintSideBySide prints a and b as textual dumps side by side,
    76  // enabling easy visual scanning for mismatches.
    77  func ObjectGoPrintSideBySide(a, b interface{}) string {
    78  	s := spew.ConfigState{
    79  		Indent: " ",
    80  		// Extra deep spew.
    81  		DisableMethods: true,
    82  	}
    83  	sA := s.Sdump(a)
    84  	sB := s.Sdump(b)
    85  
    86  	linesA := strings.Split(sA, "\n")
    87  	linesB := strings.Split(sB, "\n")
    88  	width := 0
    89  	for _, s := range linesA {
    90  		l := len(s)
    91  		if l > width {
    92  			width = l
    93  		}
    94  	}
    95  	for _, s := range linesB {
    96  		l := len(s)
    97  		if l > width {
    98  			width = l
    99  		}
   100  	}
   101  	buf := &bytes.Buffer{}
   102  	w := tabwriter.NewWriter(buf, width, 0, 1, ' ', 0)
   103  	max := len(linesA)
   104  	if len(linesB) > max {
   105  		max = len(linesB)
   106  	}
   107  	for i := 0; i < max; i++ {
   108  		var a, b string
   109  		if i < len(linesA) {
   110  			a = linesA[i]
   111  		}
   112  		if i < len(linesB) {
   113  			b = linesB[i]
   114  		}
   115  		fmt.Fprintf(w, "%s\t%s\n", a, b)
   116  	}
   117  	w.Flush()
   118  	return buf.String()
   119  }
   120  
   121  // IgnoreUnset is an option that ignores fields that are unset on the right
   122  // hand side of a comparison. This is useful in testing to assert that an
   123  // object is a derivative.
   124  func IgnoreUnset() cmp.Option {
   125  	return cmp.Options{
   126  		// ignore unset fields in v2
   127  		cmp.FilterPath(func(path cmp.Path) bool {
   128  			_, v2 := path.Last().Values()
   129  			switch v2.Kind() {
   130  			case reflect.Slice, reflect.Map:
   131  				if v2.IsNil() || v2.Len() == 0 {
   132  					return true
   133  				}
   134  			case reflect.String:
   135  				if v2.Len() == 0 {
   136  					return true
   137  				}
   138  			case reflect.Interface, reflect.Pointer:
   139  				if v2.IsNil() {
   140  					return true
   141  				}
   142  			}
   143  			return false
   144  		}, cmp.Ignore()),
   145  		// ignore map entries that aren't set in v2
   146  		cmp.FilterPath(func(path cmp.Path) bool {
   147  			switch i := path.Last().(type) {
   148  			case cmp.MapIndex:
   149  				if _, v2 := i.Values(); !v2.IsValid() {
   150  					fmt.Println("E")
   151  					return true
   152  				}
   153  			}
   154  			return false
   155  		}, cmp.Ignore()),
   156  	}
   157  }