-
-
Notifications
You must be signed in to change notification settings - Fork 771
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
Fix #1274 callCount property is incorrect #1313
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What a great PR! Thank you!
After reviewing your work, I realised that there is conflicting wording between the documentation for withArgs for spies and withArgs for stubs
Creates a spy that only records calls when the received arguments match those passed to withArgs.
vs.
Stubs the method only for the provided arguments
I think that the spy
docs suggests that withArgs
will loosely match on arguments, while the stub
documentation suggests that it only matches for exact arguments (current behaviour).
The documentation should be corrected to read something like "Creates a spy that only records calls when the received arguments exactly match those passed to withArgs
"
Once the documentation has been corrected, then I think that we should consider adding a new method withArgsMatch
, that uses sinon.match()
to match arguments more widely.
Perhaps we make a decision on those questions first, before you put in more effort on this PR.
What do you think?
lib/sinon/spy.js
Outdated
@@ -308,6 +314,16 @@ var spyApi = { | |||
return fake; | |||
}, | |||
|
|||
matchingFakes: function (args, strict) { | |||
if (!this.fakes) { | |||
return undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could return an empty array, which would make it easier to write elegant consumers of the returned value
lib/sinon/spy.js
Outdated
|
||
incrementCallCount.call(this); | ||
push.call(this.thisValues, thisValue); | ||
push.call(this.args, args); | ||
push.call(this.callIds, callId++); | ||
push.call(this.callIds, currentCallId); | ||
if (matchings) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If matchingFakes
always returns arrays, then you can simplify this code (Sinon.JS codebase uses ES5.1, so the array extras are allowed).
matchings.forEach(function (matching) {
incrementCallCount.call(matchings);
push.call(matchings.thisValues, thisValue);
push.call(matchings.args, args);
push.call(matchings.callIds, currentCallId);
});
lib/sinon/spy.js
Outdated
@@ -202,6 +195,13 @@ var spyApi = { | |||
|
|||
push.call(this.exceptions, exception); | |||
push.call(this.returnValues, returnValue); | |||
if (matchings) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, assume arrays from matchingFakes
and prefer ES5.1 array extras over for
loops.
lib/sinon/spy.js
Outdated
@@ -210,6 +210,11 @@ var spyApi = { | |||
throw err; | |||
} catch (e) {/* empty */} | |||
push.call(this.errorsWithCallStack, err); | |||
if (matchings) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, assume arrays from matchingFakes
and prefer ES5.1 array extras over for
loops.
lib/sinon/spy.js
Outdated
@@ -271,10 +276,11 @@ var spyApi = { | |||
var args = slice.call(arguments); | |||
|
|||
if (this.fakes) { | |||
var match = matchingFake(this.fakes, args, true); | |||
var matchings = this.matchingFakes(args, true); | |||
var matching = matchings && matchings.pop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If matchingFakes
always returns arrays, you don't need to test for the result first, and can just use matchings.pop()
directly.
lib/sinon/stub.js
Outdated
var args = slice.call(arguments); | ||
var matchings = functionStub.matchingFakes(args); | ||
|
||
var fnStub = (matchings && matchings.pop()) || functionStub; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would also benefit if matchingFakes
always returns an Array
lib/sinon/stub.js
Outdated
@@ -70,7 +70,15 @@ var proto = { | |||
var args = slice.call(arguments); | |||
var matchings = functionStub.matchingFakes(args); | |||
|
|||
var fnStub = (matchings && matchings.pop()) || functionStub; | |||
var fnStub; | |||
if (matchings) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
matchingFakes
should always return arrays, so this test is not necessary
Hi @mroderick, If Currently, The biggest problem I think is, how priority fakes, and the best matched fake from some fakes, and return it. For Example,
In spy or stub object is above status, What returning fake is by following action?
It seems to be good that matchingFakes function always return array of fake matched. In addition, like above question 2, if sinon.match.number prior to sinon.match.any, priority must be defined in simon-matcher. first of all, I should separate |
I'm sorry, perhaps, I might have misunderstood. I see it is different from |
Hmm ... this seems to have stalled. I am not totally sure I understand where this is going. Are you waiting for some feedback, @takasmiley? Wondering about the next step to take to get this merged. |
I use sinonjs in usage like case 1, and I found this problem and fixed it. In case4 and case5 of #1274, I think that the essence of the problem is different from case1. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few missing and misplaced tests mostly.
test/issues/issues-test.js
Outdated
@@ -200,4 +200,61 @@ describe("issues", function () { | |||
assert(firstFake !== secondFake); | |||
}); | |||
}); | |||
|
|||
describe("#1274 - spy.withArgs(args...).callCount is incorrect", function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although you're fixing a bug, I believe these tests should go in their respective test files (spy, stub, etc.)
test/issues/issues-test.js
Outdated
assert.equals(spy.withArgs(1, 1).callCount, 1); | ||
assert.equals(spy.withArgs(1, 2).callCount, 1); | ||
}); | ||
it("case2: should count accurately", function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are case 1 and 2 identical? Please make the descriptions more meaningful.
@@ -308,6 +307,12 @@ var spyApi = { | |||
return fake; | |||
}, | |||
|
|||
matchingFakes: function (args, strict) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is publicly accessible now, it should be tested thoroughly.
@takasmiley As @fearphage noted, this is good to merge, except for some very minor fixes to the tests concerning some naming and location. We would love to have your work integrated into |
Thanks for such a quick turnaround! This seems to address Phreds issues. @fearphage? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@takasmiley Thank you!
@mroderick You're up.
@mroderick do you feel there is something that needs to be addressed before merging this? I never use the matchers, so I don't feel at home in the discussion on the API behavior - even after reading through it all. |
This looks good! Thank you! |
@takasmiley would you mind rebasing the branch to get rid of the merge commit at the end? |
1. Update matchingFake function in spy.js Rename to matchingFakes, and return not last one fake (pop()) but all fakes matched. 2. Move matchingFakes function into spyApi Because of calling by stub.js 3. Modify spyApi.invoke function Apply processing at function invoked to all matching fakes. 4. Modify part of calling matchingFake() in spyApi.withArgs Fit logic, affected by 1. 5. Update proto.create.functionStub in stub.js Try to get the function stub using spyApi.matchingFakes() and pop(), affected by 1.
Change last pop to the most matched arguments at stub.
Thank you for putting up with us and our prolonged process, @takasmiley 😊 |
This has been released as |
@takasmiley, it looks like this might have introduced a regression. Do you have any chance to look into the findings in #1476? We are not totally sure what is happening, but maybe you do . |
Purpose (TL;DR)
Fix issue #1274, Rewrite matchingFake in spy.js
Background (Problem in detail)
spy.withArgs
function makes fake object and storethis.fakes
, depending on the combination of arguments.And
spy.invoke
function makes use ofthis.fakes
.matchingFake
function called byspy.invoke
, returns the only one fake if arguments are matched.And
spy.invoke
update the fake properties likecallCount
.In this time, if some fakes in
this.fakes
are matched arguments, It make this issue happen.For example
Solution
Modify matchingFake to matchingFakes, and return array of all fakes matched.
invoke
function updates properties of this and all matched fakes.spy.withArgs
andstub
are affected by the above fix.spy.withArgs
Fixed to fit conventional working.Additional
I investigate around the
matchingFake
function like stub.And found case3 of #1274.
Conventionally, matchingFake return last fake (pop()).
I Fixed to fit conventional working, but case3 is not solved.
So, I commit 4e68e4d to make use of the most matched argument.
How to verify
npm install
npm test
# include test for this issue