Skip to content

Commit

Permalink
Shallow now handles strings as well
Browse files Browse the repository at this point in the history
Add clarifications for string/slice cases.

Signed-off-by: Maxime Soulé <btik-git@scoubidou.com>
  • Loading branch information
maxatome committed Dec 6, 2018
1 parent 5f22f4c commit 9c5ee41
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 10 deletions.
36 changes: 36 additions & 0 deletions cmp_funcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,42 @@ func ExampleCmpShallow() {
// false
}

func ExampleCmpShallow_slice() {
t := &testing.T{}

back := []int{1, 2, 3, 1, 2, 3}
a := back[:3]
b := back[3:]

ok := CmpShallow(t, a, back)
fmt.Println("are ≠ but share the same area:", ok)

ok = CmpShallow(t, b, back)
fmt.Println("are = but do not point to same area:", ok)

// Output:
// are ≠ but share the same area: true
// are = but do not point to same area: false
}

func ExampleCmpShallow_string() {
t := &testing.T{}

back := "foobarfoobar"
a := back[:6]
b := back[6:]

ok := CmpShallow(t, a, back)
fmt.Println("are ≠ but share the same area:", ok)

ok = CmpShallow(t, b, a)
fmt.Println("are = but do not point to same area:", ok)

// Output:
// are ≠ but share the same area: true
// are = but do not point to same area: false
}

func ExampleCmpSlice_slice() {
t := &testing.T{}

Expand Down
36 changes: 36 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1624,6 +1624,42 @@ func ExampleShallow() {
// false
}

func ExampleShallow_slice() {
t := &testing.T{}

back := []int{1, 2, 3, 1, 2, 3}
a := back[:3]
b := back[3:]

ok := CmpDeeply(t, a, Shallow(back))
fmt.Println("are ≠ but share the same area:", ok)

ok = CmpDeeply(t, b, Shallow(back))
fmt.Println("are = but do not point to same area:", ok)

// Output:
// are ≠ but share the same area: true
// are = but do not point to same area: false
}

func ExampleShallow_string() {
t := &testing.T{}

back := "foobarfoobar"
a := back[:6]
b := back[6:]

ok := CmpDeeply(t, a, Shallow(back))
fmt.Println("are ≠ but share the same area:", ok)

ok = CmpDeeply(t, b, Shallow(a))
fmt.Println("are = but do not point to same area:", ok)

// Output:
// are ≠ but share the same area: true
// are = but do not point to same area: false
}

func ExampleSlice_slice() {
t := &testing.T{}

Expand Down
36 changes: 36 additions & 0 deletions t_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,42 @@ func ExampleT_Shallow() {
// false
}

func ExampleT_Shallow_slice() {
t := NewT(&testing.T{})

back := []int{1, 2, 3, 1, 2, 3}
a := back[:3]
b := back[3:]

ok := t.Shallow(a, back)
fmt.Println("are ≠ but share the same area:", ok)

ok = t.Shallow(b, back)
fmt.Println("are = but do not point to same area:", ok)

// Output:
// are ≠ but share the same area: true
// are = but do not point to same area: false
}

func ExampleT_Shallow_string() {
t := NewT(&testing.T{})

back := "foobarfoobar"
a := back[:6]
b := back[6:]

ok := t.Shallow(a, back)
fmt.Println("are ≠ but share the same area:", ok)

ok = t.Shallow(b, a)
fmt.Println("are = but do not point to same area:", ok)

// Output:
// are ≠ but share the same area: true
// are = but do not point to same area: false
}

func ExampleT_Slice_slice() {
t := NewT(&testing.T{})

Expand Down
47 changes: 43 additions & 4 deletions td_shallow.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package testdeep
import (
"fmt"
"reflect"
"unsafe"

"github.com/maxatome/go-testdeep/internal/ctxerr"
"github.com/maxatome/go-testdeep/internal/types"
Expand All @@ -18,20 +19,44 @@ type tdShallow struct {
Base
expectedKind reflect.Kind
expectedPointer uintptr
expectedStr string // in reflect.String case, to avoid contents GC
}

var _ TestDeep = &tdShallow{}

func stringPointer(s string) uintptr {
return (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
}

// Shallow operator compares pointers only, not their contents. It
// applies on channels, functions (with some restrictions), maps,
// pointers and slices.
// pointers, slices and strings.
//
// During a match, the compared data must be the same as
// "expectedPointer" to succeed.
//
// a, b := 123, 123
// CmpDeeply(t, &a, Shallow(&a)) // succeeds
// CmpDeeply(t, &a, Shallow(&b)) // fails even if a == b as &a != &b
//
// back := "foobarfoobar"
// a, b := back[:6], back[6:]
// // a == b but...
// CmpDeeply(t, &a, Shallow(&b)) // fails
//
// Be careful for slices and strings! Shallow can succeed but the
// slices/strings not be identical because of their different
// lengths. For example:
//
// a := "foobar yes!"
// b := a[:1] // aka. "f"
// CmpDeeply(t, &a, Shallow(&b)) // succeeds as both strings point to the same area, even if len() differ
//
// The same behavior occurs for slices:
//
// a := []int{1, 2, 3, 4, 5, 6}
// b := a[:2] // aka. []int{1, 2}
// CmpDeeply(t, &a, Shallow(&b)) // succeeds as both slices point to the same area, even if len() differ
func Shallow(expectedPtr interface{}) TestDeep {
vptr := reflect.ValueOf(expectedPtr)

Expand All @@ -56,8 +81,13 @@ func Shallow(expectedPtr interface{}) TestDeep {
shallow.expectedPointer = vptr.Pointer()
return &shallow

case reflect.String:
shallow.expectedStr = vptr.String()
shallow.expectedPointer = stringPointer(shallow.expectedStr)
return &shallow

default:
panic("usage: Shallow(CHANNEL|FUNC|MAP|PTR|SLICE|UNSAFE_PTR)")
panic("usage: Shallow(CHANNEL|FUNC|MAP|PTR|SLICE|UNSAFE_PTR|STRING)")
}
}

Expand All @@ -73,13 +103,22 @@ func (s *tdShallow) Match(ctx ctxerr.Context, got reflect.Value) *ctxerr.Error {
})
}

if got.Pointer() != s.expectedPointer {
var ptr uintptr

// Special case for strings
if s.expectedKind == reflect.String {
ptr = stringPointer(got.String())
} else {
ptr = got.Pointer()
}

if ptr != s.expectedPointer {
if ctx.BooleanError {
return ctxerr.BooleanError
}
return ctx.CollectError(&ctxerr.Error{
Message: fmt.Sprintf("%s pointer mismatch", s.expectedKind),
Got: types.RawString(fmt.Sprintf("0x%x", got.Pointer())),
Got: types.RawString(fmt.Sprintf("0x%x", ptr)),
Expected: types.RawString(fmt.Sprintf("0x%x", s.expectedPointer)),
})
}
Expand Down
36 changes: 30 additions & 6 deletions td_shallow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ import (
func TestShallow(t *testing.T) {
//
// Slice
gotSlice := []int{1, 2, 3}
expectedSlice := []int{1, 2, 3}
checkError(t, gotSlice, testdeep.Shallow(expectedSlice),
back := [...]int{1, 2, 3, 1, 2, 3}
as := back[:3]
bs := back[3:]
checkError(t, bs, testdeep.Shallow(back[:]),
expectedError{
Message: mustBe("slice pointer mismatch"),
Path: mustBe("DATA"),
Got: mustContain("0x"),
Expected: mustContain("0x"),
})

expectedSlice = gotSlice
checkOK(t, gotSlice, testdeep.Shallow(expectedSlice))
checkOK(t, as, testdeep.Shallow(back[:]))
checkOK(t, ([]byte)(nil), ([]byte)(nil))

//
Expand Down Expand Up @@ -98,6 +98,30 @@ func TestShallow(t *testing.T) {
checkOK(t, gotChan, testdeep.Shallow(expectedChan))
checkOK(t, (chan int)(nil), (chan int)(nil))

//
// String
backStr := "foobarfoobar!"
a := backStr[:6]
b := backStr[6:12]
checkOK(t, a, testdeep.Shallow(backStr))
checkOK(t, backStr, testdeep.Shallow(a))
checkOK(t, b, testdeep.Shallow(backStr[6:7]))

checkError(t, backStr, testdeep.Shallow(b),
expectedError{
Message: mustBe("string pointer mismatch"),
Path: mustBe("DATA"),
Got: mustContain("0x"),
Expected: mustContain("0x"),
})
checkError(t, b, testdeep.Shallow(backStr),
expectedError{
Message: mustBe("string pointer mismatch"),
Path: mustBe("DATA"),
Got: mustContain("0x"),
Expected: mustContain("0x"),
})

//
// Erroneous mix
checkError(t, gotMap, testdeep.Shallow(expectedChan),
Expand All @@ -110,7 +134,7 @@ func TestShallow(t *testing.T) {

//
// Bad usage
test.CheckPanic(t, func() { testdeep.Shallow("test") }, "usage: Shallow")
test.CheckPanic(t, func() { testdeep.Shallow(42) }, "usage: Shallow")

//
//
Expand Down

0 comments on commit 9c5ee41

Please sign in to comment.