| // Copyright 2008 The Closure Library Authors. All Rights Reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS-IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | /** | 
 |  * @fileoverview Matchers to be used with the mock utilities.  They allow for | 
 |  * flexible matching by type.  Custom matchers can be created by passing a | 
 |  * matcher function into an ArgumentMatcher instance. | 
 |  * | 
 |  * For examples, please see the unit test. | 
 |  * | 
 |  */ | 
 |  | 
 |  | 
 | goog.setTestOnly('goog.testing.mockmatchers'); | 
 | goog.provide('goog.testing.mockmatchers'); | 
 | goog.provide('goog.testing.mockmatchers.ArgumentMatcher'); | 
 | goog.provide('goog.testing.mockmatchers.IgnoreArgument'); | 
 | goog.provide('goog.testing.mockmatchers.InstanceOf'); | 
 | goog.provide('goog.testing.mockmatchers.ObjectEquals'); | 
 | goog.provide('goog.testing.mockmatchers.RegexpMatch'); | 
 | goog.provide('goog.testing.mockmatchers.SaveArgument'); | 
 | goog.provide('goog.testing.mockmatchers.TypeOf'); | 
 |  | 
 | goog.require('goog.array'); | 
 | goog.require('goog.dom'); | 
 | goog.require('goog.testing.asserts'); | 
 |  | 
 | goog.forwardDeclare('goog.testing.MockExpectation'); // circular | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  * A simple interface for executing argument matching.  A match in this case is | 
 |  * testing to see if a supplied object fits a given criteria.  True is returned | 
 |  * if the given criteria is met. | 
 |  * @param {Function=} opt_matchFn A function that evaluates a given argument | 
 |  *     and returns true if it meets a given criteria. | 
 |  * @param {?string=} opt_matchName The name expressing intent as part of | 
 |  *      an error message for when a match fails. | 
 |  * @constructor | 
 |  */ | 
 | goog.testing.mockmatchers.ArgumentMatcher = function( | 
 |     opt_matchFn, opt_matchName) { | 
 |   /** | 
 |    * A function that evaluates a given argument and returns true if it meets a | 
 |    * given criteria. | 
 |    * @type {Function} | 
 |    * @private | 
 |    */ | 
 |   this.matchFn_ = opt_matchFn || null; | 
 |  | 
 |   /** | 
 |    * A string indicating the match intent (e.g. isBoolean or isString). | 
 |    * @type {?string} | 
 |    * @private | 
 |    */ | 
 |   this.matchName_ = opt_matchName || null; | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * A function that takes a match argument and an optional MockExpectation | 
 |  * which (if provided) will get error information and returns whether or | 
 |  * not it matches. | 
 |  * @param {*} toVerify The argument that should be verified. | 
 |  * @param {goog.testing.MockExpectation?=} opt_expectation The expectation | 
 |  *     for this match. | 
 |  * @return {boolean} Whether or not a given argument passes verification. | 
 |  */ | 
 | goog.testing.mockmatchers.ArgumentMatcher.prototype.matches = function( | 
 |     toVerify, opt_expectation) { | 
 |   if (this.matchFn_) { | 
 |     var isamatch = this.matchFn_(toVerify); | 
 |     if (!isamatch && opt_expectation) { | 
 |       if (this.matchName_) { | 
 |         opt_expectation.addErrorMessage( | 
 |             'Expected: ' + this.matchName_ + ' but was: ' + | 
 |             _displayStringForValue(toVerify)); | 
 |       } else { | 
 |         opt_expectation.addErrorMessage( | 
 |             'Expected: missing mockmatcher' + | 
 |             ' description but was: ' + _displayStringForValue(toVerify)); | 
 |       } | 
 |     } | 
 |     return isamatch; | 
 |   } else { | 
 |     throw Error('No match function defined for this mock matcher'); | 
 |   } | 
 | }; | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is an instance of a given class. | 
 |  * @param {Function} ctor The class that will be used for verification. | 
 |  * @constructor | 
 |  * @extends {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  * @final | 
 |  */ | 
 | goog.testing.mockmatchers.InstanceOf = function(ctor) { | 
 |   goog.testing.mockmatchers.ArgumentMatcher.call(this, function(obj) { | 
 |     return obj instanceof ctor; | 
 |     // NOTE: Browser differences on ctor.toString() output | 
 |     // make using that here problematic. So for now, just let | 
 |     // people know the instanceOf() failed without providing | 
 |     // browser specific details... | 
 |   }, 'instanceOf()'); | 
 | }; | 
 | goog.inherits( | 
 |     goog.testing.mockmatchers.InstanceOf, | 
 |     goog.testing.mockmatchers.ArgumentMatcher); | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is of a given type (e.g. "object"). | 
 |  * @param {string} type The type that a given argument must have. | 
 |  * @constructor | 
 |  * @extends {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  * @final | 
 |  */ | 
 | goog.testing.mockmatchers.TypeOf = function(type) { | 
 |   goog.testing.mockmatchers.ArgumentMatcher.call(this, function(obj) { | 
 |     return goog.typeOf(obj) == type; | 
 |   }, 'typeOf(' + type + ')'); | 
 | }; | 
 | goog.inherits( | 
 |     goog.testing.mockmatchers.TypeOf, | 
 |     goog.testing.mockmatchers.ArgumentMatcher); | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument matches a given RegExp. | 
 |  * @param {RegExp} regexp The regular expression that the argument must match. | 
 |  * @constructor | 
 |  * @extends {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  * @final | 
 |  */ | 
 | goog.testing.mockmatchers.RegexpMatch = function(regexp) { | 
 |   goog.testing.mockmatchers.ArgumentMatcher.call(this, function(str) { | 
 |     return regexp.test(str); | 
 |   }, 'match(' + regexp + ')'); | 
 | }; | 
 | goog.inherits( | 
 |     goog.testing.mockmatchers.RegexpMatch, | 
 |     goog.testing.mockmatchers.ArgumentMatcher); | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that always returns true. It is useful when the user does not care | 
 |  * for some arguments. | 
 |  * For example: mockFunction('username', 'password', IgnoreArgument); | 
 |  * @constructor | 
 |  * @extends {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  * @final | 
 |  */ | 
 | goog.testing.mockmatchers.IgnoreArgument = function() { | 
 |   goog.testing.mockmatchers.ArgumentMatcher.call( | 
 |       this, function() { return true; }, 'true'); | 
 | }; | 
 | goog.inherits( | 
 |     goog.testing.mockmatchers.IgnoreArgument, | 
 |     goog.testing.mockmatchers.ArgumentMatcher); | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that the argument is an object that equals the given | 
 |  * expected object, using a deep comparison. | 
 |  * @param {Object} expectedObject An object to match against when | 
 |  *     verifying the argument. | 
 |  * @constructor | 
 |  * @extends {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.ObjectEquals = function(expectedObject) { | 
 |   /** @private */ | 
 |   this.expectedObject_ = expectedObject; | 
 | }; | 
 | goog.inherits( | 
 |     goog.testing.mockmatchers.ObjectEquals, | 
 |     goog.testing.mockmatchers.ArgumentMatcher); | 
 |  | 
 |  | 
 | /** @override */ | 
 | goog.testing.mockmatchers.ObjectEquals.prototype.matches = function( | 
 |     toVerify, opt_expectation) { | 
 |   // Override the default matches implementation to provide a custom error | 
 |   // message to opt_expectation if it exists. | 
 |   var differences = | 
 |       goog.testing.asserts.findDifferences(this.expectedObject_, toVerify); | 
 |   if (differences) { | 
 |     if (opt_expectation) { | 
 |       opt_expectation.addErrorMessage('Expected equal objects\n' + differences); | 
 |     } | 
 |     return false; | 
 |   } | 
 |   return true; | 
 | }; | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that saves the argument that it is verifying so that your unit test | 
 |  * can perform extra tests with this argument later.  For example, if the | 
 |  * argument is a callback method, the unit test can then later call this | 
 |  * callback to test the asynchronous portion of the call. | 
 |  * @param {goog.testing.mockmatchers.ArgumentMatcher|Function=} opt_matcher | 
 |  *     Argument matcher or matching function that will be used to validate the | 
 |  *     argument.  By default, argument will always be valid. | 
 |  * @param {?string=} opt_matchName The name expressing intent as part of | 
 |  *      an error message for when a match fails. | 
 |  * @constructor | 
 |  * @extends {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  * @final | 
 |  */ | 
 | goog.testing.mockmatchers.SaveArgument = function(opt_matcher, opt_matchName) { | 
 |   goog.testing.mockmatchers.ArgumentMatcher.call( | 
 |       this, /** @type {Function} */ (opt_matcher), opt_matchName); | 
 |  | 
 |   if (opt_matcher instanceof goog.testing.mockmatchers.ArgumentMatcher) { | 
 |     /** | 
 |      * Delegate match requests to this matcher. | 
 |      * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |      * @private | 
 |      */ | 
 |     this.delegateMatcher_ = opt_matcher; | 
 |   } else if (!opt_matcher) { | 
 |     this.delegateMatcher_ = goog.testing.mockmatchers.ignoreArgument; | 
 |   } | 
 | }; | 
 | goog.inherits( | 
 |     goog.testing.mockmatchers.SaveArgument, | 
 |     goog.testing.mockmatchers.ArgumentMatcher); | 
 |  | 
 |  | 
 | /** @override */ | 
 | goog.testing.mockmatchers.SaveArgument.prototype.matches = function( | 
 |     toVerify, opt_expectation) { | 
 |   this.arg = toVerify; | 
 |   if (this.delegateMatcher_) { | 
 |     return this.delegateMatcher_.matches(toVerify, opt_expectation); | 
 |   } | 
 |   return goog.testing.mockmatchers.SaveArgument.superClass_.matches.call( | 
 |       this, toVerify, opt_expectation); | 
 | }; | 
 |  | 
 |  | 
 | /** | 
 |  * Saved argument that was verified. | 
 |  * @type {*} | 
 |  */ | 
 | goog.testing.mockmatchers.SaveArgument.prototype.arg; | 
 |  | 
 |  | 
 | /** | 
 |  * An instance of the IgnoreArgument matcher. Returns true for all matches. | 
 |  * @type {goog.testing.mockmatchers.IgnoreArgument} | 
 |  */ | 
 | goog.testing.mockmatchers.ignoreArgument = | 
 |     new goog.testing.mockmatchers.IgnoreArgument(); | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is an array. | 
 |  * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.isArray = | 
 |     new goog.testing.mockmatchers.ArgumentMatcher(goog.isArray, 'isArray'); | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is a array-like.  A NodeList is an | 
 |  * example of a collection that is very close to an array. | 
 |  * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.isArrayLike = | 
 |     new goog.testing.mockmatchers.ArgumentMatcher( | 
 |         goog.isArrayLike, 'isArrayLike'); | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is a date-like. | 
 |  * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.isDateLike = | 
 |     new goog.testing.mockmatchers.ArgumentMatcher( | 
 |         goog.isDateLike, 'isDateLike'); | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is a string. | 
 |  * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.isString = | 
 |     new goog.testing.mockmatchers.ArgumentMatcher(goog.isString, 'isString'); | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is a boolean. | 
 |  * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.isBoolean = | 
 |     new goog.testing.mockmatchers.ArgumentMatcher(goog.isBoolean, 'isBoolean'); | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is a number. | 
 |  * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.isNumber = | 
 |     new goog.testing.mockmatchers.ArgumentMatcher(goog.isNumber, 'isNumber'); | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is a function. | 
 |  * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.isFunction = | 
 |     new goog.testing.mockmatchers.ArgumentMatcher( | 
 |         goog.isFunction, 'isFunction'); | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is an object. | 
 |  * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.isObject = | 
 |     new goog.testing.mockmatchers.ArgumentMatcher(goog.isObject, 'isObject'); | 
 |  | 
 |  | 
 | /** | 
 |  * A matcher that verifies that an argument is like a DOM node. | 
 |  * @type {goog.testing.mockmatchers.ArgumentMatcher} | 
 |  */ | 
 | goog.testing.mockmatchers.isNodeLike = | 
 |     new goog.testing.mockmatchers.ArgumentMatcher( | 
 |         goog.dom.isNodeLike, 'isNodeLike'); | 
 |  | 
 |  | 
 | /** | 
 |  * A function that checks to see if an array matches a given set of | 
 |  * expectations.  The expectations array can be a mix of ArgumentMatcher | 
 |  * implementations and values.  True will be returned if values are identical or | 
 |  * if a matcher returns a positive result. | 
 |  * @param {Array<?>} expectedArr An array of expectations which can be either | 
 |  *     values to check for equality or ArgumentMatchers. | 
 |  * @param {Array<?>} arr The array to match. | 
 |  * @param {goog.testing.MockExpectation?=} opt_expectation The expectation | 
 |  *     for this match. | 
 |  * @return {boolean} Whether or not the given array matches the expectations. | 
 |  */ | 
 | goog.testing.mockmatchers.flexibleArrayMatcher = function( | 
 |     expectedArr, arr, opt_expectation) { | 
 |   return goog.array.equals(expectedArr, arr, function(a, b) { | 
 |     var errCount = 0; | 
 |     if (opt_expectation) { | 
 |       errCount = opt_expectation.getErrorMessageCount(); | 
 |     } | 
 |     var isamatch = a === b || | 
 |         a instanceof goog.testing.mockmatchers.ArgumentMatcher && | 
 |             a.matches(b, opt_expectation); | 
 |     var failureMessage = null; | 
 |     if (!isamatch) { | 
 |       failureMessage = goog.testing.asserts.findDifferences(a, b); | 
 |       isamatch = !failureMessage; | 
 |     } | 
 |     if (!isamatch && opt_expectation) { | 
 |       // If the error count changed, the match sent out an error | 
 |       // message. If the error count has not changed, then | 
 |       // we need to send out an error message... | 
 |       if (errCount == opt_expectation.getErrorMessageCount()) { | 
 |         // Use the _displayStringForValue() from assert.js | 
 |         // for consistency... | 
 |         if (!failureMessage) { | 
 |           failureMessage = 'Expected: ' + _displayStringForValue(a) + | 
 |               ' but was: ' + _displayStringForValue(b); | 
 |         } | 
 |         opt_expectation.addErrorMessage(failureMessage); | 
 |       } | 
 |     } | 
 |     return isamatch; | 
 |   }); | 
 | }; |