Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MockFactory reporting unexpected calls at the end of each test #253

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions shared/src/main/scala/org/scalamock/MockFactoryBase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ trait AbstractMockFactoryBase extends Mock with MockFunctions with Matchers { th
trait MockFactoryBase extends AbstractMockFactoryBase with MockContext {
import scala.language.implicitConversions

initializeExpectations
initializeExpectations()

override protected def withExpectations[T](what: => T): T = {
if (expectationContext == null) {
// we don't reset expectations for the first test case to allow
// defining expectations in Suite scope and writing tests in OneInstancePerTest/isolated style
initializeExpectations
initializeExpectations()
}

try {
Expand Down Expand Up @@ -84,6 +84,7 @@ trait MockFactoryBase extends AbstractMockFactoryBase with MockContext {
private def initializeExpectations(): Unit = {
val initialHandlers = new UnorderedHandlers
callLog = new CallLog
unexpectedCallLog = new CallLog

expectationContext = initialHandlers
currentExpectationContext = initialHandlers
Expand All @@ -92,6 +93,7 @@ trait MockFactoryBase extends AbstractMockFactoryBase with MockContext {
private def clearExpectations(): Unit = {
// to forbid setting expectations after verification is done
callLog = null
unexpectedCallLog = null
expectationContext = null
currentExpectationContext = null
}
Expand All @@ -100,12 +102,18 @@ trait MockFactoryBase extends AbstractMockFactoryBase with MockContext {
callLog foreach expectationContext.verify _

val oldCallLog = callLog
val oldUnexpectedCallLog = unexpectedCallLog
val oldExpectationContext = expectationContext

clearExpectations()
try {
doVerifyExpectations(oldCallLog,oldUnexpectedCallLog, oldExpectationContext)
} finally {
clearExpectations()
}
}

if (!oldExpectationContext.isSatisfied)
reportUnsatisfiedExpectation(oldCallLog, oldExpectationContext)
protected def doVerifyExpectations(callLog: CallLog, unexpectedCallLog: CallLog, expectationContext: Handlers): Unit = {
if (!expectationContext.isSatisfied) reportUnsatisfiedExpectation(callLog, expectationContext)
}

private def inContext[T](context: Handlers)(what: => T): T = {
Expand All @@ -118,3 +126,12 @@ trait MockFactoryBase extends AbstractMockFactoryBase with MockContext {
}

}

trait MockFactoryRecordingUnexpectedCalls extends MockFactoryBase {

override protected def doVerifyExpectations( callLog: CallLog, unexpectedCallLog: CallLog, expectationContext: Handlers ) = {
if (!expectationContext.isSatisfied || unexpectedCallLog.nonEmpty) {
reportUnsatisfiedExpectationAndUnexpectedCalls(callLog, unexpectedCallLog, expectationContext)
}
}
}
5 changes: 4 additions & 1 deletion shared/src/main/scala/org/scalamock/context/CallLog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ private[scalamock] class CallLog {
}

def foreach(f: Call => Unit) = log foreach f


def isEmpty = log.isEmpty
def nonEmpty = log.nonEmpty

override def toString = log mkString(" ", "\n ", "")

private val log = new ListBuffer[Call]
Expand Down
22 changes: 21 additions & 1 deletion shared/src/main/scala/org/scalamock/context/MockContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ private[scalamock] trait MockContext {
type ExpectationException <: Throwable

private[scalamock] var callLog: CallLog = _
private[scalamock] var unexpectedCallLog: CallLog = _
private[scalamock] var currentExpectationContext: Handlers = _
private[scalamock] var expectationContext: Handlers = _
private[scalamock] val mockNameGenerator: MockNameGenerator = new MockNameGenerator()
Expand All @@ -38,8 +39,27 @@ private[scalamock] trait MockContext {
e
}

private[scalamock] def reportUnexpectedCall(call: Call) =
private[scalamock] def reportUnexpectedCall(call: Call) = {
unexpectedCallLog += call
throw newExpectationException(s"Unexpected call: $call\n\n${errorContext(callLog, expectationContext)}", Some(call.target.name))
}

private[scalamock] def reportUnexpectedCalls(callLog: CallLog, unexpectedCalls: CallLog, expectationContext: Handlers, message: String = "Unexpected call"): Unit = {
var calls: List[String] = Nil
unexpectedCalls.foreach {
call => calls = s"$message: $call" :: calls
}
if (calls.nonEmpty) throw newExpectationException(calls.reverse.mkString("", "\n", s"\n\n${errorContext(callLog, expectationContext)}"))
}

private[scalamock] def reportUnsatisfiedExpectationAndUnexpectedCalls(callLog: CallLog, unexpectedCalls: CallLog, expectationContext: Handlers): Unit = {
(unexpectedCalls.isEmpty, expectationContext.isSatisfied) match {
case (true, true) => // ignore, everything is OK
case (true, false) => reportUnsatisfiedExpectation(callLog, expectationContext)
case (false, true) => reportUnexpectedCalls(callLog, unexpectedCalls, expectationContext)
case (false, false) => reportUnexpectedCalls(callLog, unexpectedCalls, expectationContext, message = "Unexpected call and unsatisfied expectation")
}
}

private[scalamock] def reportUnsatisfiedExpectation(callLog: CallLog, expectationContext: Handlers) =
throw newExpectationException(s"Unsatisfied expectation:\n\n${errorContext(callLog, expectationContext)}")
Expand Down