Age | Commit message (Collapse) | Author |
|
Starting with Go 1.17, //go:build lines are preferred over // +build
lines, see https://golang.org/doc/go1.17#build-lines and
https://golang.org/design/draft-gobuild for details.
This change was generated by running Go 1.17 go fmt ./... which
automatically adds //go:build lines based on the existing // +build
lines.
Also update the corresponding GitHub action to use Go 1.17 gofmt.
|
|
Now that Go 1.11 is the minimally supported version,
we can drop some local hacks to work around bugs in
reflect that were present in Go1.9.
|
|
See golang/go#33232.
|
|
A previous attempt to add non-determinism to the diffing algorithm
unfortunately broke the algorithm for half the cases.
This change modifies the algorithm to truly switch between starting
with a forward search versus a reverse search.
The main for-loop of Difference would switch repeatedly between
performing a forward search, then a reverse search, and vice-versa.
Since we can't jump into the middle of a for-loop to start with the
reverse search first, we use a series of labels and goto statements
to accomplish the same effect.
Fixes #238
|
|
This reverts commit ab46b8bd0abd4c4557cc4709ad7ae12d47570603.
The upstream change in Go1.16 has been rolled back.
See golang/go#42123
|
|
In Go1.16, the reflect.Type.NumMethod method will no longer report
unexported fields, matching the documented behavior on the method.
This means that t.NumMethod() == 0 is no longer a reliable means
to detect whether an interface type is the empty interface or not.
Fix the code to check whether the empty interface itself implements
the target type.
|
|
There is no LICENSE.md file, but there is a LICENSE file.
|
|
Previously, the reporter could handle formatting values with cycles
in that it did not crash with a stack overflow. However, the output
was not particularly understandable as it did not surface to the user
why a particular value was truncated, and if it was truncated due
to a cyclic reference, what was the referent.
This change annotates the reporter tree with pointer information
so that a later pass can inject reference information if it is needed
to produce more understandable output.
Consider the following example:
map[string]*cmp_test.CycleAlpha{
"Foo": &⟪ref#0⟫{
Name: "Foo",
Bravos: map[string]*cmp_test.CycleBravo{
"FooBravo": &{
- ID: 101,
+ ID: 0,
Name: "FooBravo",
Mods: 100,
Alphas: {"Foo": &⟪ref#0⟫(...)},
},
},
},
}
This graph contains a cycle. To ensure that a graph can be formatted,
the cycle is truncated as indicated with: &⟪ref#0⟫(...).
The referent was identified earlier with: &⟪ref#0⟫{...}.
|
|
The reporter tries to aggresively elide data that is not interesting
to the user. However, doing so many result in an output that does not
visually indicate the difference between semantically different objects.
This CL modifies the reporter to try increasingly verbose presets until
two different objects are formatted differently.
This CL includes a custom implementation of reflect.Type.String that
can print the type with fully qualified names to disambiguate types
that happen to have the same base package name.
Fixes #194
|
|
The reporter output is documented as unstable.
The API for custom reporters also specifies that the diffing of
slices is unstable.
Introduce deliberate instability to the diffing algorithm so that
we have the flexibility to improve it in the future.
The current algorithm optimizes for speed, rather than optimality,
so there is much room for improvement.
|
|
* Fix IsZero to properly report false for IsZero(-0.0) since
we define IsZero as whether it is equal to the zero memory value.
* Add note to isLess that we don't need to handle -0.0 since
we can't possibly have both keys present in the same map.
* Use sort.SliceStable in SortedKeys for deterministic output since
it is possible to have both -0.0 and +0.0 from two different maps.
The zero key from the left left map will be taken over the right map.
|
|
Lists of primitives are a common-enough data structure that
it is worth providing specialized diffing for.
This provides significantly better readability for strings
and byte slices. There is also a heuristic for detecting
what a string should be diffed as a multiline string.
|
|
These helper options ignore slice elements or map entries based
on a user-provided predicate function. These are especially useful
for ignoring missing elements or entries.
|
|
The previous implementation of the reporter simply listed all differences,
each qualified by the full path to the difference.
This method of reporting is exact, but difficult for humans to parse.
It is one of the more common sources of complaints by users and a significant
reason why cmp is not preferred over competing libraries.
This change reimplements the reporter to format the output as a
structured literal in pseudo-Go syntax. The output resembles literals that
the user would likely have in their test code. Differences between the
x and y values are denoted by a '-' or '+' prefix at the start of the line.
An overview of the new implementation is as follows:
* report.go: The defaultReporter type implements the Reporter interface.
* report_value: Through the PushStep/PopStep API, the defaultReporter is able
to contruct an in-memory valueNode tree representing the comparison of
x and y as cmp.Equal walks the sub-values.
* report_compare.go: After report_value.go constructs an AST-representation
of the compared values, report_compare.go formats the valueNode tree as a
textNode tree, which is the textual output in a tree form.
Some relevant design decisions include:
* The format logic goes through effort to avoid printing ignored nodes.
* Some number of surrounding equal (but not ignored) struct fields,
slice elements, or map entries are printed for context.
* cmp.Equal may declare two sub-reflect.Values to be equal, but are
different values when printed. In order to present a unified view on
this "equal" node, the logic formats both values and arbitrarily choses
the one with the shorter string.
* Transformed nodes are formatted with the pseudo-Go syntax of:
Inverse(TransformerName, OutputType{...})
where Inverse is some magical pseudo-function that inverts the
transformation referred to by TransformerName. The OutputType literal
is the output of the transformation.
* report_reflect.go: This contains logic to pretty-print reflect.Values and
is relied upon by report_compare.go to format the leaves of the tree.
Note that the leaves of the tree can be any arbitrary Go type and value
(including cyclic data structures).
* report_text.go: This contains logic for purely lexicographical formatting
and is depended upon by the other report_*.go files.
Advantages:
* The output is more familiar as it uses pseudo-Go syntax for literals
* It provides context about surrounding struct fields, slice elements, or
map entries that were equal
* Inserted and removed elements in a slice are easier to visualize
* Related diffs lie on the same indentation
* For diffs in a deeply nested value, the output is easier to visualize
than having a list of all the full paths to the diff.
Disadvantages:
* The implementation is drastically more complex.
* In most cases, the output is longer (though more sparse)
|
|
|
|
Adjust the logic of NameOf for more recent versions of Go.
|
|
Switch the build tag for debugging from "debug" to "cmp_debug".
The former tag accidentally matches usages of that tag for unrelated projects.
Fixes #104
|
|
Go1.8 went GA on AppEngine.
The lack of Go1.8 support was the primary reason for much
of these backwards compatibility hacks.
Bumping to Go1.8 still ensures that we're supporting at least
the latest 2 versions of Go, which are Go1.8 and Go1.9.
|
|
The cycle detection in value.Format uses a map of uintptrs, which is not
correct as this assumes that the Go GC never uses a moving collector.
Instead, we should be using unsafe.Pointer, which the GC knows how to scan.
Also, push pointer checking of slices down to the level of individual elements.
We do this because the slice pointer is not sufficient to determine equality.
For example, v[:0] and v[:1] both have the same slice pointer, but are
clearly different values.
Since the purego environment forbids the use of unsafe, create a Pointer type
that is an abstraction over an opaque pointer. The Pointer type can only be
compared. In the purego, continue to use uintptr, which is the best we can do.
|
|
When the formatted strings are identical, the reporter tries to fallback
on more exact formatting. This fallback should include the types for
primitive types since the difference can simply be between
an int and an uint.
Fixes #64
|
|
Rather than running gofmt for every version, leading to version skew
when what gofmt considers "correct" differs between versions,
only use one specific version of gofmt.
Also, remove the "-s" flag from gofmt because it is not backwards compatible.
Suppose Go1.11 allowed for elliding types on struct literals and the "-s"
flag strips them, then this would be problematic because it would not compile
on Go1.10 and earlier.
Also, fix the code so that vet is happy. I am not sure why these checks
were not triggered before. There seems to be a bug in the caching of
$GOPATH/pkg files. This may be fixed in Go1.10 by the new caching logic.
Running "go install" before running go vet fixes the issue.
In other words, the only check we perform for differing versions
is that the tests pass (and implicitly that it builds).
|
|
|
|
|
|
Rather than searching for escape sequences, a better measure of whether
to use raw literals or not is whether the raw literal form is shorter
than the quoted string encoding.
The assumption is that shorter string length is more readable,
which is a reasonable (except for non-printable characters).
|
|
When formatting strings, avoid using strconv.Quote if the string looks
like it has already been escaped. Instead, use a raw string literal
by wrapping the string with '`' characters if possible.
For now, we still use strconv.Quote if the input string contains newlines
to maintain the property that Format outputs a single line.
Also, prefix strings obtained by the Stringer.String method with a 's'.
This allows users to more easily distinguish when an output really is
of type string or if the String method was used.
|
|
Rather than performing the heuristic for whether two slices are
"too different" in the diff package, just return the full edit-script
and move the heuristic logic into the cmp package.
The main adjustment to the heuristic is that we only print the
full slice if it is composed of a slice of primitive types (e.g., []byte)
and the difference between the two slices is sufficiently great enough.
Fixes #44
|
|
The format logic should work even if the reflect.Value is in RO mode.
|
|
Avoid using reflect.Value.Interface to de-duplicate keys since
some keys may have source from an unexported field,
causing the logic to panic. Instead, just rely on the isLess function,
which is already safe to use on unexported values.
Fixes #38
|
|
Unify the common logic for identifying the type of function.
This logic is helpful since Go lacks generics, so it is hard
to query whether a function is of the signature: func(T, T) bool
|
|
|
|
|
|
|
|
|
|
This internal package has the API:
Format(reflect.Value, useStringer bool) string
SortKeys(vs []reflect.Value) []reflect.Value
While moving Format and SortKeys, we also tweak the formatting logic
to print the type on named primitive types.
|
|
This adds an internal package with the following API:
func Difference(nx, ny int, f EqualFunc) (eq bool, es EditScript)
type EditScript []EditType
type EditType int8
const Identity EditType = iota ...
type EqualFunc func(ix int, iy int) Result
type Result struct{ ... }
The cmp.SliceIndex type has a new method SplitKeys to indicate that
elements are being compared in x and y are in different indexes.
The debug visualizer can be run:
go test -tags=debug -v github.com/google/go-cmp/cmp/internal/diff
Reviewed-By: kevlar@google.com
|
|
The API of the package is as follows:
func Equal(x, y interface{}, opts ...Option) bool
func Diff(x, y interface{}, opts ...Option) string
type Option interface{ ... }
func Ignore() Option
func Comparer(f interface{}) Option
func Transformer(name string, f interface{}) Option
func FilterPath(f func(Path) bool, opt Option) Option
func FilterValues(f interface{}, opt Option) Option
func AllowUnexported(typs ...interface{}) Option
type Options []Option
type Path []PathStep
type PathStep interface{ ... }
type Indirect interface{ ... }
type StructField interface{ ... }
type MapIndex interface{ ... }
type SliceIndex interface{ ... }
type TypeAssertion interface{ ... }
type Transform interface{ ... }
See the package docs in compare.go for a high-level view of this package.
|