Path: blob/trunk/third_party/closure/goog/testing/mockmatchers.js
4113 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview Matchers to be used with the mock utilities. They allow for8* flexible matching by type. Custom matchers can be created by passing a9* matcher function into an ArgumentMatcher instance.10*11* For examples, please see the unit test.12*/131415goog.setTestOnly('goog.testing.mockmatchers');16goog.provide('goog.testing.mockmatchers');17goog.provide('goog.testing.mockmatchers.ArgumentMatcher');18goog.provide('goog.testing.mockmatchers.IgnoreArgument');19goog.provide('goog.testing.mockmatchers.InstanceOf');20goog.provide('goog.testing.mockmatchers.ObjectEquals');21goog.provide('goog.testing.mockmatchers.RegexpMatch');22goog.provide('goog.testing.mockmatchers.SaveArgument');23goog.provide('goog.testing.mockmatchers.TypeOf');2425goog.require('goog.array');26goog.require('goog.dom');27goog.require('goog.testing.asserts');28goog.requireType('goog.testing.MockExpectation');29303132/**33* A simple interface for executing argument matching. A match in this case is34* testing to see if a supplied object fits a given criteria. True is returned35* if the given criteria is met.36* @param {Function=} opt_matchFn A function that evaluates a given argument37* and returns true if it meets a given criteria.38* @param {?string=} opt_matchName The name expressing intent as part of39* an error message for when a match fails.40* @constructor41*/42goog.testing.mockmatchers.ArgumentMatcher = function(43opt_matchFn, opt_matchName) {44'use strict';45/**46* A function that evaluates a given argument and returns true if it meets a47* given criteria.48* @type {Function}49* @private50*/51this.matchFn_ = opt_matchFn || null;5253/**54* A string indicating the match intent (e.g. isBoolean or isString).55* @type {?string}56* @private57*/58this.matchName_ = opt_matchName || null;59};606162/**63* A function that takes a match argument and an optional MockExpectation64* which (if provided) will get error information and returns whether or65* not it matches.66* @param {*} toVerify The argument that should be verified.67* @param {?goog.testing.MockExpectation=} opt_expectation The expectation68* for this match.69* @return {boolean} Whether or not a given argument passes verification.70*/71goog.testing.mockmatchers.ArgumentMatcher.prototype.matches = function(72toVerify, opt_expectation) {73'use strict';74if (this.matchFn_) {75var isamatch = this.matchFn_(toVerify);76if (!isamatch && opt_expectation) {77if (this.matchName_) {78opt_expectation.addErrorMessage(79'Expected: ' + this.matchName_ + ' but was: ' +80_displayStringForValue(toVerify));81} else {82opt_expectation.addErrorMessage(83'Expected: missing mockmatcher' +84' description but was: ' + _displayStringForValue(toVerify));85}86}87return isamatch;88} else {89throw new Error('No match function defined for this mock matcher');90}91};92939495/**96* A matcher that verifies that an argument is an instance of a given class.97* @param {Function} ctor The class that will be used for verification.98* @constructor99* @extends {goog.testing.mockmatchers.ArgumentMatcher}100* @final101*/102goog.testing.mockmatchers.InstanceOf = function(ctor) {103'use strict';104goog.testing.mockmatchers.ArgumentMatcher.call(this, function(obj) {105'use strict';106return obj instanceof ctor;107// NOTE: Browser differences on ctor.toString() output108// make using that here problematic. So for now, just let109// people know the instanceOf() failed without providing110// browser specific details...111}, 'instanceOf()');112};113goog.inherits(114goog.testing.mockmatchers.InstanceOf,115goog.testing.mockmatchers.ArgumentMatcher);116117118119/**120* A matcher that verifies that an argument is of a given type (e.g. "object").121* @param {string} type The type that a given argument must have.122* @constructor123* @extends {goog.testing.mockmatchers.ArgumentMatcher}124* @final125*/126goog.testing.mockmatchers.TypeOf = function(type) {127'use strict';128goog.testing.mockmatchers.ArgumentMatcher.call(this, function(obj) {129'use strict';130return goog.typeOf(obj) == type;131}, 'typeOf(' + type + ')');132};133goog.inherits(134goog.testing.mockmatchers.TypeOf,135goog.testing.mockmatchers.ArgumentMatcher);136137138139/**140* A matcher that verifies that an argument matches a given RegExp.141* @param {RegExp} regexp The regular expression that the argument must match.142* @constructor143* @extends {goog.testing.mockmatchers.ArgumentMatcher}144* @final145*/146goog.testing.mockmatchers.RegexpMatch = function(regexp) {147'use strict';148goog.testing.mockmatchers.ArgumentMatcher.call(this, function(str) {149'use strict';150return regexp.test(str);151}, 'match(' + regexp + ')');152};153goog.inherits(154goog.testing.mockmatchers.RegexpMatch,155goog.testing.mockmatchers.ArgumentMatcher);156157158159/**160* A matcher that always returns true. It is useful when the user does not care161* for some arguments.162* For example: mockFunction('username', 'password', new IgnoreArgument());163* @constructor164* @extends {goog.testing.mockmatchers.ArgumentMatcher}165* @final166*/167goog.testing.mockmatchers.IgnoreArgument = function() {168'use strict';169goog.testing.mockmatchers.ArgumentMatcher.call(this, function() {170'use strict';171return true;172}, 'true');173};174goog.inherits(175goog.testing.mockmatchers.IgnoreArgument,176goog.testing.mockmatchers.ArgumentMatcher);177178179180/**181* A matcher that verifies that the argument is an object that equals the given182* expected object, using a deep comparison.183* @param {Object} expectedObject An object to match against when184* verifying the argument.185* @constructor186* @extends {goog.testing.mockmatchers.ArgumentMatcher}187*/188goog.testing.mockmatchers.ObjectEquals = function(expectedObject) {189'use strict';190/** @private */191this.expectedObject_ = expectedObject;192};193goog.inherits(194goog.testing.mockmatchers.ObjectEquals,195goog.testing.mockmatchers.ArgumentMatcher);196197198/** @override */199goog.testing.mockmatchers.ObjectEquals.prototype.matches = function(200toVerify, opt_expectation) {201'use strict';202// Override the default matches implementation to provide a custom error203// message to opt_expectation if it exists.204var differences =205goog.testing.asserts.findDifferences(this.expectedObject_, toVerify);206if (differences) {207if (opt_expectation) {208opt_expectation.addErrorMessage('Expected equal objects\n' + differences);209}210return false;211}212return true;213};214215216217/**218* A matcher that saves the argument that it is verifying so that your unit test219* can perform extra tests with this argument later. For example, if the220* argument is a callback method, the unit test can then later call this221* callback to test the asynchronous portion of the call.222* @param {goog.testing.mockmatchers.ArgumentMatcher|Function=} opt_matcher223* Argument matcher or matching function that will be used to validate the224* argument. By default, argument will always be valid.225* @param {?string=} opt_matchName The name expressing intent as part of226* an error message for when a match fails.227* @constructor228* @extends {goog.testing.mockmatchers.ArgumentMatcher}229* @final230*/231goog.testing.mockmatchers.SaveArgument = function(opt_matcher, opt_matchName) {232'use strict';233goog.testing.mockmatchers.ArgumentMatcher.call(234this, /** @type {Function} */ (opt_matcher), opt_matchName);235236/**237* All saved arguments that were verified.238* @const {!Array<*>}239*/240this.allArgs = [];241242if (opt_matcher instanceof goog.testing.mockmatchers.ArgumentMatcher) {243/**244* Delegate match requests to this matcher.245* @type {goog.testing.mockmatchers.ArgumentMatcher}246* @private247*/248this.delegateMatcher_ = opt_matcher;249} else if (!opt_matcher) {250this.delegateMatcher_ = goog.testing.mockmatchers.ignoreArgument;251}252};253goog.inherits(254goog.testing.mockmatchers.SaveArgument,255goog.testing.mockmatchers.ArgumentMatcher);256257258/** @override */259goog.testing.mockmatchers.SaveArgument.prototype.matches = function(260toVerify, opt_expectation) {261'use strict';262this.arg = toVerify;263this.allArgs.push(toVerify);264if (this.delegateMatcher_) {265return this.delegateMatcher_.matches(toVerify, opt_expectation);266}267return goog.testing.mockmatchers.SaveArgument.superClass_.matches.call(268this, toVerify, opt_expectation);269};270271272/**273* The last (or only) saved argument that was verified.274* @type {*}275*/276goog.testing.mockmatchers.SaveArgument.prototype.arg;277278279/**280* An instance of the IgnoreArgument matcher. Returns true for all matches.281* @type {!goog.testing.mockmatchers.IgnoreArgument}282*/283goog.testing.mockmatchers.ignoreArgument =284new goog.testing.mockmatchers.IgnoreArgument();285286287/**288* A matcher that verifies that an argument is an array.289* @type {!goog.testing.mockmatchers.ArgumentMatcher}290*/291goog.testing.mockmatchers.isArray =292new goog.testing.mockmatchers.ArgumentMatcher(Array.isArray, 'isArray');293294295/**296* A matcher that verifies that an argument is a array-like. A NodeList is an297* example of a collection that is very close to an array.298* @type {!goog.testing.mockmatchers.ArgumentMatcher}299*/300goog.testing.mockmatchers.isArrayLike =301new goog.testing.mockmatchers.ArgumentMatcher(302goog.isArrayLike, 'isArrayLike');303304305/**306* A matcher that verifies that an argument is a date-like.307* @type {!goog.testing.mockmatchers.ArgumentMatcher}308*/309goog.testing.mockmatchers.isDateLike =310new goog.testing.mockmatchers.ArgumentMatcher(311goog.isDateLike, 'isDateLike');312313314/**315* A matcher that verifies that an argument is a string.316* @type {!goog.testing.mockmatchers.ArgumentMatcher}317*/318goog.testing.mockmatchers.isString =319new goog.testing.mockmatchers.ArgumentMatcher(320x => typeof x === 'string', 'isString');321322323/**324* A matcher that verifies that an argument is a boolean.325* @type {!goog.testing.mockmatchers.ArgumentMatcher}326*/327goog.testing.mockmatchers.isBoolean =328new goog.testing.mockmatchers.ArgumentMatcher(329x => typeof x === 'boolean', 'isBoolean');330331332/**333* A matcher that verifies that an argument is a number.334* @type {!goog.testing.mockmatchers.ArgumentMatcher}335*/336goog.testing.mockmatchers.isNumber =337new goog.testing.mockmatchers.ArgumentMatcher(338x => typeof x === 'number', 'isNumber');339340341/**342* A matcher that verifies that an argument is a function.343* @type {!goog.testing.mockmatchers.ArgumentMatcher}344*/345goog.testing.mockmatchers.isFunction =346new goog.testing.mockmatchers.ArgumentMatcher(347x => typeof x === 'function', 'isFunction');348349350/**351* A matcher that verifies that an argument is an object.352* @type {!goog.testing.mockmatchers.ArgumentMatcher}353*/354goog.testing.mockmatchers.isObject =355new goog.testing.mockmatchers.ArgumentMatcher(goog.isObject, 'isObject');356357358/**359* A matcher that verifies that an argument is like a DOM node.360* @type {!goog.testing.mockmatchers.ArgumentMatcher}361*/362goog.testing.mockmatchers.isNodeLike =363new goog.testing.mockmatchers.ArgumentMatcher(364goog.dom.isNodeLike, 'isNodeLike');365366367/**368* A function that checks to see if an array matches a given set of369* expectations. The expectations array can be a mix of ArgumentMatcher370* implementations and values. True will be returned if values are identical or371* if a matcher returns a positive result.372* @param {Array<?>} expectedArr An array of expectations which can be either373* values to check for equality or ArgumentMatchers.374* @param {Array<?>} arr The array to match.375* @param {goog.testing.MockExpectation?=} opt_expectation The expectation376* for this match.377* @return {boolean} Whether or not the given array matches the expectations.378*/379goog.testing.mockmatchers.flexibleArrayMatcher = function(380expectedArr, arr, opt_expectation) {381'use strict';382return goog.array.equals(expectedArr, arr, function(a, b) {383'use strict';384var errCount = 0;385if (opt_expectation) {386errCount = opt_expectation.getErrorMessageCount();387}388var isamatch = a === b ||389a instanceof goog.testing.mockmatchers.ArgumentMatcher &&390a.matches(b, opt_expectation);391var failureMessage = null;392if (!isamatch) {393failureMessage = goog.testing.asserts.findDifferences(a, b);394isamatch = !failureMessage;395}396if (!isamatch && opt_expectation) {397// If the error count changed, the match sent out an error398// message. If the error count has not changed, then399// we need to send out an error message...400if (errCount == opt_expectation.getErrorMessageCount()) {401// Use the _displayStringForValue() from assert.js402// for consistency...403if (!failureMessage) {404failureMessage = 'Expected: ' + _displayStringForValue(a) +405' but was: ' + _displayStringForValue(b);406}407opt_expectation.addErrorMessage(failureMessage);408}409}410return isamatch;411});412};413414415