Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.

Commit 112dfb8

Browse files
poycodyoss
authored andcommittedNov 27, 2019
Adds GotFormatter interface and WantFormatter func (#236)
- WantFormatter is used to modify a Matcher's String() method. - GotFormatter is used to format the Got value for printing a failure message.
1 parent 3fae808 commit 112dfb8

File tree

4 files changed

+170
-2
lines changed

4 files changed

+170
-2
lines changed
 

‎README.md

+47
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,53 @@ func TestFoo(t *testing.T) {
166166
}
167167
```
168168

169+
### Modifying Failure Messages
170+
171+
When a matcher reports a failure, it prints the received (`Got`) vs the
172+
expected (`Want`) value.
173+
174+
```
175+
Got: [3]
176+
Want: is equal to 2
177+
Expected call at user_test.go:33 doesn't match the argument at index 1.
178+
Got: [0 1 1 2 3]
179+
Want: is equal to 1
180+
```
181+
182+
##### Modifying `Want`
183+
184+
The `Want` value comes from the matcher's `String()` method. If the matcher's
185+
default output doesn't meet your needs, then it can be modified as follows:
186+
187+
```go
188+
gomock.WantFormatter(
189+
gomock.StringerFunc(func() string { return "is equal to fifteen" }),
190+
gomock.Eq(15),
191+
)
192+
```
193+
194+
This modifies the `gomock.Eq(15)` matcher's output for `Want:` from `is equal
195+
to 15` to `is equal to fifteen`.
196+
197+
##### Modifying `Got`
198+
199+
The `Got` value comes from the object's `String()` method if it is available.
200+
In some cases the output of an object is difficult to read (e.g., `[]byte`) and
201+
it would be helpful for the test to print it differently. The following
202+
modifies how the `Got` value is formatted:
203+
204+
```go
205+
gomock.GotFormatterAdapter(
206+
gomock.GotFormatterFunc(func(i interface{}) string {
207+
// Leading 0s
208+
return fmt.Sprintf("%02d", i)
209+
}),
210+
gomock.Eq(15),
211+
)
212+
```
213+
214+
If the received value is `3`, then it will be printed as `03`.
215+
169216
[golang]: http://golang.org/
170217
[golang-install]: http://golang.org/doc/install.html#releases
171218
[gomock-ref]: http://godoc.org/github.com/golang/mock/gomock

‎gomock/call.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,15 @@ func (c *Call) matches(args []interface{}) error {
301301

302302
for i, m := range c.args {
303303
if !m.Matches(args[i]) {
304-
return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
305-
c.origin, strconv.Itoa(i), args[i], m)
304+
got := fmt.Sprintf("%v", args[i])
305+
if gs, ok := m.(GotFormatter); ok {
306+
got = gs.Got(args[i])
307+
}
308+
309+
return fmt.Errorf(
310+
"Expected call at %s doesn't match the argument at index %d.\nGot: %v\nWant: %v",
311+
c.origin, i, got, m,
312+
)
306313
}
307314
}
308315
} else {

‎gomock/controller_test.go

+57
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,63 @@ func TestUnexpectedArgValue_SecondArg(t *testing.T) {
317317
})
318318
}
319319

320+
func TestUnexpectedArgValue_WantFormatter(t *testing.T) {
321+
reporter, ctrl := createFixtures(t)
322+
defer reporter.recoverUnexpectedFatal()
323+
subject := new(Subject)
324+
325+
expectedArg0 := TestStruct{Number: 123, Message: "hello"}
326+
ctrl.RecordCall(
327+
subject,
328+
"ActOnTestStructMethod",
329+
expectedArg0,
330+
gomock.WantFormatter(
331+
gomock.StringerFunc(func() string { return "is equal to fifteen" }),
332+
gomock.Eq(15),
333+
),
334+
)
335+
336+
reporter.assertFatal(func() {
337+
ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "hello"}, 3)
338+
}, "Unexpected call to", "doesn't match the argument at index 1",
339+
"Got: 3\nWant: is equal to fifteen")
340+
341+
reporter.assertFatal(func() {
342+
// The expected call wasn't made.
343+
ctrl.Finish()
344+
})
345+
}
346+
347+
func TestUnexpectedArgValue_GotFormatter(t *testing.T) {
348+
reporter, ctrl := createFixtures(t)
349+
defer reporter.recoverUnexpectedFatal()
350+
subject := new(Subject)
351+
352+
expectedArg0 := TestStruct{Number: 123, Message: "hello"}
353+
ctrl.RecordCall(
354+
subject,
355+
"ActOnTestStructMethod",
356+
expectedArg0,
357+
gomock.GotFormatterAdapter(
358+
gomock.GotFormatterFunc(func(i interface{}) string {
359+
// Leading 0s
360+
return fmt.Sprintf("%02d", i)
361+
}),
362+
gomock.Eq(15),
363+
),
364+
)
365+
366+
reporter.assertFatal(func() {
367+
ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "hello"}, 3)
368+
}, "Unexpected call to", "doesn't match the argument at index 1",
369+
"Got: 03\nWant: is equal to 15")
370+
371+
reporter.assertFatal(func() {
372+
// The expected call wasn't made.
373+
ctrl.Finish()
374+
})
375+
}
376+
320377
func TestAnyTimes(t *testing.T) {
321378
reporter, ctrl := createFixtures(t)
322379
subject := new(Subject)

‎gomock/matchers.go

+57
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,63 @@ type Matcher interface {
2929
String() string
3030
}
3131

32+
// WantFormatter modifies the given Matcher's String() method to the given
33+
// Stringer. This allows for control on how the "Want" is formatted when
34+
// printing .
35+
func WantFormatter(s fmt.Stringer, m Matcher) Matcher {
36+
type matcher interface {
37+
Matches(x interface{}) bool
38+
}
39+
40+
return struct {
41+
matcher
42+
fmt.Stringer
43+
}{
44+
matcher: m,
45+
Stringer: s,
46+
}
47+
}
48+
49+
// StringerFunc type is an adapter to allow the use of ordinary functions as
50+
// a Stringer. If f is a function with the appropriate signature,
51+
// StringerFunc(f) is a Stringer that calls f.
52+
type StringerFunc func() string
53+
54+
// String implements fmt.Stringer.
55+
func (f StringerFunc) String() string {
56+
return f()
57+
}
58+
59+
// GotFormatter is used to better print failure messages. If a matcher
60+
// implements GotFormatter, it will use the result from Got when printing
61+
// the failure message.
62+
type GotFormatter interface {
63+
// Got is invoked with the received value. The result is used when
64+
// printing the failure message.
65+
Got(got interface{}) string
66+
}
67+
68+
// GotFormatterFunc type is an adapter to allow the use of ordinary
69+
// functions as a GotFormatter. If f is a function with the appropriate
70+
// signature, GotFormatterFunc(f) is a GotFormatter that calls f.
71+
type GotFormatterFunc func(got interface{}) string
72+
73+
// Got implements GotFormatter.
74+
func (f GotFormatterFunc) Got(got interface{}) string {
75+
return f(got)
76+
}
77+
78+
// GotFormatterAdapter attaches a GotFormatter to a Matcher.
79+
func GotFormatterAdapter(s GotFormatter, m Matcher) Matcher {
80+
return struct {
81+
GotFormatter
82+
Matcher
83+
}{
84+
GotFormatter: s,
85+
Matcher: m,
86+
}
87+
}
88+
3289
type anyMatcher struct{}
3390

3491
func (anyMatcher) Matches(x interface{}) bool {

0 commit comments

Comments
 (0)
This repository has been archived.