github.com/joomcode/pegomock@v2.9.2-0.20220414140958-14f53b6b2a6c+incompatible/dsl_test.go (about) 1 // Copyright 2015 Peter Goetz 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pegomock_test 16 17 import ( 18 "errors" 19 "fmt" 20 "net/http" 21 "reflect" 22 "sync" 23 "testing" 24 "time" 25 26 . "github.com/petergtz/pegomock" 27 . "github.com/petergtz/pegomock/matchers" 28 29 "github.com/onsi/ginkgo" 30 "github.com/onsi/gomega" 31 "github.com/petergtz/pegomock" 32 "github.com/petergtz/pegomock/test_interface" 33 ) 34 35 var ( 36 BeforeEach = ginkgo.BeforeEach 37 It = ginkgo.It 38 FIt = ginkgo.FIt 39 Describe = ginkgo.Describe 40 Context = ginkgo.Context 41 BeNil = gomega.BeNil 42 BeTrue = gomega.BeTrue 43 ConsistOf = gomega.ConsistOf 44 ContainSubstring = gomega.ContainSubstring 45 MatchError = gomega.MatchError 46 Equal = gomega.Equal 47 Expect = gomega.Expect 48 HaveLen = gomega.HaveLen 49 HavePrefix = gomega.HavePrefix 50 Panic = gomega.Panic 51 SatisfyAll = gomega.SatisfyAll 52 ) 53 54 var checkThatInterfaceIsImplemented test_interface.Display = NewMockDisplay() 55 56 func TestDSL(t *testing.T) { 57 gomega.RegisterFailHandler(ginkgo.Fail) 58 pegomock.RegisterMockFailHandler(func(message string, callerSkip ...int) { panic(message) }) 59 ginkgo.RunSpecs(t, "DSL Suite") 60 } 61 62 func AnyError() error { 63 RegisterMatcher(NewAnyMatcher(reflect.TypeOf((*error)(nil)).Elem())) 64 return nil 65 } 66 67 func AnyRequest() http.Request { 68 RegisterMatcher(NewAnyMatcher(reflect.TypeOf((*http.Request)(nil)).Elem())) 69 return http.Request{} 70 } 71 72 func AnyRequestPtr() *http.Request { 73 RegisterMatcher(NewAnyMatcher(reflect.TypeOf((**http.Request)(nil)).Elem())) 74 return nil 75 } 76 77 type NeverMatcher struct{} 78 79 func (matcher *NeverMatcher) Matches(param Param) bool { return false } 80 func (matcher *NeverMatcher) FailureMessage() string { 81 return "This matcher never matches (and is only for testing purposes)" 82 } 83 func (matcher *NeverMatcher) String() string { return "NeverMatching" } 84 85 func NeverMatchingRequest() http.Request { 86 RegisterMatcher(&NeverMatcher{}) 87 return http.Request{} 88 } 89 90 var _ = Describe("MockDisplay", func() { 91 var display *MockDisplay 92 93 BeforeEach(func() { 94 display = NewMockDisplay() 95 }) 96 97 Context("Calling SomeValue() with no stubbing", func() { 98 It("returns zero value", func() { 99 Expect(display.SomeValue()).To(Equal("")) 100 }) 101 }) 102 103 Context("Stubbing MultipleParamsAndReturnValue() with matchers", func() { 104 BeforeEach(func() { 105 When(display.MultipleParamsAndReturnValue(EqString("Hello"), EqInt(333))).ThenReturn("Bla") 106 }) 107 108 It("fails during verification when mock was not called", func() { 109 Expect(func() { display.VerifyWasCalledOnce().MultipleParamsAndReturnValue("Hello", 333) }).To(PanicWithMessageTo(HavePrefix( 110 "Mock invocation count for MultipleParamsAndReturnValue(\"Hello\", 333) does not match expectation.\n\n\tExpected: 1; but got: 0", 111 ))) 112 }) 113 114 It("succeeds verification when mock was called", func() { 115 display.MultipleParamsAndReturnValue("Hello", 333) 116 Expect(func() { display.VerifyWasCalledOnce().MultipleParamsAndReturnValue("Hello", 333) }).NotTo(Panic()) 117 }) 118 119 It("succeeds verification when verification and invocation are mixed", func() { 120 Expect(func() { display.VerifyWasCalledOnce().MultipleParamsAndReturnValue("Hello", 333) }).To(PanicWithMessageTo(HavePrefix( 121 expectation{method: "MultipleParamsAndReturnValue(\"Hello\", 333)", expected: "1", actual: "0"}.string(), 122 ))) 123 display.MultipleParamsAndReturnValue("Hello", 333) 124 Expect(func() { display.VerifyWasCalledOnce().MultipleParamsAndReturnValue("Hello", 333) }).NotTo(Panic()) 125 }) 126 }) 127 128 Context("Calling MultipleParamsAndReturnValue() with \"Any\"-matchers", func() { 129 It("succeeds all verifications that match", func() { 130 When(display.MultipleParamsAndReturnValue(AnyString(), EqInt(333))).ThenReturn("Bla") 131 132 Expect(func() { display.VerifyWasCalledOnce().MultipleParamsAndReturnValue("Hello", 333) }).To(PanicWithMessageTo(HavePrefix( 133 expectation{method: "MultipleParamsAndReturnValue(\"Hello\", 333)", expected: "1", actual: "0"}.string(), 134 ))) 135 136 display.MultipleParamsAndReturnValue("Hello", 333) 137 display.MultipleParamsAndReturnValue("Hello again", 333) 138 display.MultipleParamsAndReturnValue("And again", 333) 139 140 Expect(func() { display.VerifyWasCalledOnce().MultipleParamsAndReturnValue("Hello", 333) }).NotTo(Panic()) 141 Expect(func() { display.VerifyWasCalledOnce().MultipleParamsAndReturnValue("Hello again", 333) }).NotTo(Panic()) 142 Expect(func() { display.VerifyWasCalledOnce().MultipleParamsAndReturnValue("And again", 333) }).NotTo(Panic()) 143 144 Expect(func() { display.VerifyWasCalledOnce().MultipleParamsAndReturnValue("And again", 444) }).To(PanicWithMessageTo(HavePrefix( 145 expectation{method: "MultipleParamsAndReturnValue(\"And again\", 444)", expected: "1", actual: "0"}.string(), 146 ))) 147 148 }) 149 }) 150 151 Context("Calling MultipleParamsAndReturnValue() only with matchers on some parameters", func() { 152 It("panics", func() { 153 Expect(func() { When(display.MultipleParamsAndReturnValue(EqString("Hello"), 333)) }).To(PanicWithMessageTo(HavePrefix( 154 "Invalid use of matchers!\n\n 2 matchers expected, 1 recorded.\n\n" + 155 "This error may occur if matchers are combined with raw values:\n" + 156 " //incorrect:\n" + 157 " someFunc(AnyInt(), \"raw String\")\n" + 158 "When using matchers, all arguments have to be provided by matchers.\n" + 159 "For example:\n" + 160 " //correct:\n" + 161 " someFunc(AnyInt(), EqString(\"String by matcher\"))", 162 ))) 163 }) 164 }) 165 166 Context("Stubbing with consecutive return values", func() { 167 BeforeEach(func() { 168 When(display.SomeValue()).ThenReturn("Hello").ThenReturn("again") 169 }) 170 171 It("returns stubbed values when calling mock", func() { 172 Expect(display.SomeValue()).To(Equal("Hello")) 173 Expect(display.SomeValue()).To(Equal("again")) 174 }) 175 176 It("returns last stubbed value repeatedly", func() { 177 Expect(display.SomeValue()).To(Equal("Hello")) 178 Expect(display.SomeValue()).To(Equal("again")) 179 Expect(display.SomeValue()).To(Equal("again")) 180 Expect(display.SomeValue()).To(Equal("again")) 181 Expect(display.SomeValue()).To(Equal("again")) 182 Expect(display.SomeValue()).To(Equal("again")) 183 }) 184 185 It("can be verified that mock was called", func() { 186 display.SomeValue() 187 Expect(func() { display.VerifyWasCalledOnce().SomeValue() }).NotTo(Panic()) 188 }) 189 190 It("fails if verify is called on mock that was not invoked.", func() { 191 Expect(func() { display.VerifyWasCalledOnce().Show("Some parameter") }).To(PanicWithMessageTo(HavePrefix( 192 expectation{method: "Show(\"Some parameter\")", expected: "1", actual: "0"}.string(), 193 ))) 194 }) 195 196 It("fails if verify is called on mock that was invoked more than once.", func() { 197 display.Show("param") 198 display.Show("param") 199 Expect(func() { display.VerifyWasCalledOnce().Show("param") }).To(PanicWithMessageTo(HavePrefix( 200 expectation{method: "Show(\"param\")", expected: "1", actual: "2"}.string(), 201 ))) 202 203 }) 204 }) 205 206 Context("Stubbing with invalid return type", func() { 207 It("panics", func() { 208 Expect(func() { When(display.SomeValue()).ThenReturn("Hello").ThenReturn(0) }).To(PanicWithMessageTo(HavePrefix( 209 "Return value of type int not assignable to return type string", 210 ))) 211 }) 212 }) 213 214 Describe("https://github.com/petergtz/pegomock/issues/24", func() { 215 Context("Stubbing with nil value", func() { 216 It("does not panic when return type is interface{}", func() { 217 When(display.InterfaceReturnValue()).ThenReturn(nil) 218 Expect(display.InterfaceReturnValue()).To(BeNil()) 219 }) 220 221 It("does not panic when return type is error interface", func() { 222 When(display.ErrorReturnValue()).ThenReturn(nil) 223 Expect(display.ErrorReturnValue()).To(BeNil()) 224 }) 225 }) 226 227 Context("Stubbing with value that implements interface{}", func() { 228 It("does not panic", func() { 229 When(display.InterfaceReturnValue()).ThenReturn("Hello") 230 Expect(display.InterfaceReturnValue()).To(Equal("Hello")) 231 }) 232 }) 233 234 Context("Stubbing with value that implements error interface", func() { 235 It("does not panic", func() { 236 When(display.ErrorReturnValue()).ThenReturn(errors.New("Ouch")) 237 Expect(display.ErrorReturnValue()).To(Equal(errors.New("Ouch"))) 238 }) 239 }) 240 241 Context("Stubbing with value that does not implement error interface", func() { 242 It("panics", func() { 243 Expect(func() { When(display.ErrorReturnValue()).ThenReturn("Blub") }).To(PanicWithMessageTo(HavePrefix( 244 "Return value of type string not assignable to return type error", 245 ))) 246 }) 247 }) 248 249 Context("Stubbing string return type with nil value", func() { 250 It("panics", func() { 251 Expect(func() { When(display.SomeValue()).ThenReturn(nil) }).To(PanicWith( 252 "Return value 'nil' not assignable to return type string", 253 )) 254 }) 255 }) 256 257 }) 258 259 Context("Stubbed method, but no invocation takes place", func() { 260 It("fails during verification", func() { 261 When(display.SomeValue()).ThenReturn("Hello") 262 Expect(func() { display.VerifyWasCalledOnce().SomeValue() }).To(PanicWithMessageTo(HavePrefix( 263 expectation{method: "SomeValue()", expected: "1", actual: "0"}.string(), 264 ))) 265 }) 266 }) 267 268 Context("Calling Flash() with specific arguments", func() { 269 270 BeforeEach(func() { display.Flash("Hello", 333) }) 271 272 It("succeeds verification if values are matching", func() { 273 Expect(func() { display.VerifyWasCalledOnce().Flash("Hello", 333) }).NotTo(Panic()) 274 }) 275 276 It("fails during verification if values are not matching", func() { 277 Expect(func() { display.VerifyWasCalledOnce().Flash("Hello", 666) }).To(PanicWithMessageTo(HavePrefix( 278 expectation{method: "Flash(\"Hello\", 666)", expected: "1", actual: "0"}.string(), 279 ))) 280 }) 281 282 It("succeeds during verification when using Any-matchers ", func() { 283 Expect(func() { display.VerifyWasCalledOnce().Flash(AnyString(), AnyInt()) }).NotTo(Panic()) 284 }) 285 286 It("succeeds during verification when using valid Eq-matchers ", func() { 287 Expect(func() { display.VerifyWasCalledOnce().Flash(EqString("Hello"), EqInt(333)) }).NotTo(Panic()) 288 }) 289 290 It("fails during verification when using invalid Eq-matchers ", func() { 291 Expect(func() { display.VerifyWasCalledOnce().Flash(EqString("Invalid"), EqInt(-1)) }).To(PanicWithMessageTo(HavePrefix( 292 expectation{method: `Flash(Eq("Invalid"), Eq(-1))`, expected: "1", actual: "0"}.string(), 293 ))) 294 }) 295 296 It("fails when not using matchers for all params", func() { 297 Expect(func() { display.VerifyWasCalledOnce().Flash("Hello", AnyInt()) }).To(PanicWith( 298 "Invalid use of matchers!\n\n 2 matchers expected, 1 recorded.\n\n" + 299 "This error may occur if matchers are combined with raw values:\n" + 300 " //incorrect:\n" + 301 " someFunc(AnyInt(), \"raw String\")\n" + 302 "When using matchers, all arguments have to be provided by matchers.\n" + 303 "For example:\n" + 304 " //correct:\n" + 305 " someFunc(AnyInt(), EqString(\"String by matcher\"))", 306 )) 307 }) 308 }) 309 310 Describe("Invocation count matching", func() { 311 312 Context("Calling Flash() twice", func() { 313 314 BeforeEach(func() { 315 display.Flash("Hello", 333) 316 display.Flash("Hello", 333) 317 }) 318 319 It("succeeds verification if verifying with Times(2)", func() { 320 Expect(func() { display.VerifyWasCalled(Times(2)).Flash("Hello", 333) }).NotTo(Panic()) 321 }) 322 323 It("fails during verification if verifying with VerifyWasCalledOnce", func() { 324 Expect(func() { display.VerifyWasCalledOnce().Flash("Hello", 333) }).To(PanicWithMessageTo(HavePrefix( 325 expectation{method: "Flash(\"Hello\", 333)", expected: "1", actual: "2"}.string(), 326 ))) 327 }) 328 329 It("fails during verification if verifying with Times(1)", func() { 330 Expect(func() { display.VerifyWasCalled(Times(1)).Flash("Hello", 333) }).To(PanicWithMessageTo(HavePrefix( 331 expectation{method: "Flash(\"Hello\", 333)", expected: "1", actual: "2"}.string(), 332 ))) 333 }) 334 335 It("succeeds during verification when using AtLeast(1)", func() { 336 Expect(func() { display.VerifyWasCalled(AtLeast(1)).Flash("Hello", 333) }).NotTo(Panic()) 337 }) 338 339 It("succeeds during verification when using AtLeast(2)", func() { 340 Expect(func() { display.VerifyWasCalled(AtLeast(2)).Flash("Hello", 333) }).NotTo(Panic()) 341 }) 342 343 It("fails during verification when using AtLeast(3)", func() { 344 Expect(func() { display.VerifyWasCalled(AtLeast(3)).Flash("Hello", 333) }).To(PanicWithMessageTo(HavePrefix( 345 expectation{method: "Flash(\"Hello\", 333)", expected: "at least 3", actual: "2"}.string(), 346 ))) 347 }) 348 349 It("succeeds during verification when using Never()", func() { 350 Expect(func() { display.VerifyWasCalled(Never()).Flash("Other value", 333) }).NotTo(Panic()) 351 }) 352 353 It("fails during verification when using Never()", func() { 354 Expect(func() { display.VerifyWasCalled(Never()).Flash("Hello", 333) }).To(PanicWithMessageTo(HavePrefix( 355 expectation{method: "Flash(\"Hello\", 333)", expected: "0", actual: "2"}.string(), 356 ))) 357 }) 358 }) 359 360 Context("Never calling Flash", func() { 361 It("succeeds during verification when using Never() and argument matchers", func() { 362 // https://github.com/petergtz/pegomock/issues/34 363 Expect(func() { display.VerifyWasCalled(Never()).Flash(AnyString(), AnyInt()) }).NotTo(Panic()) 364 }) 365 }) 366 }) 367 368 Context("Calling MultipleParamsAndReturnValue()", func() { 369 370 It("panics when stubbed to panic", func() { 371 When(display.MultipleParamsAndReturnValue(AnyString(), AnyInt())). 372 ThenPanic("I'm panicking") 373 Expect(func() { 374 display.MultipleParamsAndReturnValue("Some string", 123) 375 }).To(PanicWith("I'm panicking")) 376 }) 377 378 It("calls back when stubbed to call back", func() { 379 When(display.MultipleParamsAndReturnValue(AnyString(), AnyInt())).Then( 380 func(params []Param) ReturnValues { 381 return []ReturnValue{fmt.Sprintf("%v%v", params[0], params[1])} 382 }, 383 ) 384 Expect(display.MultipleParamsAndReturnValue("string and ", 123)). 385 To(Equal("string and 123")) 386 }) 387 388 }) 389 390 Context("Making calls in a specific order", func() { 391 392 BeforeEach(func() { 393 display.Flash("Hello", 111) 394 display.Flash("again", 222) 395 display.Flash("and again", 333) 396 }) 397 398 It("succeeds during InOrder verification when order is correct", func() { 399 Expect(func() { 400 inOrderContext := new(InOrderContext) 401 display.VerifyWasCalledInOrder(Once(), inOrderContext).Flash("Hello", 111) 402 display.VerifyWasCalledInOrder(Once(), inOrderContext).Flash("again", 222) 403 display.VerifyWasCalledInOrder(Once(), inOrderContext).Flash("and again", 333) 404 }).NotTo(Panic()) 405 }) 406 407 It("succeeds during InOrder verification when order is correct, but not all invocations are verified", func() { 408 Expect(func() { 409 inOrder := new(InOrderContext) 410 display.VerifyWasCalledInOrder(Once(), inOrder).Flash("Hello", 111) 411 // not checking for the 2nd call here 412 display.VerifyWasCalledInOrder(Once(), inOrder).Flash("and again", 333) 413 }).NotTo(Panic()) 414 }) 415 416 It("fails during InOrder verification when order is not correct", func() { 417 Expect(func() { 418 inOrder := new(InOrderContext) 419 display.VerifyWasCalledInOrder(Once(), inOrder).Flash("again", 222) 420 display.VerifyWasCalledInOrder(Once(), inOrder).Flash("Hello", 111) 421 display.VerifyWasCalledInOrder(Once(), inOrder).Flash("and again", 333) 422 }).To(PanicWithMessageTo(HavePrefix( 423 "Expected function call Flash(\"Hello\", 111) before function call Flash(\"again\", 222)", 424 ))) 425 }) 426 427 }) 428 429 Context("Capturing arguments", func() { 430 It("Returns arguments when verifying with argument capture", func() { 431 display.Flash("Hello", 111) 432 433 arg1, arg2 := display.VerifyWasCalledOnce().Flash(AnyString(), AnyInt()).GetCapturedArguments() 434 435 Expect(arg1).To(Equal("Hello")) 436 Expect(arg2).To(Equal(111)) 437 }) 438 439 It("Returns arguments of last invocation when verifying with argument capture", func() { 440 display.Flash("Hello", 111) 441 display.Flash("Again", 222) 442 443 arg1, arg2 := display.VerifyWasCalled(AtLeast(1)).Flash(AnyString(), AnyInt()).GetCapturedArguments() 444 445 Expect(arg1).To(Equal("Again")) 446 Expect(arg2).To(Equal(222)) 447 }) 448 449 It("Returns arguments of all invocations when verifying with \"all\" argument capture", func() { 450 display.Flash("Hello", 111) 451 display.Flash("Again", 222) 452 453 args1, args2 := display.VerifyWasCalled(AtLeast(1)).Flash(AnyString(), AnyInt()).GetAllCapturedArguments() 454 455 Expect(args1).To(ConsistOf("Hello", "Again")) 456 Expect(args2).To(ConsistOf(111, 222)) 457 }) 458 459 It("Returns *array* arguments of all invocations when verifying with \"all\" argument capture", func() { 460 display.ArrayParam([]string{"one", "two"}) 461 display.ArrayParam([]string{"4", "5", "3"}) 462 463 args := display.VerifyWasCalled(AtLeast(1)).ArrayParam(AnyStringSlice()).GetAllCapturedArguments() 464 465 Expect(flattenStringSliceOfSlices(args)).To(ConsistOf("one", "two", "3", "4", "5")) 466 }) 467 468 }) 469 470 Context("Stubbing using string slice", func() { 471 It("does not panic when comparing the slices in the matcher", func() { 472 When(func() { display.ArrayParam([]string{"one", "two"}) }).Then(func([]Param) ReturnValues { 473 // do nothing, because that's not our focus here. 474 return nil 475 }) 476 display.ArrayParam([]string{"one", "two"}) 477 }) 478 }) 479 480 Describe("Different \"Any\" matcher scenarios", func() { 481 It("Succeeds when int-parameter is passed as int but veryfied as float", func() { 482 display.FloatParam(1) 483 display.VerifyWasCalledOnce().FloatParam(AnyFloat32()) 484 }) 485 486 It("Panics when interface{}-parameter is passed as int, but verified as float", func() { 487 Expect(func() { 488 display.InterfaceParam(3) 489 display.VerifyWasCalledOnce().InterfaceParam(AnyFloat32()) 490 }).To(PanicWithMessageTo(HavePrefix( 491 expectation{method: "InterfaceParam(Any(float32))", expected: "1", actual: "0"}.string(), 492 ))) 493 }) 494 495 It("Panics when interface{}-parameter is passed as float, but verified as int", func() { 496 Expect(func() { 497 display.InterfaceParam(3.141) 498 display.VerifyWasCalledOnce().InterfaceParam(AnyInt()) 499 }).To(PanicWithMessageTo(HavePrefix( 500 expectation{method: "InterfaceParam(Any(int))", expected: "1", actual: "0"}.string(), 501 ))) 502 }) 503 504 It("Succeeds when interface{}-parameter is passed as int and verified as int", func() { 505 display.InterfaceParam(3) 506 display.VerifyWasCalledOnce().InterfaceParam(AnyInt()) 507 }) 508 509 It("Succeeds when interface{}-parameter is passed as nil and verified as int slice", func() { 510 display.InterfaceParam(nil) 511 display.VerifyWasCalledOnce().InterfaceParam(AnyIntSlice()) 512 }) 513 514 It("Panics when interface{}-parameter is passed as nil, but verified as int", func() { 515 Expect(func() { 516 display.InterfaceParam(nil) 517 display.VerifyWasCalledOnce().InterfaceParam(AnyInt()) 518 }).To(PanicWithMessageTo(HavePrefix( 519 expectation{method: "InterfaceParam(Any(int))", expected: "1", actual: "0"}.string(), 520 ))) 521 }) 522 523 It("Succeeds when error-parameter is passed as nil and verified as any error", func() { 524 display.ErrorParam(nil) 525 display.VerifyWasCalledOnce().ErrorParam(AnyError()) 526 }) 527 528 It("Succeeds when error-parameter is passed as string error and verified as any error", func() { 529 display.ErrorParam(errors.New("Some error")) 530 display.VerifyWasCalledOnce().ErrorParam(AnyError()) 531 }) 532 533 It("Succeeds when http.Request-parameter is passed as null value and verified as any http.Request", func() { 534 display.NetHttpRequestParam(http.Request{}) 535 display.VerifyWasCalledOnce().NetHttpRequestParam(AnyRequest()) 536 }) 537 538 It("Succeeds when http.Request-parameter is passed as null value to interface{} and verified as any http.Request", func() { 539 display.InterfaceParam(http.Request{}) 540 display.VerifyWasCalledOnce().InterfaceParam(AnyRequest()) 541 }) 542 543 It("Fails when *pointer* to http.Request-parameter is passed to interface{} and verified as any http.Request", func() { 544 display.InterfaceParam(&http.Request{}) 545 Expect(func() { display.VerifyWasCalledOnce().InterfaceParam(AnyRequest()) }).To(PanicWithMessageTo(SatisfyAll( 546 ContainSubstring("InterfaceParam(Any(http.Request))"), 547 ContainSubstring("InterfaceParam(&http.Request{Method"), 548 ))) 549 }) 550 551 It("Succeeds when http.Request-Pointer-parameter is passed as nil and verified as any *http.Request", func() { 552 display.NetHttpRequestPtrParam(nil) 553 display.VerifyWasCalledOnce().NetHttpRequestPtrParam(AnyRequestPtr()) 554 }) 555 556 It("Succeeds when http.Request-Pointer-parameter is passed as null value and verified as any *http.Request", func() { 557 display.NetHttpRequestPtrParam(&http.Request{}) 558 display.VerifyWasCalledOnce().NetHttpRequestPtrParam(AnyRequestPtr()) 559 }) 560 }) 561 562 Describe("Generated matchers", func() { 563 It("Succeeds when map-parameter is passed to interface{} and verified as any map", func() { 564 display.InterfaceParam(map[string]http.Request{"foo": http.Request{}}) 565 display.VerifyWasCalledOnce().InterfaceParam(AnyMapOfStringToHttpRequest()) 566 }) 567 568 It("Fails when string parameter is passed to interface{} and verified as any map", func() { 569 display.InterfaceParam("This will not match") 570 Expect(func() { display.VerifyWasCalledOnce().InterfaceParam(AnyMapOfStringToHttpRequest()) }).To(PanicWithMessageTo(SatisfyAll( 571 ContainSubstring("InterfaceParam(Any(map[string]http.Request))"), 572 ContainSubstring("InterfaceParam(\"This will not match\")"), 573 ))) 574 }) 575 576 It("Succeeds when map-parameter is passed to interface{} and verified as eq map", func() { 577 display.InterfaceParam(map[string]http.Request{"foo": {}}) 578 display.VerifyWasCalledOnce().InterfaceParam(EqMapOfStringToHttpRequest(map[string]http.Request{"foo": {}})) 579 }) 580 581 It("Fails when map-parameter is passed to interface{} and verified as not eq map", func() { 582 display.InterfaceParam(map[int]int{1: 2}) 583 Expect(func() { display.VerifyWasCalledOnce().InterfaceParam(NotEqMapOfIntToInt(map[int]int{1: 2})) }). 584 To(PanicWithMessageTo(ContainSubstring("InterfaceParam(NotEq(map[int]int{1:2}))"))) 585 }) 586 587 It("Succeeds when map-parameter is passed to interface{} and verified as not eq a different map", func() { 588 display.InterfaceParam(map[int]int{1: 2}) 589 display.VerifyWasCalledOnce().InterfaceParam(NotEqMapOfIntToInt(map[int]int{1: 3})) 590 }) 591 592 It("Succeeds when map-parameter is passed to interface{} and verified as not eq a time", func() { 593 display.InterfaceParam(map[int]int{1: 2}) 594 display.VerifyWasCalledOnce().InterfaceParam(NotEqTimeTime(time.Now())) 595 }) 596 597 It("Fails when map-parameter is passed to interface{} and verified as different map that satisfies equals matcher", func() { 598 display.InterfaceParam(map[int]int{1: 2}) 599 Expect(func() { display.VerifyWasCalledOnce().InterfaceParam(MapOfIntToIntThat(&EqMatcher{Value: map[int]int{1: 3}})) }). 600 To(PanicWithMessageTo(SatisfyAll( 601 ContainSubstring("InterfaceParam(Eq(map[int]int{1:3}))"), 602 ContainSubstring("InterfaceParam(map[int]int{1:2})"), 603 ))) 604 }) 605 It("Succeeds when map-parameter is passed to interface{} and verified as map that satisfies equals matcher", func() { 606 display.InterfaceParam(map[int]int{1: 2}) 607 display.VerifyWasCalledOnce().InterfaceParam(MapOfIntToIntThat(&EqMatcher{Value: map[int]int{1: 2}})) 608 }) 609 }) 610 611 Describe("Logic around matchers and verification", func() { 612 // TODO maybe this should go somewhere else 613 It("Fails when http.Request-parameter is passed as null value and verified as never matching http.Request", func() { 614 display.NetHttpRequestParam(http.Request{}) 615 Expect(func() { display.VerifyWasCalledOnce().NetHttpRequestParam(NeverMatchingRequest()) }). 616 To(PanicWithMessageTo(Equal(`Mock invocation count for NetHttpRequestParam(NeverMatching) does not match expectation. 617 618 Expected: 1; but got: 0 619 620 Actual interactions with this mock were: 621 NetHttpRequestParam(http.Request{Method:"", URL:(*url.URL)(nil), Proto:"", ProtoMajor:0, ProtoMinor:0, Header:http.Header(nil), Body:io.ReadCloser(nil), GetBody:(func() (io.ReadCloser, error))(nil), ContentLength:0, TransferEncoding:[]string(nil), Close:false, Host:"", Form:url.Values(nil), PostForm:url.Values(nil), MultipartForm:(*multipart.Form)(nil), Trailer:http.Header(nil), RemoteAddr:"", RequestURI:"", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), ctx:context.Context(nil)}) 622 `))) 623 }) 624 }) 625 626 Describe("Stubbing with multiple ThenReturns versus multiple stubbings with same parameters", func() { 627 Context("One stubbing with multiple ThenReturns", func() { 628 It("returns the values in the order of the ThenReturns", func() { 629 When(display.MultipleParamsAndReturnValue("one", 1)).ThenReturn("first").ThenReturn("second") 630 631 Expect(display.MultipleParamsAndReturnValue("one", 1)).To(Equal("first")) 632 Expect(display.MultipleParamsAndReturnValue("one", 1)).To(Equal("second")) 633 }) 634 }) 635 636 Context("Multiple stubbings with same parameters", func() { 637 It("overrides previous stubbings with last one", func() { 638 When(display.MultipleParamsAndReturnValue("one", 1)).ThenReturn("first") 639 When(display.MultipleParamsAndReturnValue("one", 1)).ThenReturn("second") 640 641 Expect(display.MultipleParamsAndReturnValue("one", 1)).To(Equal("second")) 642 Expect(display.MultipleParamsAndReturnValue("one", 1)).To(Equal("second")) 643 }) 644 }) 645 }) 646 647 Describe("Verifying gives hints about actual invocations in failure messages", func() { 648 It("shows actual interactions with same methods", func() { 649 display.Flash("Hello", 123) 650 display.Flash("Again", 456) 651 652 Expect(func() { display.VerifyWasCalledOnce().Flash("wrong string", -987) }).To(PanicWith( 653 "Mock invocation count for Flash(\"wrong string\", -987) " + 654 "does not match expectation.\n\n\tExpected: 1; but got: 0\n\n" + 655 "\tActual interactions with this mock were:\n" + 656 "\tFlash(\"Hello\", 123)\n" + 657 "\tFlash(\"Again\", 456)\n", 658 )) 659 }) 660 661 It("shows actual interactions with all methods", func() { 662 display.Show("Again") 663 display.Flash("Hello", 123) 664 665 Expect(func() { display.VerifyWasCalledOnce().Flash("wrong string", -987) }).To(PanicWith( 666 "Mock invocation count for Flash(\"wrong string\", -987) " + 667 "does not match expectation.\n\n\tExpected: 1; but got: 0\n\n" + 668 "\tActual interactions with this mock were:\n" + 669 "\tFlash(\"Hello\", 123)\n" + 670 "\tShow(\"Again\")\n"), 671 ) 672 }) 673 674 It("formats params in interactions with Go syntax for better readability", func() { 675 display.NetHttpRequestParam(http.Request{Host: "x.com"}) 676 Expect(func() { display.VerifyWasCalledOnce().NetHttpRequestParam(http.Request{Host: "y.com"}) }).To(PanicWith( 677 `Mock invocation count for NetHttpRequestParam(http.Request{Method:"", URL:(*url.URL)(nil), Proto:"", ProtoMajor:0, ProtoMinor:0, Header:http.Header(nil), Body:io.ReadCloser(nil), GetBody:(func() (io.ReadCloser, error))(nil), ContentLength:0, TransferEncoding:[]string(nil), Close:false, Host:"y.com", Form:url.Values(nil), PostForm:url.Values(nil), MultipartForm:(*multipart.Form)(nil), Trailer:http.Header(nil), RemoteAddr:"", RequestURI:"", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), ctx:context.Context(nil)}) does not match expectation. 678 679 Expected: 1; but got: 0 680 681 Actual interactions with this mock were: 682 NetHttpRequestParam(http.Request{Method:"", URL:(*url.URL)(nil), Proto:"", ProtoMajor:0, ProtoMinor:0, Header:http.Header(nil), Body:io.ReadCloser(nil), GetBody:(func() (io.ReadCloser, error))(nil), ContentLength:0, TransferEncoding:[]string(nil), Close:false, Host:"x.com", Form:url.Values(nil), PostForm:url.Values(nil), MultipartForm:(*multipart.Form)(nil), Trailer:http.Header(nil), RemoteAddr:"", RequestURI:"", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), ctx:context.Context(nil)}) 683 `, 684 )) 685 }) 686 687 It("shows no interactions if there were none", func() { 688 Expect(func() { display.VerifyWasCalledOnce().Flash("wrong string", -987) }).To(PanicWith( 689 "Mock invocation count for Flash(\"wrong string\", -987) " + 690 "does not match expectation.\n\n\tExpected: 1; but got: 0\n\n" + 691 "\tThere were no other interactions with this mock", 692 )) 693 }) 694 }) 695 696 Describe("Stubbing methods that have no return value", func() { 697 It("Can be stubbed with Panic", func() { 698 When(func() { display.Show(AnyString()) }).ThenPanic("bla") 699 Expect(func() { display.Show("Hello") }).To(PanicWith("bla")) 700 }) 701 702 It("Can still work with methods returning a func", func() { 703 When(display.FuncReturnValue()).ThenReturn(func() { panic("It's actually a success") }) 704 Expect(func() { display.FuncReturnValue()() }).To(PanicWith("It's actually a success")) 705 }) 706 707 It("Panics when not using a func with no params", func() { 708 Expect(func() { 709 When(func(invalid int) { display.Show(AnyString()) }) 710 }).To(PanicWith("When using 'When' with function that does not return a value, it expects a function with no arguments and no return value.")) 711 }) 712 }) 713 714 Describe("Verifying methods that have variadic arguments", func() { 715 Context("One single variadic argument", func() { 716 717 It("succeeds when verifying one invocation with same parameters", func() { 718 display.VariadicParam("one", "two") 719 display.VerifyWasCalledOnce().VariadicParam("one", "two") 720 }) 721 722 It("succeeds when verifying two different invocations with same parameters", func() { 723 display.VariadicParam("one", "two") 724 display.VariadicParam("three", "four", "five") 725 display.VerifyWasCalledOnce().VariadicParam("three", "four", "five") 726 display.VerifyWasCalledOnce().VariadicParam("one", "two") 727 }) 728 729 It("succeeds when verifying one invocation with arg matchers", func() { 730 display.VariadicParam("one", "two") 731 display.VerifyWasCalledOnce().VariadicParam(AnyString(), AnyString()) 732 }) 733 734 It("succeeds when verifying two different invocations with arg matchers", func() { 735 display.VariadicParam("one", "two") 736 display.VariadicParam("three", "four", "five") 737 display.VerifyWasCalledOnce().VariadicParam(AnyString(), AnyString(), AnyString()) 738 display.VerifyWasCalledOnce().VariadicParam(AnyString(), AnyString()) 739 }) 740 741 It("succeeds when verifying captured arguments", func() { 742 display.VariadicParam("one", "two") 743 args := display.VerifyWasCalledOnce().VariadicParam(AnyString(), AnyString()).GetCapturedArguments() 744 Expect(args[0]).To(Equal("one")) 745 Expect(args[1]).To(Equal("two")) 746 }) 747 748 It("succeeds when verifying all captured arguments", func() { 749 display.VariadicParam("one", "two") 750 display.VariadicParam("three", "four", "five") 751 args := display.VerifyWasCalledOnce().VariadicParam(AnyString(), AnyString(), AnyString()).GetCapturedArguments() 752 Expect(args[0]).To(Equal("three")) 753 Expect(args[1]).To(Equal("four")) 754 Expect(args[2]).To(Equal("five")) 755 }) 756 757 }) 758 759 Context("2 normal arguments and one variadic", func() { 760 It("succeeds when verifying all captured arguments (one invocation match)", func() { 761 display.NormalAndVariadicParam("one", 2, "three", "four") 762 display.NormalAndVariadicParam("five", 6, "seven", "eight", "nine") 763 764 stringArg, intArg, varArgs := display.VerifyWasCalled(AtLeast(1)).NormalAndVariadicParam(AnyString(), AnyInt(), AnyString(), AnyString()).GetAllCapturedArguments() 765 Expect(stringArg[0]).To(Equal("one")) 766 Expect(intArg[0]).To(Equal(2)) 767 Expect(varArgs[0][0]).To(Equal("three")) 768 Expect(varArgs[0][1]).To(Equal("four")) 769 770 stringArg, intArg, varArgs = display.VerifyWasCalled(AtLeast(1)).NormalAndVariadicParam(AnyString(), AnyInt(), AnyString(), AnyString(), AnyString()).GetAllCapturedArguments() 771 Expect(stringArg[0]).To(Equal("five")) 772 Expect(intArg[0]).To(Equal(6)) 773 Expect(varArgs[0][0]).To(Equal("seven")) 774 Expect(varArgs[0][1]).To(Equal("eight")) 775 Expect(varArgs[0][2]).To(Equal("nine")) 776 }) 777 778 It("succeeds when verifying all captured arguments (multiple invocation matches)", func() { 779 display.NormalAndVariadicParam("one", 2, "three", "four") 780 display.NormalAndVariadicParam("five", 6, "seven", "eight", "nine") 781 display.NormalAndVariadicParam("ten", 11, "twelf", "thirteen", "fourteen") 782 783 stringArg, intArg, varArgs := display.VerifyWasCalled(AtLeast(1)).NormalAndVariadicParam(AnyString(), AnyInt(), AnyString(), AnyString()).GetAllCapturedArguments() 784 Expect(stringArg[0]).To(Equal("one")) 785 Expect(intArg[0]).To(Equal(2)) 786 Expect(varArgs[0][0]).To(Equal("three")) 787 Expect(varArgs[0][1]).To(Equal("four")) 788 789 stringArg, intArg, varArgs = display.VerifyWasCalled(AtLeast(1)).NormalAndVariadicParam(AnyString(), AnyInt(), AnyString(), AnyString(), AnyString()).GetAllCapturedArguments() 790 Expect(stringArg[0]).To(Equal("five")) 791 Expect(intArg[0]).To(Equal(6)) 792 Expect(varArgs[0][0]).To(Equal("seven")) 793 Expect(varArgs[0][1]).To(Equal("eight")) 794 Expect(varArgs[0][2]).To(Equal("nine")) 795 796 Expect(stringArg[1]).To(Equal("ten")) 797 Expect(intArg[1]).To(Equal(11)) 798 Expect(varArgs[1][0]).To(Equal("twelf")) 799 Expect(varArgs[1][1]).To(Equal("thirteen")) 800 Expect(varArgs[1][2]).To(Equal("fourteen")) 801 }) 802 803 It("does not panic when variadic arg has 0 params", func() { 804 display.VerifyWasCalled(Never()).NormalAndVariadicParam(AnyString(), AnyInt()).GetAllCapturedArguments() 805 806 display.NormalAndVariadicParam("one", 2) 807 display.VerifyWasCalledOnce().NormalAndVariadicParam(AnyString(), AnyInt()).GetAllCapturedArguments() 808 }) 809 }) 810 811 Context("Concurrent access to mock", func() { 812 It("does not panic", func() { 813 Expect(func() { 814 wg := sync.WaitGroup{} 815 for i := 0; i < 10; i++ { 816 wg.Add(1) 817 818 go func() { 819 display.SomeValue() 820 wg.Done() 821 }() 822 } 823 wg.Wait() 824 }).ToNot(Panic()) 825 }) 826 827 Context("Concurrent access due to one mock calling the other", func() { 828 It("does not deadlock", func() { 829 When(display.SomeValue()).Then(func(params []Param) ReturnValues { 830 display.Show("Some irrelevant string") 831 return []ReturnValue{} 832 }) 833 display.SomeValue() 834 835 display.VerifyWasCalledOnce().Show(AnyString()) 836 }) 837 }) 838 839 Context("Concurrent access with multiple stubbing and validation", func() { 840 It("does not panic", func() { 841 pegomock. 842 When(display.MultipleValues()). 843 Then(func(params []pegomock.Param) pegomock.ReturnValues { 844 return pegomock.ReturnValues{"MultipleValues", 42, float32(3.14)} 845 }) 846 847 pegomock. 848 When(display.MultipleParamsAndReturnValue(AnyString(), AnyInt())). 849 Then(func(params []pegomock.Param) pegomock.ReturnValues { 850 return pegomock.ReturnValues{"MultipleParamsAndReturnValue" + params[0].(string)} 851 }) 852 853 Expect(func() { 854 wg := sync.WaitGroup{} 855 856 for i := 0; i < 10; i++ { 857 wg.Add(1) 858 859 go func() { 860 display.MultipleValues() 861 display.MultipleParamsAndReturnValue("TestString", 42) 862 wg.Done() 863 }() 864 } 865 866 wg.Wait() 867 868 display.VerifyWasCalled(Times(10)).MultipleValues() 869 display.VerifyWasCalled(Times(10)).MultipleParamsAndReturnValue(AnyString(), AnyInt()) 870 display.VerifyWasCalled(Never()).SomeValue() 871 }).ToNot(Panic()) 872 }) 873 }) 874 }) 875 876 }) 877 878 Describe("Using VerifyWasCalledEventually when object under test calls goroutine", func() { 879 It("correctly fails when timeout is shorter than mock invocation, and succeeds, when timeout is longer", func() { 880 go func() { 881 time.Sleep(1 * time.Second) 882 display.Show("hello") 883 }() 884 Expect(func() { display.VerifyWasCalledEventually(Once(), 100*time.Millisecond).Show("hello") }). 885 To(PanicWithMessageTo(SatisfyAll( 886 ContainSubstring("Mock invocation count for Show(\"hello\") does not match expectation"), 887 ContainSubstring("after timeout of 100ms"), 888 ContainSubstring("Expected: 1; but got: 0"), 889 ))) 890 891 Expect(func() { display.VerifyWasCalledEventually(Once(), 2*time.Second).Show("hello") }).NotTo(Panic()) 892 }) 893 894 }) 895 896 Describe("Manipulating out args (using pointers) in Then blocks", func() { 897 It("correctly manipulates the out args", func() { 898 type Entity struct{ i int } 899 var input = []Entity{} 900 When(func() { display.InterfaceParam(AnyInterface()) }).Then(func(params []pegomock.Param) pegomock.ReturnValues { 901 *params[0].(*[]Entity) = append(*params[0].(*[]Entity), Entity{3}) 902 return nil 903 }) 904 905 display.InterfaceParam(&input) 906 907 Expect(input).To(HaveLen(1)) 908 Expect(input[0].i).To(Equal(3)) 909 }) 910 }) 911 912 Context("Mock created with custom fail handler", func() { 913 It("calls custom fail handler instead of global one", func() { 914 failHandlerCalled := false 915 display := NewMockDisplay(WithFailHandler(func(message string, callerSkip ...int) { 916 failHandlerCalled = true 917 })) 918 919 display.VerifyWasCalledOnce().Show("This was never called") 920 921 Expect(failHandlerCalled).To(BeTrue()) 922 }) 923 }) 924 925 Context("channels", func() { 926 927 Context("using send-/receive-only channels in return types", func() { 928 It("allows to return non-direction channels from callbacks", func() { 929 When(display.ChanReturnValues()).Then(func([]pegomock.Param) pegomock.ReturnValues { 930 return []ReturnValue{make(chan string), make(chan error)} 931 }) 932 display.ChanReturnValues() 933 }) 934 935 It("allows to return directed channels from callbacks", func() { 936 When(display.ChanReturnValues()).Then(func([]pegomock.Param) pegomock.ReturnValues { 937 return []ReturnValue{make(<-chan string), make(chan<- error)} 938 }) 939 display.ChanReturnValues() 940 }) 941 942 It("does not allow to return directed channels from callbacks with wrong direction", func() { 943 When(display.ChanReturnValues()).Then(func([]pegomock.Param) pegomock.ReturnValues { 944 return []ReturnValue{make(chan<- string), make(chan<- error)} 945 }) 946 947 Expect(func() { display.ChanReturnValues() }).To(PanicWithMessageTo(MatchError( 948 "interface conversion: pegomock.ReturnValue is chan<- string, not <-chan string", 949 ))) 950 951 }) 952 }) 953 954 Context("using send-/receive-only channels", func() { 955 It("generates the mock method with correct channel directions", func() { 956 var stringReadChan <-chan string 957 var errorWriteChan chan<- error 958 display.ChanParams(stringReadChan, errorWriteChan) 959 }) 960 }) 961 }) 962 }) 963 964 func flattenStringSliceOfSlices(sliceOfSlices [][]string) (result []string) { 965 for _, slice := range sliceOfSlices { 966 result = append(result, slice...) 967 } 968 return 969 } 970 971 type expectation struct { 972 method string 973 expected string 974 actual string 975 } 976 977 func (e expectation) string() string { 978 return fmt.Sprintf("Mock invocation count for %v does not match expectation.\n\n\tExpected: %v; but got: %v", 979 e.method, e.expected, e.actual) 980 }