Documentation ¶
Overview ¶
Package diff finds the differences between a pair of Go values.
The Test, Log, and Each functions all traverse their two arguments, a and b, in parallel, looking for differences. Each difference is emitted to the given testing output function, logger, or callback function.
Here are some common usage examples:
diff.Test(t, t.Errorf, got, want) diff.Test(t, t.Fatalf, got, want) diff.Test(t, t.Logf, got, want) diff.Log(a, b) diff.Log(a, b, diff.Logger(log.New(...))) diff.Each(fmt.Printf, a, b)
Use Option values to change how it works if the default behavior isn't what you need.
Index ¶
- func Each(f func(format string, arg ...any) (int, error), a, b any, opt ...Option)
- func Log(a, b any, opt ...Option)
- func Test(h Helperer, f func(format string, arg ...any), got, want any, opt ...Option)
- type Helperer
- type Option
- func EqualFuncs(b bool) Option
- func Format[T any](f func(a, b T) string) Option
- func FormatRemove[T any]() Option
- func KeepExported[T any]() Option
- func KeepFields[T any](name ...string) Option
- func Logger(out Outputter) Option
- func OptionList(opt ...Option) Option
- func ShowOriginal() Option
- func Transform[T any](f func(T) any) Option
- func TransformRemove[T any]() Option
- func ZeroFields[T any](name ...string) Option
- type Outputter
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Each ¶
Each compares values a and b, calling f for each difference it finds. By default, its conditions for equality are like reflect.DeepEqual.
The behavior can be adjusted by supplying Option values. See Default for a complete list of default options. Values in opt apply in addition to (and override) the defaults.
Example ¶
package main import ( "fmt" "net" "time" "kr.dev/diff" ) func main() { var a, b net.Dialer a.Timeout = 5 * time.Second b.Timeout = 10 * time.Second b.LocalAddr = &net.TCPAddr{} diff.Each(fmt.Printf, a, b) }
Output: net.Dialer.Timeout: 5s != 10s net.Dialer.LocalAddr: nil != &net.TCPAddr{IP:nil, ...}
func Log ¶
Log compares values a and b, printing each difference to its logger. By default, its logger object is log.Default() and its conditions for equality are like reflect.DeepEqual.
The logger can be set using the Logger option. The behavior can also be adjusted by supplying other Option values. See Default for a complete list of default options. Values in opt apply in addition to (and override) the defaults.
Example ¶
package main import ( "log" "net/url" "os" "kr.dev/diff" ) func main() { logger := log.New(os.Stdout, "", 0) reqURL, err := url.Parse("https://example.org/?q=one") if err != nil { return } knownURL := &url.URL{ Scheme: "https", Host: "example.org", Path: "/", } diff.Log(reqURL, knownURL, diff.Logger(logger)) }
Output: url.URL.RawQuery: "q=one" != ""
func Test ¶
Test compares values got and want, calling f for each difference it finds. By default, its conditions for equality are like reflect.DeepEqual.
Test also calls h.Helper() at the top of every internal function. Note that *testing.T and *testing.B satisfy this interface. This makes test output show the file and line number of the call to Test.
The behavior can be adjusted by supplying Option values. See Default for a complete list of default options. Values in opt apply in addition to (and override) the defaults.
Example ¶
package main import ( "net" "testing" "time" "kr.dev/diff" ) var t = new(testing.T) func main() { // TestExample(t *testing.T) { got := makeDialer() want := &net.Dialer{ Timeout: 10 * time.Second, LocalAddr: &net.TCPAddr{}, } diff.Test(t, t.Errorf, got, want) // } } func makeDialer() *net.Dialer { return &net.Dialer{Timeout: 5 * time.Second} }
Output:
Types ¶
type Helperer ¶
type Helperer interface {
Helper()
}
Helperer marks the caller as a helper function. It is satisfied by *testing.T and *testing.B.
type Option ¶
type Option struct {
// contains filtered or unexported fields
}
Option values can be passed to the Each function to control how comparisons are made, how output is formatted, and various other things. Options are applied in order from left to right; later options win where there is a conflict.
var ( // Default is a copy of the default options used by Each. // (This variable is only for documentation; // modifying it has no effect on the default behavior.) Default Option = OptionList( EmitAuto, TimeEqual, TimeDelta, Logger(log.Default()), ) // Picky is a set of options for exact comparison and // maximum verbosity. Picky Option = OptionList( EmitFull, TransformRemove[time.Time](), FormatRemove[time.Time](), ) )
var ( // EmitAuto selects an output format for each difference // based on various heuristics. // It uses registered format functions. See Format. EmitAuto Option = verbosity(auto) // EmitPathOnly outputs the path to each difference // in Go notation. // It does not use registered format functions. EmitPathOnly Option = verbosity(pathOnly) // EmitFull outputs the path to each difference // and a full representation of both values // at that position, pretty-printed on multiple // lines with indentation. EmitFull Option = verbosity(full) )
var ( // TimeEqual converts Time values to a form that can be compared // meaningfully by the == operator. // See the documentation on the Time type and Time.Equal // for an explanation. TimeEqual Option = Transform(func(t time.Time) any { return t.Round(0).UTC() }) // EqualNaN causes NaN float64 values to be treated as equal. EqualNaN Option = Transform(func(f float64) any { if math.IsNaN(f) { type equalNaN struct{} return equalNaN{} } return f }) // TimeDelta outputs the difference between two times // in a more readable format, including the delta between them. TimeDelta Option = Format(func(a, b time.Time) string { as := a.Format(time.RFC3339Nano) bs := b.Format(time.RFC3339Nano) return fmt.Sprintf("%s != %s (%s)", as, bs, b.Sub(a)) }) )
func EqualFuncs ¶
EqualFuncs controls how function values are compared. If true, any two non-nil function values of the same type are treated as equal; otherwise, two non-nil functions are treated as unequal, even if they point to the same location in code. Note that EqualFuncs(false) matches the behavior of the built-in == operator.
func Format ¶
Format customizes the description of the difference between two unequal values a and b.
See FormatRemove to remove a custom format.
func FormatRemove ¶
FormatRemove removes any format for type T. See Format.
func KeepExported ¶
KeepExported transforms a value of struct type T. It makes a copy of its input, preserving exported fields only.
This effectively makes comparison use only exported fields.
See also Transform.
func KeepFields ¶
KeepFields transforms values of struct type T. It makes a copy of its input, preserving the named field values and setting all other fields to their zero values.
This effectively makes comparison use only the provided fields.
KeepFields panics if any name argument is not a visible field in T. See Transform for more info about transforms. See also ZeroFields.
func OptionList ¶
OptionList combines multiple options into one. The arguments will be applied in order from left to right.
func ShowOriginal ¶ added in v0.2.0
func ShowOriginal() Option
ShowOriginal show diffs of untransformed values in addition to the diffs of transformed values. This is mainly useful for debugging transform functions.
func Transform ¶
Transform converts values of type T to another value to be compared.
A transform is applied when the values on both sides of the comparison are of type T. The two values returned by the transform (one on each side) are then compared, and their diffs emitted. See also ShowOriginal.
Function f may return any type, not just T. In particular, during a single comparison, f may return a different type on each side (and this will result in a difference being reported).
See TransformRemove to remove a transform.
func TransformRemove ¶
TransformRemove removes any transform for type T. See Transform.
func ZeroFields ¶
ZeroFields transforms values of struct type T. It makes a copy of its input and sets the named fields to their zero values.
This effectively makes comparison ignore the given fields.
ZeroFields panics if any name argument is not a visible field in T. See Transform for more info about transforms. See also KeepFields.