11import { inspect , InspectOptions } from 'util'
22
3- import { PropertyType , isSubstitutionMethod , isAssertionMethod , SubstitutionMethod , textModifier } from './Utilities'
3+ import { PropertyType , isSubstitutionMethod , isAssertionMethod , AssertionMethod , SubstitutionMethod , textModifier , isSubstituteMethod } from './Utilities'
44import { SubstituteException } from './SubstituteException'
55import { RecordedArguments } from './RecordedArguments'
66import { SubstituteNodeBase } from './SubstituteNodeBase'
77import { SubstituteBase } from './SubstituteBase'
88import { createSubstituteProxy } from './SubstituteProxy'
99
10+ type SubstituteContext = SubstitutionMethod | AssertionMethod | 'none'
11+
1012export class SubstituteNode extends SubstituteNodeBase < SubstituteNode > {
1113 private _proxy : SubstituteNode
1214 private _propertyType : PropertyType = PropertyType . property
1315 private _accessorType : 'get' | 'set' = 'get'
1416 private _recordedArguments : RecordedArguments = RecordedArguments . none ( )
1517
16- private _hasSubstitution : boolean = false
17- private _isSubstitution : boolean = false
18-
18+ private _context : SubstituteContext = 'none'
1919 private _disabledAssertions : boolean = false
20- private _isAssertion : boolean = false
2120
2221 constructor ( property : PropertyKey , parent : SubstituteNode | SubstituteBase ) {
2322 super ( property , parent )
24- this . _proxy = new Proxy (
23+ this . _proxy = createSubstituteProxy (
2524 this ,
26- createSubstituteProxy < SubstituteNode > ( {
27- get : ( target , _ , __ , node ) => {
28- if ( target . isAssertion ) node . executeAssertion ( )
25+ {
26+ get : ( node , _ , __ , nextNode ) => {
27+ if ( node . isAssertion ) nextNode . executeAssertion ( )
2928 } ,
30- set : ( target , _ , __ , ___ , node ) => {
31- if ( target . isAssertion ) node . executeAssertion ( )
29+ set : ( node , _ , __ , ___ , nextNode ) => {
30+ if ( node . isAssertion ) nextNode . executeAssertion ( )
3231 } ,
33- apply : ( target , _ , rawArguments ) => {
34- target . handleMethod ( rawArguments )
35- return target . isIntermediateNode ( ) && target . parent . isAssertion
36- ? target . executeAssertion ( )
37- : target . read ( )
32+ apply : ( node , _ , rawArguments ) => {
33+ node . handleMethod ( rawArguments )
34+ return node . parent ?. isAssertion ?? false ? node . executeAssertion ( ) : node . read ( )
3835 }
39- } )
36+ }
4037 )
4138 }
4239
4340 public get proxy ( ) {
4441 return this . _proxy
4542 }
4643
47- get isSubstitution ( ) : boolean {
48- return this . _isSubstitution
44+ get context ( ) : SubstituteContext {
45+ return this . _context
4946 }
5047
51- get hasSubstitution ( ) : boolean {
52- return this . _hasSubstitution
48+ get hasContext ( ) : boolean {
49+ return this . context !== 'none'
50+ }
51+
52+ get isSubstitution ( ) : boolean {
53+ return isSubstitutionMethod ( this . context )
5354 }
5455
5556 get isAssertion ( ) : boolean {
56- return this . _isAssertion
57+ return isAssertionMethod ( this . context )
5758 }
5859
5960 get property ( ) {
@@ -76,24 +77,16 @@ export class SubstituteNode extends SubstituteNodeBase<SubstituteNode> {
7677 return this . _disabledAssertions
7778 }
7879
79- public labelAsSubstitution ( ) : void {
80- this . _isSubstitution = true
81- }
82-
83- public enableSubstitution ( ) : void {
84- this . _hasSubstitution = true
85- }
86-
87- public labelAsAssertion ( ) : void {
88- this . _isAssertion = true
80+ public assignContext ( context : SubstituteContext ) : void {
81+ this . _context = context
8982 }
9083
9184 public disableAssertions ( ) {
9285 this . _disabledAssertions = true
9386 }
9487
9588 public read ( ) : SubstituteNode | void | never {
96- if ( this . isSubstitution ) return
89+ if ( this . parent ?. isSubstitution ?? false ) return
9790 if ( this . isAssertion ) return this . proxy
9891
9992 const mostSuitableSubstitution = this . getMostSuitableSubstitution ( )
@@ -108,7 +101,7 @@ export class SubstituteNode extends SubstituteNodeBase<SubstituteNode> {
108101 }
109102
110103 public executeSubstitution ( contextArguments : RecordedArguments ) {
111- const substitutionMethod = this . child . property as SubstitutionMethod
104+ const substitutionMethod = this . context as SubstitutionMethod
112105 const substitutionValue = this . child . recordedArguments . value . length > 1
113106 ? this . child . recordedArguments . value . shift ( )
114107 : this . child . recordedArguments . value [ 0 ]
@@ -130,8 +123,7 @@ export class SubstituteNode extends SubstituteNodeBase<SubstituteNode> {
130123 }
131124
132125 public executeAssertion ( ) : void | never {
133- const siblings = this . getAllSiblings ( ) . filter ( n => ! n . isAssertion && ! n . hasSubstitution && n . accessorType === this . accessorType ) // isSubstitution should return this.parent.hasSubstitution
134-
126+ const siblings = [ ...this . getAllSiblings ( ) . filter ( n => ! n . hasContext && n . accessorType === this . accessorType ) ]
135127 if ( ! this . isIntermediateNode ( ) ) throw new Error ( 'Not possible' )
136128
137129 const expectedCount = this . parent . recordedArguments . value [ 0 ] ?? undefined
@@ -165,40 +157,37 @@ export class SubstituteNode extends SubstituteNodeBase<SubstituteNode> {
165157 public handleMethod ( rawArguments : any [ ] ) : void {
166158 this . _propertyType = PropertyType . method
167159 this . _recordedArguments = RecordedArguments . from ( rawArguments )
160+ if ( ! isSubstituteMethod ( this . property ) ) return
168161
169- if ( ! this . disabledAssertions && isAssertionMethod ( this . property ) ) {
170- if ( this . property === 'didNotReceive' ) this . _recordedArguments = RecordedArguments . from ( [ 0 ] )
171- this . labelAsAssertion ( )
172- }
162+ if ( this . isIntermediateNode ( ) && isSubstitutionMethod ( this . property ) ) return this . parent . assignContext ( this . property )
163+ if ( this . disabledAssertions || ! this . isHead ( ) ) return
173164
174- if ( isSubstitutionMethod ( this . property ) ) {
175- this . labelAsSubstitution ( )
176- if ( this . isIntermediateNode ( ) ) this . parent . enableSubstitution ( )
177- }
165+ this . assignContext ( this . property )
166+ if ( this . context === 'didNotReceive' ) this . _recordedArguments = RecordedArguments . from ( [ 0 ] )
178167 }
179168
180169 private getMostSuitableSubstitution ( ) : SubstituteNode {
181- const nodes = this . getAllSiblings ( ) . filter ( node => node . hasSubstitution &&
170+ const nodes = this . getAllSiblings ( ) . filter ( node => node . isSubstitution &&
182171 node . propertyType === this . propertyType &&
183172 node . recordedArguments . match ( this . recordedArguments )
184173 )
185- const sortedNodes = RecordedArguments . sort ( nodes )
174+ const sortedNodes = RecordedArguments . sort ( [ ... nodes ] )
186175 return sortedNodes [ 0 ]
187176 }
188177
189178 protected printableForm ( _ : number , options : InspectOptions ) : string {
190- const isMockNode = this . hasSubstitution || this . isAssertion
179+ const hasContext = this . hasContext
191180 const args = inspect ( this . recordedArguments , options )
192- const label = this . hasSubstitution
181+ const label = this . isSubstitution
193182 ? '=> '
194183 : this . isAssertion
195184 ? `${ this . child . property . toString ( ) } `
196185 : ''
197- const s = isMockNode
198- ? ` ${ label } ${ inspect ( this . child . recordedArguments , options ) } `
186+ const s = hasContext
187+ ? ` ${ label } ${ inspect ( this . child ? .recordedArguments , options ) } `
199188 : ''
200189
201190 const printableNode = `${ this . propertyType } <${ this . property . toString ( ) } >: ${ args } ${ s } `
202- return isMockNode ? textModifier . italic ( printableNode ) : printableNode
191+ return hasContext ? textModifier . italic ( printableNode ) : printableNode
203192 }
204193}
0 commit comments