func EqDeeply(got, expected interface{}) bool {
	return deepValueEqualOK(reflect.ValueOf(got), reflect.ValueOf(expected))
}
EqDeeply returns true if "got" matches "expected". "expected" can
be the same type as "got" is, or contains some TestDeep operators.

got := "foobar"
td.EqDeeply(got, "foobar")            // returns true
td.EqDeeply(got, td.HasPrefix("foo")) // returns true
package td
import (
	"fmt"
	"reflect"
	"github.com/maxatome/go-testdeep/helpers/tdutil"
	"github.com/maxatome/go-testdeep/internal/color"
	"github.com/maxatome/go-testdeep/internal/ctxerr"
	"github.com/maxatome/go-testdeep/internal/dark"
	"github.com/maxatome/go-testdeep/internal/types"
)
func isNilStr(isNil bool) types.RawString {
	if isNil {
		return "nil"
	}
	return "not nil"
}
func deepValueEqualFinal(ctx ctxerr.Context, got, expected reflect.Value) (err *ctxerr.Error) {
	err = deepValueEqual(ctx, got, expected)
	if err == nil {
		errMerge := ctx.MergeErrors()
		if errMerge != nil {
			return errMerge
		}
	}
	return
}
func deepValueEqualFinalOK(ctx ctxerr.Context, got, expected reflect.Value) bool {
	ctx = ctx.ResetErrors()
	ctx.BooleanError = true
	return deepValueEqualFinal(ctx, got, expected) == nil
}
func nilHandler(ctx ctxerr.Context, got, expected reflect.Value) *ctxerr.Error {
	err := ctxerr.Error{}
	if expected.IsValid() {  
		if expected.Type().Implements(testDeeper) {
			curOperator := dark.MustGetInterface(expected).(TestDeep)
			ctx.CurOperator = curOperator
			if curOperator.HandleInvalid() {
				return curOperator.Match(ctx, got)
			}
			if ctx.BooleanError {
				return ctxerr.BooleanError
			}
		} else if ctx.BooleanError {
			return ctxerr.BooleanError
		}
		err.Expected = expected
	} else {  
		switch got.Kind() {
		case reflect.Interface:
			if got.IsNil() {
				return nil
			}
		case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice:
			if ctx.BeLax && got.IsNil() {
				return nil
			}
		}
		if ctx.BooleanError {
			return ctxerr.BooleanError
		}
		err.Got = got
	}
	err.Message = "values differ"
	return ctx.CollectError(&err)
}
func isCustomEqual(a, b reflect.Value) (bool, bool) {
	aType, bType := a.Type(), b.Type()
	equal, ok := aType.MethodByName("Equal")
	if ok {
		ft := equal.Type
		if !ft.IsVariadic() &&
			ft.NumIn() == 2 &&
			ft.NumOut() == 1 &&
			ft.In(0).AssignableTo(ft.In(1)) &&
			ft.Out(0) == types.Bool &&
			bType.AssignableTo(ft.In(1)) {
			return true, equal.Func.Call([]reflect.Value{a, b})[0].Bool()
		}
	}
	return false, false
}
func deepValueEqual(ctx ctxerr.Context, got, expected reflect.Value) (err *ctxerr.Error) {
	if got.IsValid() && got.Type().Implements(testDeeper) {
		panic(color.Bad("Found a TestDeep operator in got param, " +
			"can only use it in expected one!"))
	}
	if !got.IsValid() || !expected.IsValid() {
		if got.IsValid() == expected.IsValid() {
			return
		}
		return nilHandler(ctx, got, expected)
	}
	if handled, e := ctx.Hooks.Smuggle(&got); handled {
		if e != nil {
			return ctx.CollectError(&ctxerr.Error{
				Message:  e.Error(),
				Got:      got,
				Expected: expected,
			})
		}
	}
	if handled, e := ctx.Hooks.Cmp(got, expected); handled {
		if e == nil {
			return
		}
		return ctx.CollectError(&ctxerr.Error{
			Message:  e.Error(),
			Got:      got,
			Expected: expected,
		})
	}
	if ctx.UseEqual || ctx.Hooks.UseEqual(got.Type()) {
		hasEqual, isEqual := isCustomEqual(got, expected)
		if hasEqual {
			if isEqual {
				return
			}
			if ctx.BooleanError {
				return ctxerr.BooleanError
			}
			return ctx.CollectError(&ctxerr.Error{
				Message:  "got.Equal(expected) failed",
				Got:      got,
				Expected: expected,
			})
		}
	}
	if got.Type() != expected.Type() {
		if expected.Type().Implements(testDeeper) {
			curOperator := dark.MustGetInterface(expected).(TestDeep)
			if got.Kind() == reflect.Interface {
				got = got.Elem()
				if !got.IsValid() {
					return nilHandler(ctx, got, expected)
				}
			}
			ctx.CurOperator = curOperator
			return curOperator.Match(ctx, got)
		}
		if ctx.BeLax && types.IsConvertible(expected, got.Type()) {
			return deepValueEqual(ctx, got, expected.Convert(got.Type()))
		}
		if got.Kind() == reflect.Interface {
			return deepValueEqual(ctx, got.Elem(), expected)
		}
		if ctx.BooleanError {
			return ctxerr.BooleanError
		}
		return ctx.CollectError(ctxerr.TypeMismatch(got.Type(), expected.Type()))
	}
	if ctx.Visited.Record(got, expected) {
		return
	}
	if op, ok := ctx.Anchors.ResolveAnchor(expected); ok {
		return deepValueEqual(ctx, got, op)
	}
	switch got.Kind() {
	case reflect.Array:
		for i, l := 0, got.Len(); i < l; i++ {
			err = deepValueEqual(ctx.AddArrayIndex(i),
				got.Index(i), expected.Index(i))
			if err != nil {
				return
			}
		}
		return
	case reflect.Slice:
		if got.IsNil() != expected.IsNil() {
			if ctx.BooleanError {
				return ctxerr.BooleanError
			}
			return ctx.CollectError(&ctxerr.Error{
				Message:  "nil slice",
				Got:      isNilStr(got.IsNil()),
				Expected: isNilStr(expected.IsNil()),
			})
		}
		var (
			gotLen      = got.Len()
			expectedLen = expected.Len()
		)
		if gotLen != expectedLen {
			if ctx.BooleanError {
				return ctxerr.BooleanError
			}
		} else {
			if got.Pointer() == expected.Pointer() {
				return
			}
		}
		var maxLen int
		if gotLen >= expectedLen {
			maxLen = expectedLen
		} else {
			maxLen = gotLen
		}
		if got.Type() == tupleType &&
			ctx.Path.Len() == 1 && ctx.Path.String() == contextDefaultRootName {
			ctx = ctx.ResetPath("TUPLE")
		}
		for i := 0; i < maxLen; i++ {
			err = deepValueEqual(ctx.AddArrayIndex(i),
				got.Index(i), expected.Index(i))
			if err != nil {
				return
			}
		}
		if gotLen != expectedLen {
			res := tdSetResult{
				Kind: itemsSetResult,
			}
			if gotLen > expectedLen {
				res.Extra = make([]reflect.Value, gotLen-expectedLen)
				for i := expectedLen; i < gotLen; i++ {
					res.Extra[i-expectedLen] = got.Index(i)
				}
			} else {
				res.Missing = make([]reflect.Value, expectedLen-gotLen)
				for i := gotLen; i < expectedLen; i++ {
					res.Missing[i-gotLen] = expected.Index(i)
				}
			}
			return ctx.CollectError(&ctxerr.Error{
				Message: fmt.Sprintf("comparing slices, from index #%d", maxLen),
				Summary: res.Summary(),
			})
		}
		return
	case reflect.Interface:
		return deepValueEqual(ctx, got.Elem(), expected.Elem())
	case reflect.Ptr:
		if got.Pointer() == expected.Pointer() {
			return
		}
		return deepValueEqual(ctx.AddPtr(1), got.Elem(), expected.Elem())
	case reflect.Struct:
		sType := got.Type()
		ignoreUnexported := ctx.IgnoreUnexported || ctx.Hooks.IgnoreUnexported(sType)
		for i, n := 0, got.NumField(); i < n; i++ {
			field := sType.Field(i)
			if ignoreUnexported && field.PkgPath != "" {
				continue
			}
			err = deepValueEqual(ctx.AddField(field.Name),
				got.Field(i), expected.Field(i))
			if err != nil {
				return
			}
		}
		return
	case reflect.Map:
		if got.IsNil() != expected.IsNil() {
			if ctx.BooleanError {
				return ctxerr.BooleanError
			}
			return ctx.CollectError(&ctxerr.Error{
				Message:  "nil map",
				Got:      isNilStr(got.IsNil()),
				Expected: isNilStr(expected.IsNil()),
			})
		}
		if ctx.BooleanError && got.Len() != expected.Len() {
			return ctxerr.BooleanError
		}
		if got.Pointer() == expected.Pointer() {
			return
		}
		var notFoundKeys []reflect.Value
		foundKeys := map[interface{}]bool{}
		for _, vkey := range tdutil.MapSortedKeys(expected) {
			gotValue := got.MapIndex(vkey)
			if !gotValue.IsValid() {
				notFoundKeys = append(notFoundKeys, vkey)
				continue
			}
			err = deepValueEqual(ctx.AddMapKey(vkey),
				gotValue, expected.MapIndex(vkey))
			if err != nil {
				return
			}
			foundKeys[dark.MustGetInterface(vkey)] = true
		}
		if got.Len() == len(foundKeys) {
			if len(notFoundKeys) == 0 {
				return
			}
			return ctx.CollectError(&ctxerr.Error{
				Message: "comparing map",
				Summary: (tdSetResult{
					Kind:    keysSetResult,
					Missing: notFoundKeys,
					Sort:    true,
				}).Summary(),
			})
		}
		if ctx.BooleanError {
			return ctxerr.BooleanError
		}
		res := tdSetResult{
			Kind:    keysSetResult,
			Missing: notFoundKeys,
			Extra:   make([]reflect.Value, 0, got.Len()-len(foundKeys)),
			Sort:    true,
		}
		for _, k := range tdutil.MapSortedKeys(got) {
			if !foundKeys[k.Interface()] {
				res.Extra = append(res.Extra, k)
			}
		}
		return ctx.CollectError(&ctxerr.Error{
			Message: "comparing map",
			Summary: res.Summary(),
		})
	case reflect.Func:
		if got.IsNil() && expected.IsNil() {
			return
		}
		if ctx.BooleanError {
			return ctxerr.BooleanError
		}
		return ctx.CollectError(&ctxerr.Error{
			Message: "functions mismatch",
			Summary: ctxerr.NewSummary("<can not be compared>"),
		})
	default:
		if dark.MustGetInterface(got) == dark.MustGetInterface(expected) {
			return
		}
		if ctx.BooleanError {
			return ctxerr.BooleanError
		}
		return ctx.CollectError(&ctxerr.Error{
			Message:  "values differ",
			Got:      got,
			Expected: expected,
		})
	}
}
func deepValueEqualOK(got, expected reflect.Value) bool {
	return deepValueEqualFinal(newBooleanContext(), got, expected) == nil
}