typemoq
Version:
A simple mocking library for TypeScript
139 lines (113 loc) • 5.65 kB
text/typescript
import * as _ from "lodash";
import * as all from "./_all";
import { InterceptorContext, IInterceptStrategy, InterceptionAction } from "./InterceptorContext";
import { CurrentInterceptContext } from "./CurrentInterceptContext";
import * as strategy from "./InterceptorStrategies";
export class InterceptorExecute<T> implements all.ICallInterceptor {
private _interceptorContext: InterceptorContext<T>;
constructor(mock: all.IMock<T>) {
this._interceptorContext = new InterceptorContext(mock);
}
get interceptorContext(): InterceptorContext<T> { return this._interceptorContext; }
intercept(invocation: all.ICallContext) {
let localCtx = new CurrentInterceptContext();
invocation.invocationType = all.InvocationType.EXECUTE;
_.some(this.interceptionStrategies(), (strategy: IInterceptStrategy<T>) => {
if (InterceptionAction.Stop === strategy.handleIntercept(invocation, this.interceptorContext, localCtx)) {
return true;
}
});
}
removeInvocation(invocation: all.ICallContext) {
this._interceptorContext.removeInvocation(invocation);
}
addExpectedCall(call: all.IProxyCall<T>): void {
this._interceptorContext.addExpectedCall(call);
}
verify(): void {
let expectedCalls = this._interceptorContext.expectedCalls();
let verifiableCalls: Array<all.IProxyCall<T>> = [];
if (this._interceptorContext.behavior == all.MockBehavior.Strict) { // verifiable by default when strict mocking
for (let call of expectedCalls) {
if (!call.isVerifiable)
call.setVerifiable();
verifiableCalls.push(call);
}
}
else {
verifiableCalls = _.filter(expectedCalls, (c: all.IProxyCall<T>) => c.isVerifiable);
}
for (let v of verifiableCalls)
this.verifyCallCount(v, v.expectedCallCount);
let orderedCalls: Array<all.IProxyCall<T>> = _.filter(expectedCalls, (c: all.IProxyCall<T>) => c.isInSequence);
this.verifyCallsOrder(orderedCalls);
}
verifyCallCount<T>(call: all.IProxyCall<T>, times: all.Times): void {
let expectedCalls = this._interceptorContext.expectedCalls();
let actualCalls = this._interceptorContext.actualInvocations();
let callCount: number = _.filter(actualCalls, (c: all.ICallContext) => call.matches(c)).length;
if (!times.verify(callCount))
this.throwVerifyCallCountException(call.setupCall, times, expectedCalls, actualCalls);
}
private throwVerifyCallCountException(setupCall: all.ICallContext, times: all.Times,
expectedCalls: Array<all.IProxyCall<T>>, actualCalls: Array<all.ICallContext>) {
let failMsg = times.failMessage(setupCall);
let expectedCallsMsg = expectedCalls.reduce((a, x) => `${a} ${x}\n`, "");
let actualCallsMsg = actualCalls.reduce((a, x) => `${a} ${x}\n`, "");
let msg = `${failMsg}\n Configured setups:\n${expectedCallsMsg}\n Performed invocations:\n${actualCallsMsg}`;
let e = new all.MockException(all.MockExceptionReason.CallCountVerificationFailed, setupCall, msg);
throw e;
}
private verifyCallsOrder<T>(expectedCalls: Array<all.IProxyCall<T>>): void {
let actualCalls = this._interceptorContext.actualInvocations();
this.checkCallOrderExpectations(expectedCalls, actualCalls);
}
private checkCallOrderExpectations<T>(expectedCalls: Array<all.IProxyCall<T>>, actualCalls: Array<all.ICallContext>): void {
let checkOrder = (expectedCallCountList: Array<number>): boolean => {
let expectedCallCount = _.sum(expectedCallCountList);
let aci = 0;
for (let eci = 0; eci < expectedCallCountList.length; eci++) {
let expectedCall = expectedCalls[eci];
let expectedCallCount = expectedCallCountList[eci];
for (let count = 1; count <= expectedCallCount; count++) {
let actualCall = actualCalls[aci++];
if (!expectedCall.matches(actualCall))
return false;
}
}
return aci === expectedCallCount;
}
let eureka = false;
let execute = (acc: Array<number>, i: number) => {
if (!eureka) {
if (i === expectedCalls.length)
eureka = checkOrder(acc);
else
for (let j = expectedCalls[i].expectedCallCount.min; j <= expectedCalls[i].expectedCallCount.max; j++) {
acc[i] = j;
execute(acc, i + 1);
}
}
}
execute([], 0);
if (!eureka)
this.throwVerifyCallOrderException();
}
private throwVerifyCallOrderException() {
let e = new all.MockException(all.MockExceptionReason.CallOrderVerificationFailed, null);
throw e;
}
reset(): void {
this._interceptorContext.reset();
}
private interceptionStrategies(): _.List<IInterceptStrategy<T>> {
let strategies: _.List<IInterceptStrategy<T>> = [
new strategy.AddActualInvocation(),
new strategy.ExtractProxyCall(),
new strategy.ExecuteCall(),
new strategy.InvokeBase(),
new strategy.HandleMockRecursion()
];
return strategies;
}
}