Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shallow now handles strings as well #33

Merged
merged 1 commit into from
Dec 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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