Adding mapbox-gl branch
This commit is contained in:
@@ -0,0 +1,861 @@
|
||||
// Copyright 2012 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 Provides a mocking framework in Closure to make unit tests easy
|
||||
* to write and understand. The methods provided here can be used to replace
|
||||
* implementations of existing objects with 'mock' objects to abstract out
|
||||
* external services and dependencies thereby isolating the code under test.
|
||||
* Apart from mocking, methods are also provided to just monitor calls to an
|
||||
* object (spying) and returning specific values for some or all the inputs to
|
||||
* methods (stubbing).
|
||||
*
|
||||
* Design doc : http://go/closuremock
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.labs.mock');
|
||||
goog.provide('goog.labs.mock.VerificationError');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.debug');
|
||||
goog.require('goog.debug.Error');
|
||||
goog.require('goog.functions');
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
/**
|
||||
* Mocks a given object or class.
|
||||
*
|
||||
* @param {!Object} objectOrClass An instance or a constructor of a class to be
|
||||
* mocked.
|
||||
* @return {!Object} The mocked object.
|
||||
*/
|
||||
goog.labs.mock.mock = function(objectOrClass) {
|
||||
// Go over properties of 'objectOrClass' and create a MockManager to
|
||||
// be used for stubbing out calls to methods.
|
||||
var mockObjectManager = new goog.labs.mock.MockObjectManager_(objectOrClass);
|
||||
var mockedObject = mockObjectManager.getMockedItem();
|
||||
goog.asserts.assertObject(mockedObject);
|
||||
return /** @type {!Object} */ (mockedObject);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mocks a given function.
|
||||
*
|
||||
* @param {!Function} func A function to be mocked.
|
||||
* @return {!Function} The mocked function.
|
||||
*/
|
||||
goog.labs.mock.mockFunction = function(func) {
|
||||
var mockFuncManager = new goog.labs.mock.MockFunctionManager_(func);
|
||||
var mockedFunction = mockFuncManager.getMockedItem();
|
||||
goog.asserts.assertFunction(mockedFunction);
|
||||
return /** @type {!Function} */ (mockedFunction);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Spies on a given object.
|
||||
*
|
||||
* @param {!Object} obj The object to be spied on.
|
||||
* @return {!Object} The spy object.
|
||||
*/
|
||||
goog.labs.mock.spy = function(obj) {
|
||||
// Go over properties of 'obj' and create a MockSpyManager_ to
|
||||
// be used for spying on calls to methods.
|
||||
var mockSpyManager = new goog.labs.mock.MockSpyManager_(obj);
|
||||
var spyObject = mockSpyManager.getMockedItem();
|
||||
goog.asserts.assert(spyObject);
|
||||
return spyObject;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an object that can be used to verify calls to specific methods of a
|
||||
* given mock.
|
||||
*
|
||||
* @param {!Object} obj The mocked object.
|
||||
* @return {!Object} The verifier.
|
||||
*/
|
||||
goog.labs.mock.verify = function(obj) {
|
||||
return obj.$callVerifier;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a name to identify a function. Named functions return their names,
|
||||
* unnamed functions return a string of the form '#anonymous{ID}' where ID is
|
||||
* a unique identifier for each anonymous function.
|
||||
* @private
|
||||
* @param {!Function} func The function.
|
||||
* @return {string} The function name.
|
||||
*/
|
||||
goog.labs.mock.getFunctionName_ = function(func) {
|
||||
var funcName = goog.debug.getFunctionName(func);
|
||||
if (funcName == '' || funcName == '[Anonymous]') {
|
||||
funcName = '#anonymous' + goog.labs.mock.getUid(func);
|
||||
}
|
||||
return funcName;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a nicely formatted, readble representation of a method call.
|
||||
* @private
|
||||
* @param {string} methodName The name of the method.
|
||||
* @param {Array<?>=} opt_args The method arguments.
|
||||
* @return {string} The string representation of the method call.
|
||||
*/
|
||||
goog.labs.mock.formatMethodCall_ = function(methodName, opt_args) {
|
||||
opt_args = opt_args || [];
|
||||
opt_args = goog.array.map(opt_args, function(arg) {
|
||||
if (goog.isFunction(arg)) {
|
||||
var funcName = goog.labs.mock.getFunctionName_(arg);
|
||||
return '<function ' + funcName + '>';
|
||||
} else {
|
||||
var isObjectWithClass = goog.isObject(arg) &&
|
||||
!goog.isFunction(arg) && !goog.isArray(arg) &&
|
||||
arg.constructor != Object;
|
||||
|
||||
if (isObjectWithClass) {
|
||||
return arg.toString();
|
||||
}
|
||||
|
||||
return goog.labs.mock.formatValue_(arg);
|
||||
}
|
||||
});
|
||||
return methodName + '(' + opt_args.join(', ') + ')';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An array to store objects for unique id generation.
|
||||
* @private
|
||||
* @type {!Array<!Object>}
|
||||
*/
|
||||
goog.labs.mock.uid_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* A unique Id generator that does not modify the object.
|
||||
* @param {Object!} obj The object whose unique ID we want to generate.
|
||||
* @return {number} an unique id for the object.
|
||||
*/
|
||||
goog.labs.mock.getUid = function(obj) {
|
||||
var index = goog.array.indexOf(goog.labs.mock.uid_, obj);
|
||||
if (index == -1) {
|
||||
index = goog.labs.mock.uid_.length;
|
||||
goog.labs.mock.uid_.push(obj);
|
||||
}
|
||||
return index;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is just another implementation of goog.debug.deepExpose with a more
|
||||
* compact format.
|
||||
* @private
|
||||
* @param {*} obj The object whose string representation will be returned.
|
||||
* @param {boolean=} opt_id Whether to include the id of objects or not.
|
||||
* Defaults to true.
|
||||
* @return {string} The string representation of the object.
|
||||
*/
|
||||
goog.labs.mock.formatValue_ = function(obj, opt_id) {
|
||||
var id = goog.isDef(opt_id) ? opt_id : true;
|
||||
var previous = [];
|
||||
var output = [];
|
||||
|
||||
var helper = function(obj) {
|
||||
var indentMultiline = function(output) {
|
||||
return output.replace(/\n/g, '\n');
|
||||
};
|
||||
|
||||
/** @preserveTry */
|
||||
try {
|
||||
if (!goog.isDef(obj)) {
|
||||
output.push('undefined');
|
||||
} else if (goog.isNull(obj)) {
|
||||
output.push('NULL');
|
||||
} else if (goog.isString(obj)) {
|
||||
output.push('"' + indentMultiline(obj) + '"');
|
||||
} else if (goog.isFunction(obj)) {
|
||||
var funcName = goog.labs.mock.getFunctionName_(obj);
|
||||
output.push('<function ' + funcName + '>');
|
||||
} else if (goog.isObject(obj)) {
|
||||
if (goog.array.contains(previous, obj)) {
|
||||
if (id) {
|
||||
output.push('<recursive/dupe obj_' +
|
||||
goog.labs.mock.getUid(obj) + '>');
|
||||
} else {
|
||||
output.push('<recursive/dupe>');
|
||||
}
|
||||
} else {
|
||||
previous.push(obj);
|
||||
output.push('{');
|
||||
var inner_obj = [];
|
||||
for (var x in obj) {
|
||||
output.push(' ');
|
||||
output.push('"' + x + '"' + ':');
|
||||
helper(obj[x]);
|
||||
}
|
||||
if (id) {
|
||||
output.push(' _id:' + goog.labs.mock.getUid(obj));
|
||||
}
|
||||
output.push('}');
|
||||
}
|
||||
} else {
|
||||
output.push(obj);
|
||||
}
|
||||
} catch (e) {
|
||||
output.push('*** ' + e + ' ***');
|
||||
}
|
||||
};
|
||||
|
||||
helper(obj);
|
||||
return output.join('').replace(/"closure_uid_\d+"/g, '_id')
|
||||
.replace(/{ /g, '{');
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Error thrown when verification failed.
|
||||
*
|
||||
* @param {Array<!goog.labs.mock.MethodBinding_>} recordedCalls
|
||||
* The recorded calls that didn't match the expectation.
|
||||
* @param {!string} methodName The expected method call.
|
||||
* @param {!Array<?>} args The expected arguments.
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
* @final
|
||||
*/
|
||||
goog.labs.mock.VerificationError = function(recordedCalls, methodName, args) {
|
||||
var msg = goog.labs.mock.VerificationError.getVerificationErrorMsg_(
|
||||
recordedCalls, methodName, args);
|
||||
goog.labs.mock.VerificationError.base(this, 'constructor', msg);
|
||||
};
|
||||
goog.inherits(goog.labs.mock.VerificationError, goog.debug.Error);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.labs.mock.VerificationError.prototype.name = 'VerificationError';
|
||||
|
||||
|
||||
/**
|
||||
* This array contains the name of the functions that are part of the base
|
||||
* Object prototype.
|
||||
* Basically a copy of goog.object.PROTOTYPE_FIELDS_.
|
||||
* @const
|
||||
* @type {!Array<string>}
|
||||
* @private
|
||||
*/
|
||||
goog.labs.mock.PROTOTYPE_FIELDS_ = [
|
||||
'constructor',
|
||||
'hasOwnProperty',
|
||||
'isPrototypeOf',
|
||||
'propertyIsEnumerable',
|
||||
'toLocaleString',
|
||||
'toString',
|
||||
'valueOf'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a descriptive error message for an expected method call.
|
||||
* @private
|
||||
* @param {Array<!goog.labs.mock.MethodBinding_>} recordedCalls
|
||||
* The recorded calls that didn't match the expectation.
|
||||
* @param {!string} methodName The expected method call.
|
||||
* @param {!Array<?>} args The expected arguments.
|
||||
* @return {string} The error message.
|
||||
*/
|
||||
goog.labs.mock.VerificationError.getVerificationErrorMsg_ =
|
||||
function(recordedCalls, methodName, args) {
|
||||
|
||||
recordedCalls = goog.array.filter(recordedCalls, function(binding) {
|
||||
return binding.getMethodName() == methodName;
|
||||
});
|
||||
|
||||
var expected = goog.labs.mock.formatMethodCall_(methodName, args);
|
||||
|
||||
var msg = '\nExpected: ' + expected.toString();
|
||||
msg += '\nRecorded: ';
|
||||
|
||||
if (recordedCalls.length > 0) {
|
||||
msg += recordedCalls.join(',\n ');
|
||||
} else {
|
||||
msg += 'No recorded calls';
|
||||
}
|
||||
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class that provides basic functionality for creating, adding and
|
||||
* finding bindings, offering an executor method that is called when a call to
|
||||
* the stub is made, an array to hold the bindings and the mocked item, among
|
||||
* other things.
|
||||
*
|
||||
* @constructor
|
||||
* @struct
|
||||
* @private
|
||||
*/
|
||||
goog.labs.mock.MockManager_ = function() {
|
||||
/**
|
||||
* Proxies the methods for the mocked object or class to execute the stubs.
|
||||
* @type {!Object}
|
||||
* @protected
|
||||
*/
|
||||
this.mockedItem = {};
|
||||
|
||||
/**
|
||||
* A reference to the object or function being mocked.
|
||||
* @type {Object|Function}
|
||||
* @protected
|
||||
*/
|
||||
this.mockee = null;
|
||||
|
||||
/**
|
||||
* Holds the stub bindings established so far.
|
||||
* @protected
|
||||
*/
|
||||
this.methodBindings = [];
|
||||
|
||||
/**
|
||||
* Holds a reference to the binder used to define stubs.
|
||||
* @protected
|
||||
*/
|
||||
this.$stubBinder = null;
|
||||
|
||||
/**
|
||||
* Record method calls with no stub definitions.
|
||||
* @type {!Array<!goog.labs.mock.MethodBinding_>}
|
||||
* @private
|
||||
*/
|
||||
this.callRecords_ = [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles the first step in creating a stub, returning a stub-binder that
|
||||
* is later used to bind a stub for a method.
|
||||
*
|
||||
* @param {string} methodName The name of the method being bound.
|
||||
* @param {...*} var_args The arguments to the method.
|
||||
* @return {!goog.labs.mock.StubBinder_} The stub binder.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.mock.MockManager_.prototype.handleMockCall_ =
|
||||
function(methodName, var_args) {
|
||||
var args = goog.array.slice(arguments, 1);
|
||||
return new goog.labs.mock.StubBinder_(this, methodName, args);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the mock object. This should have a stubbed method for each method
|
||||
* on the object being mocked.
|
||||
*
|
||||
* @return {!Object|!Function} The mock object.
|
||||
*/
|
||||
goog.labs.mock.MockManager_.prototype.getMockedItem = function() {
|
||||
return this.mockedItem;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a binding for the method name and arguments to be stubbed.
|
||||
*
|
||||
* @param {?string} methodName The name of the stubbed method.
|
||||
* @param {!Array<?>} args The arguments passed to the method.
|
||||
* @param {!Function} func The stub function.
|
||||
*
|
||||
*/
|
||||
goog.labs.mock.MockManager_.prototype.addBinding =
|
||||
function(methodName, args, func) {
|
||||
var binding = new goog.labs.mock.MethodBinding_(methodName, args, func);
|
||||
this.methodBindings.push(binding);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a stub, if defined, for the method name and arguments passed in.
|
||||
* If there are multiple stubs for this method name and arguments, then
|
||||
* the first one is returned and removed from the list.
|
||||
*
|
||||
* @param {string} methodName The name of the stubbed method.
|
||||
* @param {!Array<?>} args The arguments passed to the method.
|
||||
* @return {Function} The stub function or undefined.
|
||||
* @protected
|
||||
*/
|
||||
goog.labs.mock.MockManager_.prototype.getNextBinding =
|
||||
function(methodName, args) {
|
||||
var first = -1;
|
||||
var count = 0;
|
||||
var stub = null;
|
||||
goog.array.forEach(this.methodBindings, function(binding, i) {
|
||||
if (binding.matches(methodName, args, false /* isVerification */)) {
|
||||
count++;
|
||||
if (goog.isNull(stub)) {
|
||||
first = i;
|
||||
stub = binding;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (count > 1) {
|
||||
goog.array.removeAt(this.methodBindings, first);
|
||||
}
|
||||
return stub && stub.getStub();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a stub, if defined, for the method name and arguments passed in as
|
||||
* parameters.
|
||||
*
|
||||
* @param {string} methodName The name of the stubbed method.
|
||||
* @param {!Array<?>} args The arguments passed to the method.
|
||||
* @return {Function} The stub function or undefined.
|
||||
* @protected
|
||||
*/
|
||||
goog.labs.mock.MockManager_.prototype.getExecutor = function(methodName, args) {
|
||||
return this.getNextBinding(methodName, args);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Looks up the list of stubs defined on the mock object and executes the
|
||||
* function associated with that stub.
|
||||
*
|
||||
* @param {string} methodName The name of the method to execute.
|
||||
* @param {...*} var_args The arguments passed to the method.
|
||||
* @return {*} Value returned by the stub function.
|
||||
* @protected
|
||||
*/
|
||||
goog.labs.mock.MockManager_.prototype.executeStub =
|
||||
function(methodName, var_args) {
|
||||
var args = goog.array.slice(arguments, 1);
|
||||
|
||||
// Record this call
|
||||
this.recordCall_(methodName, args);
|
||||
|
||||
var func = this.getExecutor(methodName, args);
|
||||
if (func) {
|
||||
return func.apply(null, args);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Records a call to 'methodName' with arguments 'args'.
|
||||
*
|
||||
* @param {string} methodName The name of the called method.
|
||||
* @param {!Array<?>} args The array of arguments.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.mock.MockManager_.prototype.recordCall_ =
|
||||
function(methodName, args) {
|
||||
var callRecord = new goog.labs.mock.MethodBinding_(methodName, args,
|
||||
goog.nullFunction);
|
||||
|
||||
this.callRecords_.push(callRecord);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Verify invocation of a method with specific arguments.
|
||||
*
|
||||
* @param {string} methodName The name of the method.
|
||||
* @param {...*} var_args The arguments passed.
|
||||
* @protected
|
||||
*/
|
||||
goog.labs.mock.MockManager_.prototype.verifyInvocation =
|
||||
function(methodName, var_args) {
|
||||
var args = goog.array.slice(arguments, 1);
|
||||
var binding = goog.array.find(this.callRecords_, function(binding) {
|
||||
return binding.matches(methodName, args, true /* isVerification */);
|
||||
});
|
||||
|
||||
if (!binding) {
|
||||
throw new goog.labs.mock.VerificationError(
|
||||
this.callRecords_, methodName, args);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets up mock for the given object (or class), stubbing out all the defined
|
||||
* methods. By default, all stubs return {@code undefined}, though stubs can be
|
||||
* later defined using {@code goog.labs.mock.when}.
|
||||
*
|
||||
* @param {!Object|!Function} objOrClass The object or class to set up the mock
|
||||
* for. A class is a constructor function.
|
||||
*
|
||||
* @constructor
|
||||
* @struct
|
||||
* @extends {goog.labs.mock.MockManager_}
|
||||
* @private
|
||||
*/
|
||||
goog.labs.mock.MockObjectManager_ = function(objOrClass) {
|
||||
goog.labs.mock.MockObjectManager_.base(this, 'constructor');
|
||||
|
||||
/**
|
||||
* Proxies the calls to establish the first step of the stub bindings (object
|
||||
* and method name)
|
||||
* @private
|
||||
*/
|
||||
this.objectStubBinder_ = {};
|
||||
|
||||
this.mockee = objOrClass;
|
||||
|
||||
/**
|
||||
* The call verifier is used to verify the calls. It maps property names to
|
||||
* the method that does call verification.
|
||||
* @type {!Object<string, function(string, ...)>}
|
||||
* @private
|
||||
*/
|
||||
this.objectCallVerifier_ = {};
|
||||
|
||||
var obj;
|
||||
if (goog.isFunction(objOrClass)) {
|
||||
// Create a temporary subclass with a no-op constructor so that we can
|
||||
// create an instance and determine what methods it has.
|
||||
/**
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
var tempCtor = function() {};
|
||||
goog.inherits(tempCtor, objOrClass);
|
||||
obj = new tempCtor();
|
||||
} else {
|
||||
obj = objOrClass;
|
||||
}
|
||||
|
||||
// Put the object being mocked in the prototype chain of the mock so that
|
||||
// it has all the correct properties and instanceof works.
|
||||
/**
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
var mockedItemCtor = function() {};
|
||||
mockedItemCtor.prototype = obj;
|
||||
this.mockedItem = new mockedItemCtor();
|
||||
|
||||
var enumerableProperties = goog.object.getKeys(obj);
|
||||
// The non enumerable properties are added due to the fact that IE8 does not
|
||||
// enumerate any of the prototype Object functions even when overriden and
|
||||
// mocking these is sometimes needed.
|
||||
for (var i = 0; i < goog.labs.mock.PROTOTYPE_FIELDS_.length; i++) {
|
||||
var prop = goog.labs.mock.PROTOTYPE_FIELDS_[i];
|
||||
if (!goog.array.contains(enumerableProperties, prop)) {
|
||||
enumerableProperties.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the properties to the mock, creating a proxy stub for each method on
|
||||
// the instance.
|
||||
for (var i = 0; i < enumerableProperties.length; i++) {
|
||||
var prop = enumerableProperties[i];
|
||||
if (goog.isFunction(obj[prop])) {
|
||||
this.mockedItem[prop] = goog.bind(this.executeStub, this, prop);
|
||||
// The stub binder used to create bindings.
|
||||
this.objectStubBinder_[prop] =
|
||||
goog.bind(this.handleMockCall_, this, prop);
|
||||
// The verifier verifies the calls.
|
||||
this.objectCallVerifier_[prop] =
|
||||
goog.bind(this.verifyInvocation, this, prop);
|
||||
}
|
||||
}
|
||||
// The alias for stub binder exposed to the world.
|
||||
this.mockedItem.$stubBinder = this.objectStubBinder_;
|
||||
|
||||
// The alias for verifier for the world.
|
||||
this.mockedItem.$callVerifier = this.objectCallVerifier_;
|
||||
};
|
||||
goog.inherits(goog.labs.mock.MockObjectManager_,
|
||||
goog.labs.mock.MockManager_);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets up the spying behavior for the given object.
|
||||
*
|
||||
* @param {!Object} obj The object to be spied on.
|
||||
*
|
||||
* @constructor
|
||||
* @struct
|
||||
* @extends {goog.labs.mock.MockObjectManager_}
|
||||
* @private
|
||||
*/
|
||||
goog.labs.mock.MockSpyManager_ = function(obj) {
|
||||
goog.labs.mock.MockSpyManager_.base(this, 'constructor', obj);
|
||||
};
|
||||
goog.inherits(goog.labs.mock.MockSpyManager_,
|
||||
goog.labs.mock.MockObjectManager_);
|
||||
|
||||
|
||||
/**
|
||||
* Return a stub, if defined, for the method and arguments passed in. If we lack
|
||||
* a stub, instead look for a call record that matches the method and arguments.
|
||||
*
|
||||
* @return {!Function} The stub or the invocation logger, if defined.
|
||||
* @override
|
||||
*/
|
||||
goog.labs.mock.MockSpyManager_.prototype.getNextBinding =
|
||||
function(methodName, args) {
|
||||
var stub = goog.labs.mock.MockSpyManager_.base(
|
||||
this, 'getNextBinding', methodName, args);
|
||||
|
||||
if (!stub) {
|
||||
stub = goog.bind(this.mockee[methodName], this.mockee);
|
||||
}
|
||||
|
||||
return stub;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets up mock for the given function, stubbing out. By default, all stubs
|
||||
* return {@code undefined}, though stubs can be later defined using
|
||||
* {@code goog.labs.mock.when}.
|
||||
*
|
||||
* @param {!Function} func The function to set up the mock for.
|
||||
*
|
||||
* @constructor
|
||||
* @struct
|
||||
* @extends {goog.labs.mock.MockManager_}
|
||||
* @private
|
||||
*/
|
||||
goog.labs.mock.MockFunctionManager_ = function(func) {
|
||||
goog.labs.mock.MockFunctionManager_.base(this, 'constructor');
|
||||
|
||||
this.func_ = func;
|
||||
|
||||
/**
|
||||
* The stub binder used to create bindings.
|
||||
* Sets the first argument of handleMockCall_ to the function name.
|
||||
* @type {!Function}
|
||||
* @private
|
||||
*/
|
||||
this.functionStubBinder_ = this.useMockedFunctionName_(this.handleMockCall_);
|
||||
|
||||
this.mockedItem = this.useMockedFunctionName_(this.executeStub);
|
||||
this.mockedItem.$stubBinder = this.functionStubBinder_;
|
||||
|
||||
/**
|
||||
* The call verifier is used to verify function invocations.
|
||||
* Sets the first argument of verifyInvocation to the function name.
|
||||
* @type {!Function}
|
||||
*/
|
||||
this.mockedItem.$callVerifier =
|
||||
this.useMockedFunctionName_(this.verifyInvocation);
|
||||
};
|
||||
goog.inherits(goog.labs.mock.MockFunctionManager_,
|
||||
goog.labs.mock.MockManager_);
|
||||
|
||||
|
||||
/**
|
||||
* Given a method, returns a new function that calls the first one setting
|
||||
* the first argument to the mocked function name.
|
||||
* This is used to dynamically override the stub binders and call verifiers.
|
||||
* @private
|
||||
* @param {Function} nextFunc The function to override.
|
||||
* @return {!Function} The overloaded function.
|
||||
*/
|
||||
goog.labs.mock.MockFunctionManager_.prototype.useMockedFunctionName_ =
|
||||
function(nextFunc) {
|
||||
return goog.bind(function(var_args) {
|
||||
var args = goog.array.slice(arguments, 0);
|
||||
var name =
|
||||
'#mockFor<' + goog.labs.mock.getFunctionName_(this.func_) + '>';
|
||||
goog.array.insertAt(args, name, 0);
|
||||
return nextFunc.apply(this, args);
|
||||
}, this);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The stub binder is the object that helps define the stubs by binding
|
||||
* method name to the stub method.
|
||||
*
|
||||
* @param {!goog.labs.mock.MockManager_}
|
||||
* mockManager The mock manager.
|
||||
* @param {?string} name The method name.
|
||||
* @param {!Array<?>} args The other arguments to the method.
|
||||
*
|
||||
* @constructor
|
||||
* @struct
|
||||
* @private
|
||||
*/
|
||||
goog.labs.mock.StubBinder_ = function(mockManager, name, args) {
|
||||
/**
|
||||
* The mock manager instance.
|
||||
* @type {!goog.labs.mock.MockManager_}
|
||||
* @private
|
||||
*/
|
||||
this.mockManager_ = mockManager;
|
||||
|
||||
/**
|
||||
* Holds the name of the method to be bound.
|
||||
* @type {?string}
|
||||
* @private
|
||||
*/
|
||||
this.name_ = name;
|
||||
|
||||
/**
|
||||
* Holds the arguments for the method.
|
||||
* @type {!Array<?>}
|
||||
* @private
|
||||
*/
|
||||
this.args_ = args;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Defines the stub to be called for the method name and arguments bound
|
||||
* earlier.
|
||||
* TODO(user): Add support for the 'Answer' interface.
|
||||
*
|
||||
* @param {!Function} func The stub.
|
||||
*/
|
||||
goog.labs.mock.StubBinder_.prototype.then = function(func) {
|
||||
this.mockManager_.addBinding(this.name_, this.args_, func);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Defines the stub to return a specific value for a method name and arguments.
|
||||
*
|
||||
* @param {*} value The value to return.
|
||||
*/
|
||||
goog.labs.mock.StubBinder_.prototype.thenReturn = function(value) {
|
||||
this.mockManager_.addBinding(this.name_, this.args_,
|
||||
goog.functions.constant(value));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Facilitates (and is the first step in) setting up stubs. Obtains an object
|
||||
* on which, the method to be mocked is called to create a stub. Sample usage:
|
||||
*
|
||||
* var mockObj = goog.labs.mock.mock(objectBeingMocked);
|
||||
* goog.labs.mock.when(mockObj).getFoo(3).thenReturn(4);
|
||||
*
|
||||
* @param {!Object} mockObject The mocked object.
|
||||
* @return {!goog.labs.mock.StubBinder_} The property binder.
|
||||
*/
|
||||
goog.labs.mock.when = function(mockObject) {
|
||||
goog.asserts.assert(mockObject.$stubBinder, 'Stub binder cannot be null!');
|
||||
return mockObject.$stubBinder;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Represents a binding between a method name, args and a stub.
|
||||
*
|
||||
* @param {?string} methodName The name of the method being stubbed.
|
||||
* @param {!Array<?>} args The arguments passed to the method.
|
||||
* @param {!Function} stub The stub function to be called for the given method.
|
||||
* @constructor
|
||||
* @struct
|
||||
* @private
|
||||
*/
|
||||
goog.labs.mock.MethodBinding_ = function(methodName, args, stub) {
|
||||
/**
|
||||
* The name of the method being stubbed.
|
||||
* @type {?string}
|
||||
* @private
|
||||
*/
|
||||
this.methodName_ = methodName;
|
||||
|
||||
/**
|
||||
* The arguments for the method being stubbed.
|
||||
* @type {!Array<?>}
|
||||
* @private
|
||||
*/
|
||||
this.args_ = args;
|
||||
|
||||
/**
|
||||
* The stub function.
|
||||
* @type {!Function}
|
||||
* @private
|
||||
*/
|
||||
this.stub_ = stub;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Function} The stub to be executed.
|
||||
*/
|
||||
goog.labs.mock.MethodBinding_.prototype.getStub = function() {
|
||||
return this.stub_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @return {string} A readable string representation of the binding
|
||||
* as a method call.
|
||||
*/
|
||||
goog.labs.mock.MethodBinding_.prototype.toString = function() {
|
||||
return goog.labs.mock.formatMethodCall_(this.methodName_ || '', this.args_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The method name for this binding.
|
||||
*/
|
||||
goog.labs.mock.MethodBinding_.prototype.getMethodName = function() {
|
||||
return this.methodName_ || '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the given args match the stored args_. Used to determine
|
||||
* which stub to invoke for a method.
|
||||
*
|
||||
* @param {string} methodName The name of the method being stubbed.
|
||||
* @param {!Array<?>} args An array of arguments.
|
||||
* @param {boolean} isVerification Whether this is a function verification call
|
||||
* or not.
|
||||
* @return {boolean} If it matches the stored arguments.
|
||||
*/
|
||||
goog.labs.mock.MethodBinding_.prototype.matches = function(
|
||||
methodName, args, isVerification) {
|
||||
var specs = isVerification ? args : this.args_;
|
||||
var calls = isVerification ? this.args_ : args;
|
||||
|
||||
//TODO(user): More elaborate argument matching. Think about matching
|
||||
// objects.
|
||||
return this.methodName_ == methodName &&
|
||||
goog.array.equals(calls, specs, function(arg, spec) {
|
||||
// Duck-type to see if this is an object that implements the
|
||||
// goog.labs.testing.Matcher interface.
|
||||
if (goog.isFunction(spec.matches)) {
|
||||
return spec.matches(arg);
|
||||
} else {
|
||||
return goog.array.defaultCompareEquality(spec, arg);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<title>
|
||||
Closure Unit Tests - goog.labs.mock
|
||||
</title>
|
||||
<script src="../../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.labs.mockTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,517 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
goog.provide('goog.labs.mockTest');
|
||||
goog.setTestOnly('goog.labs.mockTest');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.labs.mock');
|
||||
goog.require('goog.labs.mock.VerificationError');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('goog.labs.testing.AnythingMatcher');
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('goog.labs.testing.GreaterThanMatcher');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
var ParentClass = function() {};
|
||||
ParentClass.prototype.method1 = function() {};
|
||||
ParentClass.prototype.x = 1;
|
||||
ParentClass.prototype.val = 0;
|
||||
ParentClass.prototype.incrementVal = function() { this.val++; };
|
||||
|
||||
var ChildClass = function() {};
|
||||
goog.inherits(ChildClass, ParentClass);
|
||||
ChildClass.prototype.method2 = function() {};
|
||||
ChildClass.prototype.y = 2;
|
||||
|
||||
function testParentClass() {
|
||||
var parentMock = goog.labs.mock.mock(ParentClass);
|
||||
|
||||
assertNotUndefined(parentMock.method1);
|
||||
assertUndefined(parentMock.method1());
|
||||
assertUndefined(parentMock.method2);
|
||||
assertNotUndefined(parentMock.x);
|
||||
assertUndefined(parentMock.y);
|
||||
assertTrue('Mock should be an instance of the mocked class.',
|
||||
parentMock instanceof ParentClass);
|
||||
}
|
||||
|
||||
function testChildClass() {
|
||||
var childMock = goog.labs.mock.mock(ChildClass);
|
||||
|
||||
assertNotUndefined(childMock.method1);
|
||||
assertUndefined(childMock.method1());
|
||||
assertNotUndefined(childMock.method2);
|
||||
assertUndefined(childMock.method2());
|
||||
assertNotUndefined(childMock.x);
|
||||
assertNotUndefined(childMock.y);
|
||||
assertTrue('Mock should be an instance of the mocked class.',
|
||||
childMock instanceof ChildClass);
|
||||
}
|
||||
|
||||
function testParentClassInstance() {
|
||||
var parentMock = goog.labs.mock.mock(new ParentClass());
|
||||
|
||||
assertNotUndefined(parentMock.method1);
|
||||
assertUndefined(parentMock.method1());
|
||||
assertUndefined(parentMock.method2);
|
||||
assertNotUndefined(parentMock.x);
|
||||
assertUndefined(parentMock.y);
|
||||
assertTrue('Mock should be an instance of the mocked class.',
|
||||
parentMock instanceof ParentClass);
|
||||
}
|
||||
|
||||
function testChildClassInstance() {
|
||||
var childMock = goog.labs.mock.mock(new ChildClass());
|
||||
|
||||
assertNotUndefined(childMock.method1);
|
||||
assertUndefined(childMock.method1());
|
||||
assertNotUndefined(childMock.method2);
|
||||
assertUndefined(childMock.method2());
|
||||
assertNotUndefined(childMock.x);
|
||||
assertNotUndefined(childMock.y);
|
||||
assertTrue('Mock should be an instance of the mocked class.',
|
||||
childMock instanceof ParentClass);
|
||||
}
|
||||
|
||||
function testNonEnumerableProperties() {
|
||||
var mockObject = goog.labs.mock.mock({});
|
||||
assertNotUndefined(mockObject.toString);
|
||||
goog.labs.mock.when(mockObject).toString().then(function() {
|
||||
return 'toString';
|
||||
});
|
||||
assertEquals('toString', mockObject.toString());
|
||||
}
|
||||
|
||||
function testBasicStubbing() {
|
||||
var obj = {
|
||||
method1: function(i) {
|
||||
return 2 * i;
|
||||
},
|
||||
method2: function(i, str) {
|
||||
return str;
|
||||
},
|
||||
method3: function(x) {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
var mockObj = goog.labs.mock.mock(obj);
|
||||
goog.labs.mock.when(mockObj).method1(2).then(function(i) {return i;});
|
||||
|
||||
assertEquals(4, obj.method1(2));
|
||||
assertEquals(2, mockObj.method1(2));
|
||||
assertUndefined(mockObj.method1(4));
|
||||
|
||||
goog.labs.mock.when(mockObj).method2(1, 'hi').then(function(i) {return 'oh'});
|
||||
assertEquals('hi', obj.method2(1, 'hi'));
|
||||
assertEquals('oh', mockObj.method2(1, 'hi'));
|
||||
assertUndefined(mockObj.method2(3, 'foo'));
|
||||
|
||||
goog.labs.mock.when(mockObj).method3(4).thenReturn(10);
|
||||
assertEquals(4, obj.method3(4));
|
||||
assertEquals(10, mockObj.method3(4));
|
||||
goog.labs.mock.verify(mockObj).method3(4);
|
||||
assertUndefined(mockObj.method3(5));
|
||||
}
|
||||
|
||||
function testMockFunctions() {
|
||||
function x(i) { return i; }
|
||||
|
||||
var mockedFunc = goog.labs.mock.mockFunction(x);
|
||||
goog.labs.mock.when(mockedFunc)(100).thenReturn(10);
|
||||
goog.labs.mock.when(mockedFunc)(50).thenReturn(25);
|
||||
|
||||
assertEquals(100, x(100));
|
||||
assertEquals(10, mockedFunc(100));
|
||||
assertEquals(25, mockedFunc(50));
|
||||
}
|
||||
|
||||
function testStubbingConsecutiveCalls() {
|
||||
var obj = {
|
||||
method: function(i) {
|
||||
return i * 42;
|
||||
}
|
||||
};
|
||||
|
||||
var mockObj = goog.labs.mock.mock(obj);
|
||||
goog.labs.mock.when(mockObj).method(1).thenReturn(3);
|
||||
goog.labs.mock.when(mockObj).method(1).thenReturn(4);
|
||||
|
||||
assertEquals(42, obj.method(1));
|
||||
assertEquals(3, mockObj.method(1));
|
||||
assertEquals(4, mockObj.method(1));
|
||||
assertEquals(4, mockObj.method(1));
|
||||
|
||||
var x = function(i) { return i; };
|
||||
var mockedFunc = goog.labs.mock.mockFunction(x);
|
||||
goog.labs.mock.when(mockedFunc)(100).thenReturn(10);
|
||||
goog.labs.mock.when(mockedFunc)(100).thenReturn(25);
|
||||
|
||||
assertEquals(100, x(100));
|
||||
assertEquals(10, mockedFunc(100));
|
||||
assertEquals(25, mockedFunc(100));
|
||||
assertEquals(25, mockedFunc(100));
|
||||
}
|
||||
|
||||
function testSpying() {
|
||||
var obj = {
|
||||
method1: function(i) {
|
||||
return 2 * i;
|
||||
},
|
||||
method2: function(i) {
|
||||
return 5 * i;
|
||||
}
|
||||
};
|
||||
|
||||
var spyObj = goog.labs.mock.spy(obj);
|
||||
goog.labs.mock.when(spyObj).method1(2).thenReturn(5);
|
||||
|
||||
assertEquals(2, obj.method1(1));
|
||||
assertEquals(5, spyObj.method1(2));
|
||||
goog.labs.mock.verify(spyObj).method1(2);
|
||||
assertEquals(2, spyObj.method1(1));
|
||||
goog.labs.mock.verify(spyObj).method1(1);
|
||||
assertEquals(20, spyObj.method2(4));
|
||||
goog.labs.mock.verify(spyObj).method2(4);
|
||||
}
|
||||
|
||||
function testSpyParentClassInstance() {
|
||||
var parent = new ParentClass();
|
||||
var parentMock = goog.labs.mock.spy(parent);
|
||||
|
||||
assertNotUndefined(parentMock.method1);
|
||||
assertUndefined(parentMock.method1());
|
||||
assertUndefined(parentMock.method2);
|
||||
assertNotUndefined(parentMock.x);
|
||||
assertUndefined(parentMock.y);
|
||||
assertTrue('Mock should be an instance of the mocked class.',
|
||||
parentMock instanceof ParentClass);
|
||||
var incrementedOrigVal = parent.val + 1;
|
||||
parentMock.incrementVal();
|
||||
assertEquals('Changes in the spied object should reflect in the spy.',
|
||||
incrementedOrigVal, parentMock.val);
|
||||
}
|
||||
|
||||
function testSpyChildClassInstance() {
|
||||
var child = new ChildClass();
|
||||
var childMock = goog.labs.mock.spy(child);
|
||||
|
||||
assertNotUndefined(childMock.method1);
|
||||
assertUndefined(childMock.method1());
|
||||
assertNotUndefined(childMock.method2);
|
||||
assertUndefined(childMock.method2());
|
||||
assertNotUndefined(childMock.x);
|
||||
assertNotUndefined(childMock.y);
|
||||
assertTrue('Mock should be an instance of the mocked class.',
|
||||
childMock instanceof ParentClass);
|
||||
var incrementedOrigVal = child.val + 1;
|
||||
childMock.incrementVal();
|
||||
assertEquals('Changes in the spied object should reflect in the spy.',
|
||||
incrementedOrigVal, childMock.val);
|
||||
}
|
||||
|
||||
function testVerifyForObjects() {
|
||||
var obj = {
|
||||
method1: function(i) {
|
||||
return 2 * i;
|
||||
},
|
||||
method2: function(i) {
|
||||
return 5 * i;
|
||||
}
|
||||
};
|
||||
|
||||
var mockObj = goog.labs.mock.mock(obj);
|
||||
goog.labs.mock.when(mockObj).method1(2).thenReturn(5);
|
||||
|
||||
assertEquals(5, mockObj.method1(2));
|
||||
goog.labs.mock.verify(mockObj).method1(2);
|
||||
var e = assertThrows(goog.bind(goog.labs.mock.verify(mockObj).method1, 2));
|
||||
assertTrue(e instanceof goog.labs.mock.VerificationError);
|
||||
}
|
||||
|
||||
function testVerifyForFunctions() {
|
||||
var func = function(i) {
|
||||
return i;
|
||||
};
|
||||
|
||||
var mockFunc = goog.labs.mock.mockFunction(func);
|
||||
goog.labs.mock.when(mockFunc)(2).thenReturn(55);
|
||||
assertEquals(55, mockFunc(2));
|
||||
goog.labs.mock.verify(mockFunc)(2);
|
||||
goog.labs.mock.verify(mockFunc)(lessThan(3));
|
||||
|
||||
var e = assertThrows(goog.bind(goog.labs.mock.verify(mockFunc), 3));
|
||||
assertTrue(e instanceof goog.labs.mock.VerificationError);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When a function invocation verification fails, it should show the failed
|
||||
* expectation call, as well as the recorded calls to the same method.
|
||||
*/
|
||||
function testVerificationErrorMessages() {
|
||||
var mock = goog.labs.mock.mock({
|
||||
method: function(i) {
|
||||
return i;
|
||||
}
|
||||
});
|
||||
|
||||
// Failure when there are no recorded calls.
|
||||
var e = assertThrows(function() { goog.labs.mock.verify(mock).method(4); });
|
||||
assertTrue(e instanceof goog.labs.mock.VerificationError);
|
||||
var expected = '\nExpected: method(4)\n' +
|
||||
'Recorded: No recorded calls';
|
||||
assertEquals(expected, e.message);
|
||||
|
||||
|
||||
// Failure when there are recorded calls with ints and functions
|
||||
// as arguments.
|
||||
var callback = function() {};
|
||||
var callbackId = goog.labs.mock.getUid(callback);
|
||||
|
||||
mock.method(1);
|
||||
mock.method(2);
|
||||
mock.method(callback);
|
||||
|
||||
e = assertThrows(function() { goog.labs.mock.verify(mock).method(3); });
|
||||
assertTrue(e instanceof goog.labs.mock.VerificationError);
|
||||
|
||||
expected = '\nExpected: method(3)\n' +
|
||||
'Recorded: method(1),\n' +
|
||||
' method(2),\n' +
|
||||
' method(<function #anonymous' + callbackId + '>)';
|
||||
assertEquals(expected, e.message);
|
||||
|
||||
// With mockFunctions
|
||||
var mockCallback = goog.labs.mock.mockFunction(callback);
|
||||
e = assertThrows(function() { goog.labs.mock.verify(mockCallback)(5);});
|
||||
expected = '\nExpected: #mockFor<#anonymous' + callbackId + '>(5)\n' +
|
||||
'Recorded: No recorded calls';
|
||||
|
||||
mockCallback(8);
|
||||
goog.labs.mock.verify(mockCallback)(8);
|
||||
assertEquals(expected, e.message);
|
||||
|
||||
// Objects with circular references should not fail.
|
||||
var obj = {x: 1};
|
||||
obj.y = obj;
|
||||
|
||||
mockCallback(obj);
|
||||
e = assertThrows(function() { goog.labs.mock.verify(mockCallback)(5);});
|
||||
assertTrue(e instanceof goog.labs.mock.VerificationError);
|
||||
|
||||
// Should respect string representation of different custom classes.
|
||||
var myClass = function() {};
|
||||
myClass.prototype.toString = function() { return '<superClass>'; };
|
||||
|
||||
var mockFunction = goog.labs.mock.mockFunction(function f() {});
|
||||
mockFunction(new myClass());
|
||||
|
||||
e = assertThrows(function() { goog.labs.mock.verify(mockFunction)(5);});
|
||||
expected = '\nExpected: #mockFor<f>(5)\n' +
|
||||
'Recorded: #mockFor<f>(<superClass>)';
|
||||
assertEquals(expected, e.message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Asserts that the given string contains a list of others strings
|
||||
* in the given order.
|
||||
*/
|
||||
function assertContainsInOrder(str, var_args) {
|
||||
var expected = goog.array.splice(arguments, 1);
|
||||
var indices = goog.array.map(expected, function(val) {
|
||||
return str.indexOf(val);
|
||||
});
|
||||
|
||||
for (var i = 0; i < expected.length; i++) {
|
||||
var msg = 'Missing "' + expected[i] + '" from "' + str + '"';
|
||||
assertTrue(msg, indices[i] != -1);
|
||||
|
||||
if (i > 0) {
|
||||
msg = '"' + expected[i - 1] + '" should come before "' + expected[i] +
|
||||
'" in "' + str + '"';
|
||||
assertTrue(msg, indices[i] > indices[i - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testMatchers() {
|
||||
var obj = {
|
||||
method1: function(i) {
|
||||
return 2 * i;
|
||||
},
|
||||
method2: function(i) {
|
||||
return 5 * i;
|
||||
}
|
||||
};
|
||||
|
||||
var mockObj = goog.labs.mock.mock(obj);
|
||||
|
||||
goog.labs.mock.when(mockObj).method1(greaterThan(4)).thenReturn(100);
|
||||
goog.labs.mock.when(mockObj).method1(lessThan(4)).thenReturn(40);
|
||||
|
||||
assertEquals(100, mockObj.method1(5));
|
||||
assertEquals(100, mockObj.method1(6));
|
||||
assertEquals(40, mockObj.method1(2));
|
||||
assertEquals(40, mockObj.method1(1));
|
||||
assertUndefined(mockObj.method1(4));
|
||||
}
|
||||
|
||||
function testMatcherVerify() {
|
||||
var obj = {
|
||||
method: function(i) {
|
||||
return 2 * i;
|
||||
}
|
||||
};
|
||||
|
||||
// Using spy objects.
|
||||
var spy = goog.labs.mock.spy(obj);
|
||||
|
||||
spy.method(6);
|
||||
|
||||
goog.labs.mock.verify(spy).method(greaterThan(4));
|
||||
var e = assertThrows(
|
||||
goog.bind(goog.labs.mock.verify(spy).method, lessThan(4)));
|
||||
assertTrue(e instanceof goog.labs.mock.VerificationError);
|
||||
|
||||
// Using mocks
|
||||
var mockObj = goog.labs.mock.mock(obj);
|
||||
|
||||
mockObj.method(8);
|
||||
|
||||
goog.labs.mock.verify(mockObj).method(greaterThan(7));
|
||||
var e = assertThrows(
|
||||
goog.bind(goog.labs.mock.verify(mockObj).method, lessThan(7)));
|
||||
assertTrue(e instanceof goog.labs.mock.VerificationError);
|
||||
}
|
||||
|
||||
function testMatcherVerifyCollision() {
|
||||
var obj = {
|
||||
method: function(i) {
|
||||
return 2 * i;
|
||||
}
|
||||
};
|
||||
var mockObj = goog.labs.mock.mock(obj);
|
||||
|
||||
goog.labs.mock.when(mockObj).method(5).thenReturn(100);
|
||||
assertNotEquals(100, mockObj.method(greaterThan(2)));
|
||||
}
|
||||
|
||||
function testMatcherVerifyCollisionBetweenMatchers() {
|
||||
var obj = {
|
||||
method: function(i) {
|
||||
return 2 * i;
|
||||
}
|
||||
};
|
||||
var mockObj = goog.labs.mock.mock(obj);
|
||||
|
||||
goog.labs.mock.when(mockObj).method(anything()).thenReturn(100);
|
||||
|
||||
var e = assertThrows(
|
||||
goog.bind(goog.labs.mock.verify(mockObj).method, anything()));
|
||||
assertTrue(e instanceof goog.labs.mock.VerificationError);
|
||||
}
|
||||
|
||||
function testVerifyForUnmockedMethods() {
|
||||
var Task = function() {};
|
||||
Task.prototype.run = function() {};
|
||||
|
||||
var mockTask = goog.labs.mock.mock(Task);
|
||||
mockTask.run();
|
||||
|
||||
goog.labs.mock.verify(mockTask).run();
|
||||
}
|
||||
|
||||
function testFormatMethodCall() {
|
||||
var formatMethodCall = goog.labs.mock.formatMethodCall_;
|
||||
assertEquals('alert()', formatMethodCall('alert'));
|
||||
assertEquals('sum(2, 4)', formatMethodCall('sum', [2, 4]));
|
||||
assertEquals('sum("2", "4")', formatMethodCall('sum', ['2', '4']));
|
||||
assertEquals('call(<function unicorn>)',
|
||||
formatMethodCall('call', [function unicorn() {}]));
|
||||
|
||||
var arg = {x: 1, y: {hello: 'world'}};
|
||||
assertEquals('call(' + goog.labs.mock.formatValue_(arg) + ')',
|
||||
formatMethodCall('call', [arg]));
|
||||
}
|
||||
|
||||
function testGetFunctionName() {
|
||||
var f1 = function() {};
|
||||
var f2 = function() {};
|
||||
var named = function myName() {};
|
||||
|
||||
assert(goog.string.startsWith(
|
||||
goog.labs.mock.getFunctionName_(f1), '#anonymous'));
|
||||
assert(goog.string.startsWith(
|
||||
goog.labs.mock.getFunctionName_(f2), '#anonymous'));
|
||||
assertNotEquals(
|
||||
goog.labs.mock.getFunctionName_(f1), goog.labs.mock.getFunctionName_(f2));
|
||||
assertEquals('myName', goog.labs.mock.getFunctionName_(named));
|
||||
}
|
||||
|
||||
function testFormatObject() {
|
||||
var obj, obj2, obj3;
|
||||
|
||||
obj = {x: 1};
|
||||
assertEquals(
|
||||
'{"x":1 _id:' + goog.labs.mock.getUid(obj) + '}',
|
||||
goog.labs.mock.formatValue_(obj)
|
||||
);
|
||||
assertEquals('{"x":1}', goog.labs.mock.formatValue_(obj, false /* id */));
|
||||
|
||||
obj = {x: 'hello'};
|
||||
assertEquals(
|
||||
'{"x":"hello" _id:' + goog.labs.mock.getUid(obj) + '}',
|
||||
goog.labs.mock.formatValue_(obj)
|
||||
);
|
||||
assertEquals('{"x":"hello"}',
|
||||
goog.labs.mock.formatValue_(obj, false /* id */));
|
||||
|
||||
obj3 = {};
|
||||
obj2 = {y: obj3};
|
||||
obj3.x = obj2;
|
||||
assertEquals(
|
||||
'{"x":{"y":<recursive/dupe obj_' + goog.labs.mock.getUid(obj3) + '> ' +
|
||||
'_id:' + goog.labs.mock.getUid(obj2) + '} ' +
|
||||
'_id:' + goog.labs.mock.getUid(obj3) + '}',
|
||||
goog.labs.mock.formatValue_(obj3)
|
||||
);
|
||||
assertEquals('{"x":{"y":<recursive/dupe>}}',
|
||||
goog.labs.mock.formatValue_(obj3, false /* id */)
|
||||
);
|
||||
|
||||
|
||||
obj = {x: function y() {} };
|
||||
assertEquals('{"x":<function y> _id:' + goog.labs.mock.getUid(obj) + '}',
|
||||
goog.labs.mock.formatValue_(obj));
|
||||
assertEquals('{"x":<function y>}',
|
||||
goog.labs.mock.formatValue_(obj, false /* id */));
|
||||
|
||||
}
|
||||
|
||||
function testGetUid() {
|
||||
var obj1 = {};
|
||||
var obj2 = {};
|
||||
var func1 = function() {};
|
||||
var func2 = function() {};
|
||||
|
||||
assertNotEquals(goog.labs.mock.getUid(obj1), goog.labs.mock.getUid(obj2));
|
||||
assertNotEquals(goog.labs.mock.getUid(func1), goog.labs.mock.getUid(func2));
|
||||
assertNotEquals(goog.labs.mock.getUid(obj1), goog.labs.mock.getUid(func2));
|
||||
assertEquals(goog.labs.mock.getUid(obj1), goog.labs.mock.getUid(obj1));
|
||||
assertEquals(goog.labs.mock.getUid(func1), goog.labs.mock.getUid(func1));
|
||||
}
|
||||
Reference in New Issue
Block a user