Skip to content

Commit

Permalink
Decoupled large part of Mockito from hamcrest
Browse files Browse the repository at this point in the history
- Massive commit, sorry about this.
- Majority of the classes are now decoupled from hamcrest see (#154)
- Many TODOs are pending, specifically Mockito no longer supports hamcrest matchers which is not desired
  • Loading branch information
mockitoguy committed Jun 25, 2015
1 parent d7436bd commit 7f20e63
Show file tree
Hide file tree
Showing 59 changed files with 352 additions and 432 deletions.
2 changes: 1 addition & 1 deletion src/org/mockito/AdditionalMatchers.java
Expand Up @@ -986,7 +986,7 @@ public static float eq(float value, float delta) {
return reportMatcher(new EqualsWithDelta(value, delta)).returnZero();
}

private static HandyReturnValues reportMatcher(ArgumentMatcher<?> matcher) {
private static HandyReturnValues reportMatcher(MockitoMatcher<?> matcher) {
return MOCKING_PROGRESS.getArgumentMatcherStorage().reportMatcher(matcher);
}
}
10 changes: 4 additions & 6 deletions src/org/mockito/ArgumentCaptor.java
Expand Up @@ -38,20 +38,18 @@
* Also it may reduce defect localization because if stubbed method was not called then no argument is captured.
*
* <p>
* In a way ArgumentCaptor is related to custom argument matchers (see javadoc for {@link ArgumentMatcher} class).
* In a way ArgumentCaptor is related to custom argument matchers (see javadoc for {@link MockitoMatcher} class).
* Both techniques can be used for making sure certain arguments where passed to mocks.
* However, ArgumentCaptor may be a better fit if:
* <ul>
* <li>custom argument matcher is not likely to be reused</li>
* <li>you just need it to assert on argument values to complete verification</li>
* </ul>
* Custom argument matchers via {@link ArgumentMatcher} are usually better for stubbing.
* Custom argument matchers via {@link MockitoMatcher} are usually better for stubbing.
*
* <p>
* This utility class <strong>*don't do any type checks*</strong>, the generic signatures are only there to avoid casting
* in your code. If you want specific types, then you should do that the captured values.
* This behavior might change (type checks could be added) in a
* future major release.
* in your code.
* <p>
* There is an <strong>annotation</strong> that you might find useful: &#64;{@link Captor}
* <p>
Expand Down Expand Up @@ -94,7 +92,7 @@ private ArgumentCaptor(Class<? extends T> clazz) {
/**
* Use it to capture the argument. This method <b>must be used inside of verification</b>.
* <p>
* Internally, this method registers a special implementation of an {@link ArgumentMatcher}.
* Internally, this method registers a special implementation of an {@link MockitoMatcher}.
* This argument matcher stores the argument value so that you can use it later to perform assertions.
* <p>
* See examples in javadoc for {@link ArgumentCaptor} class.
Expand Down
8 changes: 3 additions & 5 deletions src/org/mockito/ArgumentMatcher.java
Expand Up @@ -21,19 +21,19 @@
* Use {@link Matchers#argThat} method and pass an instance of hamcrest {@link Matcher}, e.g:
*
* <pre class="code"><code class="java">
* class IsListOfTwoElements extends ArgumentMatcher&lt;List&gt; {
* class ListOfTwoElements extends ArgumentMatcher&lt;List&gt; {
* public boolean matches(Object list) {
* return ((List) list).size() == 2;
* }
* }
*
* List mock = mock(List.class);
*
* when(mock.addAll(argThat(new IsListOfTwoElements()))).thenReturn(true);
* when(mock.addAll(argThat(new IsListOfTwoElements))).thenReturn(true);
*
* mock.addAll(Arrays.asList(&quot;one&quot;, &quot;two&quot;));
*
* verify(mock).addAll(argThat(new IsListOfTwoElements()));
* verify(mock).addAll(argThat(new IsLiListOfTwoElements;
* </code></pre>
*
* To keep it readable you may want to extract method, e.g:
Expand All @@ -59,8 +59,6 @@
*/
public abstract class ArgumentMatcher<T> extends BaseMatcher<T> {

private static final long serialVersionUID = -2145234737829370369L;

/**
* Returns whether this matcher accepts the given argument.
* <p>
Expand Down
36 changes: 17 additions & 19 deletions src/org/mockito/Matchers.java
Expand Up @@ -4,7 +4,6 @@
*/
package org.mockito;

import org.hamcrest.Matcher;
import org.mockito.internal.matchers.*;
import org.mockito.internal.matchers.apachecommons.ReflectionEquals;
import org.mockito.internal.progress.HandyReturnValues;
Expand Down Expand Up @@ -52,35 +51,34 @@
*
* <h1>Custom Argument Matchers</h1>
*
* Use {@link Matchers#argThat} method and pass an instance of hamcrest {@link Matcher}.
* Use {@link Matchers#argThat} method and pass an instance of {@link MockitoMatcher}.
* <p>
* Before you start implementing your own custom argument matcher, make sure you check out {@link ArgumentCaptor} api.
* <p>
* So, how to implement your own argument matcher?
* First, you might want to subclass {@link ArgumentMatcher} which is an hamcrest matcher with predefined describeTo() method.
* Default description generated by describeTo() uses <b>decamelized class name</b> - to promote meaningful class names.
* First, you might want to subclass {@link MockitoMatcher}.
* <p>
* Example:
*
* <pre class="code"><code class="java">
* class IsListOfTwoElements extends ArgumentMatcher&lt;List&gt; {
* class ListOfTwoElements extends MockitoMatcher&lt;List&gt; {
* public boolean matches(Object list) {
* return ((List) list).size() == 2;
* }
* }
*
* List mock = mock(List.class);
*
* when(mock.addAll(argThat(new IsListOfTwoElements()))).thenReturn(true);
* when(mock.addAll(argThat(new ListOfTwoElements()))).thenReturn(true);
*
* mock.addAll(Arrays.asList("one", "two"));
*
* verify(mock).addAll(argThat(new IsListOfTwoElements()));
* verify(mock).addAll(argThat(new ListOfTwoElements()));
* </code></pre>
*
* To keep it readable you may want to extract method, e.g:
* <pre class="code"><code class="java">
* verify(mock).addAll(<b>argThat(new IsListOfTwoElements())</b>);
* verify(mock).addAll(<b>argThat(new ListOfTwoElements())</b>);
* //becomes
* verify(mock).addAll(<b>listOfTwoElements()</b>);
* </code></pre>
Expand Down Expand Up @@ -700,12 +698,12 @@ public static String startsWith(String prefix) {
* In rare cases when the parameter is a primitive then you <b>*must*</b> use relevant intThat(), floatThat(), etc. method.
* This way you will avoid <code>NullPointerException</code> during auto-unboxing.
* <p>
* See examples in javadoc for {@link ArgumentMatcher} class
* See examples in javadoc for {@link Matchers} class
*
* @param matcher decides whether argument matches
* @return <code>null</code>.
*/
public static <T> T argThat(Matcher<T> matcher) {
public static <T> T argThat(MockitoMatcher<T> matcher) {
return reportMatcher(matcher).<T>returnNull();
}

Expand All @@ -717,7 +715,7 @@ public static <T> T argThat(Matcher<T> matcher) {
* @param matcher decides whether argument matches
* @return <code>0</code>.
*/
public static char charThat(Matcher<Character> matcher) {
public static char charThat(MockitoMatcher<Character> matcher) {
return reportMatcher(matcher).returnChar();
}

Expand All @@ -729,7 +727,7 @@ public static char charThat(Matcher<Character> matcher) {
* @param matcher decides whether argument matches
* @return <code>false</code>.
*/
public static boolean booleanThat(Matcher<Boolean> matcher) {
public static boolean booleanThat(MockitoMatcher<Boolean> matcher) {
return reportMatcher(matcher).returnFalse();
}

Expand All @@ -741,7 +739,7 @@ public static boolean booleanThat(Matcher<Boolean> matcher) {
* @param matcher decides whether argument matches
* @return <code>0</code>.
*/
public static byte byteThat(Matcher<Byte> matcher) {
public static byte byteThat(MockitoMatcher<Byte> matcher) {
return reportMatcher(matcher).returnZero();
}

Expand All @@ -753,7 +751,7 @@ public static byte byteThat(Matcher<Byte> matcher) {
* @param matcher decides whether argument matches
* @return <code>0</code>.
*/
public static short shortThat(Matcher<Short> matcher) {
public static short shortThat(MockitoMatcher<Short> matcher) {
return reportMatcher(matcher).returnZero();
}

Expand All @@ -765,7 +763,7 @@ public static short shortThat(Matcher<Short> matcher) {
* @param matcher decides whether argument matches
* @return <code>0</code>.
*/
public static int intThat(Matcher<Integer> matcher) {
public static int intThat(MockitoMatcher<Integer> matcher) {
return reportMatcher(matcher).returnZero();
}

Expand All @@ -777,7 +775,7 @@ public static int intThat(Matcher<Integer> matcher) {
* @param matcher decides whether argument matches
* @return <code>0</code>.
*/
public static long longThat(Matcher<Long> matcher) {
public static long longThat(MockitoMatcher<Long> matcher) {
return reportMatcher(matcher).returnZero();
}

Expand All @@ -789,7 +787,7 @@ public static long longThat(Matcher<Long> matcher) {
* @param matcher decides whether argument matches
* @return <code>0</code>.
*/
public static float floatThat(Matcher<Float> matcher) {
public static float floatThat(MockitoMatcher<Float> matcher) {
return reportMatcher(matcher).returnZero();
}

Expand All @@ -801,11 +799,11 @@ public static float floatThat(Matcher<Float> matcher) {
* @param matcher decides whether argument matches
* @return <code>0</code>.
*/
public static double doubleThat(Matcher<Double> matcher) {
public static double doubleThat(MockitoMatcher<Double> matcher) {
return reportMatcher(matcher).returnZero();
}

private static HandyReturnValues reportMatcher(Matcher<?> matcher) {
private static HandyReturnValues reportMatcher(MockitoMatcher<?> matcher) {
return MOCKING_PROGRESS.getArgumentMatcherStorage().reportMatcher(matcher);
}
}
35 changes: 35 additions & 0 deletions src/org/mockito/MockitoMatcher.java
@@ -0,0 +1,35 @@
package org.mockito;

import org.mockito.internal.util.Decamelizer;

/**
* Matcher of arguments, decoupled from hamcrest.
*/
public abstract class MockitoMatcher<T> {

/**
* Informs if this matcher accepts the given argument.
* <p>
* The method should <b>never</b> assert if the argument doesn't match. It
* should only return false.
*
* @param argument
* the argument
* @return true if this matcher accepts the given argument.
*/
public abstract boolean matches(Object argument);

/**
* By default this method decamelizes class name to promote meaningful names for matcher classes.
* <p>
* For example <b>StringWithStrongLanguage</b> matcher will generate 'String with strong language' description in case of failure.
* <p>
* You might want to override this method to
* provide more specific description of the matcher (useful when
* verification failures are reported).
*/
public String describe() {
String className = getClass().getSimpleName();
return Decamelizer.decamelizeMatcher(className);
}
}
8 changes: 4 additions & 4 deletions src/org/mockito/internal/invocation/ArgumentsComparator.java
Expand Up @@ -4,7 +4,7 @@
*/
package org.mockito.internal.invocation;

import org.hamcrest.Matcher;
import org.mockito.MockitoMatcher;
import org.mockito.internal.matchers.MatcherDecorator;
import org.mockito.internal.matchers.VarargMatcher;
import org.mockito.invocation.Invocation;
Expand Down Expand Up @@ -39,17 +39,17 @@ private boolean varArgsMatch(InvocationMatcher invocationMatcher, Invocation act

//we must use raw arguments, not arguments...
Object[] rawArgs = actual.getRawArguments();
List<Matcher> matchers = invocationMatcher.getMatchers();
List<MockitoMatcher> matchers = invocationMatcher.getMatchers();

if (rawArgs.length != matchers.size()) {
return false;
}

for (int i = 0; i < rawArgs.length; i++) {
Matcher m = matchers.get(i);
MockitoMatcher m = matchers.get(i);
//it's a vararg because it's the last array in the arg list
if (rawArgs[i] != null && rawArgs[i].getClass().isArray() && i == rawArgs.length-1) {
Matcher actualMatcher;
MockitoMatcher actualMatcher;
//this is necessary as the framework often decorates matchers
if (m instanceof MatcherDecorator) {
actualMatcher = ((MatcherDecorator)m).getActualMatcher();
Expand Down
6 changes: 3 additions & 3 deletions src/org/mockito/internal/invocation/ArgumentsProcessor.java
Expand Up @@ -4,7 +4,7 @@
*/
package org.mockito.internal.invocation;

import org.hamcrest.Matcher;
import org.mockito.MockitoMatcher;
import org.mockito.internal.matchers.ArrayEquals;
import org.mockito.internal.matchers.Equals;
import org.mockito.internal.util.collections.ArrayUtils;
Expand Down Expand Up @@ -38,8 +38,8 @@ public static Object[] expandVarArgs(final boolean isVarArgs, final Object[] arg
return newArgs;
}

public static List<Matcher> argumentsToMatchers(Object[] arguments) {
List<Matcher> matchers = new ArrayList<Matcher>(arguments.length);
public static List<MockitoMatcher> argumentsToMatchers(Object[] arguments) {
List<MockitoMatcher> matchers = new ArrayList<MockitoMatcher>(arguments.length);
for (Object arg : arguments) {
if (arg != null && arg.getClass().isArray()) {
matchers.add(new ArrayEquals(arg));
Expand Down
21 changes: 10 additions & 11 deletions src/org/mockito/internal/invocation/InvocationMatcher.java
Expand Up @@ -5,7 +5,7 @@

package org.mockito.internal.invocation;

import org.hamcrest.Matcher;
import org.mockito.MockitoMatcher;
import org.mockito.internal.matchers.CapturesArguments;
import org.mockito.internal.matchers.MatcherDecorator;
import org.mockito.internal.reporting.PrintSettings;
Expand All @@ -21,11 +21,10 @@
@SuppressWarnings("unchecked")
public class InvocationMatcher implements DescribedInvocation, CapturesArgumentsFromInvocation, Serializable {

private static final long serialVersionUID = -3047126096857467610L;
private final Invocation invocation;
private final List<Matcher> matchers;
private final List<MockitoMatcher> matchers;

public InvocationMatcher(Invocation invocation, List<Matcher> matchers) {
public InvocationMatcher(Invocation invocation, List<MockitoMatcher> matchers) {
this.invocation = invocation;
if (matchers.isEmpty()) {
this.matchers = ArgumentsProcessor.argumentsToMatchers(invocation.getArguments());
Expand All @@ -35,7 +34,7 @@ public InvocationMatcher(Invocation invocation, List<Matcher> matchers) {
}

public InvocationMatcher(Invocation invocation) {
this(invocation, Collections.<Matcher>emptyList());
this(invocation, Collections.<MockitoMatcher>emptyList());
}

public Method getMethod() {
Expand All @@ -46,7 +45,7 @@ public Invocation getInvocation() {
return this.invocation;
}

public List<Matcher> getMatchers() {
public List<MockitoMatcher> getMatchers() {
return this.matchers;
}

Expand Down Expand Up @@ -122,7 +121,7 @@ public void captureArgumentsFrom(Invocation invocation) {

private void captureRegularArguments(Invocation invocation) {
for (int position = 0; position < regularArgumentsSize(invocation); position++) {
Matcher m = matchers.get(position);
MockitoMatcher m = matchers.get(position);
if (m instanceof CapturesArguments) {
((CapturesArguments) m).captureFrom(invocation.getArgumentAt(position, Object.class));
}
Expand All @@ -134,7 +133,7 @@ private void captureVarargsPart(Invocation invocation) {
return;
}
int indexOfVararg = invocation.getRawArguments().length - 1;
for (Matcher m : uniqueMatcherSet(indexOfVararg)) {
for (MockitoMatcher m : uniqueMatcherSet(indexOfVararg)) {
if (m instanceof CapturesArguments) {
Object rawArgument = invocation.getRawArguments()[indexOfVararg];
for (int i = 0; i < Array.getLength(rawArgument); i++) {
Expand All @@ -150,10 +149,10 @@ private int regularArgumentsSize(Invocation invocation) {
: matchers.size();
}

private Set<Matcher> uniqueMatcherSet(int indexOfVararg) {
HashSet<Matcher> set = new HashSet<Matcher>();
private Set<MockitoMatcher> uniqueMatcherSet(int indexOfVararg) {
HashSet<MockitoMatcher> set = new HashSet<MockitoMatcher>();
for (int position = indexOfVararg; position < matchers.size(); position++) {
Matcher matcher = matchers.get(position);
MockitoMatcher matcher = matchers.get(position);
if (matcher instanceof MatcherDecorator) {
set.add(((MatcherDecorator) matcher).getActualMatcher());
} else {
Expand Down
6 changes: 2 additions & 4 deletions src/org/mockito/internal/invocation/MatchersBinder.java
Expand Up @@ -5,7 +5,7 @@

package org.mockito.internal.invocation;

import org.hamcrest.Matcher;
import org.mockito.MockitoMatcher;
import org.mockito.exceptions.Reporter;
import org.mockito.internal.matchers.LocalizedMatcher;
import org.mockito.internal.progress.ArgumentMatcherStorage;
Expand All @@ -17,13 +17,11 @@
@SuppressWarnings("unchecked")
public class MatchersBinder implements Serializable {

private static final long serialVersionUID = -311433939339443463L;

public InvocationMatcher bindMatchers(ArgumentMatcherStorage argumentMatcherStorage, Invocation invocation) {
List<LocalizedMatcher> lastMatchers = argumentMatcherStorage.pullLocalizedMatchers();
validateMatchers(invocation, lastMatchers);

InvocationMatcher invocationWithMatchers = new InvocationMatcher(invocation, (List<Matcher>)(List) lastMatchers);
InvocationMatcher invocationWithMatchers = new InvocationMatcher(invocation, (List<MockitoMatcher>)(List) lastMatchers);
return invocationWithMatchers;
}

Expand Down

0 comments on commit 7f20e63

Please sign in to comment.