| Index: chrome/third_party/mock4js/mock4js.js | 
| diff --git a/chrome/third_party/mock4js/mock4js.js b/chrome/third_party/mock4js/mock4js.js | 
| index 933e0a658bb1f0bb5bc8bf6a3569b4556c1cae75..98e5aa000d71c96801e01172e35cf5edf61ae531 100644 | 
| --- a/chrome/third_party/mock4js/mock4js.js | 
| +++ b/chrome/third_party/mock4js/mock4js.js | 
| @@ -1,625 +1,625 @@ | 
| -/** | 
| - * Mock4JS 0.2 | 
| - * http://mock4js.sourceforge.net/ | 
| - */ | 
| - | 
| -Mock4JS = { | 
| -	_mocksToVerify: [], | 
| -	_convertToConstraint: function(constraintOrValue) { | 
| -		if(constraintOrValue.argumentMatches) { | 
| -			return constraintOrValue; // it's already an ArgumentMatcher | 
| -		} else { | 
| -			return new MatchExactly(constraintOrValue);	// default to eq(...) | 
| -		} | 
| -	}, | 
| -	addMockSupport: function(object) { | 
| -		// mock creation | 
| -		object.mock = function(mockedType) { | 
| -			if(!mockedType) { | 
| -				throw new Mock4JSException("Cannot create mock: type to mock cannot be found or is null"); | 
| -			} | 
| -			var newMock = new Mock(mockedType); | 
| -			Mock4JS._mocksToVerify.push(newMock); | 
| -			return newMock; | 
| -		} | 
| - | 
| -		// syntactic sugar for expects() | 
| -		object.once = function() { | 
| -			return new CallCounter(1); | 
| -		} | 
| -		object.never = function() { | 
| -			return new CallCounter(0); | 
| -		} | 
| -		object.exactly = function(expectedCallCount) { | 
| -			return new CallCounter(expectedCallCount); | 
| -		} | 
| -		object.atLeastOnce = function() { | 
| -			return new InvokeAtLeastOnce(); | 
| -		} | 
| - | 
| -		// syntactic sugar for argument expectations | 
| -		object.ANYTHING = new MatchAnything(); | 
| -		object.NOT_NULL = new MatchAnythingBut(new MatchExactly(null)); | 
| -		object.NOT_UNDEFINED = new MatchAnythingBut(new MatchExactly(undefined)); | 
| -		object.eq = function(expectedValue) { | 
| -			return new MatchExactly(expectedValue); | 
| -		} | 
| -		object.not = function(valueNotExpected) { | 
| -			var argConstraint = Mock4JS._convertToConstraint(valueNotExpected); | 
| -			return new MatchAnythingBut(argConstraint); | 
| -		} | 
| -		object.and = function() { | 
| -			var constraints = []; | 
| -			for(var i=0; i<arguments.length; i++) { | 
| -				constraints[i] = Mock4JS._convertToConstraint(arguments[i]); | 
| -			} | 
| -			return new MatchAllOf(constraints); | 
| -		} | 
| -		object.or = function() { | 
| -			var constraints = []; | 
| -			for(var i=0; i<arguments.length; i++) { | 
| -				constraints[i] = Mock4JS._convertToConstraint(arguments[i]); | 
| -			} | 
| -			return new MatchAnyOf(constraints); | 
| -		} | 
| -		object.stringContains = function(substring) { | 
| -			return new MatchStringContaining(substring); | 
| -		} | 
| - | 
| -		// syntactic sugar for will() | 
| -		object.returnValue = function(value) { | 
| -			return new ReturnValueAction(value); | 
| -		} | 
| -		object.throwException = function(exception) { | 
| -			return new ThrowExceptionAction(exception); | 
| -		} | 
| -	}, | 
| -	clearMocksToVerify: function() { | 
| -		Mock4JS._mocksToVerify = []; | 
| -	}, | 
| -	verifyAllMocks: function() { | 
| -		for(var i=0; i<Mock4JS._mocksToVerify.length; i++) { | 
| -			Mock4JS._mocksToVerify[i].verify(); | 
| -		} | 
| -	} | 
| -} | 
| - | 
| -Mock4JSUtil = { | 
| -	hasFunction: function(obj, methodName) { | 
| -		return typeof obj == 'object' && typeof obj[methodName] == 'function'; | 
| -	}, | 
| -	join: function(list) { | 
| -		var result = ""; | 
| -		for(var i=0; i<list.length; i++) { | 
| -			var item = list[i]; | 
| -			if(Mock4JSUtil.hasFunction(item, "describe")) { | 
| -				result += item.describe(); | 
| -			} | 
| -			else if(typeof list[i] == 'string') { | 
| -				result += "\""+list[i]+"\""; | 
| -			} else { | 
| -				result += list[i]; | 
| -			} | 
| - | 
| -			if(i<list.length-1) result += ", "; | 
| -		} | 
| -		return result; | 
| -	} | 
| -} | 
| - | 
| -Mock4JSException = function(message) { | 
| -	this.message = message; | 
| -} | 
| - | 
| -Mock4JSException.prototype = { | 
| -	toString: function() { | 
| -		return this.message; | 
| -	} | 
| -} | 
| - | 
| -/** | 
| - * Assert function that makes use of the constraint methods | 
| - */ | 
| -assertThat = function(expected, argumentMatcher) { | 
| -	if(!argumentMatcher.argumentMatches(expected)) { | 
| -		fail("Expected '"+expected+"' to be "+argumentMatcher.describe()); | 
| -	} | 
| -} | 
| - | 
| -/** | 
| - * CallCounter | 
| - */ | 
| -function CallCounter(expectedCount) { | 
| -	this._expectedCallCount = expectedCount; | 
| -	this._actualCallCount = 0; | 
| -} | 
| - | 
| -CallCounter.prototype = { | 
| -	addActualCall: function() { | 
| -		this._actualCallCount++; | 
| -		if(this._actualCallCount > this._expectedCallCount) { | 
| -			throw new Mock4JSException("unexpected invocation"); | 
| -		} | 
| -	}, | 
| - | 
| -	verify: function() { | 
| -		if(this._actualCallCount < this._expectedCallCount) { | 
| -			throw new Mock4JSException("expected method was not invoked the expected number of times"); | 
| -		} | 
| -	}, | 
| - | 
| -	describe: function() { | 
| -		if(this._expectedCallCount == 0) { | 
| -			return "not expected"; | 
| -		} else if(this._expectedCallCount == 1) { | 
| -			var msg = "expected once"; | 
| -			if(this._actualCallCount >= 1) { | 
| -				msg += " and has been invoked"; | 
| -			} | 
| -			return msg; | 
| -		} else { | 
| -			var msg = "expected "+this._expectedCallCount+" times"; | 
| -			if(this._actualCallCount > 0) { | 
| -				msg += ", invoked "+this._actualCallCount + " times"; | 
| -			} | 
| -			return msg; | 
| -		} | 
| -	} | 
| -} | 
| - | 
| -function InvokeAtLeastOnce() { | 
| -	this._hasBeenInvoked = false; | 
| -} | 
| - | 
| -InvokeAtLeastOnce.prototype = { | 
| -	addActualCall: function() { | 
| -		this._hasBeenInvoked = true; | 
| -	}, | 
| - | 
| -	verify: function() { | 
| -		if(this._hasBeenInvoked === false) { | 
| -			throw new Mock4JSException(describe()); | 
| -		} | 
| -	}, | 
| - | 
| -	describe: function() { | 
| -		var desc = "expected at least once"; | 
| -		if(this._hasBeenInvoked) desc+=" and has been invoked"; | 
| -		return desc; | 
| -	} | 
| -} | 
| - | 
| -/** | 
| - * ArgumentMatchers | 
| - */ | 
| - | 
| -function MatchExactly(expectedValue) { | 
| -	this._expectedValue = expectedValue; | 
| -} | 
| - | 
| -MatchExactly.prototype = { | 
| -	argumentMatches: function(actualArgument) { | 
| -		if(this._expectedValue instanceof Array) { | 
| -			if(!(actualArgument instanceof Array)) return false; | 
| -			if(this._expectedValue.length != actualArgument.length) return false; | 
| -			for(var i=0; i<this._expectedValue.length; i++) { | 
| -				if(this._expectedValue[i] != actualArgument[i]) return false; | 
| -			} | 
| -			return true; | 
| -		} else { | 
| -			return this._expectedValue == actualArgument; | 
| -		} | 
| -	}, | 
| -	describe: function() { | 
| -		if(typeof this._expectedValue == "string") { | 
| -			return "eq(\""+this._expectedValue+"\")"; | 
| -		} else { | 
| -			return "eq("+this._expectedValue+")"; | 
| -		} | 
| -	} | 
| -} | 
| - | 
| -function MatchAnything() { | 
| -} | 
| - | 
| -MatchAnything.prototype = { | 
| -	argumentMatches: function(actualArgument) { | 
| -		return true; | 
| -	}, | 
| -	describe: function() { | 
| -		return "ANYTHING"; | 
| -	} | 
| -} | 
| - | 
| -function MatchAnythingBut(matcherToNotMatch) { | 
| -	this._matcherToNotMatch = matcherToNotMatch; | 
| -} | 
| - | 
| -MatchAnythingBut.prototype = { | 
| -	argumentMatches: function(actualArgument) { | 
| -		return !this._matcherToNotMatch.argumentMatches(actualArgument); | 
| -	}, | 
| -	describe: function() { | 
| -		return "not("+this._matcherToNotMatch.describe()+")"; | 
| -	} | 
| -} | 
| - | 
| -function MatchAllOf(constraints) { | 
| -	this._constraints = constraints; | 
| -} | 
| - | 
| - | 
| -MatchAllOf.prototype = { | 
| -	argumentMatches: function(actualArgument) { | 
| -		for(var i=0; i<this._constraints.length; i++) { | 
| -			var constraint = this._constraints[i]; | 
| -			if(!constraint.argumentMatches(actualArgument)) return false; | 
| -		} | 
| -		return true; | 
| -	}, | 
| -	describe: function() { | 
| -		return "and("+Mock4JSUtil.join(this._constraints)+")"; | 
| -	} | 
| -} | 
| - | 
| -function MatchAnyOf(constraints) { | 
| -	this._constraints = constraints; | 
| -} | 
| - | 
| -MatchAnyOf.prototype = { | 
| -	argumentMatches: function(actualArgument) { | 
| -		for(var i=0; i<this._constraints.length; i++) { | 
| -			var constraint = this._constraints[i]; | 
| -			if(constraint.argumentMatches(actualArgument)) return true; | 
| -		} | 
| -		return false; | 
| -	}, | 
| -	describe: function() { | 
| -		return "or("+Mock4JSUtil.join(this._constraints)+")"; | 
| -	} | 
| -} | 
| - | 
| - | 
| -function MatchStringContaining(stringToLookFor) { | 
| -	this._stringToLookFor = stringToLookFor; | 
| -} | 
| - | 
| -MatchStringContaining.prototype = { | 
| -	argumentMatches: function(actualArgument) { | 
| -		if(typeof actualArgument != 'string') throw new Mock4JSException("stringContains() must be given a string, actually got a "+(typeof actualArgument)); | 
| -		return (actualArgument.indexOf(this._stringToLookFor) != -1); | 
| -	}, | 
| -	describe: function() { | 
| -		return "a string containing \""+this._stringToLookFor+"\""; | 
| -	} | 
| -} | 
| - | 
| - | 
| -/** | 
| - * StubInvocation | 
| - */ | 
| -function StubInvocation(expectedMethodName, expectedArgs, actionSequence) { | 
| -	this._expectedMethodName = expectedMethodName; | 
| -	this._expectedArgs = expectedArgs; | 
| -	this._actionSequence = actionSequence; | 
| -} | 
| - | 
| -StubInvocation.prototype = { | 
| -	matches: function(invokedMethodName, invokedMethodArgs) { | 
| -		if (invokedMethodName != this._expectedMethodName) { | 
| -			return false; | 
| -		} | 
| - | 
| -		if (invokedMethodArgs.length != this._expectedArgs.length) { | 
| -			return false; | 
| -		} | 
| - | 
| -		for(var i=0; i<invokedMethodArgs.length; i++) { | 
| -			var expectedArg = this._expectedArgs[i]; | 
| -			var invokedArg = invokedMethodArgs[i]; | 
| -			if(!expectedArg.argumentMatches(invokedArg)) { | 
| -				return false; | 
| -			} | 
| -		} | 
| - | 
| -		return true; | 
| -	}, | 
| - | 
| -	invoked: function() { | 
| -		try { | 
| -			return this._actionSequence.invokeNextAction(); | 
| -		} catch(e) { | 
| -			if(e instanceof Mock4JSException) { | 
| -				throw new Mock4JSException(this.describeInvocationNameAndArgs()+" - "+e.message); | 
| -			} else { | 
| -				throw e; | 
| -			} | 
| -		} | 
| -	}, | 
| - | 
| -	will: function() { | 
| -		this._actionSequence.addAll.apply(this._actionSequence, arguments); | 
| -	}, | 
| - | 
| -	describeInvocationNameAndArgs: function() { | 
| -		return this._expectedMethodName+"("+Mock4JSUtil.join(this._expectedArgs)+")"; | 
| -	}, | 
| - | 
| -	describe: function() { | 
| -		return "stub: "+this.describeInvocationNameAndArgs(); | 
| -	}, | 
| - | 
| -	verify: function() { | 
| -	} | 
| -} | 
| - | 
| -/** | 
| - * ExpectedInvocation | 
| - */ | 
| -function ExpectedInvocation(expectedMethodName, expectedArgs, expectedCallCounter) { | 
| -	this._stubInvocation = new StubInvocation(expectedMethodName, expectedArgs, new ActionSequence()); | 
| -	this._expectedCallCounter = expectedCallCounter; | 
| -} | 
| - | 
| -ExpectedInvocation.prototype = { | 
| -	matches: function(invokedMethodName, invokedMethodArgs) { | 
| -		try { | 
| -			return this._stubInvocation.matches(invokedMethodName, invokedMethodArgs); | 
| -		} catch(e) { | 
| -			throw new Mock4JSException("method "+this._stubInvocation.describeInvocationNameAndArgs()+": "+e.message); | 
| -		} | 
| -	}, | 
| - | 
| -	invoked: function() { | 
| -		try { | 
| -			this._expectedCallCounter.addActualCall(); | 
| -		} catch(e) { | 
| -			throw new Mock4JSException(e.message+": "+this._stubInvocation.describeInvocationNameAndArgs()); | 
| -		} | 
| -		return this._stubInvocation.invoked(); | 
| -	}, | 
| - | 
| -	will: function() { | 
| -		this._stubInvocation.will.apply(this._stubInvocation, arguments); | 
| -	}, | 
| - | 
| -	describe: function() { | 
| -		return this._expectedCallCounter.describe()+": "+this._stubInvocation.describeInvocationNameAndArgs(); | 
| -	}, | 
| - | 
| -	verify: function() { | 
| -		try { | 
| -			this._expectedCallCounter.verify(); | 
| -		} catch(e) { | 
| -			throw new Mock4JSException(e.message+": "+this._stubInvocation.describeInvocationNameAndArgs()); | 
| -		} | 
| -	} | 
| -} | 
| - | 
| -/** | 
| - * MethodActions | 
| - */ | 
| -function ReturnValueAction(valueToReturn) { | 
| -	this._valueToReturn = valueToReturn; | 
| -} | 
| - | 
| -ReturnValueAction.prototype = { | 
| -	invoke: function() { | 
| -		return this._valueToReturn; | 
| -	}, | 
| -	describe: function() { | 
| -		return "returns "+this._valueToReturn; | 
| -	} | 
| -} | 
| - | 
| -function ThrowExceptionAction(exceptionToThrow) { | 
| -	this._exceptionToThrow = exceptionToThrow; | 
| -} | 
| - | 
| -ThrowExceptionAction.prototype = { | 
| -	invoke: function() { | 
| -		throw this._exceptionToThrow; | 
| -	}, | 
| -	describe: function() { | 
| -		return "throws "+this._exceptionToThrow; | 
| -	} | 
| -} | 
| - | 
| -function ActionSequence() { | 
| -	this._ACTIONS_NOT_SETUP = "_ACTIONS_NOT_SETUP"; | 
| -	this._actionSequence = this._ACTIONS_NOT_SETUP; | 
| -	this._indexOfNextAction = 0; | 
| -} | 
| - | 
| -ActionSequence.prototype = { | 
| -	invokeNextAction: function() { | 
| -		if(this._actionSequence === this._ACTIONS_NOT_SETUP) { | 
| -			return; | 
| -		} else { | 
| -			if(this._indexOfNextAction >= this._actionSequence.length) { | 
| -				throw new Mock4JSException("no more values to return"); | 
| -			} else { | 
| -				var action = this._actionSequence[this._indexOfNextAction]; | 
| -				this._indexOfNextAction++; | 
| -				return action.invoke(); | 
| -			} | 
| -		} | 
| -	}, | 
| - | 
| -	addAll: function() { | 
| -		this._actionSequence = []; | 
| -		for(var i=0; i<arguments.length; i++) { | 
| -			if(typeof arguments[i] != 'object' && arguments[i].invoke === undefined) { | 
| -				throw new Error("cannot add a method action that does not have an invoke() method"); | 
| -			} | 
| -			this._actionSequence.push(arguments[i]); | 
| -		} | 
| -	} | 
| -} | 
| - | 
| -function StubActionSequence() { | 
| -	this._ACTIONS_NOT_SETUP = "_ACTIONS_NOT_SETUP"; | 
| -	this._actionSequence = this._ACTIONS_NOT_SETUP; | 
| -	this._indexOfNextAction = 0; | 
| -} | 
| - | 
| -StubActionSequence.prototype = { | 
| -	invokeNextAction: function() { | 
| -		if(this._actionSequence === this._ACTIONS_NOT_SETUP) { | 
| -			return; | 
| -		} else if(this._actionSequence.length == 1) { | 
| -			// if there is only one method action, keep doing that on every invocation | 
| -			return this._actionSequence[0].invoke(); | 
| -		} else { | 
| -			if(this._indexOfNextAction >= this._actionSequence.length) { | 
| -				throw new Mock4JSException("no more values to return"); | 
| -			} else { | 
| -				var action = this._actionSequence[this._indexOfNextAction]; | 
| -				this._indexOfNextAction++; | 
| -				return action.invoke(); | 
| -			} | 
| -		} | 
| -	}, | 
| - | 
| -	addAll: function() { | 
| -		this._actionSequence = []; | 
| -		for(var i=0; i<arguments.length; i++) { | 
| -			if(typeof arguments[i] != 'object' && arguments[i].invoke === undefined) { | 
| -				throw new Error("cannot add a method action that does not have an invoke() method"); | 
| -			} | 
| -			this._actionSequence.push(arguments[i]); | 
| -		} | 
| -	} | 
| -} | 
| - | 
| - | 
| -/** | 
| - * Mock | 
| - */ | 
| -function Mock(mockedType) { | 
| -	if(mockedType === undefined || mockedType.prototype === undefined) { | 
| -		throw new Mock4JSException("Unable to create Mock: must create Mock using a class not prototype, eg. 'new Mock(TypeToMock)' or using the convenience method 'mock(TypeToMock)'"); | 
| -	} | 
| -	this._mockedType = mockedType.prototype; | 
| -	this._expectedCallCount; | 
| -	this._isRecordingExpectations = false; | 
| -	this._expectedInvocations = []; | 
| - | 
| -	// setup proxy | 
| -	var IntermediateClass = new Function(); | 
| -	IntermediateClass.prototype = mockedType.prototype; | 
| -	var ChildClass = new Function(); | 
| -	ChildClass.prototype = new IntermediateClass(); | 
| -	this._proxy = new ChildClass(); | 
| -	this._proxy.mock = this; | 
| - | 
| -	for(property in mockedType.prototype) { | 
| -		if(this._isPublicMethod(mockedType.prototype, property)) { | 
| -			var publicMethodName = property; | 
| -			this._proxy[publicMethodName] = this._createMockedMethod(publicMethodName); | 
| -			this[publicMethodName] = this._createExpectationRecordingMethod(publicMethodName); | 
| -		} | 
| -	} | 
| -} | 
| - | 
| -Mock.prototype = { | 
| - | 
| -	proxy: function() { | 
| -		return this._proxy; | 
| -	}, | 
| - | 
| -	expects: function(expectedCallCount) { | 
| -		this._expectedCallCount = expectedCallCount; | 
| -		this._isRecordingExpectations = true; | 
| -		this._isRecordingStubs = false; | 
| -		return this; | 
| -	}, | 
| - | 
| -	stubs: function() { | 
| -		this._isRecordingExpectations = false; | 
| -		this._isRecordingStubs = true; | 
| -		return this; | 
| -	}, | 
| - | 
| -	verify: function() { | 
| -		for(var i=0; i<this._expectedInvocations.length; i++) { | 
| -			var expectedInvocation = this._expectedInvocations[i]; | 
| -			try { | 
| -				expectedInvocation.verify(); | 
| -			} catch(e) { | 
| -				var failMsg = e.message+this._describeMockSetup(); | 
| -				throw new Mock4JSException(failMsg); | 
| -			} | 
| -		} | 
| -	}, | 
| - | 
| -	_isPublicMethod: function(mockedType, property) { | 
| -		try { | 
| -			var isMethod = typeof(mockedType[property]) == 'function'; | 
| -			var isPublic = property.charAt(0) != "_"; | 
| -			return isMethod && isPublic; | 
| -		} catch(e) { | 
| -			return false; | 
| -		} | 
| -	}, | 
| - | 
| -	_createExpectationRecordingMethod: function(methodName) { | 
| -		return function() { | 
| -			// ensure all arguments are instances of ArgumentMatcher | 
| -			var expectedArgs = []; | 
| -			for(var i=0; i<arguments.length; i++) { | 
| -				if(arguments[i] !== null && arguments[i] !== undefined && arguments[i].argumentMatches) { | 
| -					expectedArgs[i] = arguments[i]; | 
| -				} else { | 
| -					expectedArgs[i] = new MatchExactly(arguments[i]); | 
| -				} | 
| -			} | 
| - | 
| -			// create stub or expected invocation | 
| -			var expectedInvocation; | 
| -			if(this._isRecordingExpectations) { | 
| -				expectedInvocation = new ExpectedInvocation(methodName, expectedArgs, this._expectedCallCount); | 
| -			} else { | 
| -				expectedInvocation = new StubInvocation(methodName, expectedArgs, new StubActionSequence()); | 
| -			} | 
| - | 
| -			this._expectedInvocations.push(expectedInvocation); | 
| - | 
| -			this._isRecordingExpectations = false; | 
| -			this._isRecordingStubs = false; | 
| -			return expectedInvocation; | 
| -		} | 
| -	}, | 
| - | 
| -	_createMockedMethod: function(methodName) { | 
| -		return function() { | 
| -			// go through expectation list backwards to ensure later expectations override earlier ones | 
| -			for(var i=this.mock._expectedInvocations.length-1; i>=0; i--) { | 
| -				var expectedInvocation = this.mock._expectedInvocations[i]; | 
| -				if(expectedInvocation.matches(methodName, arguments)) { | 
| -					try { | 
| -						return expectedInvocation.invoked(); | 
| -					} catch(e) { | 
| -						if(e instanceof Mock4JSException) { | 
| -							throw new Mock4JSException(e.message+this.mock._describeMockSetup()); | 
| -						} else { | 
| -							// the user setup the mock to throw a specific error, so don't modify the message | 
| -							throw e; | 
| -						} | 
| -					} | 
| -				} | 
| -			} | 
| -			var failMsg = "unexpected invocation: "+methodName+"("+Mock4JSUtil.join(arguments)+")"+this.mock._describeMockSetup(); | 
| -			throw new Mock4JSException(failMsg); | 
| -		}; | 
| -	}, | 
| - | 
| -	_describeMockSetup: function() { | 
| -		var msg = "\nAllowed:"; | 
| -		for(var i=0; i<this._expectedInvocations.length; i++) { | 
| -			var expectedInvocation = this._expectedInvocations[i]; | 
| -			msg += "\n" + expectedInvocation.describe(); | 
| -		} | 
| -		return msg; | 
| -	} | 
| +/** | 
| + * Mock4JS 0.2 | 
| + * http://mock4js.sourceforge.net/ | 
| + */ | 
| + | 
| +Mock4JS = { | 
| +	_mocksToVerify: [], | 
| +	_convertToConstraint: function(constraintOrValue) { | 
| +		if(constraintOrValue.argumentMatches) { | 
| +			return constraintOrValue; // it's already an ArgumentMatcher | 
| +		} else { | 
| +			return new MatchExactly(constraintOrValue);	// default to eq(...) | 
| +		} | 
| +	}, | 
| +	addMockSupport: function(object) { | 
| +		// mock creation | 
| +		object.mock = function(mockedType) { | 
| +			if(!mockedType) { | 
| +				throw new Mock4JSException("Cannot create mock: type to mock cannot be found or is null"); | 
| +			} | 
| +			var newMock = new Mock(mockedType); | 
| +			Mock4JS._mocksToVerify.push(newMock); | 
| +			return newMock; | 
| +		} | 
| + | 
| +		// syntactic sugar for expects() | 
| +		object.once = function() { | 
| +			return new CallCounter(1); | 
| +		} | 
| +		object.never = function() { | 
| +			return new CallCounter(0); | 
| +		} | 
| +		object.exactly = function(expectedCallCount) { | 
| +			return new CallCounter(expectedCallCount); | 
| +		} | 
| +		object.atLeastOnce = function() { | 
| +			return new InvokeAtLeastOnce(); | 
| +		} | 
| + | 
| +		// syntactic sugar for argument expectations | 
| +		object.ANYTHING = new MatchAnything(); | 
| +		object.NOT_NULL = new MatchAnythingBut(new MatchExactly(null)); | 
| +		object.NOT_UNDEFINED = new MatchAnythingBut(new MatchExactly(undefined)); | 
| +		object.eq = function(expectedValue) { | 
| +			return new MatchExactly(expectedValue); | 
| +		} | 
| +		object.not = function(valueNotExpected) { | 
| +			var argConstraint = Mock4JS._convertToConstraint(valueNotExpected); | 
| +			return new MatchAnythingBut(argConstraint); | 
| +		} | 
| +		object.and = function() { | 
| +			var constraints = []; | 
| +			for(var i=0; i<arguments.length; i++) { | 
| +				constraints[i] = Mock4JS._convertToConstraint(arguments[i]); | 
| +			} | 
| +			return new MatchAllOf(constraints); | 
| +		} | 
| +		object.or = function() { | 
| +			var constraints = []; | 
| +			for(var i=0; i<arguments.length; i++) { | 
| +				constraints[i] = Mock4JS._convertToConstraint(arguments[i]); | 
| +			} | 
| +			return new MatchAnyOf(constraints); | 
| +		} | 
| +		object.stringContains = function(substring) { | 
| +			return new MatchStringContaining(substring); | 
| +		} | 
| + | 
| +		// syntactic sugar for will() | 
| +		object.returnValue = function(value) { | 
| +			return new ReturnValueAction(value); | 
| +		} | 
| +		object.throwException = function(exception) { | 
| +			return new ThrowExceptionAction(exception); | 
| +		} | 
| +	}, | 
| +	clearMocksToVerify: function() { | 
| +		Mock4JS._mocksToVerify = []; | 
| +	}, | 
| +	verifyAllMocks: function() { | 
| +		for(var i=0; i<Mock4JS._mocksToVerify.length; i++) { | 
| +			Mock4JS._mocksToVerify[i].verify(); | 
| +		} | 
| +	} | 
| +} | 
| + | 
| +Mock4JSUtil = { | 
| +	hasFunction: function(obj, methodName) { | 
| +		return typeof obj == 'object' && typeof obj[methodName] == 'function'; | 
| +	}, | 
| +	join: function(list) { | 
| +		var result = ""; | 
| +		for(var i=0; i<list.length; i++) { | 
| +			var item = list[i]; | 
| +			if(Mock4JSUtil.hasFunction(item, "describe")) { | 
| +				result += item.describe(); | 
| +			} | 
| +			else if(typeof list[i] == 'string') { | 
| +				result += "\""+list[i]+"\""; | 
| +			} else { | 
| +				result += list[i]; | 
| +			} | 
| + | 
| +			if(i<list.length-1) result += ", "; | 
| +		} | 
| +		return result; | 
| +	} | 
| +} | 
| + | 
| +Mock4JSException = function(message) { | 
| +	this.message = message; | 
| +} | 
| + | 
| +Mock4JSException.prototype = { | 
| +	toString: function() { | 
| +		return this.message; | 
| +	} | 
| +} | 
| + | 
| +/** | 
| + * Assert function that makes use of the constraint methods | 
| + */ | 
| +assertThat = function(expected, argumentMatcher) { | 
| +	if(!argumentMatcher.argumentMatches(expected)) { | 
| +		fail("Expected '"+expected+"' to be "+argumentMatcher.describe()); | 
| +	} | 
| +} | 
| + | 
| +/** | 
| + * CallCounter | 
| + */ | 
| +function CallCounter(expectedCount) { | 
| +	this._expectedCallCount = expectedCount; | 
| +	this._actualCallCount = 0; | 
| +} | 
| + | 
| +CallCounter.prototype = { | 
| +	addActualCall: function() { | 
| +		this._actualCallCount++; | 
| +		if(this._actualCallCount > this._expectedCallCount) { | 
| +			throw new Mock4JSException("unexpected invocation"); | 
| +		} | 
| +	}, | 
| + | 
| +	verify: function() { | 
| +		if(this._actualCallCount < this._expectedCallCount) { | 
| +			throw new Mock4JSException("expected method was not invoked the expected number of times"); | 
| +		} | 
| +	}, | 
| + | 
| +	describe: function() { | 
| +		if(this._expectedCallCount == 0) { | 
| +			return "not expected"; | 
| +		} else if(this._expectedCallCount == 1) { | 
| +			var msg = "expected once"; | 
| +			if(this._actualCallCount >= 1) { | 
| +				msg += " and has been invoked"; | 
| +			} | 
| +			return msg; | 
| +		} else { | 
| +			var msg = "expected "+this._expectedCallCount+" times"; | 
| +			if(this._actualCallCount > 0) { | 
| +				msg += ", invoked "+this._actualCallCount + " times"; | 
| +			} | 
| +			return msg; | 
| +		} | 
| +	} | 
| +} | 
| + | 
| +function InvokeAtLeastOnce() { | 
| +	this._hasBeenInvoked = false; | 
| +} | 
| + | 
| +InvokeAtLeastOnce.prototype = { | 
| +	addActualCall: function() { | 
| +		this._hasBeenInvoked = true; | 
| +	}, | 
| + | 
| +	verify: function() { | 
| +		if(this._hasBeenInvoked === false) { | 
| +			throw new Mock4JSException(describe()); | 
| +		} | 
| +	}, | 
| + | 
| +	describe: function() { | 
| +		var desc = "expected at least once"; | 
| +		if(this._hasBeenInvoked) desc+=" and has been invoked"; | 
| +		return desc; | 
| +	} | 
| +} | 
| + | 
| +/** | 
| + * ArgumentMatchers | 
| + */ | 
| + | 
| +function MatchExactly(expectedValue) { | 
| +	this._expectedValue = expectedValue; | 
| +} | 
| + | 
| +MatchExactly.prototype = { | 
| +	argumentMatches: function(actualArgument) { | 
| +		if(this._expectedValue instanceof Array) { | 
| +			if(!(actualArgument instanceof Array)) return false; | 
| +			if(this._expectedValue.length != actualArgument.length) return false; | 
| +			for(var i=0; i<this._expectedValue.length; i++) { | 
| +				if(this._expectedValue[i] != actualArgument[i]) return false; | 
| +			} | 
| +			return true; | 
| +		} else { | 
| +			return this._expectedValue == actualArgument; | 
| +		} | 
| +	}, | 
| +	describe: function() { | 
| +		if(typeof this._expectedValue == "string") { | 
| +			return "eq(\""+this._expectedValue+"\")"; | 
| +		} else { | 
| +			return "eq("+this._expectedValue+")"; | 
| +		} | 
| +	} | 
| +} | 
| + | 
| +function MatchAnything() { | 
| +} | 
| + | 
| +MatchAnything.prototype = { | 
| +	argumentMatches: function(actualArgument) { | 
| +		return true; | 
| +	}, | 
| +	describe: function() { | 
| +		return "ANYTHING"; | 
| +	} | 
| +} | 
| + | 
| +function MatchAnythingBut(matcherToNotMatch) { | 
| +	this._matcherToNotMatch = matcherToNotMatch; | 
| +} | 
| + | 
| +MatchAnythingBut.prototype = { | 
| +	argumentMatches: function(actualArgument) { | 
| +		return !this._matcherToNotMatch.argumentMatches(actualArgument); | 
| +	}, | 
| +	describe: function() { | 
| +		return "not("+this._matcherToNotMatch.describe()+")"; | 
| +	} | 
| +} | 
| + | 
| +function MatchAllOf(constraints) { | 
| +	this._constraints = constraints; | 
| +} | 
| + | 
| + | 
| +MatchAllOf.prototype = { | 
| +	argumentMatches: function(actualArgument) { | 
| +		for(var i=0; i<this._constraints.length; i++) { | 
| +			var constraint = this._constraints[i]; | 
| +			if(!constraint.argumentMatches(actualArgument)) return false; | 
| +		} | 
| +		return true; | 
| +	}, | 
| +	describe: function() { | 
| +		return "and("+Mock4JSUtil.join(this._constraints)+")"; | 
| +	} | 
| +} | 
| + | 
| +function MatchAnyOf(constraints) { | 
| +	this._constraints = constraints; | 
| +} | 
| + | 
| +MatchAnyOf.prototype = { | 
| +	argumentMatches: function(actualArgument) { | 
| +		for(var i=0; i<this._constraints.length; i++) { | 
| +			var constraint = this._constraints[i]; | 
| +			if(constraint.argumentMatches(actualArgument)) return true; | 
| +		} | 
| +		return false; | 
| +	}, | 
| +	describe: function() { | 
| +		return "or("+Mock4JSUtil.join(this._constraints)+")"; | 
| +	} | 
| +} | 
| + | 
| + | 
| +function MatchStringContaining(stringToLookFor) { | 
| +	this._stringToLookFor = stringToLookFor; | 
| +} | 
| + | 
| +MatchStringContaining.prototype = { | 
| +	argumentMatches: function(actualArgument) { | 
| +		if(typeof actualArgument != 'string') throw new Mock4JSException("stringContains() must be given a string, actually got a "+(typeof actualArgument)); | 
| +		return (actualArgument.indexOf(this._stringToLookFor) != -1); | 
| +	}, | 
| +	describe: function() { | 
| +		return "a string containing \""+this._stringToLookFor+"\""; | 
| +	} | 
| +} | 
| + | 
| + | 
| +/** | 
| + * StubInvocation | 
| + */ | 
| +function StubInvocation(expectedMethodName, expectedArgs, actionSequence) { | 
| +	this._expectedMethodName = expectedMethodName; | 
| +	this._expectedArgs = expectedArgs; | 
| +	this._actionSequence = actionSequence; | 
| +} | 
| + | 
| +StubInvocation.prototype = { | 
| +	matches: function(invokedMethodName, invokedMethodArgs) { | 
| +		if (invokedMethodName != this._expectedMethodName) { | 
| +			return false; | 
| +		} | 
| + | 
| +		if (invokedMethodArgs.length != this._expectedArgs.length) { | 
| +			return false; | 
| +		} | 
| + | 
| +		for(var i=0; i<invokedMethodArgs.length; i++) { | 
| +			var expectedArg = this._expectedArgs[i]; | 
| +			var invokedArg = invokedMethodArgs[i]; | 
| +			if(!expectedArg.argumentMatches(invokedArg)) { | 
| +				return false; | 
| +			} | 
| +		} | 
| + | 
| +		return true; | 
| +	}, | 
| + | 
| +	invoked: function() { | 
| +		try { | 
| +			return this._actionSequence.invokeNextAction(); | 
| +		} catch(e) { | 
| +			if(e instanceof Mock4JSException) { | 
| +				throw new Mock4JSException(this.describeInvocationNameAndArgs()+" - "+e.message); | 
| +			} else { | 
| +				throw e; | 
| +			} | 
| +		} | 
| +	}, | 
| + | 
| +	will: function() { | 
| +		this._actionSequence.addAll.apply(this._actionSequence, arguments); | 
| +	}, | 
| + | 
| +	describeInvocationNameAndArgs: function() { | 
| +		return this._expectedMethodName+"("+Mock4JSUtil.join(this._expectedArgs)+")"; | 
| +	}, | 
| + | 
| +	describe: function() { | 
| +		return "stub: "+this.describeInvocationNameAndArgs(); | 
| +	}, | 
| + | 
| +	verify: function() { | 
| +	} | 
| +} | 
| + | 
| +/** | 
| + * ExpectedInvocation | 
| + */ | 
| +function ExpectedInvocation(expectedMethodName, expectedArgs, expectedCallCounter) { | 
| +	this._stubInvocation = new StubInvocation(expectedMethodName, expectedArgs, new ActionSequence()); | 
| +	this._expectedCallCounter = expectedCallCounter; | 
| +} | 
| + | 
| +ExpectedInvocation.prototype = { | 
| +	matches: function(invokedMethodName, invokedMethodArgs) { | 
| +		try { | 
| +			return this._stubInvocation.matches(invokedMethodName, invokedMethodArgs); | 
| +		} catch(e) { | 
| +			throw new Mock4JSException("method "+this._stubInvocation.describeInvocationNameAndArgs()+": "+e.message); | 
| +		} | 
| +	}, | 
| + | 
| +	invoked: function() { | 
| +		try { | 
| +			this._expectedCallCounter.addActualCall(); | 
| +		} catch(e) { | 
| +			throw new Mock4JSException(e.message+": "+this._stubInvocation.describeInvocationNameAndArgs()); | 
| +		} | 
| +		return this._stubInvocation.invoked(); | 
| +	}, | 
| + | 
| +	will: function() { | 
| +		this._stubInvocation.will.apply(this._stubInvocation, arguments); | 
| +	}, | 
| + | 
| +	describe: function() { | 
| +		return this._expectedCallCounter.describe()+": "+this._stubInvocation.describeInvocationNameAndArgs(); | 
| +	}, | 
| + | 
| +	verify: function() { | 
| +		try { | 
| +			this._expectedCallCounter.verify(); | 
| +		} catch(e) { | 
| +			throw new Mock4JSException(e.message+": "+this._stubInvocation.describeInvocationNameAndArgs()); | 
| +		} | 
| +	} | 
| +} | 
| + | 
| +/** | 
| + * MethodActions | 
| + */ | 
| +function ReturnValueAction(valueToReturn) { | 
| +	this._valueToReturn = valueToReturn; | 
| +} | 
| + | 
| +ReturnValueAction.prototype = { | 
| +	invoke: function() { | 
| +		return this._valueToReturn; | 
| +	}, | 
| +	describe: function() { | 
| +		return "returns "+this._valueToReturn; | 
| +	} | 
| +} | 
| + | 
| +function ThrowExceptionAction(exceptionToThrow) { | 
| +	this._exceptionToThrow = exceptionToThrow; | 
| +} | 
| + | 
| +ThrowExceptionAction.prototype = { | 
| +	invoke: function() { | 
| +		throw this._exceptionToThrow; | 
| +	}, | 
| +	describe: function() { | 
| +		return "throws "+this._exceptionToThrow; | 
| +	} | 
| +} | 
| + | 
| +function ActionSequence() { | 
| +	this._ACTIONS_NOT_SETUP = "_ACTIONS_NOT_SETUP"; | 
| +	this._actionSequence = this._ACTIONS_NOT_SETUP; | 
| +	this._indexOfNextAction = 0; | 
| +} | 
| + | 
| +ActionSequence.prototype = { | 
| +	invokeNextAction: function() { | 
| +		if(this._actionSequence === this._ACTIONS_NOT_SETUP) { | 
| +			return; | 
| +		} else { | 
| +			if(this._indexOfNextAction >= this._actionSequence.length) { | 
| +				throw new Mock4JSException("no more values to return"); | 
| +			} else { | 
| +				var action = this._actionSequence[this._indexOfNextAction]; | 
| +				this._indexOfNextAction++; | 
| +				return action.invoke(); | 
| +			} | 
| +		} | 
| +	}, | 
| + | 
| +	addAll: function() { | 
| +		this._actionSequence = []; | 
| +		for(var i=0; i<arguments.length; i++) { | 
| +			if(typeof arguments[i] != 'object' && arguments[i].invoke === undefined) { | 
| +				throw new Error("cannot add a method action that does not have an invoke() method"); | 
| +			} | 
| +			this._actionSequence.push(arguments[i]); | 
| +		} | 
| +	} | 
| +} | 
| + | 
| +function StubActionSequence() { | 
| +	this._ACTIONS_NOT_SETUP = "_ACTIONS_NOT_SETUP"; | 
| +	this._actionSequence = this._ACTIONS_NOT_SETUP; | 
| +	this._indexOfNextAction = 0; | 
| +} | 
| + | 
| +StubActionSequence.prototype = { | 
| +	invokeNextAction: function() { | 
| +		if(this._actionSequence === this._ACTIONS_NOT_SETUP) { | 
| +			return; | 
| +		} else if(this._actionSequence.length == 1) { | 
| +			// if there is only one method action, keep doing that on every invocation | 
| +			return this._actionSequence[0].invoke(); | 
| +		} else { | 
| +			if(this._indexOfNextAction >= this._actionSequence.length) { | 
| +				throw new Mock4JSException("no more values to return"); | 
| +			} else { | 
| +				var action = this._actionSequence[this._indexOfNextAction]; | 
| +				this._indexOfNextAction++; | 
| +				return action.invoke(); | 
| +			} | 
| +		} | 
| +	}, | 
| + | 
| +	addAll: function() { | 
| +		this._actionSequence = []; | 
| +		for(var i=0; i<arguments.length; i++) { | 
| +			if(typeof arguments[i] != 'object' && arguments[i].invoke === undefined) { | 
| +				throw new Error("cannot add a method action that does not have an invoke() method"); | 
| +			} | 
| +			this._actionSequence.push(arguments[i]); | 
| +		} | 
| +	} | 
| +} | 
| + | 
| + | 
| +/** | 
| + * Mock | 
| + */ | 
| +function Mock(mockedType) { | 
| +	if(mockedType === undefined || mockedType.prototype === undefined) { | 
| +		throw new Mock4JSException("Unable to create Mock: must create Mock using a class not prototype, eg. 'new Mock(TypeToMock)' or using the convenience method 'mock(TypeToMock)'"); | 
| +	} | 
| +	this._mockedType = mockedType.prototype; | 
| +	this._expectedCallCount; | 
| +	this._isRecordingExpectations = false; | 
| +	this._expectedInvocations = []; | 
| + | 
| +	// setup proxy | 
| +	var IntermediateClass = new Function(); | 
| +	IntermediateClass.prototype = mockedType.prototype; | 
| +	var ChildClass = new Function(); | 
| +	ChildClass.prototype = new IntermediateClass(); | 
| +	this._proxy = new ChildClass(); | 
| +	this._proxy.mock = this; | 
| + | 
| +	for(property in mockedType.prototype) { | 
| +		if(this._isPublicMethod(mockedType.prototype, property)) { | 
| +			var publicMethodName = property; | 
| +			this._proxy[publicMethodName] = this._createMockedMethod(publicMethodName); | 
| +			this[publicMethodName] = this._createExpectationRecordingMethod(publicMethodName); | 
| +		} | 
| +	} | 
| +} | 
| + | 
| +Mock.prototype = { | 
| + | 
| +	proxy: function() { | 
| +		return this._proxy; | 
| +	}, | 
| + | 
| +	expects: function(expectedCallCount) { | 
| +		this._expectedCallCount = expectedCallCount; | 
| +		this._isRecordingExpectations = true; | 
| +		this._isRecordingStubs = false; | 
| +		return this; | 
| +	}, | 
| + | 
| +	stubs: function() { | 
| +		this._isRecordingExpectations = false; | 
| +		this._isRecordingStubs = true; | 
| +		return this; | 
| +	}, | 
| + | 
| +	verify: function() { | 
| +		for(var i=0; i<this._expectedInvocations.length; i++) { | 
| +			var expectedInvocation = this._expectedInvocations[i]; | 
| +			try { | 
| +				expectedInvocation.verify(); | 
| +			} catch(e) { | 
| +				var failMsg = e.message+this._describeMockSetup(); | 
| +				throw new Mock4JSException(failMsg); | 
| +			} | 
| +		} | 
| +	}, | 
| + | 
| +	_isPublicMethod: function(mockedType, property) { | 
| +		try { | 
| +			var isMethod = typeof(mockedType[property]) == 'function'; | 
| +			var isPublic = property.charAt(0) != "_"; | 
| +			return isMethod && isPublic; | 
| +		} catch(e) { | 
| +			return false; | 
| +		} | 
| +	}, | 
| + | 
| +	_createExpectationRecordingMethod: function(methodName) { | 
| +		return function() { | 
| +			// ensure all arguments are instances of ArgumentMatcher | 
| +			var expectedArgs = []; | 
| +			for(var i=0; i<arguments.length; i++) { | 
| +				if(arguments[i] !== null && arguments[i] !== undefined && arguments[i].argumentMatches) { | 
| +					expectedArgs[i] = arguments[i]; | 
| +				} else { | 
| +					expectedArgs[i] = new MatchExactly(arguments[i]); | 
| +				} | 
| +			} | 
| + | 
| +			// create stub or expected invocation | 
| +			var expectedInvocation; | 
| +			if(this._isRecordingExpectations) { | 
| +				expectedInvocation = new ExpectedInvocation(methodName, expectedArgs, this._expectedCallCount); | 
| +			} else { | 
| +				expectedInvocation = new StubInvocation(methodName, expectedArgs, new StubActionSequence()); | 
| +			} | 
| + | 
| +			this._expectedInvocations.push(expectedInvocation); | 
| + | 
| +			this._isRecordingExpectations = false; | 
| +			this._isRecordingStubs = false; | 
| +			return expectedInvocation; | 
| +		} | 
| +	}, | 
| + | 
| +	_createMockedMethod: function(methodName) { | 
| +		return function() { | 
| +			// go through expectation list backwards to ensure later expectations override earlier ones | 
| +			for(var i=this.mock._expectedInvocations.length-1; i>=0; i--) { | 
| +				var expectedInvocation = this.mock._expectedInvocations[i]; | 
| +				if(expectedInvocation.matches(methodName, arguments)) { | 
| +					try { | 
| +						return expectedInvocation.invoked(); | 
| +					} catch(e) { | 
| +						if(e instanceof Mock4JSException) { | 
| +							throw new Mock4JSException(e.message+this.mock._describeMockSetup()); | 
| +						} else { | 
| +							// the user setup the mock to throw a specific error, so don't modify the message | 
| +							throw e; | 
| +						} | 
| +					} | 
| +				} | 
| +			} | 
| +			var failMsg = "unexpected invocation: "+methodName+"("+Mock4JSUtil.join(arguments)+")"+this.mock._describeMockSetup(); | 
| +			throw new Mock4JSException(failMsg); | 
| +		}; | 
| +	}, | 
| + | 
| +	_describeMockSetup: function() { | 
| +		var msg = "\nAllowed:"; | 
| +		for(var i=0; i<this._expectedInvocations.length; i++) { | 
| +			var expectedInvocation = this._expectedInvocations[i]; | 
| +			msg += "\n" + expectedInvocation.describe(); | 
| +		} | 
| +		return msg; | 
| +	} | 
| } | 
|  |