Skip to content

Commit 5025d00

Browse files
authored
Avoid return and callArg* clearing each other's state (#2593)
* Add regression test for #2572 * Partially revert "fix returns does not override call through (#2567)" This partially reverts commit 5fde5ae: - we keep the tests - revert to the old manual clearing of props The clearing of callThrough has then been manually added to what I deem are the relevant spots. Tests are unaltered.
1 parent ed068a8 commit 5025d00

File tree

2 files changed

+98
-71
lines changed

2 files changed

+98
-71
lines changed

lib/sinon/default-behaviors.js

+74-71
Original file line numberDiff line numberDiff line change
@@ -30,150 +30,138 @@ function throwsException(fake, error, message) {
3030
}
3131
}
3232

33-
const SKIP_OPTIONS_FOR_YIELDS = {
34-
skipReturn: true,
35-
skipThrows: true,
36-
};
37-
38-
function clear(fake, options) {
39-
fake.fakeFn = undefined;
40-
41-
fake.callsThrough = undefined;
42-
fake.callsThroughWithNew = undefined;
43-
44-
if (!options || !options.skipThrows) {
45-
fake.exception = undefined;
46-
fake.exceptionCreator = undefined;
47-
fake.throwArgAt = undefined;
48-
}
49-
50-
fake.callArgAt = undefined;
51-
fake.callbackArguments = undefined;
52-
fake.callbackContext = undefined;
53-
fake.callArgProp = undefined;
54-
fake.callbackAsync = undefined;
55-
56-
if (!options || !options.skipReturn) {
57-
fake.returnValue = undefined;
58-
fake.returnValueDefined = undefined;
59-
fake.returnArgAt = undefined;
60-
fake.returnThis = undefined;
61-
}
62-
63-
fake.resolve = undefined;
64-
fake.resolveThis = undefined;
65-
fake.resolveArgAt = undefined;
66-
67-
fake.reject = undefined;
68-
}
69-
7033
const defaultBehaviors = {
7134
callsFake: function callsFake(fake, fn) {
72-
clear(fake);
73-
7435
fake.fakeFn = fn;
36+
fake.exception = undefined;
37+
fake.exceptionCreator = undefined;
38+
fake.callsThrough = false;
7539
},
7640

7741
callsArg: function callsArg(fake, index) {
7842
if (typeof index !== "number") {
7943
throw new TypeError("argument index is not number");
8044
}
81-
clear(fake);
8245

8346
fake.callArgAt = index;
8447
fake.callbackArguments = [];
48+
fake.callbackContext = undefined;
49+
fake.callArgProp = undefined;
50+
fake.callbackAsync = false;
51+
fake.callsThrough = false;
8552
},
8653

8754
callsArgOn: function callsArgOn(fake, index, context) {
8855
if (typeof index !== "number") {
8956
throw new TypeError("argument index is not number");
9057
}
91-
clear(fake);
9258

9359
fake.callArgAt = index;
9460
fake.callbackArguments = [];
9561
fake.callbackContext = context;
62+
fake.callArgProp = undefined;
63+
fake.callbackAsync = false;
64+
fake.callsThrough = false;
9665
},
9766

9867
callsArgWith: function callsArgWith(fake, index) {
9968
if (typeof index !== "number") {
10069
throw new TypeError("argument index is not number");
10170
}
102-
clear(fake);
10371

10472
fake.callArgAt = index;
10573
fake.callbackArguments = slice(arguments, 2);
74+
fake.callbackContext = undefined;
75+
fake.callArgProp = undefined;
76+
fake.callbackAsync = false;
77+
fake.callsThrough = false;
10678
},
10779

10880
callsArgOnWith: function callsArgWith(fake, index, context) {
10981
if (typeof index !== "number") {
11082
throw new TypeError("argument index is not number");
11183
}
112-
clear(fake);
11384

11485
fake.callArgAt = index;
11586
fake.callbackArguments = slice(arguments, 3);
11687
fake.callbackContext = context;
88+
fake.callArgProp = undefined;
89+
fake.callbackAsync = false;
90+
fake.callsThrough = false;
11791
},
11892

11993
usingPromise: function usingPromise(fake, promiseLibrary) {
12094
fake.promiseLibrary = promiseLibrary;
12195
},
12296

12397
yields: function (fake) {
124-
clear(fake, SKIP_OPTIONS_FOR_YIELDS);
125-
12698
fake.callArgAt = useLeftMostCallback;
12799
fake.callbackArguments = slice(arguments, 1);
100+
fake.callbackContext = undefined;
101+
fake.callArgProp = undefined;
102+
fake.callbackAsync = false;
103+
fake.fakeFn = undefined;
104+
fake.callsThrough = false;
128105
},
129106

130107
yieldsRight: function (fake) {
131-
clear(fake, SKIP_OPTIONS_FOR_YIELDS);
132-
133108
fake.callArgAt = useRightMostCallback;
134109
fake.callbackArguments = slice(arguments, 1);
110+
fake.callbackContext = undefined;
111+
fake.callArgProp = undefined;
112+
fake.callbackAsync = false;
113+
fake.callsThrough = false;
114+
fake.fakeFn = undefined;
135115
},
136116

137117
yieldsOn: function (fake, context) {
138-
clear(fake, SKIP_OPTIONS_FOR_YIELDS);
139-
140118
fake.callArgAt = useLeftMostCallback;
141119
fake.callbackArguments = slice(arguments, 2);
142120
fake.callbackContext = context;
121+
fake.callArgProp = undefined;
122+
fake.callbackAsync = false;
123+
fake.callsThrough = false;
124+
fake.fakeFn = undefined;
143125
},
144126

145127
yieldsTo: function (fake, prop) {
146-
clear(fake, SKIP_OPTIONS_FOR_YIELDS);
147-
148128
fake.callArgAt = useLeftMostCallback;
149129
fake.callbackArguments = slice(arguments, 2);
130+
fake.callbackContext = undefined;
150131
fake.callArgProp = prop;
132+
fake.callbackAsync = false;
133+
fake.callsThrough = false;
134+
fake.fakeFn = undefined;
151135
},
152136

153137
yieldsToOn: function (fake, prop, context) {
154-
clear(fake, SKIP_OPTIONS_FOR_YIELDS);
155-
156138
fake.callArgAt = useLeftMostCallback;
157139
fake.callbackArguments = slice(arguments, 3);
158140
fake.callbackContext = context;
159141
fake.callArgProp = prop;
142+
fake.callbackAsync = false;
143+
fake.fakeFn = undefined;
160144
},
161145

162146
throws: throwsException,
163147
throwsException: throwsException,
164148

165149
returns: function returns(fake, value) {
166-
clear(fake);
167-
150+
fake.callsThrough = false;
168151
fake.returnValue = value;
152+
fake.resolve = false;
153+
fake.reject = false;
169154
fake.returnValueDefined = true;
155+
fake.exception = undefined;
156+
fake.exceptionCreator = undefined;
157+
fake.fakeFn = undefined;
170158
},
171159

172160
returnsArg: function returnsArg(fake, index) {
173161
if (typeof index !== "number") {
174162
throw new TypeError("argument index is not number");
175163
}
176-
clear(fake);
164+
fake.callsThrough = false;
177165

178166
fake.returnArgAt = index;
179167
},
@@ -182,33 +170,42 @@ const defaultBehaviors = {
182170
if (typeof index !== "number") {
183171
throw new TypeError("argument index is not number");
184172
}
185-
clear(fake);
173+
fake.callsThrough = false;
186174

187175
fake.throwArgAt = index;
188176
},
189177

190178
returnsThis: function returnsThis(fake) {
191-
clear(fake);
192-
193179
fake.returnThis = true;
180+
fake.callsThrough = false;
194181
},
195182

196183
resolves: function resolves(fake, value) {
197-
clear(fake);
198-
199184
fake.returnValue = value;
200185
fake.resolve = true;
186+
fake.resolveThis = false;
187+
fake.reject = false;
201188
fake.returnValueDefined = true;
189+
fake.exception = undefined;
190+
fake.exceptionCreator = undefined;
191+
fake.fakeFn = undefined;
192+
fake.callsThrough = false;
202193
},
203194

204195
resolvesArg: function resolvesArg(fake, index) {
205196
if (typeof index !== "number") {
206197
throw new TypeError("argument index is not number");
207198
}
208-
clear(fake);
209-
210199
fake.resolveArgAt = index;
200+
fake.returnValue = undefined;
211201
fake.resolve = true;
202+
fake.resolveThis = false;
203+
fake.reject = false;
204+
fake.returnValueDefined = false;
205+
fake.exception = undefined;
206+
fake.exceptionCreator = undefined;
207+
fake.fakeFn = undefined;
208+
fake.callsThrough = false;
212209
},
213210

214211
rejects: function rejects(fake, error, message) {
@@ -221,30 +218,36 @@ const defaultBehaviors = {
221218
} else {
222219
reason = error;
223220
}
224-
clear(fake);
225-
226221
fake.returnValue = reason;
222+
fake.resolve = false;
223+
fake.resolveThis = false;
227224
fake.reject = true;
228225
fake.returnValueDefined = true;
226+
fake.exception = undefined;
227+
fake.exceptionCreator = undefined;
228+
fake.fakeFn = undefined;
229+
fake.callsThrough = false;
229230

230231
return fake;
231232
},
232233

233234
resolvesThis: function resolvesThis(fake) {
234-
clear(fake);
235-
235+
fake.returnValue = undefined;
236+
fake.resolve = false;
236237
fake.resolveThis = true;
238+
fake.reject = false;
239+
fake.returnValueDefined = false;
240+
fake.exception = undefined;
241+
fake.exceptionCreator = undefined;
242+
fake.fakeFn = undefined;
243+
fake.callsThrough = false;
237244
},
238245

239246
callThrough: function callThrough(fake) {
240-
clear(fake);
241-
242247
fake.callsThrough = true;
243248
},
244249

245250
callThroughWithNew: function callThroughWithNew(fake) {
246-
clear(fake);
247-
248251
fake.callsThroughWithNew = true;
249252
},
250253

test/issues/issues-test.js

+24
Original file line numberDiff line numberDiff line change
@@ -914,4 +914,28 @@ describe("issues", function () {
914914
object.prop;
915915
assert.equals(spy.get.callCount, 1); // should remain unchanged
916916
});
917+
918+
it("#2572 - returns should not clear callsArgWith", function () {
919+
const stub = sinon.stub();
920+
stub.callsArgWith(0, "Hello").returns("World");
921+
922+
const cb = sinon.stub();
923+
const ret = stub(cb);
924+
925+
assert.equals(ret, "World");
926+
assert(cb.calledOnce);
927+
assert.equals(cb.firstCall.args, ["Hello"]);
928+
});
929+
930+
it("#2572 - callsArgWith should not clear returns", function () {
931+
const stub = sinon.stub();
932+
stub.returns("World").callsArgWith(0, "Hello");
933+
934+
const cb = sinon.stub();
935+
const ret = stub(cb);
936+
937+
assert.equals(ret, "World");
938+
assert(cb.calledOnce);
939+
assert.equals(cb.firstCall.args, ["Hello"]);
940+
});
917941
});

0 commit comments

Comments
 (0)