mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-08 22:31:04 +00:00
vendor: Update github.com/d4l3k/messagediff
This commit is contained in:
parent
58cbd19742
commit
77c0a19451
65
vendor/github.com/d4l3k/messagediff/README.md
generated
vendored
65
vendor/github.com/d4l3k/messagediff/README.md
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
# messagediff [![Build Status](https://travis-ci.org/d4l3k/messagediff.svg?branch=master)](https://travis-ci.org/d4l3k/messagediff) [![Coverage Status](https://coveralls.io/repos/github/d4l3k/messagediff/badge.svg?branch=master)](https://coveralls.io/github/d4l3k/messagediff?branch=master) [![GoDoc](https://godoc.org/github.com/d4l3k/messagediff?status.svg)](https://godoc.org/github.com/d4l3k/messagediff)
|
|
||||||
|
|
||||||
A library for doing diffs of arbitrary Golang structs.
|
|
||||||
|
|
||||||
If the unsafe package is available messagediff will diff unexported fields in
|
|
||||||
addition to exported fields. This is primarily used for testing purposes as it
|
|
||||||
allows for providing informative error messages.
|
|
||||||
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
In a normal file:
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import "github.com/d4l3k/messagediff"
|
|
||||||
|
|
||||||
type someStruct struct {
|
|
||||||
A, b int
|
|
||||||
C []int
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
a := someStruct{1, 2, []int{1}}
|
|
||||||
b := someStruct{1, 3, []int{1, 2}}
|
|
||||||
diff, equal := messagediff.PrettyDiff(a, b)
|
|
||||||
/*
|
|
||||||
diff =
|
|
||||||
`added: .C[1] = 2
|
|
||||||
modified: .b = 3`
|
|
||||||
|
|
||||||
equal = false
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
In a test:
|
|
||||||
```go
|
|
||||||
import "github.com/d4l3k/messagediff"
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
type someStruct struct {
|
|
||||||
A, b int
|
|
||||||
C []int
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSomething(t *testing.T) {
|
|
||||||
want := someStruct{1, 2, []int{1}}
|
|
||||||
got := someStruct{1, 3, []int{1, 2}}
|
|
||||||
if diff, equal := messagediff.PrettyDiff(want, got); !equal {
|
|
||||||
t.Errorf("Something() = %#v\n%s", got, diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
See the `DeepDiff` function for using the diff results programmatically.
|
|
||||||
|
|
||||||
## License
|
|
||||||
Copyright (c) 2015 [Tristan Rice](https://fn.lc) <rice@fn.lc>
|
|
||||||
|
|
||||||
messagediff is licensed under the MIT license. See the LICENSE file for more information.
|
|
||||||
|
|
||||||
bypass.go and bypasssafe.go are borrowed from
|
|
||||||
[go-spew](https://github.com/davecgh/go-spew) and have a seperate copyright
|
|
||||||
notice.
|
|
59
vendor/github.com/d4l3k/messagediff/example/atom_test.go
generated
vendored
Normal file
59
vendor/github.com/d4l3k/messagediff/example/atom_test.go
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package examples
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/d4l3k/messagediff"
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
"golang.org/x/net/html/atom"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleAtom() {
|
||||||
|
got := data2()
|
||||||
|
want := data1()
|
||||||
|
diff, equal := messagediff.PrettyDiff(want, got)
|
||||||
|
fmt.Printf("%v %s", equal, diff)
|
||||||
|
// Output: false modified: [0].FirstChild.NextSibling.Attr = " baz"
|
||||||
|
}
|
||||||
|
|
||||||
|
func data1() []*html.Node {
|
||||||
|
n := &html.Node{
|
||||||
|
Type: html.ElementNode, Data: atom.Span.String(),
|
||||||
|
Attr: []html.Attribute{
|
||||||
|
{Key: atom.Class.String(), Val: "foo"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
n.AppendChild(
|
||||||
|
&html.Node{
|
||||||
|
Type: html.ElementNode, Data: atom.Span.String(),
|
||||||
|
Attr: []html.Attribute{
|
||||||
|
{Key: atom.Class.String(), Val: "bar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
n.AppendChild(&html.Node{
|
||||||
|
Type: html.TextNode, Data: "baz",
|
||||||
|
})
|
||||||
|
return []*html.Node{n}
|
||||||
|
}
|
||||||
|
|
||||||
|
func data2() []*html.Node {
|
||||||
|
n := &html.Node{
|
||||||
|
Type: html.ElementNode, Data: atom.Span.String(),
|
||||||
|
Attr: []html.Attribute{
|
||||||
|
{Key: atom.Class.String(), Val: "foo"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
n.AppendChild(
|
||||||
|
&html.Node{
|
||||||
|
Type: html.ElementNode, Data: atom.Span.String(),
|
||||||
|
Attr: []html.Attribute{
|
||||||
|
{Key: atom.Class.String(), Val: "bar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
n.AppendChild(&html.Node{
|
||||||
|
Type: html.TextNode, Data: " baz",
|
||||||
|
})
|
||||||
|
return []*html.Node{n}
|
||||||
|
}
|
1
vendor/github.com/d4l3k/messagediff/example/example.go
generated
vendored
Normal file
1
vendor/github.com/d4l3k/messagediff/example/example.go
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
package examples
|
108
vendor/github.com/d4l3k/messagediff/messagediff.go
generated
vendored
108
vendor/github.com/d4l3k/messagediff/messagediff.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrettyDiff does a deep comparison and returns the nicely formated results.
|
// PrettyDiff does a deep comparison and returns the nicely formated results.
|
||||||
@ -26,43 +27,87 @@ func PrettyDiff(a, b interface{}) (string, bool) {
|
|||||||
|
|
||||||
// DeepDiff does a deep comparison and returns the results.
|
// DeepDiff does a deep comparison and returns the results.
|
||||||
func DeepDiff(a, b interface{}) (*Diff, bool) {
|
func DeepDiff(a, b interface{}) (*Diff, bool) {
|
||||||
d := newdiff()
|
d := newDiff()
|
||||||
return d, diff(a, b, nil, d)
|
return d, d.diff(reflect.ValueOf(a), reflect.ValueOf(b), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newdiff() *Diff {
|
func newDiff() *Diff {
|
||||||
return &Diff{
|
return &Diff{
|
||||||
Added: make(map[*Path]interface{}),
|
Added: make(map[*Path]interface{}),
|
||||||
Removed: make(map[*Path]interface{}),
|
Removed: make(map[*Path]interface{}),
|
||||||
Modified: make(map[*Path]interface{}),
|
Modified: make(map[*Path]interface{}),
|
||||||
|
visited: make(map[visit]bool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func diff(a, b interface{}, path Path, d *Diff) bool {
|
func (d *Diff) diff(aVal, bVal reflect.Value, path Path) bool {
|
||||||
aVal := reflect.ValueOf(a)
|
// Validity checks. Should only trigger if nil is one of the original arguments.
|
||||||
bVal := reflect.ValueOf(b)
|
|
||||||
if !aVal.IsValid() && !bVal.IsValid() {
|
if !aVal.IsValid() && !bVal.IsValid() {
|
||||||
// Both are nil.
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if !aVal.IsValid() || !bVal.IsValid() {
|
if !bVal.IsValid() {
|
||||||
// One is nil and the other isn't.
|
d.Modified[&path] = nil
|
||||||
d.Modified[&path] = b
|
return false
|
||||||
|
} else if !aVal.IsValid() {
|
||||||
|
d.Modified[&path] = bVal.Interface()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if aVal.Type() != bVal.Type() {
|
if aVal.Type() != bVal.Type() {
|
||||||
d.Modified[&path] = b
|
d.Modified[&path] = bVal.Interface()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
kind := aVal.Type().Kind()
|
kind := aVal.Kind()
|
||||||
|
|
||||||
|
// Borrowed from the reflect package to handle recursive data structures.
|
||||||
|
hard := func(k reflect.Kind) bool {
|
||||||
|
switch k {
|
||||||
|
case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if aVal.CanAddr() && bVal.CanAddr() && hard(kind) {
|
||||||
|
addr1 := unsafe.Pointer(aVal.UnsafeAddr())
|
||||||
|
addr2 := unsafe.Pointer(bVal.UnsafeAddr())
|
||||||
|
if uintptr(addr1) > uintptr(addr2) {
|
||||||
|
// Canonicalize order to reduce number of entries in visited.
|
||||||
|
// Assumes non-moving garbage collector.
|
||||||
|
addr1, addr2 = addr2, addr1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short circuit if references are already seen.
|
||||||
|
typ := aVal.Type()
|
||||||
|
v := visit{addr1, addr2, typ}
|
||||||
|
if d.visited[v] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember for later.
|
||||||
|
d.visited[v] = true
|
||||||
|
}
|
||||||
|
// End of borrowed code.
|
||||||
|
|
||||||
equal := true
|
equal := true
|
||||||
|
switch kind {
|
||||||
|
case reflect.Map, reflect.Ptr, reflect.Func, reflect.Chan, reflect.Slice:
|
||||||
|
if aVal.IsNil() && bVal.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if aVal.IsNil() || bVal.IsNil() {
|
||||||
|
d.Modified[&path] = bVal.Interface()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch kind {
|
switch kind {
|
||||||
case reflect.Array, reflect.Slice:
|
case reflect.Array, reflect.Slice:
|
||||||
aLen := aVal.Len()
|
aLen := aVal.Len()
|
||||||
bLen := bVal.Len()
|
bLen := bVal.Len()
|
||||||
for i := 0; i < min(aLen, bLen); i++ {
|
for i := 0; i < min(aLen, bLen); i++ {
|
||||||
localPath := append(path, SliceIndex(i))
|
localPath := append(path, SliceIndex(i))
|
||||||
if eq := diff(aVal.Index(i).Interface(), bVal.Index(i).Interface(), localPath, d); !eq {
|
if eq := d.diff(aVal.Index(i), bVal.Index(i), localPath); !eq {
|
||||||
equal = false
|
equal = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,7 +132,7 @@ func diff(a, b interface{}, path Path, d *Diff) bool {
|
|||||||
if !bI.IsValid() {
|
if !bI.IsValid() {
|
||||||
d.Removed[&localPath] = aI.Interface()
|
d.Removed[&localPath] = aI.Interface()
|
||||||
equal = false
|
equal = false
|
||||||
} else if eq := diff(aI.Interface(), bI.Interface(), localPath, d); !eq {
|
} else if eq := d.diff(aI, bI, localPath); !eq {
|
||||||
equal = false
|
equal = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,30 +151,19 @@ func diff(a, b interface{}, path Path, d *Diff) bool {
|
|||||||
index := []int{i}
|
index := []int{i}
|
||||||
field := typ.FieldByIndex(index)
|
field := typ.FieldByIndex(index)
|
||||||
localPath := append(path, StructField(field.Name))
|
localPath := append(path, StructField(field.Name))
|
||||||
aI := unsafeReflectValue(aVal.FieldByIndex(index)).Interface()
|
aI := unsafeReflectValue(aVal.FieldByIndex(index))
|
||||||
bI := unsafeReflectValue(bVal.FieldByIndex(index)).Interface()
|
bI := unsafeReflectValue(bVal.FieldByIndex(index))
|
||||||
if eq := diff(aI, bI, localPath, d); !eq {
|
if eq := d.diff(aI, bI, localPath); !eq {
|
||||||
equal = false
|
equal = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
aVal = aVal.Elem()
|
equal = d.diff(aVal.Elem(), bVal.Elem(), path)
|
||||||
bVal = bVal.Elem()
|
|
||||||
if !aVal.IsValid() && !bVal.IsValid() {
|
|
||||||
// Both are nil.
|
|
||||||
equal = true
|
|
||||||
} else if !aVal.IsValid() || !bVal.IsValid() {
|
|
||||||
// One is nil and the other isn't.
|
|
||||||
d.Modified[&path] = b
|
|
||||||
equal = false
|
|
||||||
} else {
|
|
||||||
equal = diff(aVal.Interface(), bVal.Interface(), path, d)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
if reflect.DeepEqual(a, b) {
|
if reflect.DeepEqual(aVal.Interface(), bVal.Interface()) {
|
||||||
equal = true
|
equal = true
|
||||||
} else {
|
} else {
|
||||||
d.Modified[&path] = b
|
d.Modified[&path] = bVal.Interface()
|
||||||
equal = false
|
equal = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,9 +177,21 @@ func min(a, b int) int {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// During deepValueEqual, must keep track of checks that are
|
||||||
|
// in progress. The comparison algorithm assumes that all
|
||||||
|
// checks in progress are true when it reencounters them.
|
||||||
|
// Visited comparisons are stored in a map indexed by visit.
|
||||||
|
// This is borrowed from the reflect package.
|
||||||
|
type visit struct {
|
||||||
|
a1 unsafe.Pointer
|
||||||
|
a2 unsafe.Pointer
|
||||||
|
typ reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
// Diff represents a change in a struct.
|
// Diff represents a change in a struct.
|
||||||
type Diff struct {
|
type Diff struct {
|
||||||
Added, Removed, Modified map[*Path]interface{}
|
Added, Removed, Modified map[*Path]interface{}
|
||||||
|
visited map[visit]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path represents a path to a changed datum.
|
// Path represents a path to a changed datum.
|
||||||
|
80
vendor/github.com/d4l3k/messagediff/messagediff_test.go
generated
vendored
80
vendor/github.com/d4l3k/messagediff/messagediff_test.go
generated
vendored
@ -8,14 +8,46 @@ import (
|
|||||||
type testStruct struct {
|
type testStruct struct {
|
||||||
A, b int
|
A, b int
|
||||||
C []int
|
C []int
|
||||||
|
D [3]int
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecursiveStruct struct {
|
||||||
|
Key int
|
||||||
|
Child *RecursiveStruct
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRecursiveStruct(key int) *RecursiveStruct {
|
||||||
|
a := &RecursiveStruct{
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
b := &RecursiveStruct{
|
||||||
|
Key: key,
|
||||||
|
Child: a,
|
||||||
|
}
|
||||||
|
a.Child = b
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
a, b interface{}
|
||||||
|
diff string
|
||||||
|
equal bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkTestCases(t *testing.T, testData []testCase) {
|
||||||
|
for i, td := range testData {
|
||||||
|
diff, equal := PrettyDiff(td.a, td.b)
|
||||||
|
if diff != td.diff {
|
||||||
|
t.Errorf("%d. PrettyDiff(%#v, %#v) diff = %#v; not %#v", i, td.a, td.b, diff, td.diff)
|
||||||
|
}
|
||||||
|
if equal != td.equal {
|
||||||
|
t.Errorf("%d. PrettyDiff(%#v, %#v) equal = %#v; not %#v", i, td.a, td.b, equal, td.equal)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrettyDiff(t *testing.T) {
|
func TestPrettyDiff(t *testing.T) {
|
||||||
testData := []struct {
|
testData := []testCase{
|
||||||
a, b interface{}
|
|
||||||
diff string
|
|
||||||
equal bool
|
|
||||||
}{
|
|
||||||
{
|
{
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
@ -59,8 +91,8 @@ func TestPrettyDiff(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
testStruct{1, 2, []int{1}},
|
testStruct{1, 2, []int{1}, [3]int{4, 5, 6}},
|
||||||
testStruct{1, 3, []int{1, 2}},
|
testStruct{1, 3, []int{1, 2}, [3]int{4, 5, 6}},
|
||||||
"added: .C[1] = 2\nmodified: .b = 3\n",
|
"added: .C[1] = 2\nmodified: .b = 3\n",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
@ -71,11 +103,17 @@ func TestPrettyDiff(t *testing.T) {
|
|||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&time.Time{},
|
&struct{}{},
|
||||||
nil,
|
nil,
|
||||||
"modified: = <nil>\n",
|
"modified: = <nil>\n",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
&struct{}{},
|
||||||
|
"modified: = &struct {}{}\n",
|
||||||
|
false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
time.Time{},
|
time.Time{},
|
||||||
time.Time{},
|
time.Time{},
|
||||||
@ -89,15 +127,25 @@ func TestPrettyDiff(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, td := range testData {
|
checkTestCases(t, testData)
|
||||||
diff, equal := PrettyDiff(td.a, td.b)
|
}
|
||||||
if diff != td.diff {
|
|
||||||
t.Errorf("%d. PrettyDiff(%#v, %#v) diff = %#v; not %#v", i, td.a, td.b, diff, td.diff)
|
func TestPrettyDiffRecursive(t *testing.T) {
|
||||||
}
|
testData := []testCase{
|
||||||
if equal != td.equal {
|
{
|
||||||
t.Errorf("%d. PrettyDiff(%#v, %#v) equal = %#v; not %#v", i, td.a, td.b, equal, td.equal)
|
newRecursiveStruct(1),
|
||||||
}
|
newRecursiveStruct(1),
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
newRecursiveStruct(1),
|
||||||
|
newRecursiveStruct(2),
|
||||||
|
"modified: .Child.Key = 2\nmodified: .Key = 2\n",
|
||||||
|
false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
checkTestCases(t, testData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPathString(t *testing.T) {
|
func TestPathString(t *testing.T) {
|
||||||
|
2
vendor/manifest
vendored
2
vendor/manifest
vendored
@ -121,7 +121,7 @@
|
|||||||
{
|
{
|
||||||
"importpath": "github.com/d4l3k/messagediff",
|
"importpath": "github.com/d4l3k/messagediff",
|
||||||
"repository": "https://github.com/d4l3k/messagediff",
|
"repository": "https://github.com/d4l3k/messagediff",
|
||||||
"revision": "bf29d7cd9038386a5b4a22e2d73c8fb20ae14602",
|
"revision": "7b706999d935b04cf2dbc71a5a5afcbd288aeb48",
|
||||||
"branch": "master"
|
"branch": "master"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user