Path: blob/trunk/third_party/closure/goog/testing/strictmock.js
4506 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview This file defines a strict mock implementation.8*/910goog.setTestOnly('goog.testing.StrictMock');11goog.provide('goog.testing.StrictMock');1213goog.require('goog.array');14goog.require('goog.asserts');15goog.require('goog.testing.Mock');16goog.requireType('goog.testing.MockExpectation');17181920/**21* This is a mock that verifies that methods are called in the order that they22* are specified during the recording phase. Since it verifies order, it23* follows 'fail fast' semantics. If it detects a deviation from the24* expectations, it will throw an exception and not wait for verify to be25* called.26* @param {Object|Function} objectToMock The object that should be mocked, or27* the constructor of an object to mock.28* @param {boolean=} opt_mockStaticMethods An optional argument denoting that29* a mock should be constructed from the static functions of a class.30* @param {boolean=} opt_createProxy An optional argument denoting that31* a proxy for the target mock should be created.32* @constructor33* @extends {goog.testing.Mock}34* @final35*/36goog.testing.StrictMock = function(37objectToMock, opt_mockStaticMethods, opt_createProxy) {38'use strict';39goog.testing.Mock.call(40this, objectToMock, opt_mockStaticMethods, opt_createProxy);4142/**43* An array of MockExpectations.44* @type {!Array<!goog.testing.MockExpectation>}45* @private46*/47this.$expectations_ = [];4849/** @private {!Set<!goog.testing.MockExpectation>} */50this.awaitingExpectations_ = new Set();51};52goog.inherits(goog.testing.StrictMock, goog.testing.Mock);535455/** @override */56goog.testing.StrictMock.prototype.$recordExpectation = function() {57'use strict';58if (this.$pendingExpectation) {59this.$expectations_.push(this.$pendingExpectation);60this.awaitingExpectations_.add(this.$pendingExpectation);61}62};636465/** @override */66goog.testing.StrictMock.prototype.$recordCall = function(name, args) {67'use strict';68if (this.$expectations_.length == 0) {69this.$throwCallException(name, args);70}7172// If the current expectation has a different name, make sure it was called73// enough and then discard it. We're through with it.74var currentExpectation = this.$expectations_[0];75while (!this.$verifyCall(currentExpectation, name, args)) {76// This might be an item which has passed its min, and we can now77// look past it, or it might be below its min and generate an error.78if (currentExpectation.actualCalls < currentExpectation.minCalls) {79this.$throwCallException(name, args, currentExpectation);80}8182this.$expectations_.shift();83this.awaitingExpectations_.delete(currentExpectation);84this.maybeFinishedWithExpectations_();85if (this.$expectations_.length < 1) {86// Nothing left, but this may be a failed attempt to call the previous87// item on the list, which may have been between its min and max.88this.$throwCallException(name, args, currentExpectation);89}90currentExpectation = this.$expectations_[0];91}9293if (currentExpectation.maxCalls == 0) {94this.$throwCallException(name, args);95}9697currentExpectation.actualCalls++;98// If we hit the max number of calls for this expectation, we're finished99// with it.100if (currentExpectation.actualCalls == currentExpectation.maxCalls) {101this.$expectations_.shift();102}103if (currentExpectation.actualCalls >= currentExpectation.minCalls) {104this.awaitingExpectations_.delete(currentExpectation);105this.maybeFinishedWithExpectations_();106}107108return this.$do(currentExpectation, args);109};110111112/** @override */113goog.testing.StrictMock.prototype.$reset = function() {114'use strict';115goog.testing.StrictMock.superClass_.$reset.call(this);116117goog.array.clear(this.$expectations_);118this.awaitingExpectations_.clear();119};120121122/** @override */123goog.testing.StrictMock.prototype.$waitAndVerify = function() {124'use strict';125for (var i = 0; i < this.$expectations_.length; i++) {126var expectation = this.$expectations_[i];127goog.asserts.assert(128!isFinite(expectation.maxCalls) ||129expectation.minCalls == expectation.maxCalls,130'Mock expectations cannot have a loose number of expected calls to ' +131'use $waitAndVerify.');132}133var promise = goog.testing.StrictMock.base(this, '$waitAndVerify');134this.maybeFinishedWithExpectations_();135return promise;136};137138/**139* @private140*/141goog.testing.StrictMock.prototype.maybeFinishedWithExpectations_ = function() {142'use strict';143var unresolvedExpectations =144this.$expectations_145.filter(function(expectation) {146'use strict';147return expectation.actualCalls < expectation.minCalls;148})149.length;150if (this.waitingForExpectations && !unresolvedExpectations) {151this.waitingForExpectations.resolve();152}153};154155156/** @override */157goog.testing.StrictMock.prototype.$verify = function() {158'use strict';159goog.testing.StrictMock.superClass_.$verify.call(this);160161while (this.$expectations_.length > 0) {162var expectation = this.$expectations_[0];163if (expectation.actualCalls < expectation.minCalls) {164this.$throwException(165'Missing a call to ' + expectation.name + '\nExpected: ' +166expectation.minCalls + ' but was: ' + expectation.actualCalls);167168} else {169// Don't need to check max, that's handled when the call is made170this.$expectations_.shift();171}172}173};174175176