# lib/goog/testing/strictmock.js

    1// Copyright 2008 The Closure Library Authors. All Rights Reserved.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 at6//7//      http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// 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 and13// limitations under the License.1415/**16 * @fileoverview This file defines a strict mock implementation.17 */1819goog.provide('goog.testing.StrictMock');2021goog.require('goog.array');22goog.require('goog.testing.Mock');23242526/**27 * This is a mock that verifies that methods are called in the order that they28 * are specified during the recording phase. Since it verifies order, it29 * follows 'fail fast' semantics. If it detects a deviation from the30 * expectations, it will throw an exception and not wait for verify to be31 * called.32 * @param {Object|Function} objectToMock The object that should be mocked, or33 *    the constructor of an object to mock.34 * @param {boolean=} opt_mockStaticMethods An optional argument denoting that35 *     a mock should be constructed from the static functions of a class.36 * @param {boolean=} opt_createProxy An optional argument denoting that37 *     a proxy for the target mock should be created.38 * @constructor39 * @extends {goog.testing.Mock}40 * @final41 */42goog.testing.StrictMock = function(objectToMock, opt_mockStaticMethods,43    opt_createProxy) {44  goog.testing.Mock.call(this, objectToMock, opt_mockStaticMethods,45      opt_createProxy);4647  /**48   * An array of MockExpectations.49   * @type {Array.<goog.testing.MockExpectation>}50   * @private51   */52  this.$expectations_ = [];53};54goog.inherits(goog.testing.StrictMock, goog.testing.Mock);555657/** @override */58goog.testing.StrictMock.prototype.$recordExpectation = function() {59  this.$expectations_.push(this.$pendingExpectation);60};616263/** @override */64goog.testing.StrictMock.prototype.$recordCall = function(name, args) {65  if (this.$expectations_.length == 0) {66    this.$throwCallException(name, args);67  }6869  // If the current expectation has a different name, make sure it was called70  // enough and then discard it. We're through with it.71  var currentExpectation = this.$expectations_[0];72  while (!this.$verifyCall(currentExpectation, name, args)) {7374    // This might be an item which has passed its min, and we can now75    // look past it, or it might be below its min and generate an error.76    if (currentExpectation.actualCalls < currentExpectation.minCalls) {77      this.$throwCallException(name, args, currentExpectation);78    }7980    this.$expectations_.shift();81    if (this.$expectations_.length < 1) {82      // Nothing left, but this may be a failed attempt to call the previous83      // item on the list, which may have been between its min and max.84      this.$throwCallException(name, args, currentExpectation);85    }86    currentExpectation = this.$expectations_[0];87  }8889  if (currentExpectation.maxCalls == 0) {90    this.$throwCallException(name, args);91  }9293  currentExpectation.actualCalls++;94  // If we hit the max number of calls for this expectation, we're finished95  // with it.96  if (currentExpectation.actualCalls == currentExpectation.maxCalls) {97    this.$expectations_.shift();98  }99100  return this.$do(currentExpectation, args);101};102103104/** @override */105goog.testing.StrictMock.prototype.$reset = function() {106  goog.testing.StrictMock.superClass_.$reset.call(this);107108  goog.array.clear(this.$expectations_);109};110111112/** @override */113goog.testing.StrictMock.prototype.$verify = function() {114  goog.testing.StrictMock.superClass_.$verify.call(this);115116  while (this.$expectations_.length > 0) {117    var expectation = this.$expectations_[0];118    if (expectation.actualCalls < expectation.minCalls) {119      this.$throwException('Missing a call to ' + expectation.name +120          '\nExpected: ' + expectation.minCalls + ' but was: ' +121          expectation.actualCalls);122123    } else {124      // Don't need to check max, that's handled when the call is made125      this.$expectations_.shift();126    }127  }128};129130