/** * 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 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._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= 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=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