| package pretty |
| |
| import ( |
| "bytes" |
| "fmt" |
| "log" |
| "reflect" |
| "testing" |
| "unsafe" |
| ) |
| |
| var ( |
| _ Logfer = (*testing.T)(nil) |
| _ Logfer = (*testing.B)(nil) |
| _ Printfer = (*log.Logger)(nil) |
| ) |
| |
| type difftest struct { |
| a interface{} |
| b interface{} |
| exp []string |
| } |
| |
| type S struct { |
| A int |
| S *S |
| I interface{} |
| C []int |
| } |
| |
| type ( |
| N struct{ N int } |
| E interface{} |
| ) |
| |
| var ( |
| c0 = make(chan int) |
| c1 = make(chan int) |
| f0 = func() {} |
| f1 = func() {} |
| i0 = 0 |
| i1 = 1 |
| ) |
| |
| var diffs = []difftest{ |
| {a: nil, b: nil}, |
| {a: S{A: 1}, b: S{A: 1}}, |
| |
| {0, "", []string{`int != string`}}, |
| {0, 1, []string{`0 != 1`}}, |
| {S{}, new(S), []string{`pretty.S != *pretty.S`}}, |
| {"a", "b", []string{`"a" != "b"`}}, |
| {S{}, S{A: 1}, []string{`A: 0 != 1`}}, |
| {new(S), &S{A: 1}, []string{`A: 0 != 1`}}, |
| {S{S: new(S)}, S{S: &S{A: 1}}, []string{`S.A: 0 != 1`}}, |
| {S{}, S{I: 0}, []string{`I: nil != int(0)`}}, |
| {S{I: 1}, S{I: "x"}, []string{`I: int != string`}}, |
| {S{}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}}, |
| {S{C: []int{}}, S{C: []int{1}}, []string{`C: []int[0] != []int[1]`}}, |
| {S{C: []int{1, 2, 3}}, S{C: []int{1, 2, 4}}, []string{`C[2]: 3 != 4`}}, |
| {S{}, S{A: 1, S: new(S)}, []string{`A: 0 != 1`, `S: nil != &pretty.S{}`}}, |
| |
| // unexported fields of every reflect.Kind (both equal and unequal) |
| {struct{ x bool }{false}, struct{ x bool }{false}, nil}, |
| {struct{ x bool }{false}, struct{ x bool }{true}, []string{`x: false != true`}}, |
| {struct{ x int }{0}, struct{ x int }{0}, nil}, |
| {struct{ x int }{0}, struct{ x int }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x int8 }{0}, struct{ x int8 }{0}, nil}, |
| {struct{ x int8 }{0}, struct{ x int8 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x int16 }{0}, struct{ x int16 }{0}, nil}, |
| {struct{ x int16 }{0}, struct{ x int16 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x int32 }{0}, struct{ x int32 }{0}, nil}, |
| {struct{ x int32 }{0}, struct{ x int32 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x int64 }{0}, struct{ x int64 }{0}, nil}, |
| {struct{ x int64 }{0}, struct{ x int64 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x uint }{0}, struct{ x uint }{0}, nil}, |
| {struct{ x uint }{0}, struct{ x uint }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x uint8 }{0}, struct{ x uint8 }{0}, nil}, |
| {struct{ x uint8 }{0}, struct{ x uint8 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x uint16 }{0}, struct{ x uint16 }{0}, nil}, |
| {struct{ x uint16 }{0}, struct{ x uint16 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x uint32 }{0}, struct{ x uint32 }{0}, nil}, |
| {struct{ x uint32 }{0}, struct{ x uint32 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x uint64 }{0}, struct{ x uint64 }{0}, nil}, |
| {struct{ x uint64 }{0}, struct{ x uint64 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x uintptr }{0}, struct{ x uintptr }{0}, nil}, |
| {struct{ x uintptr }{0}, struct{ x uintptr }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x float32 }{0}, struct{ x float32 }{0}, nil}, |
| {struct{ x float32 }{0}, struct{ x float32 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x float64 }{0}, struct{ x float64 }{0}, nil}, |
| {struct{ x float64 }{0}, struct{ x float64 }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x complex64 }{0}, struct{ x complex64 }{0}, nil}, |
| {struct{ x complex64 }{0}, struct{ x complex64 }{1}, []string{`x: (0+0i) != (1+0i)`}}, |
| {struct{ x complex128 }{0}, struct{ x complex128 }{0}, nil}, |
| {struct{ x complex128 }{0}, struct{ x complex128 }{1}, []string{`x: (0+0i) != (1+0i)`}}, |
| {struct{ x [1]int }{[1]int{0}}, struct{ x [1]int }{[1]int{0}}, nil}, |
| {struct{ x [1]int }{[1]int{0}}, struct{ x [1]int }{[1]int{1}}, []string{`x[0]: 0 != 1`}}, |
| {struct{ x chan int }{c0}, struct{ x chan int }{c0}, nil}, |
| {struct{ x chan int }{c0}, struct{ x chan int }{c1}, []string{fmt.Sprintf("x: %p != %p", c0, c1)}}, |
| {struct{ x func() }{f0}, struct{ x func() }{f0}, nil}, |
| {struct{ x func() }{f0}, struct{ x func() }{f1}, []string{fmt.Sprintf("x: %p != %p", f0, f1)}}, |
| {struct{ x interface{} }{0}, struct{ x interface{} }{0}, nil}, |
| {struct{ x interface{} }{0}, struct{ x interface{} }{1}, []string{`x: 0 != 1`}}, |
| {struct{ x interface{} }{0}, struct{ x interface{} }{""}, []string{`x: int != string`}}, |
| {struct{ x interface{} }{0}, struct{ x interface{} }{nil}, []string{`x: int(0) != nil`}}, |
| {struct{ x interface{} }{nil}, struct{ x interface{} }{0}, []string{`x: nil != int(0)`}}, |
| {struct{ x map[int]int }{map[int]int{0: 0}}, struct{ x map[int]int }{map[int]int{0: 0}}, nil}, |
| {struct{ x map[int]int }{map[int]int{0: 0}}, struct{ x map[int]int }{map[int]int{0: 1}}, []string{`x[0]: 0 != 1`}}, |
| {struct{ x *int }{new(int)}, struct{ x *int }{new(int)}, nil}, |
| {struct{ x *int }{&i0}, struct{ x *int }{&i1}, []string{`x: 0 != 1`}}, |
| {struct{ x *int }{nil}, struct{ x *int }{&i0}, []string{`x: nil != &int(0)`}}, |
| {struct{ x *int }{&i0}, struct{ x *int }{nil}, []string{`x: &int(0) != nil`}}, |
| {struct{ x []int }{[]int{0}}, struct{ x []int }{[]int{0}}, nil}, |
| {struct{ x []int }{[]int{0}}, struct{ x []int }{[]int{1}}, []string{`x[0]: 0 != 1`}}, |
| {struct{ x string }{"a"}, struct{ x string }{"a"}, nil}, |
| {struct{ x string }{"a"}, struct{ x string }{"b"}, []string{`x: "a" != "b"`}}, |
| {struct{ x N }{N{0}}, struct{ x N }{N{0}}, nil}, |
| {struct{ x N }{N{0}}, struct{ x N }{N{1}}, []string{`x.N: 0 != 1`}}, |
| { |
| struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))}, |
| struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))}, |
| nil, |
| }, |
| { |
| struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(0))}, |
| struct{ x unsafe.Pointer }{unsafe.Pointer(uintptr(1))}, |
| []string{`x: 0x0 != 0x1`}, |
| }, |
| } |
| |
| func TestDiff(t *testing.T) { |
| for _, tt := range diffs { |
| expectDiffOutput(t, tt.a, tt.b, tt.exp) |
| } |
| } |
| |
| func expectDiffOutput(t *testing.T, a, b interface{}, exp []string) { |
| got := Diff(a, b) |
| eq := len(got) == len(exp) |
| if eq { |
| for i := range got { |
| eq = eq && got[i] == exp[i] |
| } |
| } |
| if !eq { |
| t.Errorf("diffing % #v", a) |
| t.Errorf("with % #v", b) |
| diffdiff(t, got, exp) |
| } |
| } |
| |
| func TestKeyEqual(t *testing.T) { |
| var emptyInterfaceZero interface{} = 0 |
| |
| cases := []interface{}{ |
| new(bool), |
| new(int), |
| new(int8), |
| new(int16), |
| new(int32), |
| new(int64), |
| new(uint), |
| new(uint8), |
| new(uint16), |
| new(uint32), |
| new(uint64), |
| new(uintptr), |
| new(float32), |
| new(float64), |
| new(complex64), |
| new(complex128), |
| new([1]int), |
| new(chan int), |
| new(unsafe.Pointer), |
| new(interface{}), |
| &emptyInterfaceZero, |
| new(*int), |
| new(string), |
| new(struct{ int }), |
| } |
| |
| for _, test := range cases { |
| rv := reflect.ValueOf(test).Elem() |
| if !keyEqual(rv, rv) { |
| t.Errorf("keyEqual(%s, %s) = false want true", rv.Type(), rv.Type()) |
| } |
| } |
| } |
| |
| func TestFdiff(t *testing.T) { |
| var buf bytes.Buffer |
| Fdiff(&buf, 0, 1) |
| want := "0 != 1\n" |
| if got := buf.String(); got != want { |
| t.Errorf("Fdiff(0, 1) = %q want %q", got, want) |
| } |
| } |
| |
| func TestDiffCycle(t *testing.T) { |
| // Diff two cyclic structs |
| a := &I{i: 1, R: nil} |
| a.R = a |
| b := &I{i: 2, R: nil} |
| b.R = b |
| expectDiffOutput(t, a, b, []string{ |
| `i: 1 != 2`, |
| }) |
| |
| // Diff two equal cyclic structs |
| b.i = 1 |
| expectDiffOutput(t, a, b, []string{}) |
| |
| // Diff two structs with different cycles |
| b2 := &I{i: 1, R: b} |
| b.R = b2 |
| expectDiffOutput(t, a, b, []string{`R: pretty.I{ |
| i: 1, |
| R: &pretty.I{(CYCLIC REFERENCE)}, |
| } (previously visited) != pretty.I{ |
| i: 1, |
| R: &pretty.I{ |
| i: 1, |
| R: &pretty.I{(CYCLIC REFERENCE)}, |
| }, |
| }`}) |
| |
| // ... and the same in the other direction |
| expectDiffOutput(t, b, a, []string{`R: pretty.I{ |
| i: 1, |
| R: &pretty.I{ |
| i: 1, |
| R: &pretty.I{(CYCLIC REFERENCE)}, |
| }, |
| } != pretty.I{ |
| i: 1, |
| R: &pretty.I{(CYCLIC REFERENCE)}, |
| } (previously visited)`}) |
| } |
| |
| func diffdiff(t *testing.T, got, exp []string) { |
| minus(t, "unexpected:", got, exp) |
| minus(t, "missing:", exp, got) |
| } |
| |
| func minus(t *testing.T, s string, a, b []string) { |
| var i, j int |
| for i = 0; i < len(a); i++ { |
| for j = 0; j < len(b); j++ { |
| if a[i] == b[j] { |
| break |
| } |
| } |
| if j == len(b) { |
| t.Error(s, a[i]) |
| } |
| } |
| } |