func limit(aObj, bObj interface{}, max int) (string, string) {
	elidedPrefix := ""
	elidedASuffix := ""
	elidedBSuffix := ""
	a, b := fmt.Sprintf("%#v", aObj), fmt.Sprintf("%#v", bObj)
	for {
		switch {
		case len(a) > max && len(a) > 4 && len(b) > 4 && a[:4] == b[:4]:
			elidedPrefix = "..."
			a = a[2:]
			b = b[2:]
		case len(b) > max && len(b) > 4 && len(a) > 4 && a[:4] == b[:4]:
			elidedPrefix = "..."
			a = a[2:]
			b = b[2:]
		case len(a) > max:
			a = a[:max]
			elidedASuffix = "..."
		case len(b) > max:
			b = b[:max]
			elidedBSuffix = "..."
		default:
			return elidedPrefix + a + elidedASuffix, elidedPrefix + b + elidedBSuffix
		}
	}
}
limit:
1. stringifies aObj and bObj
2. elides identical prefixes if either is too long
3. elides remaining content from the end if either is too long
package diff
import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"sort"
	"strings"
	"text/tabwriter"
	"github.com/davecgh/go-spew/spew"
	"k8s.io/apimachinery/pkg/util/validation/field"
)
func StringDiff(a, b string) string {
	ba := []byte(a)
	bb := []byte(b)
	out := []byte{}
	i := 0
	for ; i < len(ba) && i < len(bb); i++ {
		if ba[i] != bb[i] {
			break
		}
		out = append(out, ba[i])
	}
	out = append(out, []byte("\n\nA: ")...)
	out = append(out, ba[i:]...)
	out = append(out, []byte("\n\nB: ")...)
	out = append(out, bb[i:]...)
	out = append(out, []byte("\n\n")...)
	return string(out)
}
func ObjectDiff(a, b interface{}) string {
	ab, err := json.Marshal(a)
	if err != nil {
		panic(fmt.Sprintf("a: %v", err))
	}
	bb, err := json.Marshal(b)
	if err != nil {
		panic(fmt.Sprintf("b: %v", err))
	}
	return StringDiff(string(ab), string(bb))
}
func ObjectGoPrintDiff(a, b interface{}) string {
	s := spew.ConfigState{DisableMethods: true}
	return StringDiff(
		s.Sprintf("%#v", a),
		s.Sprintf("%#v", b),
	)
}
func ObjectReflectDiff(a, b interface{}) string {
	vA, vB := reflect.ValueOf(a), reflect.ValueOf(b)
	if vA.Type() != vB.Type() {
		return fmt.Sprintf("type A %T and type B %T do not match", a, b)
	}
	diffs := objectReflectDiff(field.NewPath("object"), vA, vB)
	if len(diffs) == 0 {
		return "<no diffs>"
	}
	out := []string{""}
	for _, d := range diffs {
		elidedA, elidedB := limit(d.a, d.b, 80)
		out = append(out,
			fmt.Sprintf("%s:", d.path),
			fmt.Sprintf("  a: %s", elidedA),
			fmt.Sprintf("  b: %s", elidedB),
		)
	}
	return strings.Join(out, "\n")
}