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 issue #1222 and #584 #1224
Fix issue #1222 and #584 #1224
Conversation
Codecov Report
@@ Coverage Diff @@
## release/2.x #1224 +/- ##
=================================================
+ Coverage 87.27% 87.34% +0.07%
- Complexity 2305 2321 +16
=================================================
Files 287 288 +1
Lines 5869 5905 +36
Branches 703 709 +6
=================================================
+ Hits 5122 5158 +36
Misses 556 556
Partials 191 191
Continue to review full report at Codecov.
|
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.
Ah cool that you were able to figure it out. Thanks a lot for the investigation and effort to create a fix @paulduffin! The implementation SFTM, but I would like either @mockitoguy or @bric3 to sign off on this logic, as they were involved in earlier changes in this code part.
I am working on fixing the code coverage problem and adding some more tests for TreatsVarargsAsArray. |
Code coverage seems mostly concerned regarding the boilerplate |
Adds a new method varargsAsArray(...) that indicates that the varargs should be matched/captured as a single array rather than separate values.
590eed7
to
be0cd33
Compare
I would like to see some test cases too, to get a feel for the API in corner cases
|
I did add some more tests after the first upload. Do you want even more? |
In the end the mockito-core members or you decide! I am as you a contributor and can only give the advices to add more non-happy-path tests. Last year I looked into the this issue and other related varargs, capturing and matching issues. Which leaded to some refactorings, regarding the whole capturing and matching process. The
Here is some other interesting test case:
|
Looking at it! |
Somewhere it should be checked that this new matcher is only allowed to be placed as last-arg of a vararg call. |
Hey guys! This is a great discussion, thank you @TimvdLippe for bringing me in! @paulduffin, this PR is conceivable! Before we merge it let's make an attempt to solve the use case more conveniently for our users. @ChristianSchwarz, can you comment on #1235? I prototyped/hacked the implementation so that the use case is handled by Mockito out of the box. Can you point out gaps / add tests that demonstrate gaps? PR #1235 makes both types of syntax work (and all existing Mockito tests are passing): mock.mixedVarargs("1", "2", "3");
//traditional verify with varargs, same number of args
verify(mock).mixedVarargs(any(), eq("2"), eq("3"));
//new matching, using an array
verify(mock).mixedVarargs(any(), eq(new String[] {"2", "3"}));
verify(mock).mixedVarargs(any(), (String[]) any()); Thanks everyone for working on this use case! |
@paulduffin Some puzzelz, but they are solvable... @Test
public void shouldNoWorkOnNonVarargParameter_argOfTypeString() {
exception.expect(MockitoException.class);
exception.expectMessage("varargsAsArray(..) is only allowed on vararg parameters");
when(mock.simpleMethod(varargsAsArray(eq("")))).thenReturn("");
}
@Test
public void shouldNoWorkOnNonVarargParameter_argOfTypeStringArray() {
exception.expect(MockitoException.class);
exception.expectMessage("varargsAsArray(..) is only allowed on vararg parameters, actual parameter is of type: String");
when(mock.simpleMethod("",varargsAsArray(eq(new String[0])))).thenReturn("");
}
@Test
public void shouldNoWorkOnNonVarargParameter_argOfTypeStringArray2() {
exception.expect(MockitoException.class);
exception.expectMessage("varargsAsArray(..) is only allowed on vararg parameters, actual parameter is of type: String[]");
when(mock.simpleMethod("",varargsAsArray(new String[0]))).thenReturn("");
}
@Test
public void shouldNotCompile() {
when(mock.intArgumentReturningInt(varargsAsArray(0))).thenReturn(1);
}
@Test
public void shouldConvertRawValuesToEqualsMatcher() {
when(mock.varargsReturningString(varargsAsArray(0))).thenReturn("");
} |
They could all cause a compile error as long as the code was compiled with Error Prone and a suitable Error Prone checker was written for it. Otherwise, the only choice is to have them as runtime errors. Preventing it being used with non-vararg and non-array parameters could be done by having it return T[] instead of T. Unfortunately, that will not work with primitive varargs. e.g. if the parameter was int... then varargsAsArray(eq(new int[] {1})) would have to return int[] but T[] cannot be assigned to int[] because T cannot be primitive. The closest it can be is Integer and Integer[] is not assignable to int[]. That would require primitive specializations of varargsAsArray, e.g. varargsAsIntArray, etc. |
Thank you for explaining the PR here and in #1235. It is immensely helpful. My feedback:
I'm doing the review of the code now. |
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.
I love it. Can you consider my feedback? If you can improve the PR using small, separate commits it will be really easy to review the delta.
I suggested improvements but the change is really good! Looking forward to merging!!!
@@ -1317,6 +1320,24 @@ public static double doubleThat(ArgumentMatcher<Double> matcher) { | |||
return 0; | |||
} | |||
|
|||
/** | |||
* Indicates that the varargs should be matched as an array rather than individual values. |
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.
Nit: "individual values" -> "individual value"
* | ||
* The value must be specified as a call to a method for matching an argument, e.g. | ||
* {@link #eq(Object)} or {@link ArgumentCaptor#capture()}. Failure to do so will result in | ||
* either an {@link EmptyStackException} or an {@link InvalidUseOfMatchersException}. |
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.
Can you add a unit test for this behavior? Let's see how the unit test looks like and what is the user experience. If the user experience is not great, can we offer a clean exception describing API misuse?
* {@code captor.capture()} | ||
* @param <T> the type of the vararg or array of varargs | ||
* @return {@code null} | ||
*/ |
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 feature is really cool and it deserves new minor version. Can you add "since" tag to the Javadoc with the next minor version? Also, let's update the "version.properties" file accordingly!
* The value must be specified as a call to a method for matching an argument, e.g. | ||
* {@link #eq(Object)} or {@link ArgumentCaptor#capture()}. Failure to do so will result in | ||
* either an {@link EmptyStackException} or an {@link InvalidUseOfMatchersException}. | ||
* |
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.
Can you add code sample to the Javadoc in a similar way we do it for other main public methods?
@@ -91,21 +93,35 @@ private static MatcherApplicationType getMatcherApplicationType(Invocation invoc | |||
final int expandedArguments = invocation.getArguments().length; | |||
final int matcherCount = matchers.size(); | |||
|
|||
boolean treatVarargsAsArray = false; |
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.
Wow. I'm very impressed that you were able to inject the new algorithm here. The code is pretty complex around here. I'd love to see it refactored at some point in the future.
It is complex but you have added fantastic test coverage that I was not able to break down :)
@@ -115,4 +115,49 @@ public void shouldDetectWhenOverloadedMethodCalled() throws Exception { | |||
fail(); | |||
} catch(WantedButNotInvoked e) {} | |||
} | |||
|
|||
@Test | |||
public void shouldVerifyVarargsAsArray_nullVarargsArray() throws Exception { |
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.
Can you move those tests to a better place? "BasicVerification" is for basic operations. I suggest to move them to existing VarargTest or create a new one like VarargAsArrayTest.
BTW. thank you very much for adding truly comprehensive test coverage!!!
|
||
mock.mixedVarargs(null, (String[]) null); | ||
|
||
verify(mock).mixedVarargs(any(), varargsAsArray(eq((String[]) null))); |
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.
Can you add coverage for negative cases, e.g. when verification error is thrown for use cases with "varargsAsArray"? This would also help us see the exception message emitted from Mockito, and if the message is handsome.
@@ -1317,6 +1320,24 @@ public static double doubleThat(ArgumentMatcher<Double> matcher) { | |||
return 0; | |||
} | |||
|
|||
/** |
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.
Can you add a new point to the main Mockito Javadoc with a short description of the feature? This is a really cool feature and it deserves a note in main Javadoc. That doc acts as Mockito user guide and also shows notable features. Feel free to bump new minor version.
@paulduffin @mockitoguy Would love to get this into a release version of Mockito! Can I help address some of the issues that @mockitoguy identified perhaps so we can finish it off? |
@mockitoguy |
Apologies for not getting back sooner on this. Things are crazy at work at
the minute. If someone else wants to address the issues that would be
really helpful.
…On 26 February 2018 at 11:34, Tim van der Lippe ***@***.***> wrote:
@ChristianSchwarz <https://github.com/christianschwarz>
https://github.com/mockito/mockito/tree/capture-vararg-as-array published
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1224 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AEtcQ1CRM51GfoNG8LxKpozcsRvGWGwoks5tYpbIgaJpZM4QHnXV>
.
|
@mockitoguy |
Closing this PR as stale. Feel free to open a new PR if you are still interested in landing these changes. |
Adds a new method varargsAsArray(...) that indicates that the varargs
should be matched/captured as a single array rather than separate
values.
Fixes #1222
Fixes #584