1package gstruct
2
3import (
4	"fmt"
5	"reflect"
6
7	"github.com/onsi/gomega/format"
8	"github.com/onsi/gomega/types"
9)
10
11//PointTo applies the given matcher to the value pointed to by actual. It fails if the pointer is
12//nil.
13//  actual := 5
14//  Expect(&actual).To(PointTo(Equal(5)))
15func PointTo(matcher types.GomegaMatcher) types.GomegaMatcher {
16	return &PointerMatcher{
17		Matcher: matcher,
18	}
19}
20
21type PointerMatcher struct {
22	Matcher types.GomegaMatcher
23
24	// Failure message.
25	failure string
26}
27
28func (m *PointerMatcher) Match(actual interface{}) (bool, error) {
29	val := reflect.ValueOf(actual)
30
31	// return error if actual type is not a pointer
32	if val.Kind() != reflect.Ptr {
33		return false, fmt.Errorf("PointerMatcher expects a pointer but we have '%s'", val.Kind())
34	}
35
36	if !val.IsValid() || val.IsNil() {
37		m.failure = format.Message(actual, "not to be <nil>")
38		return false, nil
39	}
40
41	// Forward the value.
42	elem := val.Elem().Interface()
43	match, err := m.Matcher.Match(elem)
44	if !match {
45		m.failure = m.Matcher.FailureMessage(elem)
46	}
47	return match, err
48}
49
50func (m *PointerMatcher) FailureMessage(_ interface{}) (message string) {
51	return m.failure
52}
53
54func (m *PointerMatcher) NegatedFailureMessage(actual interface{}) (message string) {
55	return m.Matcher.NegatedFailureMessage(actual)
56}
57