diff --git a/src/SubstituteException.ts b/src/SubstituteException.ts index adebbae..b396057 100644 --- a/src/SubstituteException.ts +++ b/src/SubstituteException.ts @@ -1,14 +1,8 @@ -import { SubstituteNodeModel } from './Types' -import { stringify, TextBuilder } from './utilities' - -const SubstituteExceptionType = { - callCountMismatch: 'CallCountMismatch', - PropertyNotMocked: 'PropertyNotMocked' -} as const -type SubstituteExceptionType = typeof SubstituteExceptionType[keyof typeof SubstituteExceptionType] +import { SubstituteNodeModel, SubstituteExceptionType } from './Types' +import { stringify, TextBuilder, constants } from './utilities' export class SubstituteException extends Error { - type?: SubstituteExceptionType + public type?: SubstituteExceptionType constructor(msg: string, exceptionType?: SubstituteExceptionType) { super(msg) @@ -18,16 +12,16 @@ export class SubstituteException extends Error { Error.captureStackTrace(this, errorConstructor) } - static forCallCountMismatch( + public static forCallCountMismatch( expected: { count: number | undefined, call: SubstituteNodeModel }, received: { matchCount: number, calls: SubstituteNodeModel[] } ) { - const callPath = `@Substitute.${expected.call.key.toString()}` + const callPath = `@Substitute.${expected.call.property.toString()}` const textBuilder = new TextBuilder() .add('Call count mismatch in ') .add('@Substitute.', t => t.underline()) - .add(expected.call.key.toString(), t => t.bold().underline()) + .add(expected.call.property.toString(), t => t.bold().underline()) .add(':') .newLine().add('Expected to receive ') .addParts(...stringify.expectation(expected)) @@ -36,17 +30,17 @@ export class SubstituteException extends Error { .add('.') if (received.calls.length > 0) textBuilder.newLine().add(`All property or method calls to ${callPath} received so far:${stringify.receivedCalls(callPath, expected.call, received.calls)}`) - return new this(textBuilder.toString(), SubstituteExceptionType.callCountMismatch) + return new this(textBuilder.toString(), constants.EXCEPTION.callCountMismatch) } - static forPropertyNotMocked(property: PropertyKey) { + public static forPropertyNotMocked(property: PropertyKey) { return new this( `There is no mock for property: ${property.toString()}`, - SubstituteExceptionType.PropertyNotMocked + constants.EXCEPTION.propertyNotMocked ) } - static generic(message: string) { + public static generic(message: string) { return new this(message) } } \ No newline at end of file diff --git a/src/SubstituteNode.ts b/src/SubstituteNode.ts index 820f833..8f76d2e 100644 --- a/src/SubstituteNode.ts +++ b/src/SubstituteNode.ts @@ -2,17 +2,16 @@ import { inspect, InspectOptions, types } from 'util' import { SubstituteNodeBase } from './SubstituteNodeBase' import { RecordedArguments } from './RecordedArguments' -// TODO: implement rest of constants and guards (AccessorType, Context, Filter functions, ...) -import { constants, is } from './utilities' +import { constants, is, stringify } from './utilities' import { SubstituteException } from './SubstituteException' -import type { FilterFunction, SubstituteContext, SubstitutionMethod, ClearType, PropertyType, SubstituteNodeModel } from './Types' +import type { FilterFunction, SubstituteContext, SubstitutionMethod, ClearType, PropertyType, SubstituteNodeModel, AccessorType } from './Types' import type { ObjectSubstitute } from './Transformations' const instance = Symbol('Substitute:Instance') -const clearTypeToFilterMap: Record> = { +const clearTypeToFilterMap: Record> = { all: () => true, - receivedCalls: node => !node.hasContext, - substituteValues: node => node.isSubstitution + receivedCalls: node => is.CONTEXT.none(node.context), + substituteValues: node => is.CONTEXT.substitution(node.context) } type SpecialProperty = typeof instance | typeof inspect.custom | 'then' @@ -23,10 +22,10 @@ export class SubstituteNode extends SubstituteNodeBase implements ObjectSubstitu private _rootContext: RootContext private _propertyType: PropertyType = constants.PROPERTY.property - private _accessorType: 'get' | 'set' = 'get' + private _accessorType: AccessorType = constants.ACCESSOR.get private _recordedArguments: RecordedArguments = RecordedArguments.none() - private _context: SubstituteContext = 'none' + private _context: SubstituteContext = constants.CONTEXT.none private _retrySubstitutionExecutionAttempt: boolean = false public stack?: string @@ -233,7 +232,7 @@ export class SubstituteNode extends SubstituteNodeBase implements ObjectSubstitu private _scheduledAssertionException: SubstituteException | undefined private handleSetter(value: any) { - this._accessorType = 'set' + this._accessorType = constants.ACCESSOR.set this._recordedArguments = RecordedArguments.from([value]) } @@ -277,28 +276,6 @@ export class SubstituteNode extends SubstituteNodeBase implements ObjectSubstitu } private printableForm(_: number, options: InspectOptions): string { - // TODO: Refactor this to use a TextBuilder via stringify utility - return this.isRoot() ? this.printRootNode(options) : this.printNode(options) - } - - private printRootNode(options: InspectOptions): string { - const records = inspect(this.recorder, options) - const instanceName = '@Substitute' - return instanceName + ' {' + records + '\n}' - } - - private printNode(options: InspectOptions): string { - const hasContext = this.hasContext - const args = inspect(this.recordedArguments, options) - const label = this.isSubstitution ? - '=> ' : - this.isAssertion ? - `${this.child?.property.toString()}` : - '' - const s = hasContext ? `${label}${inspect(this.child?.recordedArguments, options)}` : '' - - const printableNode = `${this.propertyType}<${this.property.toString()}>: ${args}${s}` - return printableNode - // return hasContext ? textModifier.italic(printableNode) : printableNode + return this.isRoot() ? stringify.rootNode(this, inspect(this.recorder, options)) : stringify.node(this, this.child, options) } } \ No newline at end of file