aboutsummaryrefslogtreecommitdiff
path: root/cmp
AgeCommit message (Collapse)Author
2021-05-24Print as text if mostly text (#258)Joe Tsai
The previous heuristic of treating strings as binary data if it contains any invalid UTF-8 was too strict. Loosen the heuristic to check if most of the characters are printable text. Fixes #257
2021-05-24Avoid diffing by lines if inefficient (#260)Joe Tsai
Avoid diffing by lines if it turns out to be significantly less efficient than diffing by bytes. Before this change: ( """ - d5c14bdf6bac81c27afc5429500ed750 - 25483503b557c606dad4f144d27ae10b - 90bdbcdbb6ea7156068e3dcfb7459244 - 978f480a6e3cced51e297fbff9a506b7 + Xd5c14bdf6bac81c27afc5429500ed750 + X25483503b557c606dad4f144d27ae10b + X90bdbcdbb6ea7156068e3dcfb7459244 + X978f480a6e3cced51e297fbff9a506b7 """ ) After this change: strings.Join({ + "X", "d5c14bdf6bac81c27afc5429500ed750\n", + "X", "25483503b557c606dad4f144d27ae10b\n", + "X", "90bdbcdbb6ea7156068e3dcfb7459244\n", + "X", "978f480a6e3cced51e297fbff9a506b7\n", }, "")
2021-05-24Cleanup edit groups after coalescing (#259)Joe Tsai
Even with an optimal diffing algoritm, coalescing adjacent edit groups may cause the corresponding pair of strings for an edit group to have leading or trailing spans of equal elements. While this is technically a correct representation of a diff, it is a suboptimal outcome. As such, scan through all unequal groups and move leading/trailing equal spans to the preceding/succeeding equal group. Before this change: strings.Join({ "org-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=aa", - ",#=_value _value=2 ", + " _value=2 ", `11 org-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=bb`, - ",#=_value _value=2 2", + " _value=2 2", `1 org-4747474747474747,bucket-4242424242424242:m,tag1=b,tag2=cc`, - ",#=_value", ` _value=1 21 org-4747474747474747,bucket-4242424242424242:m,tag1`, "=a,tag2", - "=dd,#=_value", + "=dd", ` _value=3 31 org-4747474747474747,bucket-4242424242424242:m,tag1`, - "=c,#=_value", + "=c", ` _value=4 41 `, }, "") After this change: strings.Join({ "org-4747474747474747,bucket-4242424242424242:m,tag1=a,tag2=aa", - ",#=_value", ` _value=2 11 org-4747474747474747,bucket-4242424242424242:m,tag1`, "=a,tag2=bb", - ",#=_value", ` _value=2 21 org-4747474747474747,bucket-4242424242424242:m,tag1`, "=b,tag2=cc", - ",#=_value", ` _value=1 21 org-4747474747474747,bucket-4242424242424242:m,tag1`, "=a,tag2=dd", - ",#=_value", ` _value=3 31 org-4747474747474747,bucket-4242424242424242:m,tag1`, "=c", - ",#=_value", ` _value=4 41 `, }, "")
2021-04-12Fix typo in path.go (#256)Ikko Ashimine
s/seperate/separate/
2021-03-03Fix reporter verbosity bug (#253)Joe Tsai
FormatDiff should only set the verbosity to 3 if the current verbosity is lower than 3. Otherwise, it may remove an intended higher verbosity setting causing the reporter output to not differentiate between two large values that are different at the end. While we are at it, increase the maxVerbosityPreset to 6.
2021-03-03De-virtualize interfaces for specialized diffing (#254)Joe Tsai
Specialized diffing strings and slices should occur for interface types where both values have the same concrete type. This is especially relevant for protocmp.Transform, which transforms every proto.Message as a map[string]interface{}.
2021-02-04cmp/cmpopts: use errors.Is with ≥go1.13 in compareErrors (#251)Tobias Klauser
Use the standard definition of errors.Is to implement compareErrors with ≥go1.13. Retain the implementation using golang.org/x/xerrors for versions <go1.13. This will allow packages using newer Go versions and already relying on the errors package to get rid of the transitive dependency on golang.org/x/xerrors.
2020-11-24Impose verbosity limit when formatting map keys (#248)Joe Tsai
Map keys should have a sensible verbosity limit imposed, otherwise the reporter can end up printing a massive data structure that cannot reasonably fit in memory.
2020-11-24Fix non-determinism in diffing algorithm (#247)Joe Tsai
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
2020-11-12Fix Diff documentation (#237)Joe Tsai
The description inaccurately describes the operation of Diff, which is y - x, where a '+' prefix denotes elements added from y and a '-' prefix denotes elements removed from x. For example: // Consider this call to Diff and its result. x y cmp.Diff({b:2, c:3}, {a:1, b:2}) => {+a:1, b:2, -c:3} // Consider the same in mathematical notation. y - x {a:1, b:2} - {b:2, c:3} = {+a:1, b:2, -c:3}
2020-11-12Revert "Adjust for reflect.Type.NumMethod change in Go1.16 (#240)" (#242)Joe Tsai
This reverts commit ab46b8bd0abd4c4557cc4709ad7ae12d47570603. The upstream change in Go1.16 has been rolled back. See golang/go#42123
2020-10-20Adjust for reflect.Type.NumMethod change in Go1.16 (#240)Joe Tsai
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.
2020-10-04Add an example for IgnoreFields (#205)colinnewell
Add an example for IgnoreFields. This resuses the test data from the example in the cmp package to provide consistency between examples.
2020-09-23Fix license headers (#236)Joe Tsai
There is no LICENSE.md file, but there is a LICENSE file.
2020-08-18Suggest use of cmpopts.EquateErrors (#234)Joe Tsai
If cmp panics because it is trying to access an unexported field, specially suggest the use of cmpopts.EquateErrors if the parent type implements the error interface. Fixes #233
2020-07-29Fix Diff documentation (#231)Ernest Galbrun
Fix the documentation on Diff. It was mentioning the plus or minus sign being printed if the field was added to y or removed from y, but both are the same. Fix it so that it properly mentions the use of a minus sign for elements removed from x.
2020-07-21Use triple-quote formatting for multiline strings (#229)Joe Tsai
For strings, []bytes containing text data, Error method output, and String method output, use the triple-quoted syntax. This improves readability by presenting the data more naturally compared to a single-line quoted string with many escaped characters.
2020-07-14Adjust panic for IgnoreUnexported and IgnoreFields (#228)k.nakada
Adjust the panic message to be more specific about what the user should do, and reduces the need for the user to look at the source code.
2020-06-22Swallow panic when calling String or Error (#221)Joe Tsai
If a panic occurs while calling String or Error, the reporter recovers from it and ignores it, proceeding with its usual functionality for formatting a value.
2020-06-17Improve reporting of values with cycles (#217)Joe Tsai
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⟫{...}.
2020-06-17Update test case names (#218)Joe Tsai
Provide a unique name for every test case. Provide a reason for every test case. The purpose of a unique name is so that insertion/removal of a case does not cause all subsequent names to suddenly shift, causing a larger number of differences in testdata/diffs.
2020-06-17Fix documentation on IgnoreFields (#220)Joe Tsai
The function now handles unexported fields since #203.
2020-06-12Disambiguate reporter output (#216)Joe Tsai
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
2020-06-11Limit verbosity of reporter output (#215)Joe Tsai
A common complaint is that the reporter it prints out too much irrelevant information, resulting in a low signal-to-noise ratio. Improve this metric by imposing a verbosity limit. For nodes that are equal, we set the verbosity level is a lower value than when the nodes are inequal. Other minor changes: * Adjust heuristic for triple-quote usage to operate on more cases. * Elide type more aggressively for equal nodes. * Printing the address for a slice includes the length and capacity. * The pointed-at value for map keys are printed.
2020-06-10Limit number of printed differences for variable-length composites (#213)Joe Tsai
For large slices, arrays, and maps, the reporter can be unreadable if there are many differences. Limit the number of results to some reasonable maximum.
2020-06-10Introduce deliberate instability to difference output (#214)Joe Tsai
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.
2020-06-10Use custom triple-quote syntax for diffing string literals (#212)Joe Tsai
Using strings.Join to denote differences in a multi-line string is visually noisy due to extensive use of quotes and escape sequences. Add a custom triple-quote syntax that unambiguously shows line differences with less visual noise. If the triple-quote syntax cannot unmabiguously show differences, then the reporter falls back on using the strings.Join format, which is never ambiguous. Fixes #195
2020-06-10Use raw string literal syntax only for valid UTF-8 (#211)Joe Tsai
2020-06-10Allow batched diffing of slices with a custom comparer (#210)Joe Tsai
For correctness, cmp checks applicability of the options for every element in a slice. For large []byte, this is a significant performance detriment. The workaround is to specify Comparer(bytes.Equal). However, we would still like to have the batched diffing if the slices are different. Specialize for this situation.
2020-06-10Batch reporter output for simple lists of textLine elements (#208)Joe Tsai
Rather than having a single element on each line, which hurts readability due to the need for scrolling quite a bit. Batch multiple elements for simple lists to be on a single line. Fixes #170
2020-06-10Mention minimally supported Go version in TODO (#209)Joe Tsai
Specify the exact minimumally supported version of Go required in order to address certain TODOs. This makes it easier to filter out inactionable TODOs.
2020-06-09Fix exporter to handle nil interface values (#207)Joe Tsai
A shallow copy with reflect.ValueOf(v.Interface()) does not work if v is a nil interface value. Special case the edge case by checking for a nil value and create a new one use reflect.Zero.
2020-06-08Avoid leaking implementation details of the exporter (#206)Joe Tsai
The current implementation for forcibly exporting fields relies on the reflect.Value.Addr method for the parent struct value, where it copies a non-addressable struct onto to the heap so that it is addressable. However, this action leaks a subtle detail of how the internal implementation works since the accessed field for within a struct is only addressable if and only if the parent struct is also addressable. Modify the implementation to avoid leaking this implementation detail by shallow copying the accessed unexported field to remove any notion of addressability if the parent struct is also unaddressable. Fixes #181
2020-06-08Forcibly export fields for use by the reporterJoe Tsai
The choice to avoid traversing unexported fields by default makes sense for the semantics of normal comparisons. However, the goal of the reporter is to prioritize humanly readable output. As such, it seems appropriate to forcibly export fields. This allows the String method to be called on such values.
2020-05-26Optimize Diff for frequent equality (#204)Joe Tsai
Diff is most often used in tests where the expected outcome is equality (and thus no reported difference). Optimize for this situation by performing a fast-pass equality check and only fall back on constructing a report if inequal.
2020-05-20Permit use of IgnoreFields with unexported fields (#203)Joe Tsai
Modify IgnoreFields to permit the specification of unexported fields. To avoid a bug with reflect.Type.FieldByName, we disallow forwarding on unexported fields. See https://golang.org/issue/4876 for details. Fixes #196
2020-05-16Do not use custom format for nil slice (#201)A. Ishikawa
The custom diff output for slices does not accurately reflect the minute differences between a nil slice and an empty slice. Avoid the custom diffing if either value is nil.
2020-05-14Format units in decimal except bytes (#199)178inaba
In general, decimal formatting is preferred except for []byte where hexadecimal is preferred for individual elements. Fixes #185
2020-05-13Refactor tests to use golden test files (#200)Joe Tsai
Refactor the unit tests to read the diffs from a file rather than being stored as a Go string literal. The advantage of using a golden file is to ease updating the diffs whenever the reporter output is changed.
2020-05-13Add reporterTests to TestDiff (#198)178inaba
2020-03-28Fix typo on example (#193)Chris Morrow
Remove redundant "be".
2020-02-27Document the test-only intentions of this package (#189)Joe Tsai
This package was never intended to be used in production code. Document the expectation that this package was only intended to be used for writing tests.
2019-12-16Add support for comparing graphs (#85)Joe Tsai
Previously, trying to call Equal on a graph would result in a stack-overflow due to infinite recursion traversing cycles on a graph. While a vast majority of Go values are trees or acyclic graphs, there exist a small number of cases where graph equality is required. As such, we add cycle detection to Equal and define what it means for two graphs to be equal. Contrary to reflect.DeepEqual, which declares two graphs to be equal so long any cycle were encountered, we require two graphs to have equivalent graph structures. Mathematically speaking, a graph G is a tuple (V, E) consisting of the set of vertices and edges in that graph. Graphs G1 and G2 are equal if V1 == V2, E1 == E2, and both have the same root vertex (entry point into the graph). When traversing G1 and G2, we remember a stack of previously visited edges ES1 and ES2. If the current edge e1 is in ES1 or e2 is in ES2, then we know that a cycle exists. The graphs have the same structure when the previously encountered edge ep1 and ep2 were encountered together. Note that edges and vertices unreachable from the root vertex are ignored. Appreciation goes to Eyal Posener (@posener), who proposed a different (but semantically equivalent) approach in #79, which served as inspiration. Fixes #74
2019-12-16Add EquateErrors helper (#178)Joe Tsai
The EquateErrors helper equates errors according to errors.Is. We also declare a sentinel AnyError value that matches any non-nil error value. This adds a dependency on golang.org/x/xerrors so that we can continue to suppport go1.8, which is our current minimally supported version of Go. Fixes #89
2019-12-16Adjust style of EquateApproxTime (#177)Joe Tsai
Adjust coding style of EquateApproxTime to match EquateApprox.
2019-12-16Add Exporter option (#176)Joe Tsai
Add an Exporter option that accepts a function to determine which struct types to permit access to unexported fields. Treat this as a first-class option and implement AllowUnexported in terms of the new Exporter option. The new Exporter option: * Better matches the existing style of top-level options both by name (e.g., Comparer, Transformer, and Reporter) and by API style (all accept a function). * Is more flexible as it enables users to functionally implement AllowAllUnexported by simply doing: Exporter(func(reflect.Type) bool { return true }) Fixes #40
2019-11-04Print type name in unexported panic (#171)Joe Tsai
In the panic message when accessing an unexported field, print the full name of the type for user convenience.
2019-10-28Make retrieveUnexportedField pass Go 1.14's checkptr validation (#169)Brad Fitzpatrick
Fixes #167
2019-08-29cmpopts: add EquateApproxTime (#158)Roger Peppe
2019-08-05cmp/internal/value: fix handling of negative zero for floats (#152)Joe Tsai
* 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.