diff options
author | Joe Tsai <joetsai@digital-static.net> | 2018-03-26 15:28:54 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-26 15:28:54 -0700 |
commit | 7d086766fb84312590ea843913dc5b8949a485c5 (patch) | |
tree | 042c548e7c08dc9d8aed2bdbb2ac779c256dbeb8 /cmp/cmpopts | |
parent | 0627e4440b70a1645f19cd9f611320f547068b45 (diff) | |
download | go-cmp-7d086766fb84312590ea843913dc5b8949a485c5.tar.gz |
Add AcyclicTransformer helper (#82)
Add AcyclicTransformer helper, which wraps Transformer with a FilterPath
that ensures that the transformer cannot be recursively applied upon
the output of itself. Adjust documentation of Transformer to suggest usage
of AcyclicTransformer if necessary.
Fixes #77
Diffstat (limited to 'cmp/cmpopts')
-rw-r--r-- | cmp/cmpopts/util_test.go | 33 | ||||
-rw-r--r-- | cmp/cmpopts/xform.go | 35 |
2 files changed, 68 insertions, 0 deletions
diff --git a/cmp/cmpopts/util_test.go b/cmp/cmpopts/util_test.go index 02c447f..790ba8d 100644 --- a/cmp/cmpopts/util_test.go +++ b/cmp/cmpopts/util_test.go @@ -716,6 +716,33 @@ func TestOptions(t *testing.T) { }, wantEqual: true, reason: "equal because all Ignore options can be composed together", + }, { + label: "AcyclicTransformer", + x: "a\nb\nc\nd", + y: "a\nb\nd\nd", + opts: []cmp.Option{ + AcyclicTransformer("", func(s string) []string { return strings.Split(s, "\n") }), + }, + wantEqual: false, + reason: "not equal because 3rd line differs, but should not recurse infinitely", + }, { + label: "AcyclicTransformer", + x: []string{"foo", "Bar", "BAZ"}, + y: []string{"Foo", "BAR", "baz"}, + opts: []cmp.Option{ + AcyclicTransformer("", func(s string) string { return strings.ToUpper(s) }), + }, + wantEqual: true, + reason: "equal because of strings.ToUpper; AcyclicTransformer unnecessary, but check this still works", + }, { + label: "AcyclicTransformer", + x: "this is a sentence", + y: "this is a sentence", + opts: []cmp.Option{ + AcyclicTransformer("", func(s string) []string { return strings.Fields(s) }), + }, + wantEqual: true, + reason: "equal because acyclic transformer splits on any contiguous whitespace", }} for _, tt := range tests { @@ -938,6 +965,12 @@ func TestPanic(t *testing.T) { fnc: IgnoreUnexported, args: args(Foo1{}, struct{ x, X int }{}), reason: "input may be named or unnamed structs", + }, { + label: "AcyclicTransformer", + fnc: AcyclicTransformer, + args: args("", "not a func"), + wantPanic: "invalid transformer function", + reason: "AcyclicTransformer has same input requirements as Transformer", }} for _, tt := range tests { diff --git a/cmp/cmpopts/xform.go b/cmp/cmpopts/xform.go new file mode 100644 index 0000000..be278f1 --- /dev/null +++ b/cmp/cmpopts/xform.go @@ -0,0 +1,35 @@ +// Copyright 2018, The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE.md file. + +package cmpopts + +import ( + "github.com/google/go-cmp/cmp" +) + +type xformFilter struct{ xform cmp.Option } + +func (xf xformFilter) filter(p cmp.Path) bool { + for _, ps := range p { + if t, ok := ps.(cmp.Transform); ok && t.Option() == xf.xform { + return false + } + } + return true +} + +// AcyclicTransformer returns a Transformer with a filter applied that ensures +// that the transformer cannot be recursively applied upon its own output. +// +// An example use case is a transformer that splits a string by lines: +// AcyclicTransformer("SplitLines", func(s string) []string{ +// return strings.Split(s, "\n") +// }) +// +// Had this been an unfiltered Transformer instead, this would result in an +// infinite cycle converting a string to []string to [][]string and so on. +func AcyclicTransformer(name string, f interface{}) cmp.Option { + xf := xformFilter{cmp.Transformer(name, f)} + return cmp.FilterPath(xf.filter, xf.xform) +} |