1// A test that uses a mock.
2package user_test
3
4import (
5	"testing"
6
7	"github.com/golang/mock/gomock"
8	user "github.com/golang/mock/sample"
9	"github.com/golang/mock/sample/imp1"
10	mock_user "github.com/golang/mock/sample/mock_user"
11)
12
13func TestRemember(t *testing.T) {
14	ctrl := gomock.NewController(t)
15	defer ctrl.Finish()
16
17	mockIndex := mock_user.NewMockIndex(ctrl)
18	mockIndex.EXPECT().Put("a", 1)            // literals work
19	mockIndex.EXPECT().Put("b", gomock.Eq(2)) // matchers work too
20
21	// NillableRet returns error. Not declaring it should result in a nil return.
22	mockIndex.EXPECT().NillableRet()
23	// Calls that returns something assignable to the return type.
24	boolc := make(chan bool)
25	// In this case, "chan bool" is assignable to "chan<- bool".
26	mockIndex.EXPECT().ConcreteRet().Return(boolc)
27	// In this case, nil is assignable to "chan<- bool".
28	mockIndex.EXPECT().ConcreteRet().Return(nil)
29
30	// Should be able to place expectations on variadic methods.
31	mockIndex.EXPECT().Ellip("%d", 0, 1, 1, 2, 3) // direct args
32	tri := []interface{}{1, 3, 6, 10, 15}
33	mockIndex.EXPECT().Ellip("%d", tri...) // args from slice
34	mockIndex.EXPECT().EllipOnly(gomock.Eq("arg"))
35
36	user.Remember(mockIndex, []string{"a", "b"}, []interface{}{1, 2})
37	// Check the ConcreteRet calls.
38	if c := mockIndex.ConcreteRet(); c != boolc {
39		t.Errorf("ConcreteRet: got %v, want %v", c, boolc)
40	}
41	if c := mockIndex.ConcreteRet(); c != nil {
42		t.Errorf("ConcreteRet: got %v, want nil", c)
43	}
44
45	// Try one with an action.
46	calledString := ""
47	mockIndex.EXPECT().Put(gomock.Any(), gomock.Any()).Do(func(key string, _ interface{}) {
48		calledString = key
49	})
50	mockIndex.EXPECT().NillableRet()
51	user.Remember(mockIndex, []string{"blah"}, []interface{}{7})
52	if calledString != "blah" {
53		t.Fatalf(`Uh oh. %q != "blah"`, calledString)
54	}
55
56	// Use Do with a nil arg.
57	mockIndex.EXPECT().Put("nil-key", gomock.Any()).Do(func(key string, value interface{}) {
58		if value != nil {
59			t.Errorf("Put did not pass through nil; got %v", value)
60		}
61	})
62	mockIndex.EXPECT().NillableRet()
63	user.Remember(mockIndex, []string{"nil-key"}, []interface{}{nil})
64}
65
66func TestVariadicFunction(t *testing.T) {
67	ctrl := gomock.NewController(t)
68	defer ctrl.Finish()
69
70	mockIndex := mock_user.NewMockIndex(ctrl)
71	mockIndex.EXPECT().Ellip("%d", 5, 6, 7, 8).Do(func(format string, nums ...int) {
72		sum := 0
73		for _, value := range nums {
74			sum += value
75		}
76		if sum != 26 {
77			t.Errorf("Expected 7, got %d", sum)
78		}
79	})
80	mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) {
81		sum := 0
82		for _, value := range nums {
83			sum += value
84		}
85		if sum != 10 {
86			t.Errorf("Expected 7, got %d", sum)
87		}
88	})
89	mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) {
90		sum := 0
91		for _, value := range nums {
92			sum += value
93		}
94		if sum != 0 {
95			t.Errorf("Expected 0, got %d", sum)
96		}
97	})
98	mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) {
99		sum := 0
100		for _, value := range nums {
101			sum += value
102		}
103		if sum != 0 {
104			t.Errorf("Expected 0, got %d", sum)
105		}
106	})
107	mockIndex.EXPECT().Ellip("%d").Do(func(format string, nums ...int) {
108		sum := 0
109		for _, value := range nums {
110			sum += value
111		}
112		if sum != 0 {
113			t.Errorf("Expected 0, got %d", sum)
114		}
115	})
116
117	mockIndex.Ellip("%d", 1, 2, 3, 4) // Match second matcher.
118	mockIndex.Ellip("%d", 5, 6, 7, 8) // Match first matcher.
119	mockIndex.Ellip("%d", 0)
120	mockIndex.Ellip("%d")
121	mockIndex.Ellip("%d")
122}
123
124func TestGrabPointer(t *testing.T) {
125	ctrl := gomock.NewController(t)
126	defer ctrl.Finish()
127
128	mockIndex := mock_user.NewMockIndex(ctrl)
129	mockIndex.EXPECT().Ptr(gomock.Any()).SetArg(0, 7) // set first argument to 7
130
131	i := user.GrabPointer(mockIndex)
132	if i != 7 {
133		t.Errorf("Expected 7, got %d", i)
134	}
135}
136
137func TestEmbeddedInterface(t *testing.T) {
138	ctrl := gomock.NewController(t)
139	defer ctrl.Finish()
140
141	mockEmbed := mock_user.NewMockEmbed(ctrl)
142	mockEmbed.EXPECT().RegularMethod()
143	mockEmbed.EXPECT().EmbeddedMethod()
144	mockEmbed.EXPECT().ForeignEmbeddedMethod()
145
146	mockEmbed.RegularMethod()
147	mockEmbed.EmbeddedMethod()
148	var emb imp1.ForeignEmbedded = mockEmbed // also does interface check
149	emb.ForeignEmbeddedMethod()
150}
151
152func TestExpectTrueNil(t *testing.T) {
153	// Make sure that passing "nil" to EXPECT (thus as a nil interface value),
154	// will correctly match a nil concrete type.
155	ctrl := gomock.NewController(t)
156	defer ctrl.Finish()
157
158	mockIndex := mock_user.NewMockIndex(ctrl)
159	mockIndex.EXPECT().Ptr(nil) // this nil is a nil interface{}
160	mockIndex.Ptr(nil)          // this nil is a nil *int
161}
162
163func TestDoAndReturnSignature(t *testing.T) {
164	t.Run("wrong number of return args", func(t *testing.T) {
165		ctrl := gomock.NewController(t)
166		defer ctrl.Finish()
167
168		mockIndex := mock_user.NewMockIndex(ctrl)
169
170		mockIndex.EXPECT().Slice(gomock.Any(), gomock.Any()).DoAndReturn(
171			func(_ []int, _ []byte) {
172				return
173			})
174
175		defer func() {
176			if r := recover(); r == nil {
177				t.Error("expected panic")
178			}
179		}()
180
181		mockIndex.Slice([]int{0}, []byte("meow"))
182	})
183
184	t.Run("wrong type of return arg", func(t *testing.T) {
185		ctrl := gomock.NewController(t)
186		defer ctrl.Finish()
187
188		mockIndex := mock_user.NewMockIndex(ctrl)
189
190		mockIndex.EXPECT().Slice(gomock.Any(), gomock.Any()).DoAndReturn(
191			func(_ []int, _ []byte) bool {
192				return true
193			})
194
195		mockIndex.Slice([]int{0}, []byte("meow"))
196	})
197}
198