diff --git a/stub.go b/stub.go index d9f0c97..12f0fd8 100644 --- a/stub.go +++ b/stub.go @@ -5,6 +5,7 @@ package testing import ( "fmt" + "reflect" "sync" jc "github.com/juju/testing/checkers" @@ -193,6 +194,31 @@ func (f *Stub) CheckCalls(c *gc.C, expected []StubCall) { c.Check(f.calls, jc.DeepEquals, expected) } +// CheckCallsUnordered verifies that the history of calls on the stub's methods +// contains the expected calls. The receivers are not checked. If they +// are significant then check Stub.Receivers separately. +// This method explicitly does not check if the calls were made in order, just +// whether they have been made. +func (f *Stub) CheckCallsUnordered(c *gc.C, expected []StubCall) { + // Take a copy of all calls made to the stub. + calls := f.calls[:] + checkCallMade := func(call StubCall) { + for i, madeCall := range calls { + if reflect.DeepEqual(call, madeCall) { + // Remove found call from the copy of all-calls-made collection. + calls = append(calls[:i], calls[i+1:]...) + break + } + } + } + + for _, call := range expected { + checkCallMade(call) + } + // If all expected calls were made, our resulting collection should be empty. + c.Check(calls, gc.DeepEquals, []StubCall{}) +} + // CheckCall checks the recorded call at the given index against the // provided values. If the index is out of bounds then the check fails. // The receiver is not checked. If it is significant for a test then it diff --git a/stub_test.go b/stub_test.go index 44aa160..79f0aae 100644 --- a/stub_test.go +++ b/stub_test.go @@ -430,3 +430,41 @@ func (s *stubSuite) TestCheckNoCalls(c *gc.C) { c.ExpectFailure(`the "standard" Stub.CheckNoCalls call should fail here`) s.stub.CheckNoCalls(c) } + +func (s *stubSuite) TestMethodCallsUnordered(c *gc.C) { + s.stub.MethodCall(s.stub, "Method1", 1, 2, 3) + s.stub.AddCall("aFunc", "arg") + s.stub.MethodCall(s.stub, "Method2") + + s.stub.CheckCallsUnordered(c, []testing.StubCall{{ + FuncName: "aFunc", + Args: []interface{}{"arg"}, + }, { + FuncName: "Method1", + Args: []interface{}{1, 2, 3}, + }, { + FuncName: "Method2", + }}) +} + +// This case checks that in the scenario when expected calls are +// [a,b,c,c] but the calls made are actually [a,b,b,c], we fail correctly. +func (s *stubSuite) TestMethodCallsUnorderedDuplicateFail(c *gc.C) { + s.stub.MethodCall(s.stub, "Method1", 1, 2, 3) + s.stub.MethodCall(s.stub, "Method1", 1, 2, 3) + s.stub.AddCall("aFunc", "arg") + s.stub.MethodCall(s.stub, "Method2") + + s.stub.CheckCallsUnordered(c, []testing.StubCall{{ + FuncName: "aFunc", + Args: []interface{}{"arg"}, + }, { + FuncName: "Method1", + Args: []interface{}{1, 2, 3}, + }, { + FuncName: "Method2", + }, { + FuncName: "Method2", + }}) + c.ExpectFailure("should have failed as expected calls differ from calls made") +}