Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose lookup types #28

Merged
merged 6 commits into from
Jan 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

coverage:
precision: 2
round: down
range: "80...100"
1 change: 1 addition & 0 deletions main/helper/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './property-replacement-helper';
export * from './module-helper';
export * from './jest-helper';
export * from './lookup-helper';
22 changes: 22 additions & 0 deletions main/helper/lookup-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ConstructorFunction, FunctionCallLookup, IMocked, LookupType } from '../mock';

export function getLookup<T, C extends ConstructorFunction<T>, U extends LookupType>(
mock: IMocked<T, C>,
lookupType: U,
): FunctionCallLookup<T, C, U> {
switch (lookupType) {
case 'function':
return mock.functionCallLookup as FunctionCallLookup<T, C, U>;
case 'getter':
return mock.getterCallLookup as FunctionCallLookup<T, C, U>;
case 'setter':
return mock.setterCallLookup as FunctionCallLookup<T, C, U>;
case 'staticFunction':
return mock.staticFunctionCallLookup as FunctionCallLookup<T, C, U>;
case 'staticGetter':
return mock.staticGetterCallLookup as FunctionCallLookup<T, C, U>;
case 'staticSetter':
return mock.staticSetterCallLookup as FunctionCallLookup<T, C, U>;
}
throw new Error(`Unknown lookup type: ${lookupType}`);
}
55 changes: 39 additions & 16 deletions main/mock/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ export type MatchFunction<T> = (passedValue: T) => boolean;
// tslint:disable-next-line:ban-types
export type FunctionsOnly<T> = Pick<T, { [K in keyof T]: Required<T>[K] extends Function ? K : never }[keyof T]>;

// tslint:disable-next-line:ban-types
export type PropertiesOnly<T> = Pick<T, { [K in keyof T]: Required<T>[K] extends Function ? never : K }[keyof T]>;

/**
* Allows custom logic to verify that a function parameter has the expected value.
*/
Expand All @@ -31,26 +34,44 @@ export type FunctionParameterMatchers<T extends any[]> = {
[P in keyof T]: T[P] extends FunctionOrConstructor ? IParameterMatcher<T[P]> : ParameterMatcher<T[P]>;
};

export type FunctionCallLookup = { [key: string]: any[][] };
export type FunctionCallLookup<T, C extends ConstructorFunction<T>, U extends LookupType> = {
[P in FunctionName<T, C, U>]?: LookupParams<T, C, U, P>[];
};

export type LookupParams<
T,
C extends ConstructorFunction<T>,
U extends LookupType,
K extends FunctionName<T, C, U>
> = U extends FunctionTypes
? FunctionParams<VerifierTarget<T, C, U>[K]>
: U extends SetterTypes
? [VerifierTarget<T, C, U>[K]]
: [];
export type FunctionParams<T> = T extends (...args: infer P) => any ? P : never;

export type ConstructorFunction<T> = new (...args: any[]) => T;

export type StaticFunctionTypes = 'staticFunction' | 'staticGetter' | 'staticSetter';
export type InstanceFunctionTypes = 'function' | 'getter' | 'setter';
export type StaticLookupTypes = 'staticFunction' | 'staticGetter' | 'staticSetter';
export type InstanceLookupTypes = 'function' | 'getter' | 'setter';
export type SetterTypes = 'staticSetter' | 'setter';
export type GetterTypes = 'staticGetter' | 'getter';
export type FunctionTypes = 'staticFunction' | 'function';
export type LookupType = StaticLookupTypes | InstanceLookupTypes;

export type VerifierTarget<T, C extends ConstructorFunction<T>, U extends FunctionType> = U extends StaticFunctionTypes
? C
export type VerifierTarget<T, C extends ConstructorFunction<T>, U extends LookupType> = U extends StaticLookupTypes
? U extends FunctionTypes
? FunctionsOnly<C>
: C
: U extends FunctionTypes
? FunctionsOnly<T>
: T;
export type FunctionType = StaticFunctionTypes | InstanceFunctionTypes;
export type FunctionName<T, C extends ConstructorFunction<T>, U extends FunctionType> = keyof VerifierTarget<T, C, U>;
export type FunctionName<T, C extends ConstructorFunction<T>, U extends LookupType> = keyof VerifierTarget<T, C, U>;

export interface IFunctionWithParametersVerification<
P extends Array<any>,
T,
U extends FunctionType,
U extends LookupType,
C extends new (...args: any[]) => T = never
> extends IFunctionVerifier<T, U, C> {
/**
Expand Down Expand Up @@ -89,15 +110,15 @@ export interface IFunctionWithParametersVerification<
withParametersEqualTo(...args: FunctionParameterMatchers<P>): IStrictFunctionVerification<T, U, C>;
}

export interface IStrictFunctionVerification<T, U extends FunctionType, C extends new (...args: any[]) => T = never>
export interface IStrictFunctionVerification<T, U extends LookupType, C extends new (...args: any[]) => T = never>
extends IFunctionVerifier<T, U, C> {
/**
* verify that the function has been called ONLY with the specified parameters and never without
*/
strict(): IFunctionVerifier<T, U, C>;
}

export interface IFunctionVerifier<T, U extends FunctionType, C extends new (...args: any[]) => T = never> {
export interface IFunctionVerifier<T, U extends LookupType, C extends new (...args: any[]) => T = never> {
type: U;
functionName: FunctionName<T, C, U>;
parameterMatchers?: (MatchFunction<any> | IParameterMatcher<any>)[];
Expand All @@ -116,13 +137,15 @@ export interface IMocked<T, C extends new (...args: any[]) => T = never> {
*/
mockConstructor: C;

functionCallLookup: FunctionCallLookup;
setterCallLookup: FunctionCallLookup;
getterCallLookup: FunctionCallLookup;
functionCallLookup: FunctionCallLookup<T, C, 'function'>;
setterCallLookup: FunctionCallLookup<T, C, 'setter'>;
getterCallLookup: FunctionCallLookup<T, C, 'getter'>;

staticFunctionCallLookup: FunctionCallLookup<T, C, 'staticFunction'>;
staticSetterCallLookup: FunctionCallLookup<T, C, 'staticSetter'>;
staticGetterCallLookup: FunctionCallLookup<T, C, 'staticGetter'>;

staticFunctionCallLookup: FunctionCallLookup;
staticSetterCallLookup: FunctionCallLookup;
staticGetterCallLookup: FunctionCallLookup;
functionReplacementLookup: Partial<Record<LookupType, Record<string, ((...args: any[]) => any) | undefined>>>;

/**
* Used to setup the mock with multiple operators.
Expand Down
6 changes: 4 additions & 2 deletions main/mock/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export class Mock {
staticSetterCallLookup: {},
staticGetterCallLookup: {},

functionReplacementLookup: {},

mock: {} as T,
// tslint:disable-next-line:no-empty
mockConstructor: ((..._args: any[]) => {}) as any,
Expand Down Expand Up @@ -66,13 +68,13 @@ export class Mock {
return mocked.withStaticGetter(propertyName);
},

withFunction: <U extends keyof T>(functionName: U) =>
withFunction: <U extends keyof FunctionsOnly<T>>(functionName: U) =>
createFunctionParameterVerifier(mocked, 'function', functionName),
withSetter: <U extends keyof T>(functionName: U) =>
createFunctionParameterVerifier(mocked, 'setter', functionName),
withGetter: <U extends keyof T>(functionName: U) => createFunctionVerifier(mocked, 'getter', functionName),

withStaticFunction: <U extends keyof C>(functionName: U) =>
withStaticFunction: <U extends keyof FunctionsOnly<C>>(functionName: U) =>
createFunctionParameterVerifier(mocked, 'staticFunction', functionName),
withStaticSetter: <U extends keyof C>(functionName: U) =>
createFunctionParameterVerifier(mocked, 'staticSetter', functionName),
Expand Down
Loading