Skip to content

Commit

Permalink
Fixes mockito#2311
Browse files Browse the repository at this point in the history
Made changes to Equals.toStringWithType by reusing same method to achieve both cases by sending a boolean as an input, based on which either simple name or fully qualified name will be used for describing the type.

Also in the method ArgumentMatchingTool.getNotMatchingArgsWithSameName return Set<String> which return the simple names of classes having more than one classes with different FQCN.
  • Loading branch information
thisisdexter committed Jun 13, 2021
1 parent d544cfc commit 446c5fe
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 61 deletions.
Expand Up @@ -9,29 +9,25 @@
* When ArgumentMatcher fails, chance is that the actual object has the same output of toString() than
* the wanted object. This looks weird when failures are reported.
* Therefore when matcher fails but toString() yields the same outputs,
* we will try to use the {@link #toStringWithType()} method.
* we will try to use the {@link #toStringWithType(boolean)} method.
*/
public interface ContainsExtraTypeInfo {

/**
* @param useFullyQualifiedClassName - uses fully qualified class name if true else simple class name
* Returns more verbose description of the object which include type information
*/
String toStringWithType();

/**
* Returns more verbose description of the object which include type information and fully qualified class name
*/
String toStringWithFullName();
String toStringWithType(boolean useFullyQualifiedClassName);

/**
* Checks if target target has matching type.
* If the type matches, there is no point in rendering result from {@link #toStringWithType()}
* If the type matches, there is no point in rendering result from {@link #toStringWithType(boolean)}
*/
boolean typeMatches(Object target);

/**
* Checks if target target's class has same simple name.
* If the simple names matches, we need to use {@link #toStringWithFullName()}
*
* @return Returns the Class of the argument
*/
boolean sameName(Object target);
Class getWantedClass();
}
14 changes: 5 additions & 9 deletions src/main/java/org/mockito/internal/matchers/Equals.java
Expand Up @@ -51,13 +51,8 @@ public int hashCode() {
}

@Override
public String toStringWithType() {
return "(" + wanted.getClass().getSimpleName() + ") " + describe(wanted);
}

@Override
public String toStringWithFullName() {
return "(" + wanted.getClass().getCanonicalName() + ") " + describe(wanted);
public String toStringWithType(boolean useFullyQualifiedClassName) {
return "(" + (useFullyQualifiedClassName ? wanted.getClass().getCanonicalName() : wanted.getClass().getSimpleName()) + ") " + describe(wanted);
}

@Override
Expand All @@ -66,7 +61,8 @@ public boolean typeMatches(Object target) {
}

@Override
public boolean sameName(Object target) {
return wanted != null && target != null && target.getClass().getSimpleName().equals(wanted.getClass().getSimpleName());
public Class getWantedClass() {
return wanted.getClass();
}

}
Expand Up @@ -31,9 +31,10 @@ private Iterator<FormattedText> applyPrintSettings(
int i = 0;
for (final ArgumentMatcher matcher : matchers) {
if (matcher instanceof ContainsExtraTypeInfo && printSettings.extraTypeInfoFor(i)) {
out.add(new FormattedText(((ContainsExtraTypeInfo) matcher).toStringWithType()));
} else if(matcher instanceof ContainsExtraTypeInfo && printSettings.fullyQualifiedNameFor(i)){
out.add(new FormattedText(((ContainsExtraTypeInfo) matcher).toStringWithFullName()));
out.add(new FormattedText(((ContainsExtraTypeInfo) matcher).toStringWithType(false)));
} else if(matcher instanceof ContainsExtraTypeInfo
&& printSettings.fullyQualifiedNameFor(((ContainsExtraTypeInfo) matcher).getWantedClass().getSimpleName())){
out.add(new FormattedText(((ContainsExtraTypeInfo) matcher).toStringWithType(true)));
} else {
out.add(new FormattedText(MatcherToString.toString(matcher)));
}
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/org/mockito/internal/reporting/PrintSettings.java
Expand Up @@ -5,8 +5,10 @@
package org.mockito.internal.reporting;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.mockito.ArgumentMatcher;
import org.mockito.internal.matchers.text.MatchersPrinter;
Expand All @@ -19,7 +21,7 @@ public class PrintSettings {
public static final int MAX_LINE_LENGTH = 45;
private boolean multiline;
private List<Integer> withTypeInfo = new LinkedList<>();
private List<Integer> withFullyQualifiedName = new LinkedList<>();
private Set<String> withFullyQualifiedName = Collections.emptySet();

public void setMultiline(boolean multiline) {
this.multiline = multiline;
Expand All @@ -39,16 +41,16 @@ public boolean extraTypeInfoFor(int argumentIndex) {
return withTypeInfo.contains(argumentIndex);
}

public boolean fullyQualifiedNameFor(int argumentIndex) {
return withFullyQualifiedName.contains(argumentIndex);
public boolean fullyQualifiedNameFor(String simpleClassName) {
return withFullyQualifiedName.contains(simpleClassName);
}

public void setMatchersToBeDescribedWithExtraTypeInfo(Integer[] indexesOfMatchers) {
this.withTypeInfo = Arrays.asList(indexesOfMatchers);
}

public void setMatchersToBeDescribedWithFullName(Integer[] indexesOfMatchers) {
this.withFullyQualifiedName= Arrays.asList(indexesOfMatchers);
public void setMatchersToBeDescribedWithFullName(Set<String> indexesOfMatchers) {
this.withFullyQualifiedName= indexesOfMatchers;
}

public String print(List<ArgumentMatcher> matchers, Invocation invocation) {
Expand Down
Expand Up @@ -7,6 +7,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.mockito.invocation.Invocation;
import org.mockito.invocation.MatchableInvocation;
Expand All @@ -29,20 +30,20 @@ public SmartPrinter(
wanted,
Collections.singletonList(actual),
indexesOfMatchersToBeDescribedWithExtraTypeInfo,
new Integer[0]);
Collections.emptySet());
}

public SmartPrinter(
MatchableInvocation wanted,
List<Invocation> allActualInvocations,
Integer[] indexesOfMatchersToBeDescribedWithExtraTypeInfo,
Integer[] indexesOfMatchersToBeDescribedWithFullName) {
Set<String> classNamesToBeDescribedWithFullName) {
PrintSettings printSettings = new PrintSettings();
printSettings.setMultiline(isMultiLine(wanted, allActualInvocations));
printSettings.setMatchersToBeDescribedWithExtraTypeInfo(
indexesOfMatchersToBeDescribedWithExtraTypeInfo);
printSettings.setMatchersToBeDescribedWithFullName(
indexesOfMatchersToBeDescribedWithFullName);
classNamesToBeDescribedWithFullName);

this.wanted = printSettings.print(wanted);

Expand Down
Expand Up @@ -4,8 +4,13 @@
*/
package org.mockito.internal.verification.argumentmatching;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.mockito.ArgumentMatcher;
import org.mockito.internal.matchers.ContainsExtraTypeInfo;
Expand Down Expand Up @@ -52,24 +57,26 @@ private static boolean toStringEquals(ArgumentMatcher m, Object arg) {
/**
* Suspiciously not matching arguments are those that don't match, and the classes have same simple name.
*/
public static Integer[] getNotMatchingArgsWithSameNameIndexes(
List<ArgumentMatcher> matchers, Object[] arguments) {
if (matchers.size() != arguments.length) {
return new Integer[0];
}

List<Integer> suspicious = new LinkedList<>();
int i = 0;
public static Set<String> getNotMatchingArgsWithSameName(
List<ArgumentMatcher> matchers, Object[] arguments) {
Set<String> repeatedClassNames = new HashSet<>();
Map<String, Set<String>> classesHavingSameName = new HashMap<>();
for (ArgumentMatcher m : matchers) {
if (m instanceof ContainsExtraTypeInfo
&& !safelyMatches(m, arguments[i])
&& !((ContainsExtraTypeInfo) m).typeMatches(arguments[i])
&& ((ContainsExtraTypeInfo) m).sameName(arguments[i])) {
suspicious.add(i);
if (m instanceof ContainsExtraTypeInfo) {
Class wantedClass = ((ContainsExtraTypeInfo) m).getWantedClass();
classesHavingSameName.computeIfAbsent(wantedClass.getSimpleName(), className -> new HashSet<>())
.add(wantedClass.getCanonicalName());
}
i++;
}
return suspicious.toArray(new Integer[0]);
for (Object argument : arguments) {
Class wantedClass = argument.getClass();
classesHavingSameName.computeIfAbsent(wantedClass.getSimpleName(), className -> new HashSet<>())
.add(wantedClass.getCanonicalName());
}
return classesHavingSameName.entrySet().stream()
.filter(classEntry -> classEntry.getValue().size() > 1)
.map(classEntry -> classEntry.getKey())
.collect(Collectors.toSet());
}

}
Expand Up @@ -11,10 +11,11 @@
import static org.mockito.internal.invocation.InvocationsFinder.findInvocations;
import static org.mockito.internal.invocation.InvocationsFinder.findPreviousVerifiedInOrder;
import static org.mockito.internal.invocation.InvocationsFinder.findSimilarInvocation;
import static org.mockito.internal.verification.argumentmatching.ArgumentMatchingTool.getNotMatchingArgsWithSameNameIndexes;
import static org.mockito.internal.verification.argumentmatching.ArgumentMatchingTool.getNotMatchingArgsWithSameName;
import static org.mockito.internal.verification.argumentmatching.ArgumentMatchingTool.getSuspiciouslyNotMatchingArgsIndexes;

import java.util.List;
import java.util.Set;

import org.mockito.internal.reporting.SmartPrinter;
import org.mockito.internal.util.collections.ListUtil;
Expand Down Expand Up @@ -42,9 +43,9 @@ public static void checkMissingInvocation(

Integer[] indexesOfSuspiciousArgs =
getSuspiciouslyNotMatchingArgsIndexes(wanted.getMatchers(), similar.getArguments());
Integer[] indexesOfArgsWithSameSimpleName =
getNotMatchingArgsWithSameNameIndexes(wanted.getMatchers(), similar.getArguments());
SmartPrinter smartPrinter = new SmartPrinter(wanted, invocations, indexesOfSuspiciousArgs,indexesOfArgsWithSameSimpleName);
Set<String> classesWithSameSimpleName =
getNotMatchingArgsWithSameName(wanted.getMatchers(), similar.getArguments());
SmartPrinter smartPrinter = new SmartPrinter(wanted, invocations, indexesOfSuspiciousArgs,classesWithSameSimpleName);
List<Location> actualLocations =
ListUtil.convert(
invocations,
Expand Down
6 changes: 3 additions & 3 deletions src/test/java/org/mockito/internal/matchers/EqualsTest.java
Expand Up @@ -28,21 +28,21 @@ public void shouldArraysBeEqual() {

@Test
public void shouldDescribeWithExtraTypeInfo() throws Exception {
String descStr = new Equals(100).toStringWithType();
String descStr = new Equals(100).toStringWithType(false);

assertEquals("(Integer) 100", descStr);
}

@Test
public void shouldDescribeWithExtraTypeInfoOfLong() throws Exception {
String descStr = new Equals(100L).toStringWithType();
String descStr = new Equals(100L).toStringWithType(false);

assertEquals("(Long) 100L", descStr);
}

@Test
public void shouldDescribeWithTypeOfString() throws Exception {
String descStr = new Equals("x").toStringWithType();
String descStr = new Equals("x").toStringWithType(false);

assertEquals("(String) \"x\"", descStr);
}
Expand Down
Expand Up @@ -111,12 +111,7 @@ public boolean matches(String item) {
}

@Override
public String toStringWithType() {
return "";
}

@Override
public String toStringWithFullName() {
public String toStringWithType(boolean useFullyQualifiedClassName) {
return "";
}

Expand All @@ -126,8 +121,8 @@ public boolean typeMatches(Object target) {
}

@Override
public boolean sameName(Object target) {
return true;
public Class getWantedClass() {
return String.class;
}

}
Expand Down

0 comments on commit 446c5fe

Please sign in to comment.